Bug 1318955 - Upgrade to Hunspell 1.5.0. r=masayuki
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 12 Jul 2016 10:37:04 -0400
changeset 323447 25c7efa29d66e8551572de9a4cbb9a6842bb578d
parent 323446 59375acb5ae8b4fdaba7fe649c25826e48536792
child 323448 99a644129efaaf128b30450a5d132a2059da3c98
push id84141
push userryanvm@gmail.com
push dateMon, 21 Nov 2016 04:50:01 +0000
treeherdermozilla-inbound@99a644129efa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmasayuki
bugs1318955
milestone53.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1318955 - Upgrade to Hunspell 1.5.0. r=masayuki
extensions/spellcheck/hunspell/glue/moz.build
extensions/spellcheck/hunspell/glue/mozHunspell.cpp
extensions/spellcheck/hunspell/glue/mozHunspell.h
extensions/spellcheck/hunspell/src/README.mozilla
extensions/spellcheck/hunspell/src/affentry.cxx
extensions/spellcheck/hunspell/src/affentry.hxx
extensions/spellcheck/hunspell/src/affixmgr.cxx
extensions/spellcheck/hunspell/src/affixmgr.hxx
extensions/spellcheck/hunspell/src/atypes.hxx
extensions/spellcheck/hunspell/src/baseaffix.hxx
extensions/spellcheck/hunspell/src/csutil.cxx
extensions/spellcheck/hunspell/src/csutil.hxx
extensions/spellcheck/hunspell/src/filemgr.cxx
extensions/spellcheck/hunspell/src/filemgr.hxx
extensions/spellcheck/hunspell/src/hashmgr.cxx
extensions/spellcheck/hunspell/src/hashmgr.hxx
extensions/spellcheck/hunspell/src/htypes.hxx
extensions/spellcheck/hunspell/src/hunspell.cxx
extensions/spellcheck/hunspell/src/hunspell.h
extensions/spellcheck/hunspell/src/hunspell.hxx
extensions/spellcheck/hunspell/src/hunvisapi.h
extensions/spellcheck/hunspell/src/hunzip.cxx
extensions/spellcheck/hunspell/src/hunzip.hxx
extensions/spellcheck/hunspell/src/langnum.hxx
extensions/spellcheck/hunspell/src/phonet.cxx
extensions/spellcheck/hunspell/src/phonet.hxx
extensions/spellcheck/hunspell/src/replist.cxx
extensions/spellcheck/hunspell/src/replist.hxx
extensions/spellcheck/hunspell/src/suggestmgr.cxx
extensions/spellcheck/hunspell/src/suggestmgr.hxx
extensions/spellcheck/hunspell/src/w_char.hxx
extensions/spellcheck/src/moz.build
--- a/extensions/spellcheck/hunspell/glue/moz.build
+++ b/extensions/spellcheck/hunspell/glue/moz.build
@@ -1,15 +1,15 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-SOURCES += [
+UNIFIED_SOURCES += [
     'mozHunspell.cpp',
     'mozHunspellDirProvider.cpp',
     'RemoteSpellCheckEngineChild.cpp',
     'RemoteSpellCheckEngineParent.cpp',
 ]
 
 CXXFLAGS += CONFIG['MOZ_HUNSPELL_CFLAGS']
 
--- a/extensions/spellcheck/hunspell/glue/mozHunspell.cpp
+++ b/extensions/spellcheck/hunspell/glue/mozHunspell.cpp
@@ -195,17 +195,17 @@ NS_IMETHODIMP mozHunspell::SetDictionary
   mDictionary = aDictionary;
   mAffixFileName = affFileName;
 
   mHunspell = new Hunspell(affFileName.get(),
                          dictFileName.get());
   if (!mHunspell)
     return NS_ERROR_OUT_OF_MEMORY;
 
-  nsDependentCString label(mHunspell->get_dic_encoding());
+  nsAutoCString label(mHunspell->get_dict_encoding().c_str());
   nsAutoCString encoding;
   if (!EncodingUtils::FindEncodingForLabelNoReplacement(label, encoding)) {
     return NS_ERROR_UCONV_NOCONV;
   }
   mEncoder = EncodingUtils::EncoderForEncoding(encoding);
   mDecoder = EncodingUtils::DecoderForEncoding(encoding);
 
   if (mEncoder)
@@ -475,32 +475,34 @@ mozHunspell::LoadDictionariesFromDir(nsI
     dict.ReplaceChar("_", '-');
 
     mDictionaries.Put(dict, file);
   }
 
   return NS_OK;
 }
 
-nsresult mozHunspell::ConvertCharset(const char16_t* aStr, char ** aDst)
+nsresult
+mozHunspell::ConvertCharset(const char16_t* aStr, std::string* aDst)
 {
   NS_ENSURE_ARG_POINTER(aDst);
   NS_ENSURE_TRUE(mEncoder, NS_ERROR_NULL_POINTER);
 
   int32_t outLength;
   int32_t inLength = NS_strlen(aStr);
   nsresult rv = mEncoder->GetMaxLength(aStr, inLength, &outLength);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  *aDst = (char *) moz_xmalloc(sizeof(char) * (outLength+1));
-  NS_ENSURE_TRUE(*aDst, NS_ERROR_OUT_OF_MEMORY);
+  aDst->resize(outLength);
 
-  rv = mEncoder->Convert(aStr, &inLength, *aDst, &outLength);
-  if (NS_SUCCEEDED(rv))
-    (*aDst)[outLength] = '\0';
+  char* dst = &aDst->operator[](0);
+  rv = mEncoder->Convert(aStr, &inLength, dst, &outLength);
+  if (NS_SUCCEEDED(rv)) {
+    aDst->resize(outLength);
+  }
 
   return rv;
 }
 
 NS_IMETHODIMP
 mozHunspell::CollectReports(nsIHandleReportCallback* aHandleReport,
                             nsISupports* aData, bool aAnonymize)
 {
@@ -513,76 +515,74 @@ mozHunspell::CollectReports(nsIHandleRep
 }
 
 NS_IMETHODIMP mozHunspell::Check(const char16_t *aWord, bool *aResult)
 {
   NS_ENSURE_ARG_POINTER(aWord);
   NS_ENSURE_ARG_POINTER(aResult);
   NS_ENSURE_TRUE(mHunspell, NS_ERROR_FAILURE);
 
-  nsXPIDLCString charsetWord;
-  nsresult rv = ConvertCharset(aWord, getter_Copies(charsetWord));
+  std::string charsetWord;
+  nsresult rv = ConvertCharset(aWord, &charsetWord);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  *aResult = !!mHunspell->spell(charsetWord);
-
+  *aResult = mHunspell->spell(charsetWord);
 
   if (!*aResult && mPersonalDictionary)
     rv = mPersonalDictionary->Check(aWord, mLanguage.get(), aResult);
 
   return rv;
 }
 
 NS_IMETHODIMP mozHunspell::Suggest(const char16_t *aWord, char16_t ***aSuggestions, uint32_t *aSuggestionCount)
 {
   NS_ENSURE_ARG_POINTER(aSuggestions);
   NS_ENSURE_ARG_POINTER(aSuggestionCount);
   NS_ENSURE_TRUE(mHunspell, NS_ERROR_FAILURE);
 
   nsresult rv;
   *aSuggestionCount = 0;
 
-  nsXPIDLCString charsetWord;
-  rv = ConvertCharset(aWord, getter_Copies(charsetWord));
+  std::string charsetWord;
+  rv = ConvertCharset(aWord, &charsetWord);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  char ** wlst;
-  *aSuggestionCount = mHunspell->suggest(&wlst, charsetWord);
+  std::vector<std::string> suggestions = mHunspell->suggest(charsetWord);
+  *aSuggestionCount = static_cast<uint32_t>(suggestions.size());
 
   if (*aSuggestionCount) {
     *aSuggestions  = (char16_t **)moz_xmalloc(*aSuggestionCount * sizeof(char16_t *));
     if (*aSuggestions) {
       uint32_t index = 0;
       for (index = 0; index < *aSuggestionCount && NS_SUCCEEDED(rv); ++index) {
         // Convert the suggestion to utf16
-        int32_t inLength = strlen(wlst[index]);
+        int32_t inLength = suggestions[index].size();
         int32_t outLength;
-        rv = mDecoder->GetMaxLength(wlst[index], inLength, &outLength);
+        rv = mDecoder->GetMaxLength(suggestions[index].c_str(), inLength, &outLength);
         if (NS_SUCCEEDED(rv))
         {
           (*aSuggestions)[index] = (char16_t *) moz_xmalloc(sizeof(char16_t) * (outLength+1));
           if ((*aSuggestions)[index])
           {
-            rv = mDecoder->Convert(wlst[index], &inLength, (*aSuggestions)[index], &outLength);
+            rv = mDecoder->Convert(suggestions[index].c_str(), &inLength, (*aSuggestions)[index], &outLength);
             if (NS_SUCCEEDED(rv))
               (*aSuggestions)[index][outLength] = 0;
           }
           else
             rv = NS_ERROR_OUT_OF_MEMORY;
         }
       }
 
       if (NS_FAILED(rv))
         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(index, *aSuggestions); // free the char16_t strings up to the point at which the error occurred
     }
     else // if (*aSuggestions)
       rv = NS_ERROR_OUT_OF_MEMORY;
   }
 
-  NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(*aSuggestionCount, wlst);
   return rv;
 }
 
 NS_IMETHODIMP
 mozHunspell::Observe(nsISupports* aSubj, const char *aTopic,
                     const char16_t *aData)
 {
   NS_ASSERTION(!strcmp(aTopic, "profile-do-change")
--- a/extensions/spellcheck/hunspell/glue/mozHunspell.h
+++ b/extensions/spellcheck/hunspell/glue/mozHunspell.h
@@ -94,17 +94,17 @@ public:
 
   mozHunspell();
 
   nsresult Init();
 
   void LoadDictionaryList(bool aNotifyChildProcesses);
 
   // helper method for converting a word to the charset of the dictionary
-  nsresult ConvertCharset(const char16_t* aStr, char ** aDst);
+  nsresult ConvertCharset(const char16_t* aStr, std::string* aDst);
 
   NS_DECL_NSIMEMORYREPORTER
 
 protected:
   virtual ~mozHunspell();
 
   nsCOMPtr<mozIPersonalDictionary> mPersonalDictionary;
   nsCOMPtr<nsIUnicodeEncoder>      mEncoder;
--- a/extensions/spellcheck/hunspell/src/README.mozilla
+++ b/extensions/spellcheck/hunspell/src/README.mozilla
@@ -1,2 +1,2 @@
-Hunspell Version:   1.4.1
+Hunspell Version:   1.5.0
 Additional Patches: See patches directory.
--- a/extensions/spellcheck/hunspell/src/affentry.cxx
+++ b/extensions/spellcheck/hunspell/src/affentry.cxx
@@ -74,62 +74,45 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <ctype.h>
 
 #include "affentry.hxx"
 #include "csutil.hxx"
 
-PfxEntry::PfxEntry(AffixMgr* pmgr, affentry* dp)
-    // register affix manager
-    : pmyMgr(pmgr),
-      next(NULL),
-      nexteq(NULL),
-      nextne(NULL),
-      flgnxt(NULL) {
-  // set up its initial values
-  aflag = dp->aflag;        // flag
-  strip = dp->strip;        // string to strip
-  appnd = dp->appnd;        // string to append
-  numconds = dp->numconds;  // length of the condition
-  opts = dp->opts;          // cross product flag
-  // then copy over all of the conditions
-  if (opts & aeLONGCOND) {
-    memcpy(c.conds, dp->c.l.conds1, MAXCONDLEN_1);
-    c.l.conds2 = dp->c.l.conds2;
-  } else
-    memcpy(c.conds, dp->c.conds, MAXCONDLEN);
-  morphcode = dp->morphcode;
-  contclass = dp->contclass;
-  contclasslen = dp->contclasslen;
-}
-
-PfxEntry::~PfxEntry() {
-  aflag = 0;
-  pmyMgr = NULL;
+AffEntry::~AffEntry() {
   if (opts & aeLONGCOND)
     free(c.l.conds2);
   if (morphcode && !(opts & aeALIASM))
     free(morphcode);
   if (contclass && !(opts & aeALIASF))
     free(contclass);
 }
 
+PfxEntry::PfxEntry(AffixMgr* pmgr)
+    // register affix manager
+    : pmyMgr(pmgr),
+      next(NULL),
+      nexteq(NULL),
+      nextne(NULL),
+      flgnxt(NULL) {
+}
+
 // add prefix to this word assuming conditions hold
-char* PfxEntry::add(const char* word, size_t len) {
+std::string PfxEntry::add(const char* word, size_t len) {
+  std::string result;
   if ((len > strip.size() || (len == 0 && pmyMgr->get_fullstrip())) &&
       (len >= numconds) && test_condition(word) &&
       (!strip.size() || (strncmp(word, strip.c_str(), strip.size()) == 0))) {
     /* we have a match so add prefix */
-    std::string tword(appnd);
-    tword.append(word + strip.size());
-    return mystrdup(tword.c_str());
+    result.assign(appnd);
+    result.append(word + strip.size());
   }
-  return NULL;
+  return result;
 }
 
 inline char* PfxEntry::nextchar(char* p) {
   if (p) {
     p++;
     if (opts & aeLONGCOND) {
       // jump to the 2nd part of the condition
       if (p == c.conds + MAXCONDLEN_1)
@@ -271,33 +254,30 @@ struct hentry* PfxEntry::checkword(const
 
       // prefix matched but no root word was found
       // if aeXPRODUCT is allowed, try again but now
       // ross checked combined with a suffix
 
       // if ((opts & aeXPRODUCT) && in_compound) {
       if ((opts & aeXPRODUCT)) {
         he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, aeXPRODUCT, this,
-                                  NULL, 0, NULL, FLAG_NULL, needflag,
-                                  in_compound);
+                                  FLAG_NULL, needflag, in_compound);
         if (he)
           return he;
       }
     }
   }
   return NULL;
 }
 
 // check if this prefix entry matches
 struct hentry* PfxEntry::check_twosfx(const char* word,
                                       int len,
                                       char in_compound,
                                       const FLAG needflag) {
-  struct hentry* he;  // hash entry of root word or NULL
-
   // on entry prefix is 0 length or already matches the beginning of the word.
   // So if the remaining root word has positive length
   // and if there are enough chars in root word and added back strip chars
   // to meet the number of characters conditions, then test it
 
   int tmpl = len - appnd.size(); // length of tmpword
 
   if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) &&
@@ -319,36 +299,37 @@ struct hentry* PfxEntry::check_twosfx(co
     if (test_condition(tmpword.c_str())) {
       tmpl += strip.size();
 
       // prefix matched but no root word was found
       // if aeXPRODUCT is allowed, try again but now
       // cross checked combined with a suffix
 
       if ((opts & aeXPRODUCT) && (in_compound != IN_CPD_BEGIN)) {
-        he = pmyMgr->suffix_check_twosfx(tmpword.c_str(), tmpl, aeXPRODUCT, this,
-                                         needflag);
+        // hash entry of root word or NULL
+        struct hentry* he = pmyMgr->suffix_check_twosfx(tmpword.c_str(), tmpl, aeXPRODUCT, this,
+                                                        needflag);
         if (he)
           return he;
       }
     }
   }
   return NULL;
 }
 
 // check if this prefix entry matches
-char* PfxEntry::check_twosfx_morph(const char* word,
-                                   int len,
-                                   char in_compound,
-                                   const FLAG needflag) {
+std::string PfxEntry::check_twosfx_morph(const char* word,
+                                         int len,
+                                         char in_compound,
+                                         const FLAG needflag) {
+  std::string result;
   // on entry prefix is 0 length or already matches the beginning of the word.
   // So if the remaining root word has positive length
   // and if there are enough chars in root word and added back strip chars
   // to meet the number of characters conditions, then test it
-
   int tmpl = len - appnd.size(); // length of tmpword
 
   if ((tmpl > 0 || (tmpl == 0 && pmyMgr->get_fullstrip())) &&
       (tmpl + strip.size() >= numconds)) {
     // generate new root word by removing prefix and adding
     // back any characters that would have been stripped
 
     std::string tmpword(strip);
@@ -365,32 +346,31 @@ char* PfxEntry::check_twosfx_morph(const
     if (test_condition(tmpword.c_str())) {
       tmpl += strip.size();
 
       // prefix matched but no root word was found
       // if aeXPRODUCT is allowed, try again but now
       // ross checked combined with a suffix
 
       if ((opts & aeXPRODUCT) && (in_compound != IN_CPD_BEGIN)) {
-        return pmyMgr->suffix_check_twosfx_morph(tmpword.c_str(), tmpl,
-                                                 aeXPRODUCT,
-                                                 this, needflag);
+        result = pmyMgr->suffix_check_twosfx_morph(tmpword.c_str(), tmpl,
+                                                   aeXPRODUCT,
+                                                   this, needflag);
       }
     }
   }
-  return NULL;
+  return result;
 }
 
 // check if this prefix entry matches
-char* PfxEntry::check_morph(const char* word,
-                            int len,
-                            char in_compound,
-                            const FLAG needflag) {
-  struct hentry* he;  // hash entry of root word or NULL
-  char* st;
+std::string PfxEntry::check_morph(const char* word,
+                                  int len,
+                                  char in_compound,
+                                  const FLAG needflag) {
+  std::string result;
 
   // on entry prefix is 0 length or already matches the beginning of the word.
   // So if the remaining root word has positive length
   // and if there are enough chars in root word and added back strip chars
   // to meet the number of characters conditions, then test it
 
   int tmpl = len - appnd.size(); // length of tmpword
 
@@ -406,19 +386,18 @@ char* PfxEntry::check_morph(const char* 
     // are met.  Please see the appendix at the end of
     // this file for more info on exactly what is being
     // tested
 
     // if all conditions are met then check if resulting
     // root word in the dictionary
 
     if (test_condition(tmpword.c_str())) {
-      std::string result;
-
       tmpl += strip.size();
+      struct hentry* he;  // hash entry of root word or NULL
       if ((he = pmyMgr->lookup(tmpword.c_str())) != NULL) {
         do {
           if (TESTAFF(he->astr, aflag, he->alen) &&
               // forbid single prefixes with needaffix flag
               !TESTAFF(contclass, pmyMgr->get_needaffix(), contclasslen) &&
               // needflag
               ((!needflag) || TESTAFF(he->astr, needflag, he->alen) ||
                (contclass && TESTAFF(contclass, needflag, contclasslen)))) {
@@ -450,86 +429,53 @@ char* PfxEntry::check_morph(const char* 
         } while (he);
       }
 
       // prefix matched but no root word was found
       // if aeXPRODUCT is allowed, try again but now
       // ross checked combined with a suffix
 
       if ((opts & aeXPRODUCT) && (in_compound != IN_CPD_BEGIN)) {
-        st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, aeXPRODUCT, this,
-                                        FLAG_NULL, needflag);
-        if (st) {
+        std::string st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, aeXPRODUCT, this,
+                                                    FLAG_NULL, needflag);
+        if (!st.empty()) {
           result.append(st);
-          free(st);
         }
       }
-
-      if (!result.empty())
-        return mystrdup(result.c_str());
     }
   }
 
-  return NULL;
+  return result;
 }
 
-SfxEntry::SfxEntry(AffixMgr* pmgr, affentry* dp)
+SfxEntry::SfxEntry(AffixMgr* pmgr)
     : pmyMgr(pmgr)  // register affix manager
       ,
       next(NULL),
       nexteq(NULL),
       nextne(NULL),
       flgnxt(NULL),
       l_morph(NULL),
       r_morph(NULL),
       eq_morph(NULL) {
-  // set up its initial values
-  aflag = dp->aflag;        // char flag
-  strip = dp->strip;        // string to strip
-  appnd = dp->appnd;        // string to append
-  numconds = dp->numconds;  // length of the condition
-  opts = dp->opts;          // cross product flag
-
-  // then copy over all of the conditions
-  if (opts & aeLONGCOND) {
-    memcpy(c.l.conds1, dp->c.l.conds1, MAXCONDLEN_1);
-    c.l.conds2 = dp->c.l.conds2;
-  } else
-    memcpy(c.conds, dp->c.conds, MAXCONDLEN);
-  rappnd = appnd;
-  reverseword(rappnd);
-  morphcode = dp->morphcode;
-  contclass = dp->contclass;
-  contclasslen = dp->contclasslen;
-}
-
-SfxEntry::~SfxEntry() {
-  aflag = 0;
-  pmyMgr = NULL;
-  if (opts & aeLONGCOND)
-    free(c.l.conds2);
-  if (morphcode && !(opts & aeALIASM))
-    free(morphcode);
-  if (contclass && !(opts & aeALIASF))
-    free(contclass);
 }
 
 // add suffix to this word assuming conditions hold
-char* SfxEntry::add(const char* word, size_t len) {
+std::string SfxEntry::add(const char* word, size_t len) {
+  std::string result;
   /* make sure all conditions match */
   if ((len > strip.size() || (len == 0 && pmyMgr->get_fullstrip())) &&
       (len >= numconds) && test_condition(word + len, word) &&
       (!strip.size() ||
        (strcmp(word + len - strip.size(), strip.c_str()) == 0))) {
-    std::string tword(word);
+    result.assign(word);
     /* we have a match so add suffix */
-    tword.replace(len - strip.size(), std::string::npos, appnd);
-    return mystrdup(tword.c_str());
+    result.replace(len - strip.size(), std::string::npos, appnd);
   }
-  return NULL;
+  return result;
 }
 
 inline char* SfxEntry::nextchar(char* p) {
   if (p) {
     p++;
     if (opts & aeLONGCOND) {
       // jump to the 2nd part of the condition
       if (p == c.l.conds1 + MAXCONDLEN_1)
@@ -664,19 +610,16 @@ inline int SfxEntry::test_condition(cons
   }
 }
 
 // see if this suffix is present in the word
 struct hentry* SfxEntry::checkword(const char* word,
                                    int len,
                                    int optflags,
                                    PfxEntry* ppfx,
-                                   char** wlst,
-                                   int maxSug,
-                                   int* ns,
                                    const FLAG cclass,
                                    const FLAG needflag,
                                    const FLAG badflag) {
   struct hentry* he;  // hash entry pointer
   PfxEntry* ep = ppfx;
 
   // if this suffix is being cross checked with a prefix
   // but it does not support cross products skip it
@@ -737,50 +680,28 @@ struct hentry* SfxEntry::checkword(const
               (!badflag || !TESTAFF(he->astr, badflag, he->alen)) &&
               // handle required flag
               ((!needflag) ||
                (TESTAFF(he->astr, needflag, he->alen) ||
                 ((contclass) && TESTAFF(contclass, needflag, contclasslen)))))
             return he;
           he = he->next_homonym;  // check homonyms
         } while (he);
-
-        // obsolote stemming code (used only by the
-        // experimental SuffixMgr:suggest_pos_stems)
-        // store resulting root in wlst
-      } else if (wlst && (*ns < maxSug)) {
-        int cwrd = 1;
-        for (int k = 0; k < *ns; k++)
-          if (strcmp(tmpword, wlst[k]) == 0) {
-            cwrd = 0;
-            break;
-          }
-        if (cwrd) {
-          wlst[*ns] = mystrdup(tmpword);
-          if (wlst[*ns] == NULL) {
-            for (int j = 0; j < *ns; j++)
-              free(wlst[j]);
-            *ns = -1;
-            return NULL;
-          }
-          (*ns)++;
-        }
       }
     }
   }
   return NULL;
 }
 
 // see if two-level suffix is present in the word
 struct hentry* SfxEntry::check_twosfx(const char* word,
                                       int len,
                                       int optflags,
                                       PfxEntry* ppfx,
                                       const FLAG needflag) {
-  struct hentry* he;  // hash entry pointer
   PfxEntry* ep = ppfx;
 
   // if this suffix is being cross checked with a prefix
   // but it does not support cross products skip it
 
   if ((optflags & aeXPRODUCT) != 0 && (opts & aeXPRODUCT) == 0)
     return NULL;
 
@@ -808,53 +729,51 @@ struct hentry* SfxEntry::check_twosfx(co
     // now make sure all of the conditions on characters
     // are met.  Please see the appendix at the end of
     // this file for more info on exactly what is being
     // tested
 
     // if all conditions are met then recall suffix_check
 
     if (test_condition(end, beg)) {
+      struct hentry* he;  // hash entry pointer
       if (ppfx) {
         // handle conditional suffix
         if ((contclass) && TESTAFF(contclass, ep->getFlag(), contclasslen))
-          he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, 0, NULL, NULL, 0, NULL,
-                                    (FLAG)aflag, needflag);
+          he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, 0, NULL,
+                                    (FLAG)aflag, needflag, IN_CPD_NOT);
         else
-          he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, optflags, ppfx, NULL, 0,
-                                    NULL, (FLAG)aflag, needflag);
+          he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, optflags, ppfx,
+                                    (FLAG)aflag, needflag, IN_CPD_NOT);
       } else {
-        he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, 0, NULL, NULL, 0, NULL,
-                                  (FLAG)aflag, needflag);
+        he = pmyMgr->suffix_check(tmpword.c_str(), tmpl, 0, NULL,
+                                  (FLAG)aflag, needflag, IN_CPD_NOT);
       }
       if (he)
         return he;
     }
   }
   return NULL;
 }
 
 // see if two-level suffix is present in the word
-char* SfxEntry::check_twosfx_morph(const char* word,
-                                   int len,
-                                   int optflags,
-                                   PfxEntry* ppfx,
-                                   const FLAG needflag) {
+std::string SfxEntry::check_twosfx_morph(const char* word,
+                                         int len,
+                                         int optflags,
+                                         PfxEntry* ppfx,
+                                         const FLAG needflag) {
   PfxEntry* ep = ppfx;
-  char* st;
 
-  char result[MAXLNLEN];
-
-  *result = '\0';
+  std::string result;
 
   // if this suffix is being cross checked with a prefix
   // but it does not support cross products skip it
 
   if ((optflags & aeXPRODUCT) != 0 && (opts & aeXPRODUCT) == 0)
-    return NULL;
+    return result;
 
   // upon entry suffix is 0 length or already matches the end of the word.
   // So if the remaining root word has positive length
   // and if there are enough chars in root word and added back strip chars
   // to meet the number of characters conditions, then test it
 
   int tmpl = len - appnd.size(); // length of tmpword
 
@@ -878,50 +797,44 @@ char* SfxEntry::check_twosfx_morph(const
     // tested
 
     // if all conditions are met then recall suffix_check
 
     if (test_condition(end, beg)) {
       if (ppfx) {
         // handle conditional suffix
         if ((contclass) && TESTAFF(contclass, ep->getFlag(), contclasslen)) {
-          st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, 0, NULL, aflag,
-                                          needflag);
-          if (st) {
+          std::string st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, 0, NULL, aflag,
+                                                      needflag);
+          if (!st.empty()) {
             if (ppfx->getMorph()) {
-              mystrcat(result, ppfx->getMorph(), MAXLNLEN);
-              mystrcat(result, " ", MAXLNLEN);
+              result.append(ppfx->getMorph());
+              result.append(" ");
             }
-            mystrcat(result, st, MAXLNLEN);
-            free(st);
+            result.append(st);
             mychomp(result);
           }
         } else {
-          st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, optflags, ppfx, aflag,
-                                          needflag);
-          if (st) {
-            mystrcat(result, st, MAXLNLEN);
-            free(st);
+          std::string st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, optflags, ppfx, aflag,
+                                                      needflag);
+          if (!st.empty()) {
+            result.append(st);
             mychomp(result);
           }
         }
       } else {
-        st =
-            pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, 0, NULL, aflag, needflag);
-        if (st) {
-          mystrcat(result, st, MAXLNLEN);
-          free(st);
+        std::string st = pmyMgr->suffix_check_morph(tmpword.c_str(), tmpl, 0, NULL, aflag, needflag);
+        if (!st.empty()) {
+          result.append(st);
           mychomp(result);
         }
       }
-      if (*result)
-        return mystrdup(result);
     }
   }
-  return NULL;
+  return result;
 }
 
 // get next homonym with same affix
 struct hentry* SfxEntry::get_next_homonym(struct hentry* he,
                                           int optflags,
                                           PfxEntry* ppfx,
                                           const FLAG cclass,
                                           const FLAG needflag) {
@@ -943,16 +856,21 @@ struct hentry* SfxEntry::get_next_homony
         ((!needflag) ||
          (TESTAFF(he->astr, needflag, he->alen) ||
           ((contclass) && TESTAFF(contclass, needflag, contclasslen)))))
       return he;
   }
   return NULL;
 }
 
+void SfxEntry::initReverseWord() {
+  rappnd = appnd;
+  reverseword(rappnd);
+}
+
 #if 0
 
 Appendix:  Understanding Affix Code
 
 
 An affix is either a  prefix or a suffix attached to root words to make 
 other words.
 
--- a/extensions/spellcheck/hunspell/src/affentry.hxx
+++ b/extensions/spellcheck/hunspell/src/affentry.hxx
@@ -66,68 +66,65 @@
  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
-#ifndef _AFFIX_HXX_
-#define _AFFIX_HXX_
-
-#include "hunvisapi.h"
+#ifndef AFFIX_HXX_
+#define AFFIX_HXX_
 
 #include "atypes.hxx"
 #include "baseaffix.hxx"
 #include "affixmgr.hxx"
 
 /* A Prefix Entry  */
 
-class LIBHUNSPELL_DLL_EXPORTED PfxEntry : protected AffEntry {
+class PfxEntry : public AffEntry {
  private:
   PfxEntry(const PfxEntry&);
   PfxEntry& operator=(const PfxEntry&);
 
  private:
   AffixMgr* pmyMgr;
 
   PfxEntry* next;
   PfxEntry* nexteq;
   PfxEntry* nextne;
   PfxEntry* flgnxt;
 
  public:
-  PfxEntry(AffixMgr* pmgr, affentry* dp);
-  ~PfxEntry();
+  explicit PfxEntry(AffixMgr* pmgr);
 
-  inline bool allowCross() { return ((opts & aeXPRODUCT) != 0); }
+  bool allowCross() const { return ((opts & aeXPRODUCT) != 0); }
   struct hentry* checkword(const char* word,
                            int len,
                            char in_compound,
                            const FLAG needflag = FLAG_NULL);
 
   struct hentry* check_twosfx(const char* word,
                               int len,
                               char in_compound,
                               const FLAG needflag = FLAG_NULL);
 
-  char* check_morph(const char* word,
-                    int len,
-                    char in_compound,
-                    const FLAG needflag = FLAG_NULL);
+  std::string check_morph(const char* word,
+                          int len,
+                          char in_compound,
+                          const FLAG needflag = FLAG_NULL);
 
-  char* check_twosfx_morph(const char* word,
-                           int len,
-                           char in_compound,
-                           const FLAG needflag = FLAG_NULL);
+  std::string check_twosfx_morph(const char* word,
+                                 int len,
+                                 char in_compound,
+                                 const FLAG needflag = FLAG_NULL);
 
-  inline FLAG getFlag() { return aflag; }
-  inline const char* getKey() { return appnd.c_str(); }
-  char* add(const char* word, size_t len);
+  FLAG getFlag() { return aflag; }
+  const char* getKey() { return appnd.c_str(); }
+  std::string add(const char* word, size_t len);
 
   inline short getKeyLen() { return appnd.size(); }
 
   inline const char* getMorph() { return morphcode; }
 
   inline const unsigned short* getCont() { return contclass; }
   inline short getContLen() { return contclasslen; }
 
@@ -142,17 +139,17 @@ class LIBHUNSPELL_DLL_EXPORTED PfxEntry 
   inline void setFlgNxt(PfxEntry* ptr) { flgnxt = ptr; }
 
   inline char* nextchar(char* p);
   inline int test_condition(const char* st);
 };
 
 /* A Suffix Entry */
 
-class LIBHUNSPELL_DLL_EXPORTED SfxEntry : protected AffEntry {
+class SfxEntry : public AffEntry {
  private:
   SfxEntry(const SfxEntry&);
   SfxEntry& operator=(const SfxEntry&);
 
  private:
   AffixMgr* pmyMgr;
   std::string rappnd;
 
@@ -161,52 +158,48 @@ class LIBHUNSPELL_DLL_EXPORTED SfxEntry 
   SfxEntry* nextne;
   SfxEntry* flgnxt;
 
   SfxEntry* l_morph;
   SfxEntry* r_morph;
   SfxEntry* eq_morph;
 
  public:
-  SfxEntry(AffixMgr* pmgr, affentry* dp);
-  ~SfxEntry();
+  explicit SfxEntry(AffixMgr* pmgr);
 
-  inline bool allowCross() { return ((opts & aeXPRODUCT) != 0); }
+  bool allowCross() const { return ((opts & aeXPRODUCT) != 0); }
   struct hentry* checkword(const char* word,
                            int len,
                            int optflags,
                            PfxEntry* ppfx,
-                           char** wlst,
-                           int maxSug,
-                           int* ns,
-                           const FLAG cclass = FLAG_NULL,
-                           const FLAG needflag = FLAG_NULL,
-                           const FLAG badflag = FLAG_NULL);
+                           const FLAG cclass,
+                           const FLAG needflag,
+                           const FLAG badflag);
 
   struct hentry* check_twosfx(const char* word,
                               int len,
                               int optflags,
                               PfxEntry* ppfx,
                               const FLAG needflag = FLAG_NULL);
 
-  char* check_twosfx_morph(const char* word,
-                           int len,
-                           int optflags,
-                           PfxEntry* ppfx,
-                           const FLAG needflag = FLAG_NULL);
+  std::string check_twosfx_morph(const char* word,
+                                 int len,
+                                 int optflags,
+                                 PfxEntry* ppfx,
+                                 const FLAG needflag = FLAG_NULL);
   struct hentry* get_next_homonym(struct hentry* he);
   struct hentry* get_next_homonym(struct hentry* word,
                                   int optflags,
                                   PfxEntry* ppfx,
                                   const FLAG cclass,
                                   const FLAG needflag);
 
-  inline FLAG getFlag() { return aflag; }
-  inline const char* getKey() { return rappnd.c_str(); }
-  char* add(const char* word, size_t len);
+  FLAG getFlag() { return aflag; }
+  const char* getKey() { return rappnd.c_str(); }
+  std::string add(const char* word, size_t len);
 
   inline const char* getMorph() { return morphcode; }
 
   inline const unsigned short* getCont() { return contclass; }
   inline short getContLen() { return contclasslen; }
   inline const char* getAffix() { return appnd.c_str(); }
 
   inline short getKeyLen() { return appnd.size(); }
@@ -219,14 +212,15 @@ class LIBHUNSPELL_DLL_EXPORTED SfxEntry 
   inline SfxEntry* getRM() { return r_morph; }
   inline SfxEntry* getEQM() { return eq_morph; }
   inline SfxEntry* getFlgNxt() { return flgnxt; }
 
   inline void setNext(SfxEntry* ptr) { next = ptr; }
   inline void setNextNE(SfxEntry* ptr) { nextne = ptr; }
   inline void setNextEQ(SfxEntry* ptr) { nexteq = ptr; }
   inline void setFlgNxt(SfxEntry* ptr) { flgnxt = ptr; }
+  void initReverseWord();
 
   inline char* nextchar(char* p);
   inline int test_condition(const char* st, const char* begin);
 };
 
 #endif
--- a/extensions/spellcheck/hunspell/src/affixmgr.cxx
+++ b/extensions/spellcheck/hunspell/src/affixmgr.cxx
@@ -83,43 +83,34 @@
 
 #include "affixmgr.hxx"
 #include "affentry.hxx"
 #include "langnum.hxx"
 
 #include "csutil.hxx"
 
 AffixMgr::AffixMgr(const char* affpath,
-                   HashMgr** ptr,
-                   int* md,
-                   const char* key) {
+                   const std::vector<HashMgr*>& ptr,
+                   const char* key)
+  : alldic(ptr)
+  , pHMgr(ptr[0]) {
+
   // register hash manager and load affix data from aff file
-  pHMgr = ptr[0];
-  alldic = ptr;
-  maxdic = md;
-  keystring = NULL;
-  trystring = NULL;
-  encoding = NULL;
   csconv = NULL;
   utf8 = 0;
   complexprefixes = 0;
-  maptable = NULL;
-  nummap = 0;
-  breaktable = NULL;
-  numbreak = -1;
-  reptable = NULL;
-  numrep = 0;
+  parsedmaptable = false;
+  parsedbreaktable = false;
+  parsedrep = false;
   iconvtable = NULL;
   oconvtable = NULL;
-  checkcpdtable = NULL;
   // allow simplified compound forms (see 3rd field of CHECKCOMPOUNDPATTERN)
   simplifiedcpd = 0;
-  numcheckcpd = 0;
-  defcpdtable = NULL;
-  numdefcpd = 0;
+  parsedcheckcpd = false;
+  parseddefcpd = false;
   phone = NULL;
   compoundflag = FLAG_NULL;        // permits word in compound forms
   compoundbegin = FLAG_NULL;       // may be first word in compound forms
   compoundmiddle = FLAG_NULL;      // may be middle word in compound forms
   compoundend = FLAG_NULL;         // may be last word in compound forms
   compoundroot = FLAG_NULL;        // compound word signing flag
   compoundpermitflag = FLAG_NULL;  // compound permitting flag for suffixed word
   compoundforbidflag = FLAG_NULL;  // compound fordidden flag for suffixed word
@@ -130,35 +121,25 @@ AffixMgr::AffixMgr(const char* affpath,
   checkcompoundcase =
       0;  // forbid upper and lowercase combinations at word bounds
   checkcompoundtriple = 0;  // forbid compounds with triple letters
   simplifiedtriple = 0;     // allow simplified triple letters in compounds
                             // (Schiff+fahrt -> Schiffahrt)
   forbiddenword = FORBIDDENWORD;  // forbidden word signing flag
   nosuggest = FLAG_NULL;  // don't suggest words signed with NOSUGGEST flag
   nongramsuggest = FLAG_NULL;
-  lang = NULL;  // language
   langnum = 0;  // language code (see http://l10n.openoffice.org/languages.html)
   needaffix = FLAG_NULL;  // forbidden root, allowed only with suffixes
   cpdwordmax = -1;        // default: unlimited wordcount in compound words
   cpdmin = -1;            // undefined
   cpdmaxsyllable = 0;     // default: unlimited syllablecount in compound words
-  cpdvowels = NULL;  // vowels (for calculating of Hungarian compounding limit,
-                     // O(n) search! XXX)
-  cpdvowels_utf16 =
-      NULL;  // vowels for UTF-8 encoding (bsearch instead of O(n) search)
-  cpdvowels_utf16_len = 0;  // vowels
   pfxappnd = NULL;  // previous prefix for counting syllables of the prefix BUG
   sfxappnd = NULL;  // previous suffix for counting syllables of the suffix BUG
   sfxextra = 0;     // modifier for syllable count of sfxappnd BUG
-  cpdsyllablenum = NULL;      // syllable count incrementing flag
   checknum = 0;               // checking numbers, and word with numbers
-  wordchars = NULL;           // letters + spec. word characters
-  ignorechars = NULL;         // letters + spec. word characters
-  version = NULL;             // affix and dictionary file version string
   havecontclass = 0;  // flags of possible continuing classes (double affix)
   // LEMMA_PRESENT: not put root into the morphological output. Lemma presents
   // in morhological description in dictionary file. It's often combined with
   // PSEUDOROOT.
   lemma_present = FLAG_NULL;
   circumfix = FLAG_NULL;
   onlyincompound = FLAG_NULL;
   maxngramsugs = -1;  // undefined
@@ -220,93 +201,20 @@ AffixMgr::~AffixMgr() {
       nptr = ptr->getNext();
       delete (ptr);
       ptr = nptr;
       nptr = NULL;
     }
     sStart[j] = NULL;
   }
 
-  if (keystring)
-    free(keystring);
-  keystring = NULL;
-  if (trystring)
-    free(trystring);
-  trystring = NULL;
-  if (encoding)
-    free(encoding);
-  encoding = NULL;
-  if (maptable) {
-    for (int j = 0; j < nummap; j++) {
-      for (int k = 0; k < maptable[j].len; k++) {
-        if (maptable[j].set[k])
-          free(maptable[j].set[k]);
-      }
-      free(maptable[j].set);
-      maptable[j].set = NULL;
-      maptable[j].len = 0;
-    }
-    free(maptable);
-    maptable = NULL;
-  }
-  nummap = 0;
-  if (breaktable) {
-    for (int j = 0; j < numbreak; j++) {
-      if (breaktable[j])
-        free(breaktable[j]);
-      breaktable[j] = NULL;
-    }
-    free(breaktable);
-    breaktable = NULL;
-  }
-  numbreak = 0;
-  if (reptable) {
-    for (int j = 0; j < numrep; j++) {
-      free(reptable[j].pattern);
-      free(reptable[j].pattern2);
-    }
-    free(reptable);
-    reptable = NULL;
-  }
-  if (iconvtable)
-    delete iconvtable;
-  if (oconvtable)
-    delete oconvtable;
-  if (phone && phone->rules) {
-    for (int j = 0; j < phone->num + 1; j++) {
-      free(phone->rules[j * 2]);
-      free(phone->rules[j * 2 + 1]);
-    }
-    free(phone->rules);
-    free(phone);
-    phone = NULL;
-  }
-
-  if (defcpdtable) {
-    for (int j = 0; j < numdefcpd; j++) {
-      free(defcpdtable[j].def);
-      defcpdtable[j].def = NULL;
-    }
-    free(defcpdtable);
-    defcpdtable = NULL;
-  }
-  numrep = 0;
-  if (checkcpdtable) {
-    for (int j = 0; j < numcheckcpd; j++) {
-      free(checkcpdtable[j].pattern);
-      free(checkcpdtable[j].pattern2);
-      free(checkcpdtable[j].pattern3);
-      checkcpdtable[j].pattern = NULL;
-      checkcpdtable[j].pattern2 = NULL;
-      checkcpdtable[j].pattern3 = NULL;
-    }
-    free(checkcpdtable);
-    checkcpdtable = NULL;
-  }
-  numcheckcpd = 0;
+  delete iconvtable;
+  delete oconvtable;
+  delete phone;
+
   FREE_FLAG(compoundflag);
   FREE_FLAG(compoundbegin);
   FREE_FLAG(compoundmiddle);
   FREE_FLAG(compoundend);
   FREE_FLAG(compoundpermitflag);
   FREE_FLAG(compoundforbidflag);
   FREE_FLAG(compoundroot);
   FREE_FLAG(forbiddenword);
@@ -316,49 +224,33 @@ AffixMgr::~AffixMgr() {
   FREE_FLAG(lemma_present);
   FREE_FLAG(circumfix);
   FREE_FLAG(onlyincompound);
 
   cpdwordmax = 0;
   pHMgr = NULL;
   cpdmin = 0;
   cpdmaxsyllable = 0;
-  if (cpdvowels)
-    free(cpdvowels);
-  if (cpdvowels_utf16)
-    free(cpdvowels_utf16);
-  if (cpdsyllablenum)
-    free(cpdsyllablenum);
   free_utf_tbl();
-  if (lang)
-    free(lang);
-  if (wordchars)
-    free(wordchars);
-  if (ignorechars)
-    free(ignorechars);
-  if (version)
-    free(version);
   checknum = 0;
 #ifdef MOZILLA_CLIENT
   delete[] csconv;
 #endif
 }
 
 void AffixMgr::finishFileMgr(FileMgr* afflst) {
   delete afflst;
 
   // convert affix trees to sorted list
   process_pfx_tree_to_list();
   process_sfx_tree_to_list();
 }
 
 // read in aff file and build up prefix and suffix entry objects
 int AffixMgr::parse_file(const char* affpath, const char* key) {
-  char* line;  // io buffers
-  char ft;     // affix type
 
   // checking flag duplication
   char dupflags[CONTSIZE];
   char dupflags_ini = 1;
 
   // first line indicator for removing byte order mark
   int firstline = 1;
 
@@ -370,449 +262,450 @@ int AffixMgr::parse_file(const char* aff
     return 1;
   }
 
   // step one is to parse the affix file building up the internal
   // affix data structures
 
   // read in each line ignoring any that do not
   // start with a known line type indicator
-  while ((line = afflst->getline()) != NULL) {
+  std::string line;
+  while (afflst->getline(line)) {
     mychomp(line);
 
     /* remove byte order mark */
     if (firstline) {
       firstline = 0;
       // Affix file begins with byte order mark: possible incompatibility with
       // old Hunspell versions
-      if (strncmp(line, "\xEF\xBB\xBF", 3) == 0) {
-        memmove(line, line + 3, strlen(line + 3) + 1);
+      if (line.compare(0, 3, "\xEF\xBB\xBF", 3) == 0) {
+        line.erase(0, 3);
       }
     }
 
     /* parse in the keyboard string */
-    if (strncmp(line, "KEY", 3) == 0) {
-      if (parse_string(line, &keystring, afflst->getlinenum())) {
+    if (line.compare(0, 3, "KEY", 3) == 0) {
+      if (!parse_string(line, keystring, afflst->getlinenum())) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the try string */
-    if (strncmp(line, "TRY", 3) == 0) {
-      if (parse_string(line, &trystring, afflst->getlinenum())) {
+    if (line.compare(0, 3, "TRY", 3) == 0) {
+      if (!parse_string(line, trystring, afflst->getlinenum())) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the name of the character set used by the .dict and .aff */
-    if (strncmp(line, "SET", 3) == 0) {
-      if (parse_string(line, &encoding, afflst->getlinenum())) {
+    if (line.compare(0, 3, "SET", 3) == 0) {
+      if (!parse_string(line, encoding, afflst->getlinenum())) {
         finishFileMgr(afflst);
         return 1;
       }
-      if (strcmp(encoding, "UTF-8") == 0) {
+      if (encoding == "UTF-8") {
         utf8 = 1;
 #ifndef OPENOFFICEORG
 #ifndef MOZILLA_CLIENT
-        if (initialize_utf_tbl()) {
-          finishFileMgr(afflst);
-          return 1;
-        }
+        initialize_utf_tbl();
 #endif
 #endif
       }
     }
 
     /* parse COMPLEXPREFIXES for agglutinative languages with right-to-left
      * writing system */
-    if (strncmp(line, "COMPLEXPREFIXES", 15) == 0)
+    if (line.compare(0, 15, "COMPLEXPREFIXES", 15) == 0)
       complexprefixes = 1;
 
     /* parse in the flag used by the controlled compound words */
-    if (strncmp(line, "COMPOUNDFLAG", 12) == 0) {
-      if (parse_flag(line, &compoundflag, afflst)) {
+    if (line.compare(0, 12, "COMPOUNDFLAG", 12) == 0) {
+      if (!parse_flag(line, &compoundflag, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by compound words */
-    if (strncmp(line, "COMPOUNDBEGIN", 13) == 0) {
+    if (line.compare(0, 13, "COMPOUNDBEGIN", 13) == 0) {
       if (complexprefixes) {
-        if (parse_flag(line, &compoundend, afflst)) {
+        if (!parse_flag(line, &compoundend, afflst)) {
           finishFileMgr(afflst);
           return 1;
         }
       } else {
-        if (parse_flag(line, &compoundbegin, afflst)) {
+        if (!parse_flag(line, &compoundbegin, afflst)) {
           finishFileMgr(afflst);
           return 1;
         }
       }
     }
 
     /* parse in the flag used by compound words */
-    if (strncmp(line, "COMPOUNDMIDDLE", 14) == 0) {
-      if (parse_flag(line, &compoundmiddle, afflst)) {
+    if (line.compare(0, 14, "COMPOUNDMIDDLE", 14) == 0) {
+      if (!parse_flag(line, &compoundmiddle, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
+
     /* parse in the flag used by compound words */
-    if (strncmp(line, "COMPOUNDEND", 11) == 0) {
+    if (line.compare(0, 11, "COMPOUNDEND", 11) == 0) {
       if (complexprefixes) {
-        if (parse_flag(line, &compoundbegin, afflst)) {
+        if (!parse_flag(line, &compoundbegin, afflst)) {
           finishFileMgr(afflst);
           return 1;
         }
       } else {
-        if (parse_flag(line, &compoundend, afflst)) {
+        if (!parse_flag(line, &compoundend, afflst)) {
           finishFileMgr(afflst);
           return 1;
         }
       }
     }
 
     /* parse in the data used by compound_check() method */
-    if (strncmp(line, "COMPOUNDWORDMAX", 15) == 0) {
-      if (parse_num(line, &cpdwordmax, afflst)) {
+    if (line.compare(0, 15, "COMPOUNDWORDMAX", 15) == 0) {
+      if (!parse_num(line, &cpdwordmax, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag sign compounds in dictionary */
-    if (strncmp(line, "COMPOUNDROOT", 12) == 0) {
-      if (parse_flag(line, &compoundroot, afflst)) {
+    if (line.compare(0, 12, "COMPOUNDROOT", 12) == 0) {
+      if (!parse_flag(line, &compoundroot, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by compound_check() method */
-    if (strncmp(line, "COMPOUNDPERMITFLAG", 18) == 0) {
-      if (parse_flag(line, &compoundpermitflag, afflst)) {
+    if (line.compare(0, 18, "COMPOUNDPERMITFLAG", 18) == 0) {
+      if (!parse_flag(line, &compoundpermitflag, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by compound_check() method */
-    if (strncmp(line, "COMPOUNDFORBIDFLAG", 18) == 0) {
-      if (parse_flag(line, &compoundforbidflag, afflst)) {
+    if (line.compare(0, 18, "COMPOUNDFORBIDFLAG", 18) == 0) {
+      if (!parse_flag(line, &compoundforbidflag, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
-    if (strncmp(line, "COMPOUNDMORESUFFIXES", 20) == 0) {
+    if (line.compare(0, 20, "COMPOUNDMORESUFFIXES", 20) == 0) {
       compoundmoresuffixes = 1;
     }
 
-    if (strncmp(line, "CHECKCOMPOUNDDUP", 16) == 0) {
+    if (line.compare(0, 16, "CHECKCOMPOUNDDUP", 16) == 0) {
       checkcompounddup = 1;
     }
 
-    if (strncmp(line, "CHECKCOMPOUNDREP", 16) == 0) {
+    if (line.compare(0, 16, "CHECKCOMPOUNDREP", 16) == 0) {
       checkcompoundrep = 1;
     }
 
-    if (strncmp(line, "CHECKCOMPOUNDTRIPLE", 19) == 0) {
+    if (line.compare(0, 19, "CHECKCOMPOUNDTRIPLE", 19) == 0) {
       checkcompoundtriple = 1;
     }
 
-    if (strncmp(line, "SIMPLIFIEDTRIPLE", 16) == 0) {
+    if (line.compare(0, 16, "SIMPLIFIEDTRIPLE", 16) == 0) {
       simplifiedtriple = 1;
     }
 
-    if (strncmp(line, "CHECKCOMPOUNDCASE", 17) == 0) {
+    if (line.compare(0, 17, "CHECKCOMPOUNDCASE", 17) == 0) {
       checkcompoundcase = 1;
     }
 
-    if (strncmp(line, "NOSUGGEST", 9) == 0) {
-      if (parse_flag(line, &nosuggest, afflst)) {
+    if (line.compare(0, 9, "NOSUGGEST", 9) == 0) {
+      if (!parse_flag(line, &nosuggest, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
-    if (strncmp(line, "NONGRAMSUGGEST", 14) == 0) {
-      if (parse_flag(line, &nongramsuggest, afflst)) {
+    if (line.compare(0, 14, "NONGRAMSUGGEST", 14) == 0) {
+      if (!parse_flag(line, &nongramsuggest, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by forbidden words */
-    if (strncmp(line, "FORBIDDENWORD", 13) == 0) {
-      if (parse_flag(line, &forbiddenword, afflst)) {
+    if (line.compare(0, 13, "FORBIDDENWORD", 13) == 0) {
+      if (!parse_flag(line, &forbiddenword, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by forbidden words */
-    if (strncmp(line, "LEMMA_PRESENT", 13) == 0) {
-      if (parse_flag(line, &lemma_present, afflst)) {
+    if (line.compare(0, 13, "LEMMA_PRESENT", 13) == 0) {
+      if (!parse_flag(line, &lemma_present, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by circumfixes */
-    if (strncmp(line, "CIRCUMFIX", 9) == 0) {
-      if (parse_flag(line, &circumfix, afflst)) {
+    if (line.compare(0, 9, "CIRCUMFIX", 9) == 0) {
+      if (!parse_flag(line, &circumfix, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by fogemorphemes */
-    if (strncmp(line, "ONLYINCOMPOUND", 14) == 0) {
-      if (parse_flag(line, &onlyincompound, afflst)) {
+    if (line.compare(0, 14, "ONLYINCOMPOUND", 14) == 0) {
+      if (!parse_flag(line, &onlyincompound, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by `needaffixs' */
-    if (strncmp(line, "PSEUDOROOT", 10) == 0) {
-      if (parse_flag(line, &needaffix, afflst)) {
+    if (line.compare(0, 10, "PSEUDOROOT", 10) == 0) {
+      if (!parse_flag(line, &needaffix, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by `needaffixs' */
-    if (strncmp(line, "NEEDAFFIX", 9) == 0) {
-      if (parse_flag(line, &needaffix, afflst)) {
+    if (line.compare(0, 9, "NEEDAFFIX", 9) == 0) {
+      if (!parse_flag(line, &needaffix, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the minimal length for words in compounds */
-    if (strncmp(line, "COMPOUNDMIN", 11) == 0) {
-      if (parse_num(line, &cpdmin, afflst)) {
+    if (line.compare(0, 11, "COMPOUNDMIN", 11) == 0) {
+      if (!parse_num(line, &cpdmin, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
       if (cpdmin < 1)
         cpdmin = 1;
     }
 
     /* parse in the max. words and syllables in compounds */
-    if (strncmp(line, "COMPOUNDSYLLABLE", 16) == 0) {
-      if (parse_cpdsyllable(line, afflst)) {
+    if (line.compare(0, 16, "COMPOUNDSYLLABLE", 16) == 0) {
+      if (!parse_cpdsyllable(line, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by compound_check() method */
-    if (strncmp(line, "SYLLABLENUM", 11) == 0) {
-      if (parse_string(line, &cpdsyllablenum, afflst->getlinenum())) {
+    if (line.compare(0, 11, "SYLLABLENUM", 11) == 0) {
+      if (!parse_string(line, cpdsyllablenum, afflst->getlinenum())) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by the controlled compound words */
-    if (strncmp(line, "CHECKNUM", 8) == 0) {
+    if (line.compare(0, 8, "CHECKNUM", 8) == 0) {
       checknum = 1;
     }
 
     /* parse in the extra word characters */
-    if (strncmp(line, "WORDCHARS", 9) == 0) {
-      if (!parse_array(line, &wordchars, wordchars_utf16,
+    if (line.compare(0, 9, "WORDCHARS", 9) == 0) {
+      if (!parse_array(line, wordchars, wordchars_utf16,
                        utf8, afflst->getlinenum())) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the ignored characters (for example, Arabic optional diacretics
      * charachters */
-    if (strncmp(line, "IGNORE", 6) == 0) {
-      if (!parse_array(line, &ignorechars, ignorechars_utf16,
+    if (line.compare(0, 6, "IGNORE", 6) == 0) {
+      if (!parse_array(line, ignorechars, ignorechars_utf16,
                        utf8, afflst->getlinenum())) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the typical fault correcting table */
-    if (strncmp(line, "REP", 3) == 0) {
-      if (parse_reptable(line, afflst)) {
+    if (line.compare(0, 3, "REP", 3) == 0) {
+      if (!parse_reptable(line, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the input conversion table */
-    if (strncmp(line, "ICONV", 5) == 0) {
-      if (parse_convtable(line, afflst, &iconvtable, "ICONV")) {
+    if (line.compare(0, 5, "ICONV", 5) == 0) {
+      if (!parse_convtable(line, afflst, &iconvtable, "ICONV")) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the input conversion table */
-    if (strncmp(line, "OCONV", 5) == 0) {
-      if (parse_convtable(line, afflst, &oconvtable, "OCONV")) {
+    if (line.compare(0, 5, "OCONV", 5) == 0) {
+      if (!parse_convtable(line, afflst, &oconvtable, "OCONV")) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the phonetic translation table */
-    if (strncmp(line, "PHONE", 5) == 0) {
-      if (parse_phonetable(line, afflst)) {
+    if (line.compare(0, 5, "PHONE", 5) == 0) {
+      if (!parse_phonetable(line, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the checkcompoundpattern table */
-    if (strncmp(line, "CHECKCOMPOUNDPATTERN", 20) == 0) {
-      if (parse_checkcpdtable(line, afflst)) {
+    if (line.compare(0, 20, "CHECKCOMPOUNDPATTERN", 20) == 0) {
+      if (!parse_checkcpdtable(line, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the defcompound table */
-    if (strncmp(line, "COMPOUNDRULE", 12) == 0) {
-      if (parse_defcpdtable(line, afflst)) {
+    if (line.compare(0, 12, "COMPOUNDRULE", 12) == 0) {
+      if (!parse_defcpdtable(line, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the related character map table */
-    if (strncmp(line, "MAP", 3) == 0) {
-      if (parse_maptable(line, afflst)) {
+    if (line.compare(0, 3, "MAP", 3) == 0) {
+      if (!parse_maptable(line, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the word breakpoints table */
-    if (strncmp(line, "BREAK", 5) == 0) {
-      if (parse_breaktable(line, afflst)) {
+    if (line.compare(0, 5, "BREAK", 5) == 0) {
+      if (!parse_breaktable(line, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the language for language specific codes */
-    if (strncmp(line, "LANG", 4) == 0) {
-      if (parse_string(line, &lang, afflst->getlinenum())) {
+    if (line.compare(0, 4, "LANG", 4) == 0) {
+      if (!parse_string(line, lang, afflst->getlinenum())) {
         finishFileMgr(afflst);
         return 1;
       }
       langnum = get_lang_num(lang);
     }
 
-    if (strncmp(line, "VERSION", 7) == 0) {
-      for (line = line + 7; *line == ' ' || *line == '\t'; line++)
-        ;
-      version = mystrdup(line);
+    if (line.compare(0, 7, "VERSION", 7) == 0) {
+      size_t startpos = line.find_first_not_of(" \t", 7);
+      if (startpos != std::string::npos) {
+          version = line.substr(startpos);
+      }
     }
 
-    if (strncmp(line, "MAXNGRAMSUGS", 12) == 0) {
-      if (parse_num(line, &maxngramsugs, afflst)) {
+    if (line.compare(0, 12, "MAXNGRAMSUGS", 12) == 0) {
+      if (!parse_num(line, &maxngramsugs, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
-    if (strncmp(line, "ONLYMAXDIFF", 11) == 0)
+    if (line.compare(0, 11, "ONLYMAXDIFF", 11) == 0)
       onlymaxdiff = 1;
 
-    if (strncmp(line, "MAXDIFF", 7) == 0) {
-      if (parse_num(line, &maxdiff, afflst)) {
+    if (line.compare(0, 7, "MAXDIFF", 7) == 0) {
+      if (!parse_num(line, &maxdiff, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
-    if (strncmp(line, "MAXCPDSUGS", 10) == 0) {
-      if (parse_num(line, &maxcpdsugs, afflst)) {
+    if (line.compare(0, 10, "MAXCPDSUGS", 10) == 0) {
+      if (!parse_num(line, &maxcpdsugs, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
-    if (strncmp(line, "NOSPLITSUGS", 11) == 0) {
+    if (line.compare(0, 11, "NOSPLITSUGS", 11) == 0) {
       nosplitsugs = 1;
     }
 
-    if (strncmp(line, "FULLSTRIP", 9) == 0) {
+    if (line.compare(0, 9, "FULLSTRIP", 9) == 0) {
       fullstrip = 1;
     }
 
-    if (strncmp(line, "SUGSWITHDOTS", 12) == 0) {
+    if (line.compare(0, 12, "SUGSWITHDOTS", 12) == 0) {
       sugswithdots = 1;
     }
 
     /* parse in the flag used by forbidden words */
-    if (strncmp(line, "KEEPCASE", 8) == 0) {
-      if (parse_flag(line, &keepcase, afflst)) {
+    if (line.compare(0, 8, "KEEPCASE", 8) == 0) {
+      if (!parse_flag(line, &keepcase, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by `forceucase' */
-    if (strncmp(line, "FORCEUCASE", 10) == 0) {
-      if (parse_flag(line, &forceucase, afflst)) {
+    if (line.compare(0, 10, "FORCEUCASE", 10) == 0) {
+      if (!parse_flag(line, &forceucase, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
     /* parse in the flag used by `warn' */
-    if (strncmp(line, "WARN", 4) == 0) {
-      if (parse_flag(line, &warn, afflst)) {
+    if (line.compare(0, 4, "WARN", 4) == 0) {
+      if (!parse_flag(line, &warn, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
-    if (strncmp(line, "FORBIDWARN", 10) == 0) {
+    if (line.compare(0, 10, "FORBIDWARN", 10) == 0) {
       forbidwarn = 1;
     }
 
     /* parse in the flag used by the affix generator */
-    if (strncmp(line, "SUBSTANDARD", 11) == 0) {
-      if (parse_flag(line, &substandard, afflst)) {
+    if (line.compare(0, 11, "SUBSTANDARD", 11) == 0) {
+      if (!parse_flag(line, &substandard, afflst)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
 
-    if (strncmp(line, "CHECKSHARPS", 11) == 0) {
+    if (line.compare(0, 11, "CHECKSHARPS", 11) == 0) {
       checksharps = 1;
     }
 
     /* parse this affix: P - prefix, S - suffix */
-    ft = ' ';
-    if (strncmp(line, "PFX", 3) == 0)
+    // affix type
+    char ft = ' ';
+    if (line.compare(0, 3, "PFX", 3) == 0)
       ft = complexprefixes ? 'S' : 'P';
-    if (strncmp(line, "SFX", 3) == 0)
+    if (line.compare(0, 3, "SFX", 3) == 0)
       ft = complexprefixes ? 'P' : 'S';
     if (ft != ' ') {
       if (dupflags_ini) {
         memset(dupflags, 0, sizeof(dupflags));
         dupflags_ini = 0;
       }
-      if (parse_affix(line, ft, afflst, dupflags)) {
+      if (!parse_affix(line, ft, afflst, dupflags)) {
         finishFileMgr(afflst);
         return 1;
       }
     }
   }
 
   finishFileMgr(afflst);
   // affix trees are sorted now
@@ -843,47 +736,32 @@ int AffixMgr::parse_file(const char* aff
   // initialize
   // the nextne and nexteq pointers that relate them
 
   process_pfx_order();
   process_sfx_order();
 
   /* get encoding for CHECKCOMPOUNDCASE */
   if (!utf8) {
-    char* enc = get_encoding();
-    csconv = get_current_cs(enc);
-    free(enc);
-    enc = NULL;
-
-    std::string expw;
-    if (wordchars) {
-      expw.assign(wordchars);
-      free(wordchars);
-    }
-
+    csconv = get_current_cs(get_encoding());
     for (int i = 0; i <= 255; i++) {
       if ((csconv[i].cupper != csconv[i].clower) &&
-          (expw.find((char)i) == std::string::npos)) {
-        expw.push_back((char)i);
+          (wordchars.find((char)i) == std::string::npos)) {
+        wordchars.push_back((char)i);
       }
     }
 
-    wordchars = mystrdup(expw.c_str());
   }
 
   // default BREAK definition
-  if (numbreak == -1) {
-    breaktable = (char**)malloc(sizeof(char*) * 3);
-    if (!breaktable)
-      return 1;
-    breaktable[0] = mystrdup("-");
-    breaktable[1] = mystrdup("^-");
-    breaktable[2] = mystrdup("-$");
-    if (breaktable[0] && breaktable[1] && breaktable[2])
-      numbreak = 3;
+  if (!parsedbreaktable) {
+    breaktable.push_back("-");
+    breaktable.push_back("^-");
+    breaktable.push_back("-$");
+    parsedbreaktable = true;
   }
   return 0;
 }
 
 // we want to be able to quickly access prefix information
 // both by prefix flag, and sorted by prefix string itself
 // so we need to set up two indexes
 
@@ -944,16 +822,19 @@ int AffixMgr::build_pfxtree(PfxEntry* pf
   }
   return 0;
 }
 
 // we want to be able to quickly access suffix information
 // both by suffix flag, and sorted by the reverse of the
 // suffix string itself; so we need to set up two indexes
 int AffixMgr::build_sfxtree(SfxEntry* sfxptr) {
+
+  sfxptr->initReverseWord();
+
   SfxEntry* ptr;
   SfxEntry* pptr;
   SfxEntry* ep = sfxptr;
 
   /* get the right starting point */
   const char* key = ep->getKey();
   const unsigned char flg = (unsigned char)(ep->getFlag() & 0x00FF);
 
@@ -1138,27 +1019,16 @@ int AffixMgr::process_sfx_order() {
       if (mptr)
         mptr->setNextNE(NULL);
     }
   }
   return 0;
 }
 
 // add flags to the result for dictionary debugging
-void AffixMgr::debugflag(char* result, unsigned short flag) {
-  char* st = encode_flag(flag);
-  mystrcat(result, " ", MAXLNLEN);
-  mystrcat(result, MORPH_FLAG, MAXLNLEN);
-  if (st) {
-    mystrcat(result, st, MAXLNLEN);
-    free(st);
-  }
-}
-
-// add flags to the result for dictionary debugging
 std::string& AffixMgr::debugflag(std::string& result, unsigned short flag) {
   char* st = encode_flag(flag);
   result.append(" ");
   result.append(MORPH_FLAG);
   if (st) {
     result.append(st);
     free(st);
   }
@@ -1176,23 +1046,28 @@ int AffixMgr::condlen(const char* st) {
     } else if (*st == ']')
       group = false;
     else if (!group && (!utf8 || (!(*st & 0x80) || ((*st & 0xc0) == 0x80))))
       l++;
   }
   return l;
 }
 
-int AffixMgr::encodeit(affentry& entry, const char* cs) {
+int AffixMgr::encodeit(AffEntry& entry, const char* cs) {
   if (strcmp(cs, ".") != 0) {
     entry.numconds = (char)condlen(cs);
-    // coverity[buffer_size_warning] - deliberate use of lack of end of conds
-    // padded by strncpy as long condition flag
-    strncpy(entry.c.conds, cs, MAXCONDLEN);
-    if (entry.c.conds[MAXCONDLEN - 1] && cs[MAXCONDLEN]) {
+    const size_t cslen = strlen(cs);
+    const size_t short_part = std::min<size_t>(MAXCONDLEN, cslen);
+    memcpy(entry.c.conds, cs, short_part);
+    if (short_part < MAXCONDLEN) {
+      //blank out the remaining space
+      memset(entry.c.conds + short_part, 0, MAXCONDLEN - short_part);
+    } else if (cs[MAXCONDLEN]) {
+      //there is more conditions than fit in fixed space, so its
+      //a long condition
       entry.opts += aeLONGCOND;
       entry.c.l.conds2 = mystrdup(cs + MAXCONDLEN_1);
       if (!entry.c.l.conds2)
         return 1;
     }
   } else {
     entry.numconds = 0;
     entry.c.conds[0] = '\0';
@@ -1311,156 +1186,149 @@ struct hentry* AffixMgr::prefix_check_tw
       pptr = pptr->getNextNE();
     }
   }
 
   return NULL;
 }
 
 // check word for prefixes
-char* AffixMgr::prefix_check_morph(const char* word,
-                                   int len,
-                                   char in_compound,
-                                   const FLAG needflag) {
-
-  char result[MAXLNLEN];
-  result[0] = '\0';
+std::string AffixMgr::prefix_check_morph(const char* word,
+                                         int len,
+                                         char in_compound,
+                                         const FLAG needflag) {
+
+  std::string result;
 
   pfx = NULL;
   sfxappnd = NULL;
   sfxextra = 0;
 
   // first handle the special case of 0 length prefixes
   PfxEntry* pe = pStart[0];
   while (pe) {
-    char* st = pe->check_morph(word, len, in_compound, needflag);
-    if (st) {
-      mystrcat(result, st, MAXLNLEN);
-      free(st);
-    }
-    // if (rv) return rv;
-    pe = pe->getNext();
-  }
-
-  // now handle the general case
-  unsigned char sp = *((const unsigned char*)word);
-  PfxEntry* pptr = pStart[sp];
-
-  while (pptr) {
-    if (isSubset(pptr->getKey(), word)) {
-      char* st = pptr->check_morph(word, len, in_compound, needflag);
-      if (st) {
-        // fogemorpheme
-        if ((in_compound != IN_CPD_NOT) ||
-            !((pptr->getCont() && (TESTAFF(pptr->getCont(), onlyincompound,
-                                           pptr->getContLen()))))) {
-          mystrcat(result, st, MAXLNLEN);
-          pfx = pptr;
-        }
-        free(st);
-      }
-      pptr = pptr->getNextEQ();
-    } else {
-      pptr = pptr->getNextNE();
-    }
-  }
-
-  if (*result)
-    return mystrdup(result);
-  return NULL;
-}
-
-// check word for prefixes
-char* AffixMgr::prefix_check_twosfx_morph(const char* word,
-                                          int len,
-                                          char in_compound,
-                                          const FLAG needflag) {
-  char result[MAXLNLEN];
-  result[0] = '\0';
-
-  pfx = NULL;
-  sfxappnd = NULL;
-  sfxextra = 0;
-
-  // first handle the special case of 0 length prefixes
-  PfxEntry* pe = pStart[0];
-  while (pe) {
-    char* st = pe->check_twosfx_morph(word, len, in_compound, needflag);
-    if (st) {
-      mystrcat(result, st, MAXLNLEN);
-      free(st);
+    std::string st = pe->check_morph(word, len, in_compound, needflag);
+    if (!st.empty()) {
+      result.append(st);
     }
     pe = pe->getNext();
   }
 
   // now handle the general case
   unsigned char sp = *((const unsigned char*)word);
   PfxEntry* pptr = pStart[sp];
 
   while (pptr) {
     if (isSubset(pptr->getKey(), word)) {
-      char* st = pptr->check_twosfx_morph(word, len, in_compound, needflag);
-      if (st) {
-        mystrcat(result, st, MAXLNLEN);
-        free(st);
+      std::string st = pptr->check_morph(word, len, in_compound, needflag);
+      if (!st.empty()) {
+        // fogemorpheme
+        if ((in_compound != IN_CPD_NOT) ||
+            !((pptr->getCont() && (TESTAFF(pptr->getCont(), onlyincompound,
+                                           pptr->getContLen()))))) {
+          result.append(st);
+          pfx = pptr;
+        }
+      }
+      pptr = pptr->getNextEQ();
+    } else {
+      pptr = pptr->getNextNE();
+    }
+  }
+
+  return result;
+}
+
+// check word for prefixes
+std::string AffixMgr::prefix_check_twosfx_morph(const char* word,
+                                                int len,
+                                                char in_compound,
+                                                const FLAG needflag) {
+  std::string result;
+
+  pfx = NULL;
+  sfxappnd = NULL;
+  sfxextra = 0;
+
+  // first handle the special case of 0 length prefixes
+  PfxEntry* pe = pStart[0];
+  while (pe) {
+    std::string st = pe->check_twosfx_morph(word, len, in_compound, needflag);
+    if (!st.empty()) {
+      result.append(st);
+    }
+    pe = pe->getNext();
+  }
+
+  // now handle the general case
+  unsigned char sp = *((const unsigned char*)word);
+  PfxEntry* pptr = pStart[sp];
+
+  while (pptr) {
+    if (isSubset(pptr->getKey(), word)) {
+      std::string st = pptr->check_twosfx_morph(word, len, in_compound, needflag);
+      if (!st.empty()) {
+        result.append(st);
         pfx = pptr;
       }
       pptr = pptr->getNextEQ();
     } else {
       pptr = pptr->getNextNE();
     }
   }
 
-  if (*result)
-    return mystrdup(result);
-  return NULL;
+  return result;
 }
 
 // Is word a non compound with a REP substitution (see checkcompoundrep)?
 int AffixMgr::cpdrep_check(const char* word, int wl) {
 
-  if ((wl < 2) || !numrep)
+  if ((wl < 2) || reptable.empty())
     return 0;
 
-  for (int i = 0; i < numrep; i++) {
+  for (size_t i = 0; i < reptable.size(); ++i) {
     const char* r = word;
-    int lenp = strlen(reptable[i].pattern);
+    const size_t lenp = reptable[i].pattern.size();
     // search every occurence of the pattern in the word
-    while ((r = strstr(r, reptable[i].pattern)) != NULL) {
+    while ((r = strstr(r, reptable[i].pattern.c_str())) != NULL) {
       std::string candidate(word);
-      candidate.replace(r - word, lenp, reptable[i].pattern2);
+      size_t type = r == word ? 1 : 0;
+      if (r - word + reptable[i].pattern.size() == lenp)
+        type += 2;
+      candidate.replace(r - word, lenp, reptable[i].outstrings[type]);
       if (candidate_check(candidate.c_str(), candidate.size()))
         return 1;
-      r++;  // search for the next letter
+      ++r;  // search for the next letter
     }
   }
+
   return 0;
 }
 
 // forbid compoundings when there are special patterns at word bound
 int AffixMgr::cpdpat_check(const char* word,
                            int pos,
                            hentry* r1,
                            hentry* r2,
                            const char /*affixed*/) {
-  int len;
-  for (int i = 0; i < numcheckcpd; i++) {
-    if (isSubset(checkcpdtable[i].pattern2, word + pos) &&
+  for (size_t i = 0; i < checkcpdtable.size(); ++i) {
+    size_t len;
+    if (isSubset(checkcpdtable[i].pattern2.c_str(), word + pos) &&
         (!r1 || !checkcpdtable[i].cond ||
          (r1->astr && TESTAFF(r1->astr, checkcpdtable[i].cond, r1->alen))) &&
         (!r2 || !checkcpdtable[i].cond2 ||
          (r2->astr && TESTAFF(r2->astr, checkcpdtable[i].cond2, r2->alen))) &&
         // zero length pattern => only TESTAFF
         // zero pattern (0/flag) => unmodified stem (zero affixes allowed)
-        (!*(checkcpdtable[i].pattern) ||
-         ((*(checkcpdtable[i].pattern) == '0' && r1->blen <= pos &&
+        (checkcpdtable[i].pattern.empty() ||
+         ((checkcpdtable[i].pattern[0] == '0' && r1->blen <= pos &&
            strncmp(word + pos - r1->blen, r1->word, r1->blen) == 0) ||
-          (*(checkcpdtable[i].pattern) != '0' &&
-           ((len = strlen(checkcpdtable[i].pattern)) != 0) &&
-           strncmp(word + pos - len, checkcpdtable[i].pattern, len) == 0)))) {
+          (checkcpdtable[i].pattern[0] != '0' &&
+           ((len = checkcpdtable[i].pattern.size()) != 0) &&
+           strncmp(word + pos - len, checkcpdtable[i].pattern.c_str(), len) == 0)))) {
       return 1;
     }
   }
   return 0;
 }
 
 // forbid compounding with neighbouring upper and lower case characters at word
 // bounds
@@ -1508,63 +1376,62 @@ int AffixMgr::defcpd_check(hentry*** wor
 
   if (!*words) {
     return 0;
   }
 
   std::vector<metachar_data> btinfo(1);
 
   short bt = 0;
-  int i, j;
 
   (*words)[wnum] = rv;
 
   // has the last word COMPOUNDRULE flag?
   if (rv->alen == 0) {
     (*words)[wnum] = NULL;
     if (w)
       *words = NULL;
     return 0;
   }
   int ok = 0;
-  for (i = 0; i < numdefcpd; i++) {
-    for (j = 0; j < defcpdtable[i].len; j++) {
-      if (defcpdtable[i].def[j] != '*' && defcpdtable[i].def[j] != '?' &&
-          TESTAFF(rv->astr, defcpdtable[i].def[j], rv->alen)) {
+  for (size_t i = 0; i < defcpdtable.size(); ++i) {
+    for (size_t j = 0; j < defcpdtable[i].size(); ++j) {
+      if (defcpdtable[i][j] != '*' && defcpdtable[i][j] != '?' &&
+          TESTAFF(rv->astr, defcpdtable[i][j], rv->alen)) {
         ok = 1;
         break;
       }
     }
   }
   if (ok == 0) {
     (*words)[wnum] = NULL;
     if (w)
       *words = NULL;
     return 0;
   }
 
-  for (i = 0; i < numdefcpd; i++) {
-    signed short pp = 0;  // pattern position
+  for (size_t i = 0; i < defcpdtable.size(); ++i) {
+    size_t pp = 0;  // pattern position
     signed short wp = 0;  // "words" position
     int ok2;
     ok = 1;
     ok2 = 1;
     do {
-      while ((pp < defcpdtable[i].len) && (wp <= wnum)) {
-        if (((pp + 1) < defcpdtable[i].len) &&
-            ((defcpdtable[i].def[pp + 1] == '*') ||
-             (defcpdtable[i].def[pp + 1] == '?'))) {
-          int wend = (defcpdtable[i].def[pp + 1] == '?') ? wp : wnum;
+      while ((pp < defcpdtable[i].size()) && (wp <= wnum)) {
+        if (((pp + 1) < defcpdtable[i].size()) &&
+            ((defcpdtable[i][pp + 1] == '*') ||
+             (defcpdtable[i][pp + 1] == '?'))) {
+          int wend = (defcpdtable[i][pp + 1] == '?') ? wp : wnum;
           ok2 = 1;
           pp += 2;
           btinfo[bt].btpp = pp;
           btinfo[bt].btwp = wp;
           while (wp <= wend) {
             if (!(*words)[wp]->alen ||
-                !TESTAFF((*words)[wp]->astr, defcpdtable[i].def[pp - 2],
+                !TESTAFF((*words)[wp]->astr, defcpdtable[i][pp - 2],
                          (*words)[wp]->alen)) {
               ok2 = 0;
               break;
             }
             wp++;
           }
           if (wp <= wnum)
             ok2 = 0;
@@ -1573,56 +1440,56 @@ int AffixMgr::defcpd_check(hentry*** wor
             ++bt;
             btinfo.resize(bt+1);
           }
           if (ok2)
             break;
         } else {
           ok2 = 1;
           if (!(*words)[wp] || !(*words)[wp]->alen ||
-              !TESTAFF((*words)[wp]->astr, defcpdtable[i].def[pp],
+              !TESTAFF((*words)[wp]->astr, defcpdtable[i][pp],
                        (*words)[wp]->alen)) {
             ok = 0;
             break;
           }
           pp++;
           wp++;
-          if ((defcpdtable[i].len == pp) && !(wp > wnum))
+          if ((defcpdtable[i].size() == pp) && !(wp > wnum))
             ok = 0;
         }
       }
       if (ok && ok2) {
-        int r = pp;
-        while ((defcpdtable[i].len > r) && ((r + 1) < defcpdtable[i].len) &&
-               ((defcpdtable[i].def[r + 1] == '*') ||
-                (defcpdtable[i].def[r + 1] == '?')))
+        size_t r = pp;
+        while ((defcpdtable[i].size() > r) && ((r + 1) < defcpdtable[i].size()) &&
+               ((defcpdtable[i][r + 1] == '*') ||
+                (defcpdtable[i][r + 1] == '?')))
           r += 2;
-        if (defcpdtable[i].len <= r)
+        if (defcpdtable[i].size() <= r)
           return 1;
       }
       // backtrack
       if (bt)
         do {
           ok = 1;
           btinfo[bt - 1].btnum--;
           pp = btinfo[bt - 1].btpp;
           wp = btinfo[bt - 1].btwp + (signed short)btinfo[bt - 1].btnum;
         } while ((btinfo[bt - 1].btnum < 0) && --bt);
     } while (bt);
 
-    if (ok && ok2 && (!all || (defcpdtable[i].len <= pp)))
+    if (ok && ok2 && (!all || (defcpdtable[i].size() <= pp)))
       return 1;
 
     // check zero ending
-    while (ok && ok2 && (defcpdtable[i].len > pp) &&
-           ((pp + 1) < defcpdtable[i].len) &&
-           ((defcpdtable[i].def[pp + 1] == '*') ||
-            (defcpdtable[i].def[pp + 1] == '?')))
+    while (ok && ok2 && (defcpdtable[i].size() > pp) &&
+           ((pp + 1) < defcpdtable[i].size()) &&
+           ((defcpdtable[i][pp + 1] == '*') ||
+            (defcpdtable[i][pp + 1] == '?')))
       pp += 2;
-    if (ok && ok2 && (defcpdtable[i].len <= pp))
+    if (ok && ok2 && (defcpdtable[i].size() <= pp))
       return 1;
   }
   (*words)[wnum] = NULL;
   if (w)
     *words = NULL;
   return 0;
 }
 
@@ -1646,30 +1513,33 @@ inline int AffixMgr::candidate_check(con
 short AffixMgr::get_syllable(const std::string& word) {
   if (cpdmaxsyllable == 0)
     return 0;
 
   short num = 0;
 
   if (!utf8) {
     for (size_t i = 0; i < word.size(); ++i) {
-      if (strchr(cpdvowels, word[i]))
-        num++;
+      if (std::binary_search(cpdvowels.begin(), cpdvowels.end(),
+                             word[i])) {
+        ++num;
+      }
     }
-  } else if (cpdvowels_utf16) {
+  } else if (!cpdvowels_utf16.empty()) {
     std::vector<w_char> w;
-    int i = u8_u16(w, word);
-    for (; i > 0; i--) {
-      if (std::binary_search(cpdvowels_utf16,
-                             cpdvowels_utf16 + cpdvowels_utf16_len,
-                             w[i - 1])) {
+    u8_u16(w, word);
+    for (size_t i = 0; i < w.size(); ++i) {
+      if (std::binary_search(cpdvowels_utf16.begin(),
+                             cpdvowels_utf16.end(),
+                             w[i])) {
         ++num;
       }
     }
   }
+
   return num;
 }
 
 void AffixMgr::setcminmax(int* cmin, int* cmax, const char* word, int len) {
   if (utf8) {
     int i;
     for (*cmin = 0, i = 0; (i < cpdmin) && *cmin < len; i++) {
       for ((*cmin)++; *cmin < len && (word[*cmin] & 0xc0) == 0x80; (*cmin)++)
@@ -1682,18 +1552,17 @@ void AffixMgr::setcminmax(int* cmin, int
   } else {
     *cmin = cpdmin;
     *cmax = len - cpdmin + 1;
   }
 }
 
 // check if compound word is correctly spelled
 // hu_mov_rule = spec. Hungarian rule (XXX)
-struct hentry* AffixMgr::compound_check(const char* word,
-                                        int len,
+struct hentry* AffixMgr::compound_check(const std::string& word,
                                         short wordnum,
                                         short numsyllable,
                                         short maxwordnum,
                                         short wnum,
                                         hentry** words = NULL,
                                         hentry** rwords = NULL,
                                         char hu_mov_rule = 0,
                                         char is_sug = 0,
@@ -1702,73 +1571,73 @@ struct hentry* AffixMgr::compound_check(
   short oldnumsyllable, oldnumsyllable2, oldwordnum, oldwordnum2;
   struct hentry* rv = NULL;
   struct hentry* rv_first;
   std::string st;
   char ch = '\0';
   int cmin;
   int cmax;
   int striple = 0;
-  int scpd = 0;
+  size_t scpd = 0;
   int soldi = 0;
   int oldcmin = 0;
   int oldcmax = 0;
   int oldlen = 0;
   int checkedstriple = 0;
-  int onlycpdrule;
   char affixed = 0;
   hentry** oldwords = words;
+  size_t len = word.size();
 
   int checked_prefix;
 
-  setcminmax(&cmin, &cmax, word, len);
+  setcminmax(&cmin, &cmax, word.c_str(), len);
 
   st.assign(word);
 
   for (i = cmin; i < cmax; i++) {
     // go to end of the UTF-8 character
     if (utf8) {
       for (; (st[i] & 0xc0) == 0x80; i++)
         ;
       if (i >= cmax)
         return NULL;
     }
 
     words = oldwords;
-    onlycpdrule = (words) ? 1 : 0;
+    int onlycpdrule = (words) ? 1 : 0;
 
     do {  // onlycpdrule loop
 
       oldnumsyllable = numsyllable;
       oldwordnum = wordnum;
       checked_prefix = 0;
 
       do {  // simplified checkcompoundpattern loop
 
         if (scpd > 0) {
-          for (; scpd <= numcheckcpd &&
-                 (!checkcpdtable[scpd - 1].pattern3 ||
-                  strncmp(word + i, checkcpdtable[scpd - 1].pattern3,
-                          strlen(checkcpdtable[scpd - 1].pattern3)) != 0);
+          for (; scpd <= checkcpdtable.size() &&
+                 (checkcpdtable[scpd - 1].pattern3.empty() ||
+                  strncmp(word.c_str() + i, checkcpdtable[scpd - 1].pattern3.c_str(),
+                          checkcpdtable[scpd - 1].pattern3.size()) != 0);
                scpd++)
             ;
 
-          if (scpd > numcheckcpd)
+          if (scpd > checkcpdtable.size())
             break;  // break simplified checkcompoundpattern loop
           st.replace(i, std::string::npos, checkcpdtable[scpd - 1].pattern);
           soldi = i;
-          i += strlen(checkcpdtable[scpd - 1].pattern);
+          i += checkcpdtable[scpd - 1].pattern.size();
           st.replace(i, std::string::npos, checkcpdtable[scpd - 1].pattern2);
-          st.replace(i + strlen(checkcpdtable[scpd - 1].pattern2), std::string::npos,
-                 word + soldi + strlen(checkcpdtable[scpd - 1].pattern3));
+          st.replace(i + checkcpdtable[scpd - 1].pattern2.size(), std::string::npos,
+                 word.substr(soldi + checkcpdtable[scpd - 1].pattern3.size()));
 
           oldlen = len;
-          len += strlen(checkcpdtable[scpd - 1].pattern) +
-                 strlen(checkcpdtable[scpd - 1].pattern2) -
-                 strlen(checkcpdtable[scpd - 1].pattern3);
+          len += checkcpdtable[scpd - 1].pattern.size() +
+                 checkcpdtable[scpd - 1].pattern2.size() -
+                 checkcpdtable[scpd - 1].pattern3.size();
           oldcmin = cmin;
           oldcmax = cmax;
           setcminmax(&cmin, &cmax, st.c_str(), len);
 
           cmax = len - cpdmin + 1;
         }
 
         ch = st[i];
@@ -1786,17 +1655,17 @@ struct hentry* AffixMgr::compound_check(
         while ((rv) && !hu_mov_rule &&
                ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) ||
                 !((compoundflag && !words && !onlycpdrule &&
                    TESTAFF(rv->astr, compoundflag, rv->alen)) ||
                   (compoundbegin && !wordnum && !onlycpdrule &&
                    TESTAFF(rv->astr, compoundbegin, rv->alen)) ||
                   (compoundmiddle && wordnum && !words && !onlycpdrule &&
                    TESTAFF(rv->astr, compoundmiddle, rv->alen)) ||
-                  (numdefcpd && onlycpdrule &&
+                  (!defcpdtable.empty() && onlycpdrule &&
                    ((!words && !wordnum &&
                      defcpd_check(&words, wnum, rv, rwords, 0)) ||
                     (words &&
                      defcpd_check(&words, wnum, rv, rwords, 0))))) ||
                 (scpd != 0 && checkcpdtable[scpd - 1].cond != FLAG_NULL &&
                  !TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond, rv->alen)))) {
           rv = rv->next_homonym;
         }
@@ -1807,45 +1676,45 @@ struct hentry* AffixMgr::compound_check(
         if (!rv) {
           if (onlycpdrule)
             break;
           if (compoundflag &&
               !(rv = prefix_check(st.c_str(), i,
                                   hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN,
                                   compoundflag))) {
             if (((rv = suffix_check(
-                      st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL, compoundflag,
+                      st.c_str(), i, 0, NULL, FLAG_NULL, compoundflag,
                       hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) ||
                  (compoundmoresuffixes &&
                   (rv = suffix_check_twosfx(st.c_str(), i, 0, NULL, compoundflag)))) &&
                 !hu_mov_rule && sfx->getCont() &&
                 ((compoundforbidflag &&
                   TESTAFF(sfx->getCont(), compoundforbidflag,
                           sfx->getContLen())) ||
                  (compoundend &&
                   TESTAFF(sfx->getCont(), compoundend, sfx->getContLen())))) {
               rv = NULL;
             }
           }
 
           if (rv ||
               (((wordnum == 0) && compoundbegin &&
                 ((rv = suffix_check(
-                      st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL, compoundbegin,
+                      st.c_str(), i, 0, NULL, FLAG_NULL, compoundbegin,
                       hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) ||
                  (compoundmoresuffixes &&
                   (rv = suffix_check_twosfx(
                        st.c_str(), i, 0, NULL,
                        compoundbegin))) ||  // twofold suffixes + compound
                  (rv = prefix_check(st.c_str(), i,
                                     hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN,
                                     compoundbegin)))) ||
                ((wordnum > 0) && compoundmiddle &&
                 ((rv = suffix_check(
-                      st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL, compoundmiddle,
+                      st.c_str(), i, 0, NULL, FLAG_NULL, compoundmiddle,
                       hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) ||
                  (compoundmoresuffixes &&
                   (rv = suffix_check_twosfx(
                        st.c_str(), i, 0, NULL,
                        compoundmiddle))) ||  // twofold suffixes + compound
                  (rv = prefix_check(st.c_str(), i,
                                     hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN,
                                     compoundmiddle))))))
@@ -1906,18 +1775,17 @@ struct hentry* AffixMgr::compound_check(
 
         // first word is acceptable in compound words?
         if (((rv) &&
              (checked_prefix || (words && words[wnum]) ||
               (compoundflag && TESTAFF(rv->astr, compoundflag, rv->alen)) ||
               ((oldwordnum == 0) && compoundbegin &&
                TESTAFF(rv->astr, compoundbegin, rv->alen)) ||
               ((oldwordnum > 0) && compoundmiddle &&
-               TESTAFF(rv->astr, compoundmiddle, rv->alen))  // ||
-              //            (numdefcpd && )
+               TESTAFF(rv->astr, compoundmiddle, rv->alen))
 
               // LANG_hu section: spec. Hungarian rule
               || ((langnum == LANG_hu) && hu_mov_rule &&
                   (TESTAFF(
                        rv->astr, 'F',
                        rv->alen) ||  // XXX hardwired Hungarian dictionary codes
                    TESTAFF(rv->astr, 'G', rv->alen) ||
                    TESTAFF(rv->astr, 'H', rv->alen)))
@@ -1929,17 +1797,17 @@ struct hentry* AffixMgr::compound_check(
                  TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond, rv->alen)) &&
              !((checkcompoundtriple && scpd == 0 &&
                 !words &&  // test triple letters
                 (word[i - 1] == word[i]) &&
                 (((i > 1) && (word[i - 1] == word[i - 2])) ||
                  ((word[i - 1] == word[i + 1]))  // may be word[i+1] == '\0'
                  )) ||
                (checkcompoundcase && scpd == 0 && !words &&
-                cpdcase_check(word, i))))
+                cpdcase_check(word.c_str(), i))))
             // LANG_hu section: spec. Hungarian rule
             || ((!rv) && (langnum == LANG_hu) && hu_mov_rule &&
                 (rv = affix_check(st.c_str(), i)) &&
                 (sfx && sfx->getCont() &&
                  (  // XXX hardwired Hungarian dic. codes
                      TESTAFF(sfx->getCont(), (unsigned short)'x',
                              sfx->getContLen()) ||
                      TESTAFF(
@@ -1963,30 +1831,30 @@ struct hentry* AffixMgr::compound_check(
 
           do {  // striple loop
 
             // check simplifiedtriple
             if (simplifiedtriple) {
               if (striple) {
                 checkedstriple = 1;
                 i--;  // check "fahrt" instead of "ahrt" in "Schiffahrt"
-              } else if (i > 2 && *(word + i - 1) == *(word + i - 2))
+              } else if (i > 2 && word[i - 1] == word[i - 2])
                 striple = 1;
             }
 
             rv = lookup(st.c_str() + i);  // perhaps without prefix
 
             // search homonym with compound flag
             while ((rv) &&
                    ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) ||
                     !((compoundflag && !words &&
                        TESTAFF(rv->astr, compoundflag, rv->alen)) ||
                       (compoundend && !words &&
                        TESTAFF(rv->astr, compoundend, rv->alen)) ||
-                      (numdefcpd && words &&
+                      (!defcpdtable.empty() && words &&
                        defcpd_check(&words, wnum + 1, rv, NULL, 1))) ||
                     (scpd != 0 && checkcpdtable[scpd - 1].cond2 != FLAG_NULL &&
                      !TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond2,
                               rv->alen)))) {
               rv = rv->next_homonym;
             }
 
             // check FORCEUCASE
@@ -2033,63 +1901,63 @@ struct hentry* AffixMgr::compound_check(
                 ((compoundflag && TESTAFF(rv->astr, compoundflag, rv->alen)) ||
                  (compoundend && TESTAFF(rv->astr, compoundend, rv->alen))) &&
                 (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) ||
                  ((cpdmaxsyllable != 0) &&
                   (numsyllable + get_syllable(std::string(HENTRY_WORD(rv), rv->clen)) <=
                    cpdmaxsyllable))) &&
                 (
                     // test CHECKCOMPOUNDPATTERN
-                    !numcheckcpd || scpd != 0 ||
-                    !cpdpat_check(word, i, rv_first, rv, 0)) &&
+                    checkcpdtable.empty() || scpd != 0 ||
+                    !cpdpat_check(word.c_str(), i, rv_first, rv, 0)) &&
                 ((!checkcompounddup || (rv != rv_first)))
                 // test CHECKCOMPOUNDPATTERN conditions
                 &&
                 (scpd == 0 || checkcpdtable[scpd - 1].cond2 == FLAG_NULL ||
                  TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond2, rv->alen))) {
               // forbid compound word, if it is a non compound word with typical
               // fault
-              if (checkcompoundrep && cpdrep_check(word, len))
+              if (checkcompoundrep && cpdrep_check(word.c_str(), len))
                 return NULL;
               return rv_first;
             }
 
             numsyllable = oldnumsyllable2;
             wordnum = oldwordnum2;
 
             // perhaps second word has prefix or/and suffix
             sfx = NULL;
             sfxflag = FLAG_NULL;
             rv = (compoundflag && !onlycpdrule)
-                     ? affix_check((word + i), strlen(word + i), compoundflag,
+                     ? affix_check((word.c_str() + i), strlen(word.c_str() + i), compoundflag,
                                    IN_CPD_END)
                      : NULL;
             if (!rv && compoundend && !onlycpdrule) {
               sfx = NULL;
               pfx = NULL;
-              rv = affix_check((word + i), strlen(word + i), compoundend,
+              rv = affix_check((word.c_str() + i), strlen(word.c_str() + i), compoundend,
                                IN_CPD_END);
             }
 
-            if (!rv && numdefcpd && words) {
-              rv = affix_check((word + i), strlen(word + i), 0, IN_CPD_END);
+            if (!rv && !defcpdtable.empty() && words) {
+              rv = affix_check((word.c_str() + i), strlen(word.c_str() + i), 0, IN_CPD_END);
               if (rv && defcpd_check(&words, wnum + 1, rv, NULL, 1))
                 return rv_first;
               rv = NULL;
             }
 
             // test CHECKCOMPOUNDPATTERN conditions (allowed forms)
             if (rv &&
                 !(scpd == 0 || checkcpdtable[scpd - 1].cond2 == FLAG_NULL ||
                   TESTAFF(rv->astr, checkcpdtable[scpd - 1].cond2, rv->alen)))
               rv = NULL;
 
             // test CHECKCOMPOUNDPATTERN conditions (forbidden compounds)
-            if (rv && numcheckcpd && scpd == 0 &&
-                cpdpat_check(word, i, rv_first, rv, affixed))
+            if (rv && !checkcpdtable.empty() && scpd == 0 &&
+                cpdpat_check(word.c_str(), i, rv_first, rv, affixed))
               rv = NULL;
 
             // check non_compound flag in suffix and prefix
             if ((rv) && ((pfx && pfx->getCont() &&
                           TESTAFF(pfx->getCont(), compoundforbidflag,
                                   pfx->getContLen())) ||
                          (sfx && sfx->getCont() &&
                           TESTAFF(sfx->getCont(), compoundforbidflag,
@@ -2113,17 +1981,17 @@ struct hentry* AffixMgr::compound_check(
 
             // pfxappnd = prefix of word+i, or NULL
             // calculate syllable number of prefix.
             // hungarian convention: when syllable number of prefix is more,
             // than 1, the prefix+word counts as two words.
 
             if (langnum == LANG_hu) {
               // calculate syllable number of the word
-              numsyllable += get_syllable(word + i);
+              numsyllable += get_syllable(word.c_str() + i);
 
               // - affix syllable num.
               // XXX only second suffix (inflections, not derivations)
               if (sfxappnd) {
                 std::string tmp(sfxappnd);
                 reverseword(tmp);
                 numsyllable -= get_syllable(tmp) + sfxextra;
               }
@@ -2131,17 +1999,17 @@ struct hentry* AffixMgr::compound_check(
               // + 1 word, if syllable number of the prefix > 1 (hungarian
               // convention)
               if (pfx && (get_syllable(pfx->getKey()) > 1))
                 wordnum++;
 
               // increment syllable num, if last word has a SYLLABLENUM flag
               // and the suffix is beginning `s'
 
-              if (cpdsyllablenum) {
+              if (!cpdsyllablenum.empty()) {
                 switch (sfxflag) {
                   case 'c': {
                     numsyllable += 2;
                     break;
                   }
                   case 'J': {
                     numsyllable += 1;
                     break;
@@ -2166,62 +2034,61 @@ struct hentry* AffixMgr::compound_check(
             // when compound forms consist 2 word, otherwise
             // the syllable number of root words is 6, or lesser.
             if ((rv) &&
                 (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) ||
                  ((cpdmaxsyllable != 0) && (numsyllable <= cpdmaxsyllable))) &&
                 ((!checkcompounddup || (rv != rv_first)))) {
               // forbid compound word, if it is a non compound word with typical
               // fault
-              if (checkcompoundrep && cpdrep_check(word, len))
+              if (checkcompoundrep && cpdrep_check(word.c_str(), len))
                 return NULL;
               return rv_first;
             }
 
             numsyllable = oldnumsyllable2;
             wordnum = oldwordnum2;
 
             // perhaps second word is a compound word (recursive call)
             if (wordnum < maxwordnum) {
-              rv = compound_check(st.c_str() + i, strlen(st.c_str() + i), wordnum + 1,
+              rv = compound_check(st.substr(i), wordnum + 1,
                                   numsyllable, maxwordnum, wnum + 1, words, rwords, 0,
                                   is_sug, info);
 
-              if (rv && numcheckcpd &&
+              if (rv && !checkcpdtable.empty() &&
                   ((scpd == 0 &&
-                    cpdpat_check(word, i, rv_first, rv, affixed)) ||
+                    cpdpat_check(word.c_str(), i, rv_first, rv, affixed)) ||
                    (scpd != 0 &&
-                    !cpdpat_check(word, i, rv_first, rv, affixed))))
+                    !cpdpat_check(word.c_str(), i, rv_first, rv, affixed))))
                 rv = NULL;
             } else {
               rv = NULL;
             }
             if (rv) {
               // forbid compound word, if it is a non compound word with typical
               // fault
               if (checkcompoundrep || forbiddenword) {
-                struct hentry* rv2 = NULL;
-
-                if (checkcompoundrep && cpdrep_check(word, len))
+
+                if (checkcompoundrep && cpdrep_check(word.c_str(), len))
                   return NULL;
 
                 // check first part
-                if (strncmp(rv->word, word + i, rv->blen) == 0) {
+                if (strncmp(rv->word, word.c_str() + i, rv->blen) == 0) {
                   char r = st[i + rv->blen];
                   st[i + rv->blen] = '\0';
 
                   if (checkcompoundrep && cpdrep_check(st.c_str(), i + rv->blen)) {
                     st[ + i + rv->blen] = r;
                     continue;
                   }
 
                   if (forbiddenword) {
-                    rv2 = lookup(word);
+                    struct hentry* rv2 = lookup(word.c_str());
                     if (!rv2)
-                      rv2 = affix_check(word, len);
+                      rv2 = affix_check(word.c_str(), len);
                     if (rv2 && rv2->astr &&
                         TESTAFF(rv2->astr, forbiddenword, rv2->alen) &&
                         (strncmp(rv2->word, st.c_str(), i + rv->blen) == 0)) {
                       return NULL;
                     }
                   }
                   st[i + rv->blen] = r;
                 }
@@ -2243,65 +2110,64 @@ struct hentry* AffixMgr::compound_check(
           soldi = 0;
           len = oldlen;
           cmin = oldcmin;
           cmax = oldcmax;
         }
         scpd++;
 
       } while (!onlycpdrule && simplifiedcpd &&
-               scpd <= numcheckcpd);  // end of simplifiedcpd loop
+               scpd <= checkcpdtable.size());  // end of simplifiedcpd loop
 
       scpd = 0;
       wordnum = oldwordnum;
       numsyllable = oldnumsyllable;
 
       if (soldi != 0) {
         i = soldi;
         st.assign(word);  // XXX add more optim.
         soldi = 0;
       } else
         st[i] = ch;
 
-    } while (numdefcpd && oldwordnum == 0 &&
+    } while (!defcpdtable.empty() && oldwordnum == 0 &&
              onlycpdrule++ < 1);  // end of onlycpd loop
   }
 
   return NULL;
 }
 
 // check if compound word is correctly spelled
 // hu_mov_rule = spec. Hungarian rule (XXX)
 int AffixMgr::compound_check_morph(const char* word,
                                    int len,
                                    short wordnum,
                                    short numsyllable,
                                    short maxwordnum,
                                    short wnum,
                                    hentry** words,
                                    hentry** rwords,
-                                   char hu_mov_rule = 0,
-                                   char** result = NULL,
-                                   char* partresult = NULL) {
+                                   char hu_mov_rule,
+                                   std::string& result,
+                                   const std::string* partresult) {
   int i;
   short oldnumsyllable, oldnumsyllable2, oldwordnum, oldwordnum2;
   int ok = 0;
 
   struct hentry* rv = NULL;
   struct hentry* rv_first;
   std::string st;
   char ch;
 
   int checked_prefix;
-  char presult[MAXLNLEN];
+  std::string presult;
 
   int cmin;
   int cmax;
 
-  int onlycpdrule;
   char affixed = 0;
   hentry** oldwords = words;
 
   setcminmax(&cmin, &cmax, word, len);
 
   st.assign(word);
 
   for (i = cmin; i < cmax; i++) {
@@ -2309,138 +2175,133 @@ int AffixMgr::compound_check_morph(const
     if (utf8) {
       for (; (st[i] & 0xc0) == 0x80; i++)
         ;
       if (i >= cmax)
         return 0;
     }
 
     words = oldwords;
-    onlycpdrule = (words) ? 1 : 0;
+    int onlycpdrule = (words) ? 1 : 0;
 
     do {  // onlycpdrule loop
 
       oldnumsyllable = numsyllable;
       oldwordnum = wordnum;
       checked_prefix = 0;
 
       ch = st[i];
       st[i] = '\0';
       sfx = NULL;
 
       // FIRST WORD
 
       affixed = 1;
 
-      *presult = '\0';
+      presult.clear();
       if (partresult)
-        mystrcat(presult, partresult, MAXLNLEN);
+        presult.append(*partresult);
 
       rv = lookup(st.c_str());  // perhaps without prefix
 
       // search homonym with compound flag
       while ((rv) && !hu_mov_rule &&
              ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) ||
               !((compoundflag && !words && !onlycpdrule &&
                  TESTAFF(rv->astr, compoundflag, rv->alen)) ||
                 (compoundbegin && !wordnum && !onlycpdrule &&
                  TESTAFF(rv->astr, compoundbegin, rv->alen)) ||
                 (compoundmiddle && wordnum && !words && !onlycpdrule &&
                  TESTAFF(rv->astr, compoundmiddle, rv->alen)) ||
-                (numdefcpd && onlycpdrule &&
+                (!defcpdtable.empty() && onlycpdrule &&
                  ((!words && !wordnum &&
                    defcpd_check(&words, wnum, rv, rwords, 0)) ||
                   (words &&
                    defcpd_check(&words, wnum, rv, rwords, 0))))))) {
         rv = rv->next_homonym;
       }
 
       if (rv)
         affixed = 0;
 
       if (rv) {
-        sprintf(presult + strlen(presult), "%c%s%s", MSEP_FLD, MORPH_PART, st.c_str());
+        presult.push_back(MSEP_FLD);
+        presult.append(MORPH_PART);
+        presult.append(st.c_str());
         if (!HENTRY_FIND(rv, MORPH_STEM)) {
-          sprintf(presult + strlen(presult), "%c%s%s", MSEP_FLD, MORPH_STEM,
-                  st.c_str());
+          presult.push_back(MSEP_FLD);
+          presult.append(MORPH_STEM);
+          presult.append(st.c_str());
         }
-        // store the pointer of the hash entry
-        //            sprintf(presult + strlen(presult), "%c%s%p", MSEP_FLD,
-        //            MORPH_HENTRY, rv);
         if (HENTRY_DATA(rv)) {
-          sprintf(presult + strlen(presult), "%c%s", MSEP_FLD,
-                  HENTRY_DATA2(rv));
+          presult.push_back(MSEP_FLD);
+          presult.append(HENTRY_DATA2(rv));
         }
       }
 
       if (!rv) {
-        if (onlycpdrule && strlen(*result) > MAXLNLEN / 10)
-          break;
         if (compoundflag &&
             !(rv =
                   prefix_check(st.c_str(), i, hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN,
                                compoundflag))) {
-          if (((rv = suffix_check(st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL,
+          if (((rv = suffix_check(st.c_str(), i, 0, NULL, FLAG_NULL,
                                   compoundflag,
                                   hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) ||
                (compoundmoresuffixes &&
                 (rv = suffix_check_twosfx(st.c_str(), i, 0, NULL, compoundflag)))) &&
               !hu_mov_rule && sfx->getCont() &&
               ((compoundforbidflag &&
                 TESTAFF(sfx->getCont(), compoundforbidflag,
                         sfx->getContLen())) ||
                (compoundend &&
                 TESTAFF(sfx->getCont(), compoundend, sfx->getContLen())))) {
             rv = NULL;
           }
         }
 
         if (rv ||
             (((wordnum == 0) && compoundbegin &&
-              ((rv = suffix_check(st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL,
+              ((rv = suffix_check(st.c_str(), i, 0, NULL, FLAG_NULL,
                                   compoundbegin,
                                   hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) ||
                (compoundmoresuffixes &&
                 (rv = suffix_check_twosfx(
                      st.c_str(), i, 0, NULL,
                      compoundbegin))) ||  // twofold suffix+compound
                (rv = prefix_check(st.c_str(), i,
                                   hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN,
                                   compoundbegin)))) ||
              ((wordnum > 0) && compoundmiddle &&
-              ((rv = suffix_check(st.c_str(), i, 0, NULL, NULL, 0, NULL, FLAG_NULL,
+              ((rv = suffix_check(st.c_str(), i, 0, NULL, FLAG_NULL,
                                   compoundmiddle,
                                   hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN)) ||
                (compoundmoresuffixes &&
                 (rv = suffix_check_twosfx(
                      st.c_str(), i, 0, NULL,
                      compoundmiddle))) ||  // twofold suffix+compound
                (rv = prefix_check(st.c_str(), i,
                                   hu_mov_rule ? IN_CPD_OTHER : IN_CPD_BEGIN,
                                   compoundmiddle)))))) {
-          // char * p = prefix_check_morph(st, i, 0, compound);
-          char* p = NULL;
+          std::string p;
           if (compoundflag)
             p = affix_check_morph(st.c_str(), i, compoundflag);
-          if (!p || (*p == '\0')) {
-            if (p)
-              free(p);
-            p = NULL;
+          if (p.empty()) {
             if ((wordnum == 0) && compoundbegin) {
               p = affix_check_morph(st.c_str(), i, compoundbegin);
             } else if ((wordnum > 0) && compoundmiddle) {
               p = affix_check_morph(st.c_str(), i, compoundmiddle);
             }
           }
-          if (p && (*p != '\0')) {
-            sprintf(presult + strlen(presult), "%c%s%s%s", MSEP_FLD, MORPH_PART,
-                    st.c_str(), line_uniq_app(&p, MSEP_REC));
+          if (!p.empty()) {
+            presult.push_back(MSEP_FLD);
+            presult.append(MORPH_PART);
+            presult.append(st.c_str());
+            line_uniq_app(p, MSEP_REC);
+            presult.append(p);
           }
-          if (p)
-            free(p);
           checked_prefix = 1;
         }
         // else check forbiddenwords
       } else if (rv->astr && (TESTAFF(rv->astr, forbiddenword, rv->alen) ||
                               TESTAFF(rv->astr, ONLYUPCASEFLAG, rv->alen) ||
                               TESTAFF(rv->astr, needaffix, rv->alen))) {
         st[i] = ch;
         continue;
@@ -2502,17 +2363,17 @@ int AffixMgr::compound_check_morph(const
             ) &&
            !((checkcompoundtriple && !words &&  // test triple letters
               (word[i - 1] == word[i]) &&
               (((i > 1) && (word[i - 1] == word[i - 2])) ||
                ((word[i - 1] == word[i + 1]))  // may be word[i+1] == '\0'
                )) ||
              (
                  // test CHECKCOMPOUNDPATTERN
-                 numcheckcpd && !words &&
+                 !checkcpdtable.empty() && !words &&
                  cpdpat_check(word, i, rv, NULL, affixed)) ||
              (checkcompoundcase && !words && cpdcase_check(word, i))))
           // LANG_hu section: spec. Hungarian rule
           ||
           ((!rv) && (langnum == LANG_hu) && hu_mov_rule &&
            (rv = affix_check(st.c_str(), i)) &&
            (sfx && sfx->getCont() &&
             (TESTAFF(sfx->getCont(), (unsigned short)'x', sfx->getContLen()) ||
@@ -2536,41 +2397,39 @@ int AffixMgr::compound_check_morph(const
         rv = lookup((word + i));  // perhaps without prefix
 
         // search homonym with compound flag
         while ((rv) && ((needaffix && TESTAFF(rv->astr, needaffix, rv->alen)) ||
                         !((compoundflag && !words &&
                            TESTAFF(rv->astr, compoundflag, rv->alen)) ||
                           (compoundend && !words &&
                            TESTAFF(rv->astr, compoundend, rv->alen)) ||
-                          (numdefcpd && words &&
+                          (!defcpdtable.empty() && words &&
                            defcpd_check(&words, wnum + 1, rv, NULL, 1))))) {
           rv = rv->next_homonym;
         }
 
         if (rv && words && words[wnum + 1]) {
-          mystrcat(*result, presult, MAXLNLEN);
-          mystrcat(*result, " ", MAXLNLEN);
-          mystrcat(*result, MORPH_PART, MAXLNLEN);
-          mystrcat(*result, word + i, MAXLNLEN);
+          result.append(presult);
+          result.append(" ");
+          result.append(MORPH_PART);
+          result.append(word + i);
           if (complexprefixes && HENTRY_DATA(rv))
-            mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN);
+            result.append(HENTRY_DATA2(rv));
           if (!HENTRY_FIND(rv, MORPH_STEM)) {
-            mystrcat(*result, " ", MAXLNLEN);
-            mystrcat(*result, MORPH_STEM, MAXLNLEN);
-            mystrcat(*result, HENTRY_WORD(rv), MAXLNLEN);
+            result.append(" ");
+            result.append(MORPH_STEM);
+            result.append(HENTRY_WORD(rv));
           }
           // store the pointer of the hash entry
-          //                  sprintf(*result + strlen(*result), " %s%p",
-          //                  MORPH_HENTRY, rv);
           if (!complexprefixes && HENTRY_DATA(rv)) {
-            mystrcat(*result, " ", MAXLNLEN);
-            mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN);
+            result.append(" ");
+            result.append(HENTRY_DATA2(rv));
           }
-          mystrcat(*result, "\n", MAXLNLEN);
+          result.append("\n");
           return 0;
         }
 
         oldnumsyllable2 = numsyllable;
         oldwordnum2 = wordnum;
 
         // LANG_hu section: spec. Hungarian rule
         if ((rv) && (langnum == LANG_hu) &&
@@ -2601,38 +2460,36 @@ int AffixMgr::compound_check_morph(const
             ((compoundflag && TESTAFF(rv->astr, compoundflag, rv->alen)) ||
              (compoundend && TESTAFF(rv->astr, compoundend, rv->alen))) &&
             (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) ||
              ((cpdmaxsyllable != 0) &&
               (numsyllable + get_syllable(std::string(HENTRY_WORD(rv), rv->blen)) <=
                cpdmaxsyllable))) &&
             ((!checkcompounddup || (rv != rv_first)))) {
           // bad compound word
-          mystrcat(*result, presult, MAXLNLEN);
-          mystrcat(*result, " ", MAXLNLEN);
-          mystrcat(*result, MORPH_PART, MAXLNLEN);
-          mystrcat(*result, word + i, MAXLNLEN);
+          result.append(presult);
+          result.append(" ");
+          result.append(MORPH_PART);
+          result.append(word + i);
 
           if (HENTRY_DATA(rv)) {
             if (complexprefixes)
-              mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN);
+              result.append(HENTRY_DATA2(rv));
             if (!HENTRY_FIND(rv, MORPH_STEM)) {
-              mystrcat(*result, " ", MAXLNLEN);
-              mystrcat(*result, MORPH_STEM, MAXLNLEN);
-              mystrcat(*result, HENTRY_WORD(rv), MAXLNLEN);
+              result.append(" ");
+              result.append(MORPH_STEM);
+              result.append(HENTRY_WORD(rv));
             }
             // store the pointer of the hash entry
-            //                        sprintf(*result + strlen(*result), "
-            //                        %s%p", MORPH_HENTRY, rv);
             if (!complexprefixes) {
-              mystrcat(*result, " ", MAXLNLEN);
-              mystrcat(*result, HENTRY_DATA2(rv), MAXLNLEN);
+              result.append(" ");
+              result.append(HENTRY_DATA2(rv));
             }
           }
-          mystrcat(*result, "\n", MAXLNLEN);
+          result.append("\n");
           ok = 1;
         }
 
         numsyllable = oldnumsyllable2;
         wordnum = oldwordnum2;
 
         // perhaps second word has prefix or/and suffix
         sfx = NULL;
@@ -2644,37 +2501,34 @@ int AffixMgr::compound_check_morph(const
           rv = NULL;
 
         if (!rv && compoundend && !onlycpdrule) {
           sfx = NULL;
           pfx = NULL;
           rv = affix_check((word + i), strlen(word + i), compoundend);
         }
 
-        if (!rv && numdefcpd && words) {
+        if (!rv && !defcpdtable.empty() && words) {
           rv = affix_check((word + i), strlen(word + i), 0, IN_CPD_END);
           if (rv && words && defcpd_check(&words, wnum + 1, rv, NULL, 1)) {
-            char* m = NULL;
+            std::string m;
             if (compoundflag)
               m = affix_check_morph((word + i), strlen(word + i), compoundflag);
-            if ((!m || *m == '\0') && compoundend) {
-              if (m)
-                free(m);
+            if (m.empty() && compoundend) {
               m = affix_check_morph((word + i), strlen(word + i), compoundend);
             }
-            mystrcat(*result, presult, MAXLNLEN);
-            if (m || (*m != '\0')) {
-              char m2[MAXLNLEN];
-              sprintf(m2, "%c%s%s%s", MSEP_FLD, MORPH_PART, word + i,
-                      line_uniq_app(&m, MSEP_REC));
-              mystrcat(*result, m2, MAXLNLEN);
+            result.append(presult);
+            if (!m.empty()) {
+              result.push_back(MSEP_FLD);
+              result.append(MORPH_PART);
+              result.append(word + i);
+              line_uniq_app(m, MSEP_REC);
+              result.append(m);
             }
-            if (m)
-              free(m);
-            mystrcat(*result, "\n", MAXLNLEN);
+            result.append("\n");
             ok = 1;
           }
         }
 
         // check non_compound flag in suffix and prefix
         if ((rv) &&
             ((pfx && pfx->getCont() &&
               TESTAFF(pfx->getCont(), compoundforbidflag, pfx->getContLen())) ||
@@ -2708,17 +2562,17 @@ int AffixMgr::compound_check_morph(const
           // + 1 word, if syllable number of the prefix > 1 (hungarian
           // convention)
           if (pfx && (get_syllable(pfx->getKey()) > 1))
             wordnum++;
 
           // increment syllable num, if last word has a SYLLABLENUM flag
           // and the suffix is beginning `s'
 
-          if (cpdsyllablenum) {
+          if (!cpdsyllablenum.empty()) {
             switch (sfxflag) {
               case 'c': {
                 numsyllable += 2;
                 break;
               }
               case 'J': {
                 numsyllable += 1;
                 break;
@@ -2740,94 +2594,73 @@ int AffixMgr::compound_check_morph(const
         // second word is acceptable, as a word with prefix or/and suffix?
         // hungarian conventions: compounding is acceptable,
         // when compound forms consist 2 word, otherwise
         // the syllable number of root words is 6, or lesser.
         if ((rv) &&
             (((cpdwordmax == -1) || (wordnum + 1 < cpdwordmax)) ||
              ((cpdmaxsyllable != 0) && (numsyllable <= cpdmaxsyllable))) &&
             ((!checkcompounddup || (rv != rv_first)))) {
-          char* m = NULL;
+          std::string m;
           if (compoundflag)
             m = affix_check_morph((word + i), strlen(word + i), compoundflag);
-          if ((!m || *m == '\0') && compoundend) {
-            if (m)
-              free(m);
+          if (m.empty() && compoundend) {
             m = affix_check_morph((word + i), strlen(word + i), compoundend);
           }
-          mystrcat(*result, presult, MAXLNLEN);
-          if (m && (*m != '\0')) {
-            char m2[MAXLNLEN];
-            sprintf(m2, "%c%s%s%s", MSEP_FLD, MORPH_PART, word + i,
-                    line_uniq_app(&m, MSEP_REC));
-            mystrcat(*result, m2, MAXLNLEN);
+          result.append(presult);
+          if (!m.empty()) {
+            result.push_back(MSEP_FLD);
+            result.append(MORPH_PART);
+            result.append(word + 1);
+            line_uniq_app(m, MSEP_REC);
+            result.append(m);
           }
-          if (m)
-            free(m);
-          if (strlen(*result) + 1 < MAXLNLEN)
-            sprintf(*result + strlen(*result), "%c", MSEP_REC);
+          result.push_back(MSEP_REC);
           ok = 1;
         }
 
         numsyllable = oldnumsyllable2;
         wordnum = oldwordnum2;
 
         // perhaps second word is a compound word (recursive call)
         if ((wordnum < maxwordnum) && (ok == 0)) {
           compound_check_morph((word + i), strlen(word + i), wordnum + 1,
                                numsyllable, maxwordnum, wnum + 1, words, rwords, 0,
-                               result, presult);
+                               result, &presult);
         } else {
           rv = NULL;
         }
       }
       st[i] = ch;
       wordnum = oldwordnum;
       numsyllable = oldnumsyllable;
 
-    } while (numdefcpd && oldwordnum == 0 &&
+    } while (!defcpdtable.empty() && oldwordnum == 0 &&
              onlycpdrule++ < 1);  // end of onlycpd loop
   }
   return 0;
 }
 
 
-// return 1 if s1 (reversed) is a leading subset of end of s2
-/* inline int AffixMgr::isRevSubset(const char * s1, const char * end_of_s2, int
- len)
- {
-    while ((len > 0) && *s1 && (*s1 == *end_of_s2)) {
-        s1++;
-        end_of_s2--;
-        len--;
-    }
-    return (*s1 == '\0');
- }
- */
-
 inline int AffixMgr::isRevSubset(const char* s1,
                                  const char* end_of_s2,
                                  int len) {
   while ((len > 0) && (*s1 != '\0') && ((*s1 == *end_of_s2) || (*s1 == '.'))) {
     s1++;
     end_of_s2--;
     len--;
   }
   return (*s1 == '\0');
 }
 
 // check word for suffixes
-
 struct hentry* AffixMgr::suffix_check(const char* word,
                                       int len,
                                       int sfxopts,
                                       PfxEntry* ppfx,
-                                      char** wlst,
-                                      int maxSug,
-                                      int* ns,
                                       const FLAG cclass,
                                       const FLAG needflag,
                                       char in_compound) {
   struct hentry* rv = NULL;
   PfxEntry* ep = ppfx;
 
   // first handle the special case of 0 length suffixes
   SfxEntry* se = sStart[0];
@@ -2856,17 +2689,17 @@ struct hentry* AffixMgr::suffix_check(co
              (TESTAFF(se->getCont(), onlyincompound, se->getContLen())))) &&
           // needaffix on prefix or first suffix
           (cclass ||
            !(se->getCont() &&
              TESTAFF(se->getCont(), needaffix, se->getContLen())) ||
            (ppfx &&
             !((ep->getCont()) &&
               TESTAFF(ep->getCont(), needaffix, ep->getContLen()))))) {
-        rv = se->checkword(word, len, sfxopts, ppfx, wlst, maxSug, ns,
+        rv = se->checkword(word, len, sfxopts, ppfx,
                            (FLAG)cclass, needflag,
                            (in_compound ? 0 : onlyincompound));
         if (rv) {
           sfx = se;  // BUG: sfx not stateless
           return rv;
         }
       }
     }
@@ -2907,17 +2740,17 @@ struct hentry* AffixMgr::suffix_check(co
            !(sptr->getCont() &&
              TESTAFF(sptr->getCont(), needaffix, sptr->getContLen())) ||
            (ppfx &&
             !((ep->getCont()) &&
               TESTAFF(ep->getCont(), needaffix, ep->getContLen())))))
         if (in_compound != IN_CPD_END || ppfx ||
             !(sptr->getCont() &&
               TESTAFF(sptr->getCont(), onlyincompound, sptr->getContLen()))) {
-          rv = sptr->checkword(word, len, sfxopts, ppfx, wlst, maxSug, ns,
+          rv = sptr->checkword(word, len, sfxopts, ppfx,
                                cclass, needflag,
                                (in_compound ? 0 : onlyincompound));
           if (rv) {
             sfx = sptr;                 // BUG: sfx not stateless
             sfxflag = sptr->getFlag();  // BUG: sfxflag not stateless
             if (!sptr->getCont())
               sfxappnd = sptr->getKey();  // BUG: sfxappnd not stateless
             // LANG_hu section: spec. Hungarian rule
@@ -2980,69 +2813,65 @@ struct hentry* AffixMgr::suffix_check_tw
     } else {
       sptr = sptr->getNextNE();
     }
   }
 
   return NULL;
 }
 
-char* AffixMgr::suffix_check_twosfx_morph(const char* word,
-                                          int len,
-                                          int sfxopts,
-                                          PfxEntry* ppfx,
-                                          const FLAG needflag) {
+std::string AffixMgr::suffix_check_twosfx_morph(const char* word,
+                                                int len,
+                                                int sfxopts,
+                                                PfxEntry* ppfx,
+                                                const FLAG needflag) {
   std::string result;
   std::string result2;
   std::string result3;
 
-  char* st;
-
   // first handle the special case of 0 length suffixes
   SfxEntry* se = sStart[0];
   while (se) {
     if (contclasses[se->getFlag()]) {
-      st = se->check_twosfx_morph(word, len, sfxopts, ppfx, needflag);
-      if (st) {
+      std::string st = se->check_twosfx_morph(word, len, sfxopts, ppfx, needflag);
+      if (!st.empty()) {
         if (ppfx) {
           if (ppfx->getMorph()) {
             result.append(ppfx->getMorph());
             result.append(" ");
           } else
             debugflag(result, ppfx->getFlag());
         }
         result.append(st);
-        free(st);
         if (se->getMorph()) {
           result.append(" ");
           result.append(se->getMorph());
         } else
           debugflag(result, se->getFlag());
         result.append("\n");
       }
     }
     se = se->getNext();
   }
 
   // now handle the general case
   if (len == 0)
-    return NULL;  // FULLSTRIP
+    return std::string();  // FULLSTRIP
   unsigned char sp = *((const unsigned char*)(word + len - 1));
   SfxEntry* sptr = sStart[sp];
 
   while (sptr) {
     if (isRevSubset(sptr->getKey(), word + len - 1, len)) {
       if (contclasses[sptr->getFlag()]) {
-        st = sptr->check_twosfx_morph(word, len, sfxopts, ppfx, needflag);
-        if (st) {
+        std::string st = sptr->check_twosfx_morph(word, len, sfxopts, ppfx, needflag);
+        if (!st.empty()) {
           sfxflag = sptr->getFlag();  // BUG: sfxflag not stateless
           if (!sptr->getCont())
             sfxappnd = sptr->getKey();  // BUG: sfxappnd not stateless
           result2.assign(st);
-          free(st);
 
           result3.clear();
 
           if (sptr->getMorph()) {
             result3.append(" ");
             result3.append(sptr->getMorph());
           } else
             debugflag(result3, sptr->getFlag());
@@ -3052,35 +2881,30 @@ char* AffixMgr::suffix_check_twosfx_morp
         }
       }
       sptr = sptr->getNextEQ();
     } else {
       sptr = sptr->getNextNE();
     }
   }
 
-  if (!result.empty())
-    return mystrdup(result.c_str());
-
-  return NULL;
+  return result;
 }
 
-char* AffixMgr::suffix_check_morph(const char* word,
-                                   int len,
-                                   int sfxopts,
-                                   PfxEntry* ppfx,
-                                   const FLAG cclass,
-                                   const FLAG needflag,
-                                   char in_compound) {
-  char result[MAXLNLEN];
+std::string AffixMgr::suffix_check_morph(const char* word,
+                                         int len,
+                                         int sfxopts,
+                                         PfxEntry* ppfx,
+                                         const FLAG cclass,
+                                         const FLAG needflag,
+                                         char in_compound) {
+  std::string result;
 
   struct hentry* rv = NULL;
 
-  result[0] = '\0';
-
   PfxEntry* ep = ppfx;
 
   // first handle the special case of 0 length suffixes
   SfxEntry* se = sStart[0];
   while (se) {
     if (!cclass || se->getCont()) {
       // suffixes are not allowed in beginning of compounds
       if (((((in_compound != IN_CPD_BEGIN)) ||  // && !cclass
@@ -3104,56 +2928,53 @@ char* AffixMgr::suffix_check_morph(const
                (TESTAFF(se->getCont(), onlyincompound, se->getContLen()))))) &&
            // needaffix on prefix or first suffix
            (cclass ||
             !(se->getCont() &&
               TESTAFF(se->getCont(), needaffix, se->getContLen())) ||
             (ppfx &&
              !((ep->getCont()) &&
                TESTAFF(ep->getCont(), needaffix, ep->getContLen()))))))
-        rv = se->checkword(word, len, sfxopts, ppfx, NULL, 0, 0, cclass,
-                           needflag);
+        rv = se->checkword(word, len, sfxopts, ppfx, cclass,
+                           needflag, FLAG_NULL);
       while (rv) {
         if (ppfx) {
           if (ppfx->getMorph()) {
-            mystrcat(result, ppfx->getMorph(), MAXLNLEN);
-            mystrcat(result, " ", MAXLNLEN);
+            result.append(ppfx->getMorph());
+            result.append(" ");
           } else
             debugflag(result, ppfx->getFlag());
         }
         if (complexprefixes && HENTRY_DATA(rv))
-          mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN);
+          result.append(HENTRY_DATA2(rv));
         if (!HENTRY_FIND(rv, MORPH_STEM)) {
-          mystrcat(result, " ", MAXLNLEN);
-          mystrcat(result, MORPH_STEM, MAXLNLEN);
-          mystrcat(result, HENTRY_WORD(rv), MAXLNLEN);
+          result.append(" ");
+          result.append(MORPH_STEM);
+          result.append(HENTRY_WORD(rv));
         }
-        // store the pointer of the hash entry
-        //            sprintf(result + strlen(result), " %s%p", MORPH_HENTRY,
-        //            rv);
 
         if (!complexprefixes && HENTRY_DATA(rv)) {
-          mystrcat(result, " ", MAXLNLEN);
-          mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN);
+          result.append(" ");
+          result.append(HENTRY_DATA2(rv));
         }
         if (se->getMorph()) {
-          mystrcat(result, " ", MAXLNLEN);
-          mystrcat(result, se->getMorph(), MAXLNLEN);
+          result.append(" ");
+          result.append(se->getMorph());
         } else
           debugflag(result, se->getFlag());
-        mystrcat(result, "\n", MAXLNLEN);
+        result.append("\n");
         rv = se->get_next_homonym(rv, sfxopts, ppfx, cclass, needflag);
       }
     }
     se = se->getNext();
   }
 
   // now handle the general case
   if (len == 0)
-    return NULL;  // FULLSTRIP
+    return std::string();  // FULLSTRIP
   unsigned char sp = *((const unsigned char*)(word + len - 1));
   SfxEntry* sptr = sStart[sp];
 
   while (sptr) {
     if (isRevSubset(sptr->getKey(), word + len - 1, len)) {
       // suffixes are not allowed in beginning of compounds
       if (((((in_compound != IN_CPD_BEGIN)) ||  // && !cclass
             // except when signed with compoundpermitflag flag
@@ -3174,76 +2995,70 @@ char* AffixMgr::suffix_check_morph(const
            // fogemorpheme
            (in_compound ||
             !((sptr->getCont() && (TESTAFF(sptr->getCont(), onlyincompound,
                                            sptr->getContLen()))))) &&
            // needaffix on first suffix
            (cclass ||
             !(sptr->getCont() &&
               TESTAFF(sptr->getCont(), needaffix, sptr->getContLen())))))
-        rv = sptr->checkword(word, len, sfxopts, ppfx, NULL, 0, 0, cclass,
-                             needflag);
+        rv = sptr->checkword(word, len, sfxopts, ppfx, cclass,
+                             needflag, FLAG_NULL);
       while (rv) {
         if (ppfx) {
           if (ppfx->getMorph()) {
-            mystrcat(result, ppfx->getMorph(), MAXLNLEN);
-            mystrcat(result, " ", MAXLNLEN);
+            result.append(ppfx->getMorph());
+            result.append(" ");
           } else
             debugflag(result, ppfx->getFlag());
         }
         if (complexprefixes && HENTRY_DATA(rv))
-          mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN);
+          result.append(HENTRY_DATA2(rv));
         if (!HENTRY_FIND(rv, MORPH_STEM)) {
-          mystrcat(result, " ", MAXLNLEN);
-          mystrcat(result, MORPH_STEM, MAXLNLEN);
-          mystrcat(result, HENTRY_WORD(rv), MAXLNLEN);
+          result.append(" ");
+          result.append(MORPH_STEM);
+          result.append(HENTRY_WORD(rv));
         }
-        // store the pointer of the hash entry
-        //                    sprintf(result + strlen(result), " %s%p",
-        //                    MORPH_HENTRY, rv);
 
         if (!complexprefixes && HENTRY_DATA(rv)) {
-          mystrcat(result, " ", MAXLNLEN);
-          mystrcat(result, HENTRY_DATA2(rv), MAXLNLEN);
+          result.append(" ");
+          result.append(HENTRY_DATA2(rv));
         }
 
         if (sptr->getMorph()) {
-          mystrcat(result, " ", MAXLNLEN);
-          mystrcat(result, sptr->getMorph(), MAXLNLEN);
+          result.append(" ");
+          result.append(sptr->getMorph());
         } else
           debugflag(result, sptr->getFlag());
-        mystrcat(result, "\n", MAXLNLEN);
+        result.append("\n");
         rv = sptr->get_next_homonym(rv, sfxopts, ppfx, cclass, needflag);
       }
       sptr = sptr->getNextEQ();
     } else {
       sptr = sptr->getNextNE();
     }
   }
 
-  if (*result)
-    return mystrdup(result);
-  return NULL;
+  return result;
 }
 
 // check if word with affixes is correctly spelled
 struct hentry* AffixMgr::affix_check(const char* word,
                                      int len,
                                      const FLAG needflag,
                                      char in_compound) {
   struct hentry* rv = NULL;
 
   // check all prefixes (also crossed with suffixes if allowed)
   rv = prefix_check(word, len, in_compound, needflag);
   if (rv)
     return rv;
 
   // if still not found check all suffixes
-  rv = suffix_check(word, len, 0, NULL, NULL, 0, NULL, FLAG_NULL, needflag,
-                    in_compound);
+  rv = suffix_check(word, len, 0, NULL, FLAG_NULL, needflag, in_compound);
 
   if (havecontclass) {
     sfx = NULL;
     pfx = NULL;
 
     if (rv)
       return rv;
     // if still not found check all two-level suffixes
@@ -3254,77 +3069,153 @@ struct hentry* AffixMgr::affix_check(con
     // if still not found check all two-level suffixes
     rv = prefix_check_twosfx(word, len, IN_CPD_NOT, needflag);
   }
 
   return rv;
 }
 
 // check if word with affixes is correctly spelled
-char* AffixMgr::affix_check_morph(const char* word,
+std::string AffixMgr::affix_check_morph(const char* word,
                                   int len,
                                   const FLAG needflag,
                                   char in_compound) {
-  char result[MAXLNLEN];
-  char* st = NULL;
-
-  *result = '\0';
+  std::string result;
 
   // check all prefixes (also crossed with suffixes if allowed)
-  st = prefix_check_morph(word, len, in_compound);
-  if (st) {
-    mystrcat(result, st, MAXLNLEN);
-    free(st);
+  std::string st = prefix_check_morph(word, len, in_compound);
+  if (!st.empty()) {
+    result.append(st);
   }
 
   // if still not found check all suffixes
   st = suffix_check_morph(word, len, 0, NULL, '\0', needflag, in_compound);
-  if (st) {
-    mystrcat(result, st, MAXLNLEN);
-    free(st);
+  if (!st.empty()) {
+    result.append(st);
   }
 
   if (havecontclass) {
     sfx = NULL;
     pfx = NULL;
     // if still not found check all two-level suffixes
     st = suffix_check_twosfx_morph(word, len, 0, NULL, needflag);
-    if (st) {
-      mystrcat(result, st, MAXLNLEN);
-      free(st);
+    if (!st.empty()) {
+      result.append(st);
     }
 
     // if still not found check all two-level suffixes
     st = prefix_check_twosfx_morph(word, len, IN_CPD_NOT, needflag);
-    if (st) {
-      mystrcat(result, st, MAXLNLEN);
-      free(st);
+    if (!st.empty()) {
+      result.append(st);
     }
   }
 
-  return mystrdup(result);
+  return result;
 }
 
-char* AffixMgr::morphgen(const char* ts,
-                         int wl,
-                         const unsigned short* ap,
-                         unsigned short al,
-                         const char* morph,
-                         const char* targetmorph,
+// morphcmp(): compare MORPH_DERI_SFX, MORPH_INFL_SFX and MORPH_TERM_SFX fields
+// in the first line of the inputs
+// return 0, if inputs equal
+// return 1, if inputs may equal with a secondary suffix
+// otherwise return -1
+static int morphcmp(const char* s, const char* t) {
+  int se = 0;
+  int te = 0;
+  const char* sl;
+  const char* tl;
+  const char* olds;
+  const char* oldt;
+  if (!s || !t)
+    return 1;
+  olds = s;
+  sl = strchr(s, '\n');
+  s = strstr(s, MORPH_DERI_SFX);
+  if (!s || (sl && sl < s))
+    s = strstr(olds, MORPH_INFL_SFX);
+  if (!s || (sl && sl < s)) {
+    s = strstr(olds, MORPH_TERM_SFX);
+    olds = NULL;
+  }
+  oldt = t;
+  tl = strchr(t, '\n');
+  t = strstr(t, MORPH_DERI_SFX);
+  if (!t || (tl && tl < t))
+    t = strstr(oldt, MORPH_INFL_SFX);
+  if (!t || (tl && tl < t)) {
+    t = strstr(oldt, MORPH_TERM_SFX);
+    oldt = NULL;
+  }
+  while (s && t && (!sl || sl > s) && (!tl || tl > t)) {
+    s += MORPH_TAG_LEN;
+    t += MORPH_TAG_LEN;
+    se = 0;
+    te = 0;
+    while ((*s == *t) && !se && !te) {
+      s++;
+      t++;
+      switch (*s) {
+        case ' ':
+        case '\n':
+        case '\t':
+        case '\0':
+          se = 1;
+      }
+      switch (*t) {
+        case ' ':
+        case '\n':
+        case '\t':
+        case '\0':
+          te = 1;
+      }
+    }
+    if (!se || !te) {
+      // not terminal suffix difference
+      if (olds)
+        return -1;
+      return 1;
+    }
+    olds = s;
+    s = strstr(s, MORPH_DERI_SFX);
+    if (!s || (sl && sl < s))
+      s = strstr(olds, MORPH_INFL_SFX);
+    if (!s || (sl && sl < s)) {
+      s = strstr(olds, MORPH_TERM_SFX);
+      olds = NULL;
+    }
+    oldt = t;
+    t = strstr(t, MORPH_DERI_SFX);
+    if (!t || (tl && tl < t))
+      t = strstr(oldt, MORPH_INFL_SFX);
+    if (!t || (tl && tl < t)) {
+      t = strstr(oldt, MORPH_TERM_SFX);
+      oldt = NULL;
+    }
+  }
+  if (!s && !t && se && te)
+    return 0;
+  return 1;
+}
+
+std::string AffixMgr::morphgen(const char* ts,
+                               int wl,
+                               const unsigned short* ap,
+                               unsigned short al,
+                               const char* morph,
+                               const char* targetmorph,
                          int level) {
   // handle suffixes
   if (!morph)
-    return NULL;
+    return std::string();
 
   // check substandard flag
   if (TESTAFF(ap, substandard, al))
-    return NULL;
+    return std::string();
 
   if (morphcmp(morph, targetmorph) == 0)
-    return mystrdup(ts);
+    return ts;
 
   size_t stemmorphcatpos;
   std::string mymorph;
 
   // use input suffix fields, if exist
   if (strstr(morph, MORPH_INFL_SFX) || strstr(morph, MORPH_DERI_SFX)) {
     mymorph.assign(morph);
     mymorph.append(" ");
@@ -3347,51 +3238,46 @@ char* AffixMgr::morphgen(const char* ts,
           stemmorph = mymorph.c_str();
         } else {
           stemmorph = sptr->getMorph();
         }
 
         int cmp = morphcmp(stemmorph, targetmorph);
 
         if (cmp == 0) {
-          char* newword = sptr->add(ts, wl);
-          if (newword) {
-            hentry* check = pHMgr->lookup(newword);  // XXX extra dic
+          std::string newword = sptr->add(ts, wl);
+          if (!newword.empty()) {
+            hentry* check = pHMgr->lookup(newword.c_str());  // XXX extra dic
             if (!check || !check->astr ||
                 !(TESTAFF(check->astr, forbiddenword, check->alen) ||
                   TESTAFF(check->astr, ONLYUPCASEFLAG, check->alen))) {
               return newword;
             }
-            free(newword);
           }
         }
 
         // recursive call for secondary suffixes
         if ((level == 0) && (cmp == 1) && (sptr->getContLen() > 0) &&
-            //                    (get_sfxcount(stemmorph) < targetcount) &&
             !TESTAFF(sptr->getCont(), substandard, sptr->getContLen())) {
-          char* newword = sptr->add(ts, wl);
-          if (newword) {
-            char* newword2 =
-                morphgen(newword, strlen(newword), sptr->getCont(),
+          std::string newword = sptr->add(ts, wl);
+          if (!newword.empty()) {
+            std::string newword2 =
+                morphgen(newword.c_str(), newword.size(), sptr->getCont(),
                          sptr->getContLen(), stemmorph, targetmorph, 1);
 
-            if (newword2) {
-              free(newword);
+            if (!newword2.empty()) {
               return newword2;
             }
-            free(newword);
-            newword = NULL;
           }
         }
       }
       sptr = sptr->getFlgNxt();
     }
   }
-  return NULL;
+  return std::string();
 }
 
 int AffixMgr::expand_rootword(struct guessword* wlst,
                               int maxn,
                               const char* ts,
                               int wl,
                               const unsigned short* ap,
                               unsigned short al,
@@ -3434,40 +3320,38 @@ int AffixMgr::expand_rootword(struct gue
           // check needaffix flag
           !(sptr->getCont() &&
             ((needaffix &&
               TESTAFF(sptr->getCont(), needaffix, sptr->getContLen())) ||
              (circumfix &&
               TESTAFF(sptr->getCont(), circumfix, sptr->getContLen())) ||
              (onlyincompound &&
               TESTAFF(sptr->getCont(), onlyincompound, sptr->getContLen()))))) {
-        char* newword = sptr->add(ts, wl);
-        if (newword) {
+        std::string newword = sptr->add(ts, wl);
+        if (!newword.empty()) {
           if (nh < maxn) {
-            wlst[nh].word = newword;
+            wlst[nh].word = mystrdup(newword.c_str());
             wlst[nh].allow = sptr->allowCross();
             wlst[nh].orig = NULL;
             nh++;
             // add special phonetic version
             if (phon && (nh < maxn)) {
               std::string prefix(phon);
               std::string key(sptr->getKey());
               reverseword(key);
               prefix.append(key);
               wlst[nh].word = mystrdup(prefix.c_str());
               if (!wlst[nh].word)
                 return nh - 1;
               wlst[nh].allow = (1 == 0);
-              wlst[nh].orig = mystrdup(newword);
+              wlst[nh].orig = mystrdup(newword.c_str());
               if (!wlst[nh].orig)
                 return nh - 1;
               nh++;
             }
-          } else {
-            free(newword);
           }
         }
       }
       sptr = sptr->getFlgNxt();
     }
   }
 
   int n = nh;
@@ -3479,25 +3363,23 @@ int AffixMgr::expand_rootword(struct gue
         const unsigned char c = (unsigned char)(ap[k] & 0x00FF);
         PfxEntry* cptr = pFlag[c];
         while (cptr) {
           if ((cptr->getFlag() == ap[k]) && cptr->allowCross() &&
               (!cptr->getKeyLen() ||
                ((badl > cptr->getKeyLen()) &&
                 (strncmp(cptr->getKey(), bad, cptr->getKeyLen()) == 0)))) {
             int l1 = strlen(wlst[j].word);
-            char* newword = cptr->add(wlst[j].word, l1);
-            if (newword) {
+            std::string newword = cptr->add(wlst[j].word, l1);
+            if (!newword.empty()) {
               if (nh < maxn) {
-                wlst[nh].word = newword;
+                wlst[nh].word = mystrdup(newword.c_str());
                 wlst[nh].allow = cptr->allowCross();
                 wlst[nh].orig = NULL;
                 nh++;
-              } else {
-                free(newword);
               }
             }
           }
           cptr = cptr->getFlgNxt();
         }
       }
     }
 
@@ -3513,44 +3395,35 @@ int AffixMgr::expand_rootword(struct gue
           // check needaffix flag
           !(ptr->getCont() &&
             ((needaffix &&
               TESTAFF(ptr->getCont(), needaffix, ptr->getContLen())) ||
              (circumfix &&
               TESTAFF(ptr->getCont(), circumfix, ptr->getContLen())) ||
              (onlyincompound &&
               TESTAFF(ptr->getCont(), onlyincompound, ptr->getContLen()))))) {
-        char* newword = ptr->add(ts, wl);
-        if (newword) {
+        std::string newword = ptr->add(ts, wl);
+        if (!newword.empty()) {
           if (nh < maxn) {
-            wlst[nh].word = newword;
+            wlst[nh].word = mystrdup(newword.c_str());
             wlst[nh].allow = ptr->allowCross();
             wlst[nh].orig = NULL;
             nh++;
-          } else {
-            free(newword);
           }
         }
       }
       ptr = ptr->getFlgNxt();
     }
   }
 
   return nh;
 }
 
-// return length of replacing table
-int AffixMgr::get_numrep() const {
-  return numrep;
-}
-
 // return replacing table
-struct replentry* AffixMgr::get_reptable() const {
-  if (!reptable)
-    return NULL;
+const std::vector<replentry>& AffixMgr::get_reptable() const {
   return reptable;
 }
 
 // return iconv table
 RepList* AffixMgr::get_iconvtable() const {
   if (!iconvtable)
     return NULL;
   return iconvtable;
@@ -3565,45 +3438,31 @@ RepList* AffixMgr::get_oconvtable() cons
 
 // return replacing table
 struct phonetable* AffixMgr::get_phonetable() const {
   if (!phone)
     return NULL;
   return phone;
 }
 
-// return length of character map table
-int AffixMgr::get_nummap() const {
-  return nummap;
+// return character map table
+const std::vector<mapentry>& AffixMgr::get_maptable() const {
+  return maptable;
 }
 
 // return character map table
-struct mapentry* AffixMgr::get_maptable() const {
-  if (!maptable)
-    return NULL;
-  return maptable;
-}
-
-// return length of word break table
-int AffixMgr::get_numbreak() const {
-  return numbreak;
-}
-
-// return character map table
-char** AffixMgr::get_breaktable() const {
-  if (!breaktable)
-    return NULL;
+const std::vector<std::string>& AffixMgr::get_breaktable() const {
   return breaktable;
 }
 
 // return text encoding of dictionary
-char* AffixMgr::get_encoding() {
-  if (!encoding)
-    encoding = mystrdup(SPELL_ENCODING);
-  return mystrdup(encoding);
+const std::string& AffixMgr::get_encoding() {
+  if (encoding.empty())
+    encoding = SPELL_ENCODING;
+  return encoding;
 }
 
 // return text encoding of dictionary
 int AffixMgr::get_langnum() const {
   return langnum;
 }
 
 // return double prefix option
@@ -3636,53 +3495,53 @@ int AffixMgr::get_checksharps() const {
   return checksharps;
 }
 
 char* AffixMgr::encode_flag(unsigned short aflag) const {
   return pHMgr->encode_flag(aflag);
 }
 
 // return the preferred ignore string for suggestions
-char* AffixMgr::get_ignore() const {
-  if (!ignorechars)
+const char* AffixMgr::get_ignore() const {
+  if (ignorechars.empty())
     return NULL;
-  return ignorechars;
+  return ignorechars.c_str();
 }
 
 // return the preferred ignore string for suggestions
 const std::vector<w_char>& AffixMgr::get_ignore_utf16() const {
   return ignorechars_utf16;
 }
 
 // return the keyboard string for suggestions
 char* AffixMgr::get_key_string() {
-  if (!keystring)
-    keystring = mystrdup(SPELL_KEYSTRING);
-  return mystrdup(keystring);
+  if (keystring.empty())
+    keystring = SPELL_KEYSTRING;
+  return mystrdup(keystring.c_str());
 }
 
 // return the preferred try string for suggestions
 char* AffixMgr::get_try_string() const {
-  if (!trystring)
+  if (trystring.empty())
     return NULL;
-  return mystrdup(trystring);
+  return mystrdup(trystring.c_str());
 }
 
 // return the preferred try string for suggestions
-const char* AffixMgr::get_wordchars() const {
+const std::string& AffixMgr::get_wordchars() const {
   return wordchars;
 }
 
 const std::vector<w_char>& AffixMgr::get_wordchars_utf16() const {
   return wordchars_utf16;
 }
 
 // is there compounding?
 int AffixMgr::get_compound() const {
-  return compoundflag || compoundbegin || numdefcpd;
+  return compoundflag || compoundbegin || !defcpdtable.empty();
 }
 
 // return the compound words control flag
 FLAG AffixMgr::get_compoundflag() const {
   return compoundflag;
 }
 
 // return the forbidden words control flag
@@ -3705,59 +3564,26 @@ FLAG AffixMgr::get_needaffix() const {
   return needaffix;
 }
 
 // return the onlyincompound flag
 FLAG AffixMgr::get_onlyincompound() const {
   return onlyincompound;
 }
 
-// return the compound word signal flag
-FLAG AffixMgr::get_compoundroot() const {
-  return compoundroot;
-}
-
-// return the compound begin signal flag
-FLAG AffixMgr::get_compoundbegin() const {
-  return compoundbegin;
-}
-
-// return the value of checknum
-int AffixMgr::get_checknum() const {
-  return checknum;
-}
-
-// return the value of prefix
-const char* AffixMgr::get_prefix() const {
-  if (pfx)
-    return pfx->getKey();
-  return NULL;
-}
-
 // return the value of suffix
-const char* AffixMgr::get_suffix() const {
-  return sfxappnd;
-}
-
-// return the value of suffix
-const char* AffixMgr::get_version() const {
+const std::string& AffixMgr::get_version() const {
   return version;
 }
 
-// return lemma_present flag
-FLAG AffixMgr::get_lemma_present() const {
-  return lemma_present;
-}
-
 // utility method to look up root words in hash table
 struct hentry* AffixMgr::lookup(const char* word) {
-  int i;
   struct hentry* he = NULL;
-  for (i = 0; i < *maxdic && !he; i++) {
-    he = (alldic[i])->lookup(word);
+  for (size_t i = 0; i < alldic.size() && !he; ++i) {
+    he = alldic[i]->lookup(word);
   }
   return he;
 }
 
 // return the value of suffix
 int AffixMgr::have_contclass() const {
   return havecontclass;
 }
@@ -3789,849 +3615,761 @@ int AffixMgr::get_nosplitsugs(void) cons
 }
 
 // return sugswithdots
 int AffixMgr::get_sugswithdots(void) const {
   return sugswithdots;
 }
 
 /* parse flag */
-int AffixMgr::parse_flag(char* line, unsigned short* out, FileMgr* af) {
-  char* s = NULL;
+bool AffixMgr::parse_flag(const std::string& line, unsigned short* out, FileMgr* af) {
   if (*out != FLAG_NULL && !(*out >= DEFAULTFLAGS)) {
     HUNSPELL_WARNING(
         stderr,
         "error: line %d: multiple definitions of an affix file parameter\n",
         af->getlinenum());
-    return 1;
+    return false;
   }
-  if (parse_string(line, &s, af->getlinenum()))
-    return 1;
-  *out = pHMgr->decode_flag(s);
-  free(s);
-  return 0;
+  std::string s;
+  if (!parse_string(line, s, af->getlinenum()))
+    return false;
+  *out = pHMgr->decode_flag(s.c_str());
+  return true;
 }
 
 /* parse num */
-int AffixMgr::parse_num(char* line, int* out, FileMgr* af) {
-  char* s = NULL;
+bool AffixMgr::parse_num(const std::string& line, int* out, FileMgr* af) {
   if (*out != -1) {
     HUNSPELL_WARNING(
         stderr,
         "error: line %d: multiple definitions of an affix file parameter\n",
         af->getlinenum());
-    return 1;
+    return false;
   }
-  if (parse_string(line, &s, af->getlinenum()))
-    return 1;
-  *out = atoi(s);
-  free(s);
-  return 0;
+  std::string s;
+  if (!parse_string(line, s, af->getlinenum()))
+    return false;
+  *out = atoi(s.c_str());
+  return true;
 }
 
 /* parse in the max syllablecount of compound words and  */
-int AffixMgr::parse_cpdsyllable(char* line, FileMgr* af) {
-  char* tp = line;
-  char* piece;
+bool AffixMgr::parse_cpdsyllable(const std::string& line, FileMgr* af) {
   int i = 0;
   int np = 0;
-  piece = mystrsep(&tp, 0);
-  while (piece) {
-    if (*piece != '\0') {
-      switch (i) {
-        case 0: {
-          np++;
-          break;
-        }
-        case 1: {
-          cpdmaxsyllable = atoi(piece);
-          np++;
-          break;
+  std::string::const_iterator iter = line.begin();
+  std::string::const_iterator start_piece = mystrsep(line, iter);
+  while (start_piece != line.end()) {
+    switch (i) {
+      case 0: {
+        np++;
+        break;
+      }
+      case 1: {
+        cpdmaxsyllable = atoi(std::string(start_piece, iter).c_str());
+        np++;
+        break;
+      }
+      case 2: {
+        if (!utf8) {
+          cpdvowels.assign(start_piece, iter);
+          std::sort(cpdvowels.begin(), cpdvowels.end());
+        } else {
+          std::string piece(start_piece, iter);
+          u8_u16(cpdvowels_utf16, piece);
+          std::sort(cpdvowels_utf16.begin(), cpdvowels_utf16.end());
         }
-        case 2: {
-          if (!utf8) {
-            cpdvowels = mystrdup(piece);
-          } else {
-            std::vector<w_char> w;
-            u8_u16(w, piece);
-            if (!w.empty()) {
-              std::sort(w.begin(), w.end());
-              cpdvowels_utf16 = (w_char*)malloc(w.size() * sizeof(w_char));
-              if (!cpdvowels_utf16)
-                return 1;
-              memcpy(cpdvowels_utf16, &w[0], w.size());
-            }
-            cpdvowels_utf16_len = w.size();
-          }
-          np++;
-          break;
-        }
-        default:
-          break;
+        np++;
+        break;
       }
-      i++;
+      default:
+        break;
     }
-    piece = mystrsep(&tp, 0);
+    ++i;
+    start_piece = mystrsep(line, iter);
   }
   if (np < 2) {
     HUNSPELL_WARNING(stderr,
                      "error: line %d: missing compoundsyllable information\n",
                      af->getlinenum());
     return 1;
   }
   if (np == 2)
-    cpdvowels = mystrdup("aeiouAEIOU");
+    cpdvowels = "AEIOUaeiou";
   return 0;
 }
 
 /* parse in the typical fault correcting table */
-int AffixMgr::parse_reptable(char* line, FileMgr* af) {
-  if (numrep != 0) {
+bool AffixMgr::parse_reptable(const std::string& line, FileMgr* af) {
+  if (parsedrep) {
     HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
                      af->getlinenum());
-    return 1;
+    return false;
   }
-  char* tp = line;
-  char* piece;
+  parsedrep = true;
+  int numrep = -1;
   int i = 0;
   int np = 0;
-  piece = mystrsep(&tp, 0);
-  while (piece) {
-    if (*piece != '\0') {
-      switch (i) {
-        case 0: {
-          np++;
-          break;
+  std::string::const_iterator iter = line.begin();
+  std::string::const_iterator start_piece = mystrsep(line, iter);
+  while (start_piece != line.end()) {
+    switch (i) {
+      case 0: {
+        np++;
+        break;
+      }
+      case 1: {
+        numrep = atoi(std::string(start_piece, iter).c_str());
+        if (numrep < 1) {
+          HUNSPELL_WARNING(stderr, "error: line %d: incorrect entry number\n",
+                           af->getlinenum());
+          return false;
         }
-        case 1: {
-          numrep = atoi(piece);
-          if (numrep < 1) {
-            HUNSPELL_WARNING(stderr, "error: line %d: incorrect entry number\n",
-                             af->getlinenum());
-            return 1;
-          }
-          reptable = (replentry*)malloc(numrep * sizeof(struct replentry));
-          if (!reptable)
-            return 1;
-          np++;
-          break;
-        }
-        default:
-          break;
+        reptable.reserve(numrep);
+        np++;
+        break;
       }
-      i++;
+      default:
+        break;
     }
-    piece = mystrsep(&tp, 0);
+    ++i;
+    start_piece = mystrsep(line, iter);
   }
   if (np != 2) {
     HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
                      af->getlinenum());
-    return 1;
+    return false;
   }
 
   /* now parse the numrep lines to read in the remainder of the table */
-  char* nl;
-  for (int j = 0; j < numrep; j++) {
-    if ((nl = af->getline()) == NULL)
-      return 1;
+  for (int j = 0; j < numrep; ++j) {
+    std::string nl;
+    if (!af->getline(nl))
+      return false;
     mychomp(nl);
-    tp = nl;
+    reptable.push_back(replentry());
+    iter = nl.begin();
     i = 0;
-    reptable[j].pattern = NULL;
-    reptable[j].pattern2 = NULL;
-    piece = mystrsep(&tp, 0);
-    while (piece) {
-      if (*piece != '\0') {
-        switch (i) {
-          case 0: {
-            if (strncmp(piece, "REP", 3) != 0) {
-              HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                               af->getlinenum());
-              numrep = 0;
-              return 1;
-            }
-            break;
-          }
-          case 1: {
-            if (*piece == '^')
-              reptable[j].start = true;
-            else
-              reptable[j].start = false;
-            reptable[j].pattern =
-                mystrrep(mystrdup(piece + int(reptable[j].start)), "_", " ");
-            int lr = strlen(reptable[j].pattern) - 1;
-            if (reptable[j].pattern[lr] == '$') {
-              reptable[j].end = true;
-              reptable[j].pattern[lr] = '\0';
-            } else
-              reptable[j].end = false;
-            break;
-          }
-          case 2: {
-            reptable[j].pattern2 = mystrrep(mystrdup(piece), "_", " ");
-            break;
-          }
-          default:
-            break;
-        }
-        i++;
-      }
-      piece = mystrsep(&tp, 0);
-    }
-    if ((!(reptable[j].pattern)) || (!(reptable[j].pattern2))) {
-      HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                       af->getlinenum());
-      numrep = 0;
-      return 1;
-    }
-  }
-  return 0;
-}
-
-/* parse in the typical fault correcting table */
-int AffixMgr::parse_convtable(char* line,
-                              FileMgr* af,
-                              RepList** rl,
-                              const char* keyword) {
-  if (*rl) {
-    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;
-  int numrl = 0;
-  piece = mystrsep(&tp, 0);
-  while (piece) {
-    if (*piece != '\0') {
+    int type = 0;
+    start_piece = mystrsep(nl, iter);
+    while (start_piece != nl.end()) {
       switch (i) {
         case 0: {
-          np++;
+          if (nl.compare(start_piece - nl.begin(), 3, "REP", 3) != 0) {
+            HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                             af->getlinenum());
+            reptable.clear();
+            return false;
+          }
           break;
         }
         case 1: {
-          numrl = atoi(piece);
-          if (numrl < 1) {
-            HUNSPELL_WARNING(stderr, "error: line %d: incorrect entry number\n",
-                             af->getlinenum());
-            return 1;
+          if (*start_piece == '^')
+            type = 1;
+          reptable.back().pattern.assign(start_piece + type, iter);
+          mystrrep(reptable.back().pattern, "_", " ");
+          if (!reptable.back().pattern.empty() && reptable.back().pattern[reptable.back().pattern.size() - 1] == '$') {
+            type += 2;
+            reptable.back().pattern.resize(reptable.back().pattern.size() - 1);
           }
-          *rl = new RepList(numrl);
-          if (!*rl)
-            return 1;
-          np++;
+          break;
+        }
+        case 2: {
+          reptable.back().outstrings[type].assign(start_piece, iter);
+          mystrrep(reptable.back().outstrings[type], "_", " ");
           break;
         }
         default:
           break;
       }
-      i++;
+      ++i;
+      start_piece = mystrsep(nl, iter);
+    }
+    if (reptable.back().pattern.empty() || reptable.back().outstrings[type].empty()) {
+      HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                       af->getlinenum());
+      reptable.clear();
+      return false;
     }
-    piece = mystrsep(&tp, 0);
+  }
+  return true;
+}
+
+/* parse in the typical fault correcting table */
+bool AffixMgr::parse_convtable(const std::string& line,
+                              FileMgr* af,
+                              RepList** rl,
+                              const std::string& keyword) {
+  if (*rl) {
+    HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
+                     af->getlinenum());
+    return false;
+  }
+  int i = 0;
+  int np = 0;
+  int numrl = 0;
+  std::string::const_iterator iter = line.begin();
+  std::string::const_iterator start_piece = mystrsep(line, iter);
+  while (start_piece != line.end()) {
+    switch (i) {
+      case 0: {
+        np++;
+        break;
+      }
+      case 1: {
+        numrl = atoi(std::string(start_piece, iter).c_str());
+        if (numrl < 1) {
+          HUNSPELL_WARNING(stderr, "error: line %d: incorrect entry number\n",
+                           af->getlinenum());
+          return false;
+        }
+        *rl = new RepList(numrl);
+        if (!*rl)
+          return false;
+        np++;
+        break;
+      }
+      default:
+        break;
+    }
+    ++i;
+    start_piece = mystrsep(line, iter);
   }
   if (np != 2) {
     HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
                      af->getlinenum());
-    return 1;
+    return false;
   }
 
   /* now parse the num lines to read in the remainder of the table */
-  char* nl;
   for (int j = 0; j < numrl; j++) {
-    if (!(nl = af->getline()))
-      return 1;
+    std::string nl;
+    if (!af->getline(nl))
+      return false;
     mychomp(nl);
-    tp = nl;
     i = 0;
-    char* pattern = NULL;
-    char* pattern2 = NULL;
-    piece = mystrsep(&tp, 0);
-    while (piece) {
-      if (*piece != '\0') {
+    std::string pattern;
+    std::string pattern2;
+    iter = nl.begin();
+    start_piece = mystrsep(nl, iter);
+    while (start_piece != nl.end()) {
+      {
         switch (i) {
           case 0: {
-            if (strncmp(piece, keyword, strlen(keyword)) != 0) {
+            if (nl.compare(start_piece - nl.begin(), keyword.size(), keyword, 0, keyword.size()) != 0) {
               HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
                                af->getlinenum());
               delete *rl;
               *rl = NULL;
-              return 1;
+              return false;
             }
             break;
           }
           case 1: {
-            pattern = mystrrep(mystrdup(piece), "_", " ");
+            pattern.assign(start_piece, iter);
             break;
           }
           case 2: {
-            pattern2 = mystrrep(mystrdup(piece), "_", " ");
+            pattern2.assign(start_piece, iter);
             break;
           }
           default:
             break;
         }
-        i++;
+        ++i;
       }
-      piece = mystrsep(&tp, 0);
+      start_piece = mystrsep(nl, iter);
     }
-    if (!pattern || !pattern2) {
-      if (pattern)
-        free(pattern);
-      if (pattern2)
-        free(pattern2);
+    if (pattern.empty() || pattern2.empty()) {
       HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
                        af->getlinenum());
-      return 1;
+      return false;
     }
     (*rl)->add(pattern, pattern2);
   }
-  return 0;
+  return true;
 }
 
 /* parse in the typical fault correcting table */
-int AffixMgr::parse_phonetable(char* line, FileMgr* af) {
+bool AffixMgr::parse_phonetable(const std::string& line, FileMgr* af) {
   if (phone) {
     HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
                      af->getlinenum());
-    return 1;
+    return false;
   }
-  char* tp = line;
-  char* piece;
+  int num = -1;
   int i = 0;
   int np = 0;
-  piece = mystrsep(&tp, 0);
-  while (piece) {
-    if (*piece != '\0') {
-      switch (i) {
-        case 0: {
-          np++;
-          break;
+  std::string::const_iterator iter = line.begin();
+  std::string::const_iterator start_piece = mystrsep(line, iter);
+  while (start_piece != line.end()) {
+    switch (i) {
+      case 0: {
+        np++;
+        break;
+      }
+      case 1: {
+        num = atoi(std::string(start_piece, iter).c_str());
+        if (num < 1) {
+          HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
+                           af->getlinenum());
+          return false;
         }
-        case 1: {
-          phone = (phonetable*)malloc(sizeof(struct phonetable));
-          if (!phone)
-            return 1;
-          phone->num = atoi(piece);
-          phone->rules = NULL;
-          phone->utf8 = (char)utf8;
-          if (phone->num < 1) {
-            HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
-                             af->getlinenum());
-            return 1;
-          }
-          phone->rules = (char**)malloc(2 * (phone->num + 1) * sizeof(char*));
-          if (!phone->rules) {
-            free(phone);
-            phone = NULL;
-            return 1;
-          }
-          np++;
-          break;
-        }
-        default:
-          break;
+        phone = new phonetable;
+        phone->utf8 = (char)utf8;
+        np++;
+        break;
       }
-      i++;
+      default:
+        break;
     }
-    piece = mystrsep(&tp, 0);
+    ++i;
+    start_piece = mystrsep(line, iter);
   }
   if (np != 2) {
     HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
                      af->getlinenum());
-    return 1;
+    return false;
   }
 
   /* now parse the phone->num lines to read in the remainder of the table */
-  char* nl;
-  for (int j = 0; j < phone->num; j++) {
-    if (!(nl = af->getline()))
-      return 1;
+  for (int j = 0; j < num; ++j) {
+    std::string nl;
+    if (!af->getline(nl))
+      return false;
     mychomp(nl);
-    tp = nl;
     i = 0;
-    phone->rules[j * 2] = NULL;
-    phone->rules[j * 2 + 1] = NULL;
-    piece = mystrsep(&tp, 0);
-    while (piece) {
-      if (*piece != '\0') {
+    const size_t old_size = phone->rules.size();
+    iter = nl.begin();
+    start_piece = mystrsep(nl, iter);
+    while (start_piece != nl.end()) {
+      {
         switch (i) {
           case 0: {
-            if (strncmp(piece, "PHONE", 5) != 0) {
+            if (nl.compare(start_piece - nl.begin(), 5, "PHONE", 5) != 0) {
               HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
                                af->getlinenum());
-              phone->num = 0;
-              return 1;
+              return false;
             }
             break;
           }
           case 1: {
-            phone->rules[j * 2] = mystrrep(mystrdup(piece), "_", "");
+            phone->rules.push_back(std::string(start_piece, iter));
             break;
           }
           case 2: {
-            phone->rules[j * 2 + 1] = mystrrep(mystrdup(piece), "_", "");
+            phone->rules.push_back(std::string(start_piece, iter));
+            mystrrep(phone->rules.back(), "_", "");
             break;
           }
           default:
             break;
         }
-        i++;
+        ++i;
       }
-      piece = mystrsep(&tp, 0);
+      start_piece = mystrsep(nl, iter);
     }
-    if ((!(phone->rules[j * 2])) || (!(phone->rules[j * 2 + 1]))) {
+    if (phone->rules.size() != old_size + 2) {
       HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
                        af->getlinenum());
-      phone->num = 0;
-      return 1;
+      phone->rules.clear();
+      return false;
     }
   }
-  phone->rules[phone->num * 2] = mystrdup("");
-  phone->rules[phone->num * 2 + 1] = mystrdup("");
+  phone->rules.push_back("");
+  phone->rules.push_back("");
   init_phonet_hash(*phone);
-  return 0;
+  return true;
 }
 
 /* parse in the checkcompoundpattern table */
-int AffixMgr::parse_checkcpdtable(char* line, FileMgr* af) {
-  if (numcheckcpd != 0) {
+bool AffixMgr::parse_checkcpdtable(const std::string& line, FileMgr* af) {
+  if (parsedcheckcpd) {
     HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
                      af->getlinenum());
-    return 1;
+    return false;
   }
-  char* tp = line;
-  char* piece;
+  parsedcheckcpd = true;
+  int numcheckcpd = -1;
   int i = 0;
   int np = 0;
-  piece = mystrsep(&tp, 0);
-  while (piece) {
-    if (*piece != '\0') {
+  std::string::const_iterator iter = line.begin();
+  std::string::const_iterator start_piece = mystrsep(line, iter);
+  while (start_piece != line.end()) {
+    switch (i) {
+      case 0: {
+        np++;
+        break;
+      }
+      case 1: {
+        numcheckcpd = atoi(std::string(start_piece, iter).c_str());
+        if (numcheckcpd < 1) {
+          HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
+                           af->getlinenum());
+          return false;
+        }
+        checkcpdtable.reserve(numcheckcpd);
+        np++;
+        break;
+      }
+      default:
+        break;
+    }
+    ++i;
+    start_piece = mystrsep(line, iter);
+  }
+  if (np != 2) {
+    HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
+                     af->getlinenum());
+    return false;
+  }
+
+  /* now parse the numcheckcpd lines to read in the remainder of the table */
+  for (int j = 0; j < numcheckcpd; ++j) {
+    std::string nl;
+    if (!af->getline(nl))
+      return false;
+    mychomp(nl);
+    i = 0;
+    checkcpdtable.push_back(patentry());
+    iter = nl.begin();
+    start_piece = mystrsep(nl, iter);
+    while (start_piece != nl.end()) {
       switch (i) {
         case 0: {
-          np++;
+          if (nl.compare(start_piece - nl.begin(), 20, "CHECKCOMPOUNDPATTERN", 20) != 0) {
+            HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                             af->getlinenum());
+            return false;
+          }
           break;
         }
         case 1: {
-          numcheckcpd = atoi(piece);
-          if (numcheckcpd < 1) {
-            HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
-                             af->getlinenum());
-            return 1;
+          checkcpdtable.back().pattern.assign(start_piece, iter);
+          size_t slash_pos = checkcpdtable.back().pattern.find('/');
+          if (slash_pos != std::string::npos) {
+            std::string chunk(checkcpdtable.back().pattern, slash_pos + 1);
+            checkcpdtable.back().pattern.resize(slash_pos);
+            checkcpdtable.back().cond = pHMgr->decode_flag(chunk.c_str());
           }
-          checkcpdtable =
-              (patentry*)malloc(numcheckcpd * sizeof(struct patentry));
-          if (!checkcpdtable)
-            return 1;
-          np++;
+          break;
+        }
+        case 2: {
+          checkcpdtable.back().pattern2.assign(start_piece, iter);
+          size_t slash_pos = checkcpdtable.back().pattern2.find('/');
+          if (slash_pos != std::string::npos) {
+            std::string chunk(checkcpdtable.back().pattern2, slash_pos + 1);
+            checkcpdtable.back().pattern2.resize(slash_pos);
+            checkcpdtable.back().cond2 = pHMgr->decode_flag(chunk.c_str());
+          }
+          break;
+        }
+        case 3: {
+          checkcpdtable.back().pattern3.assign(start_piece, iter);
+          simplifiedcpd = 1;
           break;
         }
         default:
           break;
       }
       i++;
+      start_piece = mystrsep(nl, iter);
     }
-    piece = mystrsep(&tp, 0);
+  }
+  return true;
+}
+
+/* parse in the compound rule table */
+bool AffixMgr::parse_defcpdtable(const std::string& line, FileMgr* af) {
+  if (parseddefcpd) {
+    HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
+                     af->getlinenum());
+    return false;
+  }
+  parseddefcpd = true;
+  int numdefcpd = -1;
+  int i = 0;
+  int np = 0;
+  std::string::const_iterator iter = line.begin();
+  std::string::const_iterator start_piece = mystrsep(line, iter);
+  while (start_piece != line.end()) {
+    switch (i) {
+      case 0: {
+        np++;
+        break;
+      }
+      case 1: {
+        numdefcpd = atoi(std::string(start_piece, iter).c_str());
+        if (numdefcpd < 1) {
+          HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
+                           af->getlinenum());
+          return false;
+        }
+        defcpdtable.reserve(numdefcpd);
+        np++;
+        break;
+      }
+      default:
+        break;
+    }
+    ++i;
+    start_piece = mystrsep(line, iter);
   }
   if (np != 2) {
     HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
                      af->getlinenum());
-    return 1;
+    return false;
   }
 
-  /* now parse the numcheckcpd lines to read in the remainder of the table */
-  char* nl;
-  for (int j = 0; j < numcheckcpd; j++) {
-    if (!(nl = af->getline()))
-      return 1;
+  /* now parse the numdefcpd lines to read in the remainder of the table */
+  for (int j = 0; j < numdefcpd; ++j) {
+    std::string nl;
+    if (!af->getline(nl))
+      return false;
     mychomp(nl);
-    tp = nl;
     i = 0;
-    checkcpdtable[j].pattern = NULL;
-    checkcpdtable[j].pattern2 = NULL;
-    checkcpdtable[j].pattern3 = NULL;
-    checkcpdtable[j].cond = FLAG_NULL;
-    checkcpdtable[j].cond2 = FLAG_NULL;
-    piece = mystrsep(&tp, 0);
-    while (piece) {
-      if (*piece != '\0') {
-        switch (i) {
-          case 0: {
-            if (strncmp(piece, "CHECKCOMPOUNDPATTERN", 20) != 0) {
-              HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                               af->getlinenum());
-              numcheckcpd = 0;
-              return 1;
-            }
-            break;
-          }
-          case 1: {
-            checkcpdtable[j].pattern = mystrdup(piece);
-            char* p = strchr(checkcpdtable[j].pattern, '/');
-            if (p) {
-              *p = '\0';
-              checkcpdtable[j].cond = pHMgr->decode_flag(p + 1);
-            }
-            break;
-          }
-          case 2: {
-            checkcpdtable[j].pattern2 = mystrdup(piece);
-            char* p = strchr(checkcpdtable[j].pattern2, '/');
-            if (p) {
-              *p = '\0';
-              checkcpdtable[j].cond2 = pHMgr->decode_flag(p + 1);
-            }
-            break;
-          }
-          case 3: {
-            checkcpdtable[j].pattern3 = mystrdup(piece);
-            simplifiedcpd = 1;
-            break;
-          }
-          default:
-            break;
-        }
-        i++;
-      }
-      piece = mystrsep(&tp, 0);
-    }
-    if ((!(checkcpdtable[j].pattern)) || (!(checkcpdtable[j].pattern2))) {
-      HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                       af->getlinenum());
-      numcheckcpd = 0;
-      return 1;
-    }
-  }
-  return 0;
-}
-
-/* parse in the compound rule table */
-int AffixMgr::parse_defcpdtable(char* line, FileMgr* af) {
-  if (numdefcpd != 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') {
+    defcpdtable.push_back(flagentry());
+    iter = nl.begin();
+    start_piece = mystrsep(nl, iter);
+    while (start_piece != nl.end()) {
       switch (i) {
         case 0: {
-          np++;
+          if (nl.compare(start_piece - nl.begin(), 12, "COMPOUNDRULE", 12) != 0) {
+            HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                             af->getlinenum());
+            numdefcpd = 0;
+            return false;
+          }
           break;
         }
-        case 1: {
-          numdefcpd = atoi(piece);
-          if (numdefcpd < 1) {
-            HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
-                             af->getlinenum());
-            return 1;
+        case 1: {  // handle parenthesized flags
+          if (std::find(start_piece, iter, '(') != iter) {
+            for (std::string::const_iterator k = start_piece; k != iter; ++k) {
+              std::string::const_iterator chb = k;
+              std::string::const_iterator che = k + 1;
+              if (*k == '(') {
+                std::string::const_iterator parpos = std::find(k, iter, ')');
+                if (parpos != iter) {
+                  chb = k + 1;
+                  che = parpos;
+                  k = parpos;
+                }
+              }
+
+              if (*chb == '*' || *chb == '?') {
+                defcpdtable.back().push_back((FLAG)*chb);
+              } else {
+                pHMgr->decode_flags(defcpdtable.back(), std::string(chb, che), af);
+              }
+            }
+          } else {
+            pHMgr->decode_flags(defcpdtable.back(), std::string(start_piece, iter), af);
           }
-          defcpdtable = (flagentry*)malloc(numdefcpd * sizeof(flagentry));
-          if (!defcpdtable)
-            return 1;
-          np++;
           break;
         }
         default:
           break;
       }
-      i++;
+      ++i;
+      start_piece = mystrsep(nl, iter);
+    }
+    if (defcpdtable.back().empty()) {
+      HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                       af->getlinenum());
+      return false;
     }
-    piece = mystrsep(&tp, 0);
+  }
+  return true;
+}
+
+/* parse in the character map table */
+bool AffixMgr::parse_maptable(const std::string& line, FileMgr* af) {
+  if (parsedmaptable) {
+    HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
+                     af->getlinenum());
+    return false;
+  }
+  parsedmaptable = true;
+  int nummap = -1;
+  int i = 0;
+  int np = 0;
+  std::string::const_iterator iter = line.begin();
+  std::string::const_iterator start_piece = mystrsep(line, iter);
+  while (start_piece != line.end()) {
+    switch (i) {
+      case 0: {
+        np++;
+        break;
+      }
+      case 1: {
+        nummap = atoi(std::string(start_piece, iter).c_str());
+        if (nummap < 1) {
+          HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
+                           af->getlinenum());
+          return false;
+        }
+        maptable.reserve(nummap);
+        np++;
+        break;
+      }
+      default:
+        break;
+    }
+    ++i;
+    start_piece = mystrsep(line, iter);
   }
   if (np != 2) {
     HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
                      af->getlinenum());
-    return 1;
+    return false;
   }
 
-  /* now parse the numdefcpd lines to read in the remainder of the table */
-  char* nl;
-  for (int j = 0; j < numdefcpd; j++) {
-    if (!(nl = af->getline()))
-      return 1;
+  /* now parse the nummap lines to read in the remainder of the table */
+  for (int j = 0; j < nummap; ++j) {
+    std::string nl;
+    if (!af->getline(nl))
+      return false;
     mychomp(nl);
-    tp = nl;
     i = 0;
-    defcpdtable[j].def = NULL;
-    defcpdtable[j].len = 0;
-    piece = mystrsep(&tp, 0);
-    while (piece) {
-      if (*piece != '\0') {
-        switch (i) {
-          case 0: {
-            if (strncmp(piece, "COMPOUNDRULE", 12) != 0) {
-              HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                               af->getlinenum());
-              numdefcpd = 0;
-              return 1;
-            }
-            break;
-          }
-          case 1: {  // handle parenthesized flags
-            if (strchr(piece, '(')) {
-              defcpdtable[j].def = (FLAG*)malloc(strlen(piece) * sizeof(FLAG));
-              defcpdtable[j].len = 0;
-              int end = 0;
-              FLAG* conv;
-              while (!end) {
-                char* par = piece + 1;
-                while (*par != '(' && *par != ')' && *par != '\0')
-                  par++;
-                if (*par == '\0')
-                  end = 1;
-                else
-                  *par = '\0';
-                if (*piece == '(')
-                  piece++;
-                if (*piece == '*' || *piece == '?') {
-                  defcpdtable[j].def[defcpdtable[j].len++] = (FLAG)*piece;
-                } else if (*piece != '\0') {
-                  int l = pHMgr->decode_flags(&conv, piece, af);
-                  for (int k = 0; k < l; k++)
-                    defcpdtable[j].def[defcpdtable[j].len++] = conv[k];
-                  free(conv);
-                }
-                piece = par + 1;
-              }
-            } else {
-              defcpdtable[j].len =
-                  pHMgr->decode_flags(&(defcpdtable[j].def), piece, af);
-            }
-            break;
-          }
-          default:
-            break;
-        }
-        i++;
-      }
-      piece = mystrsep(&tp, 0);
-    }
-    if (!defcpdtable[j].len) {
-      HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                       af->getlinenum());
-      numdefcpd = 0;
-      return 1;
-    }
-  }
-  return 0;
-}
-
-/* parse in the character map table */
-int AffixMgr::parse_maptable(char* line, FileMgr* af) {
-  if (nummap != 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') {
+    maptable.push_back(mapentry());
+    iter = nl.begin();
+    start_piece = mystrsep(nl, iter);
+    while (start_piece != nl.end()) {
       switch (i) {
         case 0: {
-          np++;
+          if (nl.compare(start_piece - nl.begin(), 3, "MAP", 3) != 0) {
+            HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                             af->getlinenum());
+            nummap = 0;
+            return false;
+          }
           break;
         }
         case 1: {
-          nummap = atoi(piece);
-          if (nummap < 1) {
-            HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
-                             af->getlinenum());
-            return 1;
+          for (std::string::const_iterator k = start_piece; k != iter; ++k) {
+            std::string::const_iterator chb = k;
+            std::string::const_iterator che = k + 1;
+            if (*k == '(') {
+              std::string::const_iterator parpos = std::find(k, iter, ')');
+              if (parpos != iter) {
+                chb = k + 1;
+                che = parpos;
+                k = parpos;
+              }
+            } else {
+              if (utf8 && (*k & 0xc0) == 0xc0) {
+                ++k;
+                while (k != iter && (*k & 0xc0) == 0x80)
+                    ++k;
+                che = k;
+                --k;
+              }
+            }
+            maptable.back().push_back(std::string(chb, che));
           }
-          maptable = (mapentry*)malloc(nummap * sizeof(struct mapentry));
-          if (!maptable)
-            return 1;
-          np++;
           break;
         }
         default:
           break;
       }
-      i++;
+      ++i;
+      start_piece = mystrsep(nl, iter);
+    }
+    if (maptable.back().empty()) {
+      HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                       af->getlinenum());
+      return false;
     }
-    piece = mystrsep(&tp, 0);
+  }
+  return true;
+}
+
+/* parse in the word breakpoint table */
+bool AffixMgr::parse_breaktable(const std::string& line, FileMgr* af) {
+  if (parsedbreaktable) {
+    HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
+                     af->getlinenum());
+    return false;
+  }
+  parsedbreaktable = true;
+  int numbreak = -1;
+  int i = 0;
+  int np = 0;
+  std::string::const_iterator iter = line.begin();
+  std::string::const_iterator start_piece = mystrsep(line, iter);
+  while (start_piece != line.end()) {
+    switch (i) {
+      case 0: {
+        np++;
+        break;
+      }
+      case 1: {
+        numbreak = atoi(std::string(start_piece, iter).c_str());
+        if (numbreak < 0) {
+          HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
+                           af->getlinenum());
+          return false;
+        }
+        if (numbreak == 0)
+          return true;
+        breaktable.reserve(numbreak);
+        np++;
+        break;
+      }
+      default:
+        break;
+    }
+    ++i;
+    start_piece = mystrsep(line, iter);
   }
   if (np != 2) {
     HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
                      af->getlinenum());
-    return 1;
+    return false;
   }
 
-  /* now parse the nummap lines to read in the remainder of the table */
-  char* nl;
-  for (int j = 0; j < nummap; j++) {
-    if (!(nl = af->getline()))
-      return 1;
+  /* now parse the numbreak lines to read in the remainder of the table */
+  for (int j = 0; j < numbreak; ++j) {
+    std::string nl;
+    if (!af->getline(nl))
+      return false;
     mychomp(nl);
-    tp = nl;
     i = 0;
-    maptable[j].set = NULL;
-    maptable[j].len = 0;
-    piece = mystrsep(&tp, 0);
-    while (piece) {
-      if (*piece != '\0') {
-        switch (i) {
-          case 0: {
-            if (strncmp(piece, "MAP", 3) != 0) {
-              HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                               af->getlinenum());
-              nummap = 0;
-              return 1;
-            }
-            break;
-          }
-          case 1: {
-            int setn = 0;
-            maptable[j].len = strlen(piece);
-            maptable[j].set = (char**)malloc(maptable[j].len * sizeof(char*));
-            if (!maptable[j].set)
-              return 1;
-            for (int k = 0; k < maptable[j].len; k++) {
-              int chl = 1;
-              int chb = k;
-              if (piece[k] == '(') {
-                char* parpos = strchr(piece + k, ')');
-                if (parpos != NULL) {
-                  chb = k + 1;
-                  chl = (int)(parpos - piece) - k - 1;
-                  k = k + chl + 1;
-                }
-              } else {
-                if (utf8 && (piece[k] & 0xc0) == 0xc0) {
-                  for (k++; utf8 && (piece[k] & 0xc0) == 0x80; k++)
-                    ;
-                  chl = k - chb;
-                  k--;
-                }
-              }
-              maptable[j].set[setn] = (char*)malloc(chl + 1);
-              if (!maptable[j].set[setn])
-                return 1;
-              strncpy(maptable[j].set[setn], piece + chb, chl);
-              maptable[j].set[setn][chl] = '\0';
-              setn++;
-            }
-            maptable[j].len = setn;
-            break;
-          }
-          default:
-            break;
-        }
-        i++;
-      }
-      piece = mystrsep(&tp, 0);
-    }
-    if (!maptable[j].set || !maptable[j].len) {
-      HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                       af->getlinenum());
-      nummap = 0;
-      return 1;
-    }
-  }
-  return 0;
-}
-
-/* parse in the word breakpoint table */
-int AffixMgr::parse_breaktable(char* line, FileMgr* af) {
-  if (numbreak > -1) {
-    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') {
+    iter = nl.begin();
+    start_piece = mystrsep(nl, iter);
+    while (start_piece != nl.end()) {
       switch (i) {
         case 0: {
-          np++;
+          if (nl.compare(start_piece - nl.begin(), 5, "BREAK", 5) != 0) {
+            HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                             af->getlinenum());
+            numbreak = 0;
+            return false;
+          }
           break;
         }
         case 1: {
-          numbreak = atoi(piece);
-          if (numbreak < 0) {
-            HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
-                             af->getlinenum());
-            return 1;
-          }
-          if (numbreak == 0)
-            return 0;
-          breaktable = (char**)malloc(numbreak * sizeof(char*));
-          if (!breaktable)
-            return 1;
-          np++;
+          breaktable.push_back(std::string(start_piece, iter));
           break;
         }
         default:
           break;
       }
-      i++;
-    }
-    piece = mystrsep(&tp, 0);
-  }
-  if (np != 2) {
-    HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
-                     af->getlinenum());
-    return 1;
-  }
-
-  /* now parse the numbreak lines to read in the remainder of the table */
-  char* nl;
-  for (int j = 0; j < numbreak; j++) {
-    if (!(nl = af->getline()))
-      return 1;
-    mychomp(nl);
-    tp = nl;
-    i = 0;
-    piece = mystrsep(&tp, 0);
-    while (piece) {
-      if (*piece != '\0') {
-        switch (i) {
-          case 0: {
-            if (strncmp(piece, "BREAK", 5) != 0) {
-              HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                               af->getlinenum());
-              numbreak = 0;
-              return 1;
-            }
-            break;
-          }
-          case 1: {
-            breaktable[j] = mystrdup(piece);
-            break;
-          }
-          default:
-            break;
-        }
-        i++;
-      }
-      piece = mystrsep(&tp, 0);
-    }
-    if (!breaktable) {
-      HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                       af->getlinenum());
-      numbreak = 0;
-      return 1;
+      ++i;
+      start_piece = mystrsep(nl, iter);
     }
   }
-  return 0;
+
+  if (breaktable.size() != static_cast<size_t>(numbreak)) {
+    HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                     af->getlinenum());
+    return false;
+  }
+
+  return true;
 }
 
 void AffixMgr::reverse_condition(std::string& piece) {
   if (piece.empty())
       return;
 
   int neg = 0;
   for (std::string::reverse_iterator k = piece.rbegin(); k != piece.rend(); ++k) {
@@ -4660,314 +4398,356 @@ void AffixMgr::reverse_condition(std::st
       default: {
         if (neg)
           *(k - 1) = *k;
       }
     }
   }
 }
 
-int AffixMgr::parse_affix(char* line,
+class entries_container {
+  std::vector<AffEntry*> entries;
+  AffixMgr* m_mgr;
+  char m_at;
+public:
+  entries_container(char at, AffixMgr* mgr)
+    : m_mgr(mgr)
+    , m_at(at) {
+  }
+  void release() {
+    entries.clear();
+  }
+  void initialize(int numents,
+                  char opts, unsigned short aflag) {
+    entries.reserve(numents);
+
+    if (m_at == 'P') {
+      entries.push_back(new PfxEntry(m_mgr));
+    } else {
+      entries.push_back(new SfxEntry(m_mgr));
+    }
+
+    entries.back()->opts = opts;
+    entries.back()->aflag = aflag;
+  }
+
+  AffEntry* add_entry(char opts) {
+    if (m_at == 'P') {
+      entries.push_back(new PfxEntry(m_mgr));
+    } else {
+      entries.push_back(new SfxEntry(m_mgr));
+    }
+    AffEntry* ret = entries.back();
+    ret->opts = entries[0]->opts & opts;
+    return ret;
+  }
+
+  AffEntry* first_entry() {
+    return entries.empty() ? NULL : entries[0];
+  }
+
+  ~entries_container() {
+    for (size_t i = 0; i < entries.size(); ++i) {
+        delete entries[i];
+    }
+  }
+
+  std::vector<AffEntry*>::iterator begin() { return entries.begin(); }
+  std::vector<AffEntry*>::iterator end() { return entries.end(); }
+};
+
+bool AffixMgr::parse_affix(const std::string& line,
                           const char at,
                           FileMgr* af,
                           char* dupflags) {
-  int numents = 0;  // number of affentry structures to parse
+  int numents = 0;  // number of AffEntry structures to parse
 
   unsigned short aflag = 0;  // affix char identifier
 
   char ff = 0;
-  std::vector<affentry> affentries;
-
-  char* tp = line;
-  char* nl = line;
-  char* piece;
+  entries_container affentries(at, this);
+
   int i = 0;
 
 // checking lines with bad syntax
 #ifdef DEBUG
   int basefieldnum = 0;
 #endif
 
   // split affix header line into pieces
 
   int np = 0;
-
-  piece = mystrsep(&tp, 0);
-  while (piece) {
-    if (*piece != '\0') {
-      switch (i) {
-        // piece 1 - is type of affix
-        case 0: {
-          np++;
-          break;
-        }
-
-        // piece 2 - is affix char
-        case 1: {
-          np++;
-          aflag = pHMgr->decode_flag(piece);
-          if (((at == 'S') && (dupflags[aflag] & dupSFX)) ||
-              ((at == 'P') && (dupflags[aflag] & dupPFX))) {
-            HUNSPELL_WARNING(
-                stderr,
-                "error: line %d: multiple definitions of an affix flag\n",
-                af->getlinenum());
-            // return 1; XXX permissive mode for bad dictionaries
-          }
-          dupflags[aflag] += (char)((at == 'S') ? dupSFX : dupPFX);
-          break;
-        }
-        // piece 3 - is cross product indicator
-        case 2: {
-          np++;
-          if (*piece == 'Y')
-            ff = aeXPRODUCT;
-          break;
+  std::string::const_iterator iter = line.begin();
+  std::string::const_iterator start_piece = mystrsep(line, iter);
+  while (start_piece != line.end()) {
+    switch (i) {
+      // piece 1 - is type of affix
+      case 0: {
+        np++;
+        break;
+      }
+
+      // piece 2 - is affix char
+      case 1: {
+        np++;
+        aflag = pHMgr->decode_flag(std::string(start_piece, iter).c_str());
+        if (((at == 'S') && (dupflags[aflag] & dupSFX)) ||
+            ((at == 'P') && (dupflags[aflag] & dupPFX))) {
+          HUNSPELL_WARNING(
+              stderr,
+              "error: line %d: multiple definitions of an affix flag\n",
+              af->getlinenum());
         }
-
-        // piece 4 - is number of affentries
-        case 3: {
-          np++;
-          numents = atoi(piece);
-          if ((numents <= 0) || ((std::numeric_limits<size_t>::max() /
-                                  sizeof(struct affentry)) < static_cast<size_t>(numents))) {
-            char* err = pHMgr->encode_flag(aflag);
-            if (err) {
-              HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
-                               af->getlinenum());
-              free(err);
-            }
-            return 1;
+        dupflags[aflag] += (char)((at == 'S') ? dupSFX : dupPFX);
+        break;
+      }
+      // piece 3 - is cross product indicator
+      case 2: {
+        np++;
+        if (*start_piece == 'Y')
+          ff = aeXPRODUCT;
+        break;
+      }
+
+      // piece 4 - is number of affentries
+      case 3: {
+        np++;
+        numents = atoi(std::string(start_piece, iter).c_str());
+        if ((numents <= 0) || ((std::numeric_limits<size_t>::max() /
+                                sizeof(AffEntry)) < static_cast<size_t>(numents))) {
+          char* err = pHMgr->encode_flag(aflag);
+          if (err) {
+            HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
+                             af->getlinenum());
+            free(err);
           }
-          affentries.resize(numents);
-          affentries[0].opts = ff;
-          if (utf8)
-            affentries[0].opts += aeUTF8;
-          if (pHMgr->is_aliasf())
-            affentries[0].opts += aeALIASF;
-          if (pHMgr->is_aliasm())
-            affentries[0].opts += aeALIASM;
-          affentries[0].aflag = aflag;
+          return false;
         }
 
-        default:
-          break;
+        char opts = ff;
+        if (utf8)
+          opts += aeUTF8;
+        if (pHMgr->is_aliasf())
+          opts += aeALIASF;
+        if (pHMgr->is_aliasm())
+          opts += aeALIASM;
+        affentries.initialize(numents, opts, aflag);
       }
-      i++;
+
+      default:
+        break;
     }
-    piece = mystrsep(&tp, 0);
+    ++i;
+    start_piece = mystrsep(line, iter);
   }
   // check to make sure we parsed enough pieces
   if (np != 4) {
     char* err = pHMgr->encode_flag(aflag);
     if (err) {
       HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
                        af->getlinenum());
       free(err);
     }
-    return 1;
+    return false;
   }
 
   // now parse numents affentries for this affix
-  std::vector<affentry>::iterator start = affentries.begin();
-  std::vector<affentry>::iterator end = affentries.end();
-  for (std::vector<affentry>::iterator entry = start; entry != end; ++entry) {
-    if ((nl = af->getline()) == NULL)
-      return 1;
+  AffEntry* entry = affentries.first_entry();
+  for (int ent = 0; ent < numents; ++ent) {
+    std::string nl;
+    if (!af->getline(nl))
+      return false;
     mychomp(nl);
-    tp = nl;
+
+    iter = nl.begin();
     i = 0;
     np = 0;
 
     // split line into pieces
-    piece = mystrsep(&tp, 0);
-    while (piece) {
-      if (*piece != '\0') {
-        switch (i) {
-          // piece 1 - is type
-          case 0: {
-            np++;
-            if (entry != start)
-              entry->opts = start->opts &
-                            (char)(aeXPRODUCT + aeUTF8 + aeALIASF + aeALIASM);
-            break;
+    start_piece = mystrsep(nl, iter);
+    while (start_piece != nl.end()) {
+      switch (i) {
+        // piece 1 - is type
+        case 0: {
+          np++;
+          if (ent != 0)
+            entry = affentries.add_entry((char)(aeXPRODUCT + aeUTF8 + aeALIASF + aeALIASM));
+          break;
+        }
+
+        // piece 2 - is affix char
+        case 1: {
+          np++;
+          std::string chunk(start_piece, iter);
+          if (pHMgr->decode_flag(chunk.c_str()) != aflag) {
+            char* err = pHMgr->encode_flag(aflag);
+            if (err) {
+              HUNSPELL_WARNING(stderr,
+                               "error: line %d: affix %s is corrupt\n",
+                               af->getlinenum(), err);
+              free(err);
+            }
+            return false;
+          }
+
+          if (ent != 0) {
+            AffEntry* start_entry = affentries.first_entry();
+            entry->aflag = start_entry->aflag;
           }
-
-          // piece 2 - is affix char
-          case 1: {
-            np++;
-            if (pHMgr->decode_flag(piece) != aflag) {
-              char* err = pHMgr->encode_flag(aflag);
-              if (err) {
-                HUNSPELL_WARNING(stderr,
-                                 "error: line %d: affix %s is corrupt\n",
-                                 af->getlinenum(), err);
-                free(err);
+          break;
+        }
+
+        // piece 3 - is string to strip or 0 for null
+        case 2: {
+          np++;
+          entry->strip = std::string(start_piece, iter);
+          if (complexprefixes) {
+            if (utf8)
+              reverseword_utf(entry->strip);
+            else
+              reverseword(entry->strip);
+          }
+          if (entry->strip.compare("0") == 0) {
+            entry->strip.clear();
+          }
+          break;
+        }
+
+        // piece 4 - is affix string or 0 for null
+        case 3: {
+          entry->morphcode = NULL;
+          entry->contclass = NULL;
+          entry->contclasslen = 0;
+          np++;
+          std::string::const_iterator dash = std::find(start_piece, iter, '/');
+          if (dash != iter) {
+            entry->appnd = std::string(start_piece, dash);
+            std::string dash_str(dash + 1, iter);
+
+            if (!ignorechars.empty()) {
+              if (utf8) {
+                remove_ignored_chars_utf(entry->appnd, ignorechars_utf16);
+              } else {
+                remove_ignored_chars(entry->appnd, ignorechars);
               }
-              return 1;
             }
 
-            if (entry != start)
-              entry->aflag = start->aflag;
-            break;
-          }
-
-          // piece 3 - is string to strip or 0 for null
-          case 2: {
-            np++;
-            entry->strip = piece;
             if (complexprefixes) {
               if (utf8)
-                reverseword_utf(entry->strip);
+                reverseword_utf(entry->appnd);
               else
-                reverseword(entry->strip);
-            }
-            if (entry->strip.compare("0") == 0) {
-              entry->strip.clear();
+                reverseword(entry->appnd);
             }
-            break;
-          }
-
-          // piece 4 - is affix string or 0 for null
-          case 3: {
-            char* dash;
-            entry->morphcode = NULL;
-            entry->contclass = NULL;
-            entry->contclasslen = 0;
-            np++;
-            dash = strchr(piece, '/');
-            if (dash) {
-              *dash = '\0';
-
-              entry->appnd = piece;
-
-              if (ignorechars) {
-                if (utf8) {
-                  remove_ignored_chars_utf(entry->appnd, ignorechars_utf16);
-                } else {
-                  remove_ignored_chars(entry->appnd, ignorechars);
-                }
-              }
-
-              if (complexprefixes) {
-                if (utf8)
-                  reverseword_utf(entry->appnd);
-                else
-                  reverseword(entry->appnd);
-              }
-
-              if (pHMgr->is_aliasf()) {
-                int index = atoi(dash + 1);
-                entry->contclasslen = (unsigned short)pHMgr->get_aliasf(
-                    index, &(entry->contclass), af);
-                if (!entry->contclasslen)
-                  HUNSPELL_WARNING(stderr,
-                                   "error: bad affix flag alias: \"%s\"\n",
-                                   dash + 1);
+
+            if (pHMgr->is_aliasf()) {
+              int index = atoi(dash_str.c_str());
+              entry->contclasslen = (unsigned short)pHMgr->get_aliasf(
+                  index, &(entry->contclass), af);
+              if (!entry->contclasslen)
+                HUNSPELL_WARNING(stderr,
+                                 "error: bad affix flag alias: \"%s\"\n",
+                                 dash_str.c_str());
+            } else {
+              entry->contclasslen = (unsigned short)pHMgr->decode_flags(
+                  &(entry->contclass), dash_str.c_str(), af);
+              std::sort(entry->contclass, entry->contclass + entry->contclasslen);
+            }
+
+            havecontclass = 1;
+            for (unsigned short _i = 0; _i < entry->contclasslen; _i++) {
+              contclasses[(entry->contclass)[_i]] = 1;
+            }
+          } else {
+            entry->appnd = std::string(start_piece, iter);
+
+            if (!ignorechars.empty()) {
+              if (utf8) {
+                remove_ignored_chars_utf(entry->appnd, ignorechars_utf16);
               } else {
-                entry->contclasslen = (unsigned short)pHMgr->decode_flags(
-                    &(entry->contclass), dash + 1, af);
-                std::sort(entry->contclass, entry->contclass + entry->contclasslen);
-              }
-              *dash = '/';
-
-              havecontclass = 1;
-              for (unsigned short _i = 0; _i < entry->contclasslen; _i++) {
-                contclasses[(entry->contclass)[_i]] = 1;
-              }
-            } else {
-              entry->appnd = piece;
-
-              if (ignorechars) {
-                if (utf8) {
-                  remove_ignored_chars_utf(entry->appnd, ignorechars_utf16);
-                } else {
-                  remove_ignored_chars(entry->appnd, ignorechars);
-                }
-              }
-
-              if (complexprefixes) {
-                if (utf8)
-                  reverseword_utf(entry->appnd);
-                else
-                  reverseword(entry->appnd);
+                remove_ignored_chars(entry->appnd, ignorechars);
               }
             }
 
-            if (entry->appnd.compare("0") == 0) {
-              entry->appnd.clear();
+            if (complexprefixes) {
+              if (utf8)
+                reverseword_utf(entry->appnd);
+              else
+                reverseword(entry->appnd);
             }
-            break;
+          }
+
+          if (entry->appnd.compare("0") == 0) {
+            entry->appnd.clear();
           }
-
-          // piece 5 - is the conditions descriptions
-          case 4: {
-            std::string chunk(piece);
-            np++;
-            if (complexprefixes) {
+          break;
+        }
+
+        // piece 5 - is the conditions descriptions
+        case 4: {
+          std::string chunk(start_piece, iter);
+          np++;
+          if (complexprefixes) {
+            if (utf8)
+              reverseword_utf(chunk);
+            else
+              reverseword(chunk);
+            reverse_condition(chunk);
+          }
+          if (!entry->strip.empty() && chunk != "." &&
+              redundant_condition(at, entry->strip.c_str(), entry->strip.size(), chunk.c_str(),
+                                  af->getlinenum()))
+            chunk = ".";
+          if (at == 'S') {
+            reverseword(chunk);
+            reverse_condition(chunk);
+          }
+          if (encodeit(*entry, chunk.c_str()))
+            return false;
+          break;
+        }
+
+        case 5: {
+          std::string chunk(start_piece, iter);
+          np++;
+          if (pHMgr->is_aliasm()) {
+            int index = atoi(chunk.c_str());
+            entry->morphcode = pHMgr->get_aliasm(index);
+          } else {
+            if (complexprefixes) {  // XXX - fix me for morph. gen.
               if (utf8)
                 reverseword_utf(chunk);
               else
                 reverseword(chunk);
-              reverse_condition(chunk);
             }
-            if (!entry->strip.empty() && chunk != "." &&
-                redundant_condition(at, entry->strip.c_str(), entry->strip.size(), chunk.c_str(),
-                                    af->getlinenum()))
-              chunk = ".";
-            if (at == 'S') {
-              reverseword(chunk);
-              reverse_condition(chunk);
+            // add the remaining of the line
+            std::string::const_iterator end = nl.end();
+            if (iter != end) {
+              chunk.append(iter, end);
             }
-            if (encodeit(*entry, chunk.c_str()))
-              return 1;
-            break;
+            entry->morphcode = mystrdup(chunk.c_str());
+            if (!entry->morphcode)
+              return false;
           }
-
-          case 5: {
-            std::string chunk(piece);
-            np++;
-            if (pHMgr->is_aliasm()) {
-              int index = atoi(chunk.c_str());
-              entry->morphcode = pHMgr->get_aliasm(index);
-            } else {
-              if (complexprefixes) {  // XXX - fix me for morph. gen.
-                if (utf8)
-                  reverseword_utf(chunk);
-                else
-                  reverseword(chunk);
-              }
-              // add the remaining of the line
-              if (*tp) {
-                *(tp - 1) = ' ';
-                chunk.push_back(' ');
-                chunk.append(tp);
-              }
-              entry->morphcode = mystrdup(chunk.c_str());
-              if (!entry->morphcode)
-                return 1;
-            }
-            break;
-          }
-          default:
-            break;
+          break;
         }
-        i++;
+        default:
+          break;
       }
-      piece = mystrsep(&tp, 0);
+      i++;
+      start_piece = mystrsep(nl, iter);
     }
     // check to make sure we parsed enough pieces
     if (np < 4) {
       char* err = pHMgr->encode_flag(aflag);
       if (err) {
         HUNSPELL_WARNING(stderr, "error: line %d: affix %s is corrupt\n",
                          af->getlinenum(), err);
         free(err);
       }
-      return 1;
+      return false;
     }
 
 #ifdef DEBUG
     // detect unnecessary fields, excepting comments
     if (basefieldnum) {
       int fieldnum =
           !(entry->morphcode) ? 5 : ((*(entry->morphcode) == '#') ? 5 : 6);
       if (fieldnum != basefieldnum)
@@ -4977,26 +4757,30 @@ int AffixMgr::parse_affix(char* line,
       basefieldnum =
           !(entry->morphcode) ? 5 : ((*(entry->morphcode) == '#') ? 5 : 6);
     }
 #endif
   }
 
   // now create SfxEntry or PfxEntry objects and use links to
   // build an ordered (sorted by affix string) list
-  for (std::vector<affentry>::iterator entry = start; entry != end; ++entry) {
+  std::vector<AffEntry*>::iterator start = affentries.begin();
+  std::vector<AffEntry*>::iterator end = affentries.end();
+  for (std::vector<AffEntry*>::iterator affentry = start; affentry != end; ++affentry) {
     if (at == 'P') {
-      PfxEntry* pfxptr = new PfxEntry(this, &(*entry));
-      build_pfxtree(pfxptr);
+      build_pfxtree(static_cast<PfxEntry*>(*affentry));
     } else {
-      SfxEntry* sfxptr = new SfxEntry(this, &(*entry));
-      build_sfxtree(sfxptr);
+      build_sfxtree(static_cast<SfxEntry*>(*affentry));
     }
   }
-  return 0;
+
+  //contents belong to AffixMgr now
+  affentries.release();
+
+  return true;
 }
 
 int AffixMgr::redundant_condition(char ft,
                                   const char* strip,
                                   int stripl,
                                   const char* cond,
                                   int linenum) {
   int condl = strlen(cond);
@@ -5083,35 +4867,33 @@ int AffixMgr::redundant_condition(char f
       }
       if (j < 0)
         return 1;
     }
   }
   return 0;
 }
 
-int AffixMgr::get_suffix_words(short unsigned* suff,
+std::vector<std::string> AffixMgr::get_suffix_words(short unsigned* suff,
                                int len,
-                               const char* root_word,
-                               char** slst) {
-  int suff_words_cnt = 0;
+                               const char* root_word) {
+  std::vector<std::string> slst;
   short unsigned* start_ptr = suff;
   for (int j = 0; j < SETSIZE; j++) {
     SfxEntry* ptr = sStart[j];
     while (ptr) {
       suff = start_ptr;
       for (int i = 0; i < len; i++) {
         if ((*suff) == ptr->getFlag()) {
           std::string nw(root_word);
           nw.append(ptr->getAffix());
-          hentry* ht = ptr->checkword(nw.c_str(), nw.size(), 0, NULL, NULL, 0,
-                                      NULL, 0, 0, 0);
+          hentry* ht = ptr->checkword(nw.c_str(), nw.size(), 0, NULL, 0, 0, 0);
           if (ht) {
-            slst[suff_words_cnt++] = mystrdup(nw.c_str());
+            slst.push_back(nw);
           }
         }
         suff++;
       }
       ptr = ptr->getNext();
     }
   }
-  return suff_words_cnt;
+  return slst;
 }
--- a/extensions/spellcheck/hunspell/src/affixmgr.hxx
+++ b/extensions/spellcheck/hunspell/src/affixmgr.hxx
@@ -66,49 +66,47 @@
  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
-#ifndef _AFFIXMGR_HXX_
-#define _AFFIXMGR_HXX_
-
-#include "hunvisapi.h"
+#ifndef AFFIXMGR_HXX_
+#define AFFIXMGR_HXX_
 
 #include <stdio.h>
 
 #include <string>
+#include <vector>
 
 #include "atypes.hxx"
 #include "baseaffix.hxx"
 #include "hashmgr.hxx"
 #include "phonet.hxx"
 #include "replist.hxx"
 
 // check flag duplication
 #define dupSFX (1 << 0)
 #define dupPFX (1 << 1)
 
 class PfxEntry;
 class SfxEntry;
 
-class LIBHUNSPELL_DLL_EXPORTED AffixMgr {
+class AffixMgr {
   PfxEntry* pStart[SETSIZE];
   SfxEntry* sStart[SETSIZE];
   PfxEntry* pFlag[SETSIZE];
   SfxEntry* sFlag[SETSIZE];
-  HashMgr* pHMgr;
-  HashMgr** alldic;
-  int* maxdic;
-  char* keystring;
-  char* trystring;
-  char* encoding;
+  const std::vector<HashMgr*>& alldic;
+  const HashMgr* pHMgr;
+  std::string keystring;
+  std::string trystring;
+  std::string encoding;
   struct cs_info* csconv;
   int utf8;
   int complexprefixes;
   FLAG compoundflag;
   FLAG compoundbegin;
   FLAG compoundmiddle;
   FLAG compoundend;
   FLAG compoundroot;
@@ -120,56 +118,55 @@ class LIBHUNSPELL_DLL_EXPORTED AffixMgr 
   int checkcompoundcase;
   int checkcompoundtriple;
   int simplifiedtriple;
   FLAG forbiddenword;
   FLAG nosuggest;
   FLAG nongramsuggest;
   FLAG needaffix;
   int cpdmin;
-  int numrep;
-  replentry* reptable;
+  bool parsedrep;
+  std::vector<replentry> reptable;
   RepList* iconvtable;
   RepList* oconvtable;
-  int nummap;
-  mapentry* maptable;
-  int numbreak;
-  char** breaktable;
-  int numcheckcpd;
-  patentry* checkcpdtable;
+  bool parsedmaptable;
+  std::vector<mapentry> maptable;
+  bool parsedbreaktable;
+  std::vector<std::string> breaktable;
+  bool parsedcheckcpd;
+  std::vector<patentry> checkcpdtable;
   int simplifiedcpd;
-  int numdefcpd;
-  flagentry* defcpdtable;
+  bool parseddefcpd;
+  std::vector<flagentry> defcpdtable;
   phonetable* phone;
   int maxngramsugs;
   int maxcpdsugs;
   int maxdiff;
   int onlymaxdiff;
   int nosplitsugs;
   int sugswithdots;
   int cpdwordmax;
   int cpdmaxsyllable;
-  char* cpdvowels;
-  w_char* cpdvowels_utf16;
-  int cpdvowels_utf16_len;
-  char* cpdsyllablenum;
+  std::string cpdvowels; // vowels (for calculating of Hungarian compounding limit,
+  std::vector<w_char> cpdvowels_utf16; //vowels for UTF-8 encoding
+  std::string cpdsyllablenum; // syllable count incrementing flag
   const char* pfxappnd;  // BUG: not stateless
   const char* sfxappnd;  // BUG: not stateless
   int sfxextra;          // BUG: not stateless
   FLAG sfxflag;          // BUG: not stateless
   char* derived;         // BUG: not stateless
   SfxEntry* sfx;         // BUG: not stateless
   PfxEntry* pfx;         // BUG: not stateless
   int checknum;
-  char* wordchars;
+  std::string wordchars; // letters + spec. word characters
   std::vector<w_char> wordchars_utf16;
-  char* ignorechars;
+  std::string ignorechars; // letters + spec. word characters
   std::vector<w_char> ignorechars_utf16;
-  char* version;
-  char* lang;
+  std::string version;   // affix and dictionary file version string
+  std::string lang;	 // language
   int langnum;
   FLAG lemma_present;
   FLAG circumfix;
   FLAG onlyincompound;
   FLAG keepcase;
   FLAG forceucase;
   FLAG warn;
   int forbidwarn;
@@ -177,17 +174,17 @@ class LIBHUNSPELL_DLL_EXPORTED AffixMgr 
   int checksharps;
   int fullstrip;
 
   int havecontclass;           // boolean variable
   char contclasses[CONTSIZE];  // flags of possible continuing classes (twofold
                                // affix)
 
  public:
-  AffixMgr(const char* affpath, HashMgr** ptr, int* md, const char* key = NULL);
+  AffixMgr(const char* affpath, const std::vector<HashMgr*>& ptr, const char* key = NULL);
   ~AffixMgr();
   struct hentry* affix_check(const char* word,
                              int len,
                              const unsigned short needflag = (unsigned short)0,
                              char in_compound = IN_CPD_NOT);
   struct hentry* prefix_check(const char* word,
                               int len,
                               char in_compound,
@@ -197,61 +194,58 @@ class LIBHUNSPELL_DLL_EXPORTED AffixMgr 
                                      int len,
                                      char in_compound,
                                      const FLAG needflag = FLAG_NULL);
   inline int isRevSubset(const char* s1, const char* end_of_s2, int len);
   struct hentry* suffix_check(const char* word,
                               int len,
                               int sfxopts,
                               PfxEntry* ppfx,
-                              char** wlst,
-                              int maxSug,
-                              int* ns,
                               const FLAG cclass = FLAG_NULL,
                               const FLAG needflag = FLAG_NULL,
                               char in_compound = IN_CPD_NOT);
   struct hentry* suffix_check_twosfx(const char* word,
                                      int len,
                                      int sfxopts,
                                      PfxEntry* ppfx,
                                      const FLAG needflag = FLAG_NULL);
 
-  char* affix_check_morph(const char* word,
-                          int len,
-                          const FLAG needflag = FLAG_NULL,
-                          char in_compound = IN_CPD_NOT);
-  char* prefix_check_morph(const char* word,
-                           int len,
-                           char in_compound,
-                           const FLAG needflag = FLAG_NULL);
-  char* suffix_check_morph(const char* word,
-                           int len,
-                           int sfxopts,
-                           PfxEntry* ppfx,
-                           const FLAG cclass = FLAG_NULL,
-                           const FLAG needflag = FLAG_NULL,
-                           char in_compound = IN_CPD_NOT);
+  std::string affix_check_morph(const char* word,
+                                int len,
+                                const FLAG needflag = FLAG_NULL,
+                                char in_compound = IN_CPD_NOT);
+  std::string prefix_check_morph(const char* word,
+                                 int len,
+                                 char in_compound,
+                                 const FLAG needflag = FLAG_NULL);
+  std::string suffix_check_morph(const char* word,
+                                 int len,
+                                 int sfxopts,
+                                 PfxEntry* ppfx,
+                                 const FLAG cclass = FLAG_NULL,
+                                 const FLAG needflag = FLAG_NULL,
+                                 char in_compound = IN_CPD_NOT);
 
-  char* prefix_check_twosfx_morph(const char* word,
-                                  int len,
-                                  char in_compound,
-                                  const FLAG needflag = FLAG_NULL);
-  char* suffix_check_twosfx_morph(const char* word,
-                                  int len,
-                                  int sfxopts,
-                                  PfxEntry* ppfx,
-                                  const FLAG needflag = FLAG_NULL);
+  std::string prefix_check_twosfx_morph(const char* word,
+                                        int len,
+                                        char in_compound,
+                                        const FLAG needflag = FLAG_NULL);
+  std::string suffix_check_twosfx_morph(const char* word,
+                                        int len,
+                                        int sfxopts,
+                                        PfxEntry* ppfx,
+                                        const FLAG needflag = FLAG_NULL);
 
-  char* morphgen(const char* ts,
-                 int wl,
-                 const unsigned short* ap,
-                 unsigned short al,
-                 const char* morph,
-                 const char* targetmorph,
-                 int level);
+  std::string morphgen(const char* ts,
+                       int wl,
+                       const unsigned short* ap,
+                       unsigned short al,
+                       const char* morph,
+                       const char* targetmorph,
+                       int level);
 
   int expand_rootword(struct guessword* wlst,
                       int maxn,
                       const char* ts,
                       int wl,
                       const unsigned short* ap,
                       unsigned short al,
                       const char* bad,
@@ -268,18 +262,17 @@ class LIBHUNSPELL_DLL_EXPORTED AffixMgr 
   int defcpd_check(hentry*** words,
                    short wnum,
                    hentry* rv,
                    hentry** rwords,
                    char all);
   int cpdcase_check(const char* word, int len);
   inline int candidate_check(const char* word, int len);
   void setcminmax(int* cmin, int* cmax, const char* word, int len);
-  struct hentry* compound_check(const char* word,
-                                int len,
+  struct hentry* compound_check(const std::string& word,
                                 short wordnum,
                                 short numsyllable,
                                 short maxwordnum,
                                 short wnum,
                                 hentry** words,
                                 hentry** rwords,
                                 char hu_mov_rule,
                                 char is_sug,
@@ -289,57 +282,47 @@ class LIBHUNSPELL_DLL_EXPORTED AffixMgr 
                            int len,
                            short wordnum,
                            short numsyllable,
                            short maxwordnum,
                            short wnum,
                            hentry** words,
                            hentry** rwords,
                            char hu_mov_rule,
-                           char** result,
-                           char* partresult);
+                           std::string& result,
+                           const std::string* partresult);
 
-  int get_suffix_words(short unsigned* suff,
+  std::vector<std::string> get_suffix_words(short unsigned* suff,
                        int len,
-                       const char* root_word,
-                       char** slst);
+                       const char* root_word);
 
   struct hentry* lookup(const char* word);
-  int get_numrep() const;
-  struct replentry* get_reptable() const;
+  const std::vector<replentry>& get_reptable() const;
   RepList* get_iconvtable() const;
   RepList* get_oconvtable() const;
   struct phonetable* get_phonetable() const;
-  int get_nummap() const;
-  struct mapentry* get_maptable() const;
-  int get_numbreak() const;
-  char** get_breaktable() const;
-  char* get_encoding();
+  const std::vector<mapentry>& get_maptable() const;
+  const std::vector<std::string>& get_breaktable() const;
+  const std::string& get_encoding();
   int get_langnum() const;
   char* get_key_string();
   char* get_try_string() const;
-  const char* get_wordchars() const;
+  const std::string& get_wordchars() const;
   const std::vector<w_char>& get_wordchars_utf16() const;
-  char* get_ignore() const;
+  const char* get_ignore() const;
   const std::vector<w_char>& get_ignore_utf16() const;
   int get_compound() const;
   FLAG get_compoundflag() const;
-  FLAG get_compoundbegin() const;
   FLAG get_forbiddenword() const;
   FLAG get_nosuggest() const;
   FLAG get_nongramsuggest() const;
   FLAG get_needaffix() const;
   FLAG get_onlyincompound() const;
-  FLAG get_compoundroot() const;
-  FLAG get_lemma_present() const;
-  int get_checknum() const;
-  const char* get_prefix() const;
-  const char* get_suffix() const;
   const char* get_derived() const;
-  const char* get_version() const;
+  const std::string& get_version() const;
   int have_contclass() const;
   int get_utf8() const;
   int get_complexprefixes() const;
   char* get_suffixed(char) const;
   int get_maxngramsugs() const;
   int get_maxcpdsugs() const;
   int get_maxdiff() const;
   int get_onlymaxdiff() const;
@@ -350,36 +333,35 @@ class LIBHUNSPELL_DLL_EXPORTED AffixMgr 
   FLAG get_warn(void) const;
   int get_forbidwarn(void) const;
   int get_checksharps(void) const;
   char* encode_flag(unsigned short aflag) const;
   int get_fullstrip() const;
 
  private:
   int parse_file(const char* affpath, const char* key);
-  int parse_flag(char* line, unsigned short* out, FileMgr* af);
-  int parse_num(char* line, int* out, FileMgr* af);
-  int parse_cpdsyllable(char* line, FileMgr* af);
-  int parse_reptable(char* line, FileMgr* af);
-  int parse_convtable(char* line,
+  bool parse_flag(const std::string& line, unsigned short* out, FileMgr* af);
+  bool parse_num(const std::string& line, int* out, FileMgr* af);
+  bool parse_cpdsyllable(const std::string& line, FileMgr* af);
+  bool parse_reptable(const std::string& line, FileMgr* af);
+  bool parse_convtable(const std::string& line,
                       FileMgr* af,
                       RepList** rl,
-                      const char* keyword);
-  int parse_phonetable(char* line, FileMgr* af);
-  int parse_maptable(char* line, FileMgr* af);
-  int parse_breaktable(char* line, FileMgr* af);
-  int parse_checkcpdtable(char* line, FileMgr* af);
-  int parse_defcpdtable(char* line, FileMgr* af);
-  int parse_affix(char* line, const char at, FileMgr* af, char* dupflags);
+                      const std::string& keyword);
+  bool parse_phonetable(const std::string& line, FileMgr* af);
+  bool parse_maptable(const std::string& line, FileMgr* af);
+  bool parse_breaktable(const std::string& line, FileMgr* af);
+  bool parse_checkcpdtable(const std::string& line, FileMgr* af);
+  bool parse_defcpdtable(const std::string& line, FileMgr* af);
+  bool parse_affix(const std::string& line, const char at, FileMgr* af, char* dupflags);
 
   void reverse_condition(std::string&);
-  void debugflag(char* result, unsigned short flag);
   std::string& debugflag(std::string& result, unsigned short flag);
   int condlen(const char*);
-  int encodeit(affentry& entry, const char* cs);
+  int encodeit(AffEntry& entry, const char* cs);
   int build_pfxtree(PfxEntry* pfxptr);
   int build_sfxtree(SfxEntry* sfxptr);
   int process_pfx_order();
   int process_sfx_order();
   PfxEntry* process_pfx_in_order(PfxEntry* ptr, PfxEntry* nptr);
   SfxEntry* process_sfx_in_order(SfxEntry* ptr, SfxEntry* nptr);
   int process_pfx_tree_to_list();
   int process_sfx_tree_to_list();
--- a/extensions/spellcheck/hunspell/src/atypes.hxx
+++ b/extensions/spellcheck/hunspell/src/atypes.hxx
@@ -33,18 +33,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#ifndef _ATYPES_HXX_
-#define _ATYPES_HXX_
+#ifndef ATYPES_HXX_
+#define ATYPES_HXX_
 
 #ifndef HUNSPELL_WARNING
 #include <stdio.h>
 #ifdef HUNSPELL_WARNING_ON
 #define HUNSPELL_WARNING fprintf
 #else
 // empty inline function to switch off warnings (instead of the C99 standard
 // variadic macros)
@@ -58,17 +58,17 @@ static inline void HUNSPELL_WARNING(FILE
 #include "hashmgr.hxx"
 #include "w_char.hxx"
 #include <algorithm>
 #include <string>
 
 #define SETSIZE 256
 #define CONTSIZE 65536
 
-// affentry options
+// AffEntry options
 #define aeXPRODUCT (1 << 0)
 #define aeUTF8 (1 << 1)
 #define aeALIASF (1 << 2)
 #define aeALIASM (1 << 3)
 #define aeLONGCOND (1 << 4)
 
 // compound options
 #define IN_CPD_NOT 0
@@ -80,66 +80,43 @@ static inline void HUNSPELL_WARNING(FILE
 #define SPELL_COMPOUND (1 << 0)
 #define SPELL_FORBIDDEN (1 << 1)
 #define SPELL_ALLCAP (1 << 2)
 #define SPELL_NOCAP (1 << 3)
 #define SPELL_INITCAP (1 << 4)
 #define SPELL_ORIGCAP (1 << 5)
 #define SPELL_WARN (1 << 6)
 
-#define MAXLNLEN 8192
-
 #define MINCPDLEN 3
 #define MAXCOMPOUND 10
 #define MAXCONDLEN 20
 #define MAXCONDLEN_1 (MAXCONDLEN - sizeof(char*))
 
 #define MAXACC 1000
 
 #define FLAG unsigned short
 #define FLAG_NULL 0x00
 #define FREE_FLAG(a) a = 0
 
 #define TESTAFF(a, b, c) (std::binary_search(a, a + c, b))
 
-struct affentry {
-  std::string strip;
-  std::string appnd;
-  char numconds;
-  char opts;
-  unsigned short aflag;
-  unsigned short* contclass;
-  short contclasslen;
-  union {
-    char conds[MAXCONDLEN];
-    struct {
-      char conds1[MAXCONDLEN_1];
-      char* conds2;
-    } l;
-  } c;
-  char* morphcode;
-};
-
 struct guessword {
   char* word;
   bool allow;
   char* orig;
 };
 
-struct mapentry {
-  char** set;
-  int len;
-};
-
-struct flagentry {
-  FLAG* def;
-  int len;
-};
+typedef std::vector<std::string> mapentry;
+typedef std::vector<FLAG> flagentry;
 
 struct patentry {
-  char* pattern;
-  char* pattern2;
-  char* pattern3;
+  std::string pattern;
+  std::string pattern2;
+  std::string pattern3;
   FLAG cond;
   FLAG cond2;
+  patentry()
+    : cond(FLAG_NULL)
+    , cond2(FLAG_NULL) {
+  }
 };
 
 #endif
--- a/extensions/spellcheck/hunspell/src/baseaffix.hxx
+++ b/extensions/spellcheck/hunspell/src/baseaffix.hxx
@@ -33,35 +33,35 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#ifndef _BASEAFF_HXX_
-#define _BASEAFF_HXX_
+#ifndef BASEAFF_HXX_
+#define BASEAFF_HXX_
 
-#include "hunvisapi.h"
 #include <string>
 
-class LIBHUNSPELL_DLL_EXPORTED AffEntry {
+class AffEntry {
  private:
   AffEntry(const AffEntry&);
   AffEntry& operator=(const AffEntry&);
 
- protected:
+ public:
   AffEntry()
       : numconds(0),
         opts(0),
         aflag(0),
         morphcode(0),
         contclass(NULL),
         contclasslen(0) {}
+  virtual ~AffEntry();
   std::string appnd;
   std::string strip;
   unsigned char numconds;
   char opts;
   unsigned short aflag;
   union {
     char conds[MAXCONDLEN];
     struct {
--- a/extensions/spellcheck/hunspell/src/csutil.cxx
+++ b/extensions/spellcheck/hunspell/src/csutil.cxx
@@ -71,16 +71,17 @@
  * SUCH DAMAGE.
  */
 
 #include <algorithm>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <ctype.h>
+#include <sstream>
 
 #include "csutil.hxx"
 #include "atypes.hxx"
 #include "langnum.hxx"
 
 // Unicode character encoding information
 struct unicode_info {
   unsigned short c;
@@ -117,36 +118,34 @@ struct unicode_info2 {
   unsigned short cupper;
   unsigned short clower;
 };
 
 static struct unicode_info2* utf_tbl = NULL;
 static int utf_tbl_count =
     0;  // utf_tbl can be used by multiple Hunspell instances
 
-FILE* myfopen(const char* path, const char* mode) {
-#ifdef _WIN32
+void myopen(std::ifstream& stream, const char* path, std::ios_base::openmode mode)
+{
+#if defined(_WIN32) && defined(_MSC_VER)
 #define WIN32_LONG_PATH_PREFIX "\\\\?\\"
   if (strncmp(path, WIN32_LONG_PATH_PREFIX, 4) == 0) {
     int len = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0);
-    wchar_t* buff = (wchar_t*)malloc(len * sizeof(wchar_t));
-    wchar_t* buff2 = (wchar_t*)malloc(len * sizeof(wchar_t));
-    FILE* f = NULL;
-    if (buff && buff2) {
-      MultiByteToWideChar(CP_UTF8, 0, path, -1, buff, len);
-      if (_wfullpath(buff2, buff, len) != NULL) {
-        f = _wfopen(buff2, (strcmp(mode, "r") == 0) ? L"r" : L"rb");
-      }
-      free(buff);
-      free(buff2);
+    wchar_t* buff = new wchar_t[len];
+    wchar_t* buff2 = new wchar_t[len];
+    MultiByteToWideChar(CP_UTF8, 0, path, -1, buff, len);
+    if (_wfullpath(buff2, buff, len) != NULL) {
+      stream.open(buff2, mode);
     }
-    return f;
+    delete [] buff;
+    delete [] buff2;
   }
+  else
 #endif
-  return fopen(path, mode);
+  stream.open(path, mode);
 }
 
 std::string& u16_u8(std::string& dest, const std::vector<w_char>& src) {
   dest.clear();
   std::vector<w_char>::const_iterator u2 = src.begin();
   std::vector<w_char>::const_iterator u2_max = src.end();
   while (u2 < u2_max) {
     signed char u8;
@@ -213,17 +212,17 @@ int u8_u16(std::vector<w_char>& dest, co
         u2.h = 0xff;
         u2.l = 0xfd;
         break;
       }
       case 0xc0:
       case 0xd0: {  // 2-byte UTF-8 codes
         if ((*(u8 + 1) & 0xc0) == 0x80) {
           u2.h = (*u8 & 0x1f) >> 2;
-          u2.l = (*u8 << 6) + (*(u8 + 1) & 0x3f);
+          u2.l = (static_cast<unsigned char>(*u8) << 6) + (*(u8 + 1) & 0x3f);
           ++u8;
         } else {
           HUNSPELL_WARNING(stderr,
                            "UTF-8 encoding error. Missing continuation byte in "
                            "%ld. character position:\n%s\n",
                            static_cast<long>(std::distance(src.begin(), u8)),
                            src.c_str());
           u2.h = 0xff;
@@ -270,44 +269,45 @@ int u8_u16(std::vector<w_char>& dest, co
     }
     dest.push_back(u2);
     ++u8;
   }
 
   return dest.size();
 }
 
-// strip strings into token based on single char delimiter
-// acts like strsep() but only uses a delim char and not
-// a delim string
-// default delimiter: white space characters
+namespace {
+class is_any_of {
+ public:
+  explicit is_any_of(const std::string& in) : chars(in) {}
+
+  bool operator()(char c) { return chars.find(c) != std::string::npos; }
+
+ private:
+  std::string chars;
+};
+}
 
-char* mystrsep(char** stringp, const char delim) {
-  char* mp = *stringp;
-  if (*mp != '\0') {
-    char* dp;
-    if (delim) {
-      dp = strchr(mp, delim);
-    } else {
-      // don't use isspace() here, the string can be in some random charset
-      // that's way different than the locale's
-      for (dp = mp; (*dp && *dp != ' ' && *dp != '\t'); dp++)
-        ;
-      if (!*dp)
-        dp = NULL;
-    }
-    if (dp) {
-      *stringp = dp + 1;
-      *dp = '\0';
-    } else {
-      *stringp = mp + strlen(mp);
-    }
-    return mp;
-  }
-  return NULL;
+std::string::const_iterator mystrsep(const std::string &str,
+                                     std::string::const_iterator& start) {
+  std::string::const_iterator end = str.end();
+
+  is_any_of op(" \t");
+  // don't use isspace() here, the string can be in some random charset
+  // that's way different than the locale's
+  std::string::const_iterator sp = start;
+  while (sp != end && op(*sp))
+      ++sp;
+
+  std::string::const_iterator dp = sp;
+  while (dp != end && !op(*dp))
+      ++dp;
+
+  start = dp;
+  return sp;
 }
 
 // replaces strdup with ansi version
 char* mystrdup(const char* s) {
   char* d = NULL;
   if (s) {
     size_t sl = strlen(s) + 1;
     d = (char*)malloc(sl);
@@ -315,270 +315,121 @@ char* mystrdup(const char* s) {
       memcpy(d, s, sl);
     } else {
       HUNSPELL_WARNING(stderr, "Can't allocate memory.\n");
     }
   }
   return d;
 }
 
-// strcat for limited length destination string
-char* mystrcat(char* dest, const char* st, int max) {
-  int len;
-  int len2;
-  if (dest == NULL || st == NULL)
-    return dest;
-  len = strlen(dest);
-  len2 = strlen(st);
-  if (len + len2 + 1 > max)
-    return dest;
-  strcpy(dest + len, st);
-  return dest;
-}
-
 // remove cross-platform text line end characters
-void mychomp(char* s) {
-  size_t k = strlen(s);
-  if ((k > 0) && ((*(s + k - 1) == '\r') || (*(s + k - 1) == '\n')))
-    *(s + k - 1) = '\0';
-  if ((k > 1) && (*(s + k - 2) == '\r'))
-    *(s + k - 2) = '\0';
+void mychomp(std::string& s) {
+  size_t k = s.size();
+  size_t newsize = k;
+  if ((k > 0) && ((s[k - 1] == '\r') || (s[k - 1] == '\n')))
+    --newsize;
+  if ((k > 1) && (s[k - 2] == '\r'))
+    --newsize;
+  s.resize(newsize);
 }
 
 // break text to lines
-// return number of lines
-int line_tok(const char* text, char*** lines, char breakchar) {
-  int linenum = 0;
-  if (!text) {
-    return linenum;
-  }
-  char* dup = mystrdup(text);
-  char* p = strchr(dup, breakchar);
-  while (p) {
-    linenum++;
-    *p = '\0';
-    p++;
-    p = strchr(p, breakchar);
-  }
-  linenum++;
-  *lines = (char**)malloc(linenum * sizeof(char*));
-  if (!(*lines)) {
-    free(dup);
-    return 0;
+std::vector<std::string> line_tok(const std::string& text, char breakchar) {
+  std::vector<std::string> ret;
+  if (text.empty()) {
+    return ret;
   }
 
-  p = dup;
-  int l = 0;
-  for (int i = 0; i < linenum; i++) {
-    if (*p != '\0') {
-      (*lines)[l] = mystrdup(p);
-      if (!(*lines)[l]) {
-        for (i = 0; i < l; i++)
-          free((*lines)[i]);
-        free(dup);
-        return 0;
-      }
-      l++;
+  std::stringstream ss(text);
+  std::string tok;
+  while(std::getline(ss, tok, breakchar)) {
+    if (!tok.empty()) {
+      ret.push_back(tok);
     }
-    p += strlen(p) + 1;
   }
-  free(dup);
-  if (!l) {
-    free(*lines);
-    *lines = NULL;
-  }
-  return l;
+
+  return ret;
 }
 
 // uniq line in place
-char* line_uniq(char* text, char breakchar) {
-  char** lines;
-  int linenum = line_tok(text, &lines, breakchar);
-  int i;
-  strcpy(text, lines[0]);
-  for (i = 1; i < linenum; i++) {
-    int dup = 0;
-    for (int j = 0; j < i; j++) {
-      if (strcmp(lines[i], lines[j]) == 0) {
-        dup = 1;
+void line_uniq(std::string& text, char breakchar)
+{
+  std::vector<std::string> lines = line_tok(text, breakchar);
+  text.clear();
+  if (lines.empty()) {
+    return;
+  }
+  text = lines[0];
+  for (size_t i = 1; i < lines.size(); ++i) {
+    bool dup = false;
+    for (size_t j = 0; j < i; ++j) {
+      if (lines[i] == lines[j]) {
+        dup = true;
         break;
       }
     }
     if (!dup) {
-      if ((i > 1) || (*(lines[0]) != '\0')) {
-        sprintf(text + strlen(text), "%c", breakchar);
-      }
-      strcat(text, lines[i]);
+      if (!text.empty())
+        text.push_back(breakchar);
+      text.append(lines[i]);
     }
   }
-  for (i = 0; i < linenum; i++) {
-    free(lines[i]);
-  }
-  free(lines);
-  return text;
 }
 
 // uniq and boundary for compound analysis: "1\n\2\n\1" -> " ( \1 | \2 ) "
-char* line_uniq_app(char** text, char breakchar) {
-  if (!strchr(*text, breakchar)) {
-    return *text;
+void line_uniq_app(std::string& text, char breakchar) {
+  if (text.find(breakchar) == std::string::npos) {
+    return;
   }
 
-  char** lines;
-  int i;
-  int linenum = line_tok(*text, &lines, breakchar);
-  int dup = 0;
-  for (i = 0; i < linenum; i++) {
-    for (int j = 0; j < (i - 1); j++) {
-      if (strcmp(lines[i], lines[j]) == 0) {
-        *(lines[i]) = '\0';
-        dup++;
+  std::vector<std::string> lines = line_tok(text, breakchar);
+  text.clear();
+  if (lines.empty()) {
+    return;
+  }
+  text = lines[0];
+  for (size_t i = 1; i < lines.size(); ++i) {
+    bool dup = false;
+    for (size_t j = 0; j < i; ++j) {
+      if (lines[i] == lines[j]) {
+        dup = true;
         break;
       }
     }
-  }
-  if ((linenum - dup) == 1) {
-    strcpy(*text, lines[0]);
-    freelist(&lines, linenum);
-    return *text;
+    if (!dup) {
+      if (!text.empty())
+        text.push_back(breakchar);
+      text.append(lines[i]);
+    }
   }
-  char* newtext = (char*)malloc(strlen(*text) + 2 * linenum + 3 + 1);
-  if (newtext) {
-    free(*text);
-    *text = newtext;
-  } else {
-    freelist(&lines, linenum);
-    return *text;
+
+  if (lines.size() == 1) {
+    text = lines[0];
+    return;
   }
-  strcpy(*text, " ( ");
-  for (i = 0; i < linenum; i++)
-    if (*(lines[i])) {
-      sprintf(*text + strlen(*text), "%s%s", lines[i], " | ");
-    }
-  (*text)[strlen(*text) - 2] = ')';  // " ) "
-  freelist(&lines, linenum);
-  return *text;
+
+  text.assign(" ( ");
+  for (size_t i = 0; i < lines.size(); ++i) {
+      text.append(lines[i]);
+      text.append(" | ");
+  }
+  text[text.size() - 2] = ')';  // " ) "
 }
 
 // append s to ends of every lines in text
 std::string& strlinecat(std::string& str, const std::string& apd) {
   size_t pos = 0;
   while ((pos = str.find('\n', pos)) != std::string::npos) {
     str.insert(pos, apd);
     pos += apd.length() + 1;
   }
   str.append(apd);
   return str;
 }
 
-// morphcmp(): compare MORPH_DERI_SFX, MORPH_INFL_SFX and MORPH_TERM_SFX fields
-// in the first line of the inputs
-// return 0, if inputs equal
-// return 1, if inputs may equal with a secondary suffix
-// otherwise return -1
-int morphcmp(const char* s, const char* t) {
-  int se = 0;
-  int te = 0;
-  const char* sl;
-  const char* tl;
-  const char* olds;
-  const char* oldt;
-  if (!s || !t)
-    return 1;
-  olds = s;
-  sl = strchr(s, '\n');
-  s = strstr(s, MORPH_DERI_SFX);
-  if (!s || (sl && sl < s))
-    s = strstr(olds, MORPH_INFL_SFX);
-  if (!s || (sl && sl < s)) {
-    s = strstr(olds, MORPH_TERM_SFX);
-    olds = NULL;
-  }
-  oldt = t;
-  tl = strchr(t, '\n');
-  t = strstr(t, MORPH_DERI_SFX);
-  if (!t || (tl && tl < t))
-    t = strstr(oldt, MORPH_INFL_SFX);
-  if (!t || (tl && tl < t)) {
-    t = strstr(oldt, MORPH_TERM_SFX);
-    oldt = NULL;
-  }
-  while (s && t && (!sl || sl > s) && (!tl || tl > t)) {
-    s += MORPH_TAG_LEN;
-    t += MORPH_TAG_LEN;
-    se = 0;
-    te = 0;
-    while ((*s == *t) && !se && !te) {
-      s++;
-      t++;
-      switch (*s) {
-        case ' ':
-        case '\n':
-        case '\t':
-        case '\0':
-          se = 1;
-      }
-      switch (*t) {
-        case ' ':
-        case '\n':
-        case '\t':
-        case '\0':
-          te = 1;
-      }
-    }
-    if (!se || !te) {
-      // not terminal suffix difference
-      if (olds)
-        return -1;
-      return 1;
-    }
-    olds = s;
-    s = strstr(s, MORPH_DERI_SFX);
-    if (!s || (sl && sl < s))
-      s = strstr(olds, MORPH_INFL_SFX);
-    if (!s || (sl && sl < s)) {
-      s = strstr(olds, MORPH_TERM_SFX);
-      olds = NULL;
-    }
-    oldt = t;
-    t = strstr(t, MORPH_DERI_SFX);
-    if (!t || (tl && tl < t))
-      t = strstr(oldt, MORPH_INFL_SFX);
-    if (!t || (tl && tl < t)) {
-      t = strstr(oldt, MORPH_TERM_SFX);
-      oldt = NULL;
-    }
-  }
-  if (!s && !t && se && te)
-    return 0;
-  return 1;
-}
-
-int get_sfxcount(const char* morph) {
-  if (!morph || !*morph)
-    return 0;
-  int n = 0;
-  const char* old = morph;
-  morph = strstr(morph, MORPH_DERI_SFX);
-  if (!morph)
-    morph = strstr(old, MORPH_INFL_SFX);
-  if (!morph)
-    morph = strstr(old, MORPH_TERM_SFX);
-  while (morph) {
-    n++;
-    old = morph;
-    morph = strstr(morph + 1, MORPH_DERI_SFX);
-    if (!morph)
-      morph = strstr(old + 1, MORPH_INFL_SFX);
-    if (!morph)
-      morph = strstr(old + 1, MORPH_TERM_SFX);
-  }
-  return n;
-}
-
 int fieldlen(const char* r) {
   int n = 0;
   while (r && *r != ' ' && *r != '\t' && *r != '\0' && *r != '\n') {
     r++;
     n++;
   }
   return n;
 }
@@ -610,87 +461,44 @@ std::string& mystrrep(std::string& str,
   size_t pos = 0;
   while ((pos = str.find(search, pos)) != std::string::npos) {
     str.replace(pos, search.length(), replace);
     pos += replace.length();
   }
   return str;
 }
 
-char* mystrrep(char* word, const char* pat, const char* rep) {
-  char* pos = strstr(word, pat);
-  if (pos) {
-    int replen = strlen(rep);
-    int patlen = strlen(pat);
-    while (pos) {
-      if (replen < patlen) {
-        char* end = word + strlen(word);
-        char* next = pos + replen;
-        char* prev = pos + strlen(pat);
-        for (; prev < end;* next = *prev, prev++, next++)
-          ;
-        *next = '\0';
-      } else if (replen > patlen) {
-        char* end = pos + patlen;
-        char* next = word + strlen(word) + replen - patlen;
-        char* prev = next - replen + patlen;
-        for (; prev >= end;* next = *prev, prev--, next--)
-          ;
-      }
-      strncpy(pos, rep, replen);
-      pos = strstr(word, pat);
-    }
-  }
-  return word;
-}
-
 // reverse word
 size_t reverseword(std::string& word) {
   std::reverse(word.begin(), word.end());
   return word.size();
 }
 
 // reverse word
 size_t reverseword_utf(std::string& word) {
   std::vector<w_char> w;
   u8_u16(w, word);
   std::reverse(w.begin(), w.end());
   u16_u8(word, w);
   return w.size();
 }
 
-int uniqlist(char** list, int n) {
-  int i;
-  if (n < 2)
-    return n;
-  for (i = 0; i < n; i++) {
-    for (int j = 0; j < i; j++) {
-      if (list[j] && list[i] && (strcmp(list[j], list[i]) == 0)) {
-        free(list[i]);
-        list[i] = NULL;
-        break;
-      }
-    }
+void uniqlist(std::vector<std::string>& list) {
+  if (list.size() < 2)
+    return;
+
+  std::vector<std::string> ret;
+  ret.push_back(list[0]);
+
+  for (size_t i = 1; i < list.size(); ++i) {
+    if (std::find(ret.begin(), ret.end(), list[i]) == ret.end())
+        ret.push_back(list[i]);
   }
-  int m = 1;
-  for (i = 1; i < n; i++)
-    if (list[i]) {
-      list[m] = list[i];
-      m++;
-    }
-  return m;
-}
 
-void freelist(char*** list, int n) {
-  if (list && *list) {
-    for (int i = 0; i < n; i++)
-      free((*list)[i]);
-    free(*list);
-    *list = NULL;
-  }
+  list.swap(ret);
 }
 
 namespace {
 unsigned char cupper(const struct cs_info* csconv, int nIndex) {
   if (nIndex < 0 || nIndex > 255)
     return nIndex;
   return csconv[nIndex].cupper;
 }
@@ -2452,60 +2260,60 @@ static void toAsciiLowerAndRemoveNonAlph
     }
 
     pName++;
   }
 
   *pBuf = '\0';
 }
 
-struct cs_info* get_current_cs(const char* es) {
-  char* normalized_encoding = new char[strlen(es) + 1];
-  toAsciiLowerAndRemoveNonAlphanumeric(es, normalized_encoding);
+struct cs_info* get_current_cs(const std::string& es) {
+  char* normalized_encoding = new char[es.size() + 1];
+  toAsciiLowerAndRemoveNonAlphanumeric(es.c_str(), normalized_encoding);
 
   struct cs_info* ccs = NULL;
   int n = sizeof(encds) / sizeof(encds[0]);
   for (int i = 0; i < n; i++) {
     if (strcmp(normalized_encoding, encds[i].enc_name) == 0) {
       ccs = encds[i].cs_table;
       break;
     }
   }
 
   delete[] normalized_encoding;
 
   if (!ccs) {
     HUNSPELL_WARNING(stderr,
-                     "error: unknown encoding %s: using %s as fallback\n", es,
+                     "error: unknown encoding %s: using %s as fallback\n", es.c_str(),
                      encds[0].enc_name);
     ccs = encds[0].cs_table;
   }
 
   return ccs;
 }
 #else
 // XXX This function was rewritten for mozilla. Instead of storing the
 // conversion tables static in this file, create them when needed
 // with help the mozilla backend.
-struct cs_info* get_current_cs(const char* es) {
+struct cs_info* get_current_cs(const std::string& es) {
   struct cs_info* ccs = new cs_info[256];
   // Initialze the array with dummy data so that we wouldn't need
   // to return null in case of failures.
   for (int i = 0; i <= 0xff; ++i) {
     ccs[i].ccase = false;
     ccs[i].clower = i;
     ccs[i].cupper = i;
   }
 
   nsCOMPtr<nsIUnicodeEncoder> encoder;
   nsCOMPtr<nsIUnicodeDecoder> decoder;
 
   nsresult rv;
 
-  nsAutoCString label(es);
+  nsAutoCString label(es.c_str());
   nsAutoCString encoding;
   if (!EncodingUtils::FindEncodingForLabelNoReplacement(label, encoding)) {
     return ccs;
   }
   encoder = EncodingUtils::EncoderForEncoding(encoding);
   decoder = EncodingUtils::DecoderForEncoding(encoding);
   encoder->SetOutputErrorBehavior(encoder->kOnError_Signal, nullptr, '?');
   decoder->SetInputErrorBehavior(decoder->kOnError_Signal);
@@ -2560,31 +2368,28 @@ struct cs_info* get_current_cs(const cha
       ccs[i].ccase = false;
   }
 
   return ccs;
 }
 #endif
 
 // primitive isalpha() replacement for tokenization
-char* get_casechars(const char* enc) {
+std::string get_casechars(const char* enc) {
   struct cs_info* csconv = get_current_cs(enc);
-  char expw[MAXLNLEN];
-  char* p = expw;
-  for (int i = 0; i <= 255; i++) {
+  std::string expw;
+  for (int i = 0; i <= 255; ++i) {
     if (cupper(csconv, i) != clower(csconv, i)) {
-      *p = static_cast<char>(i);
-      p++;
+      expw.push_back(static_cast<char>(i));
     }
   }
-  *p = '\0';
 #ifdef MOZILLA_CLIENT
   delete[] csconv;
 #endif
-  return mystrdup(expw);
+  return expw;
 }
 
 // language to encoding default map
 
 struct lang_map {
   const char* lang;
   int num;
 };
@@ -2601,57 +2406,52 @@ static struct lang_map lang2enc[] =
      {"hu", LANG_hu},    {"hu_HU", LANG_hu},  // for back-compatibility
      {"it", LANG_it},    {"la", LANG_la},
      {"lv", LANG_lv},    {"nl", LANG_nl},
      {"pl", LANG_pl},    {"pt", LANG_pt},
      {"sv", LANG_sv},    {"tr", LANG_tr},
      {"tr_TR", LANG_tr},  // for back-compatibility
      {"ru", LANG_ru},    {"uk", LANG_uk}};
 
-int get_lang_num(const char* lang) {
+int get_lang_num(const std::string& lang) {
   int n = sizeof(lang2enc) / sizeof(lang2enc[0]);
   for (int i = 0; i < n; i++) {
-    if (strcmp(lang, lang2enc[i].lang) == 0) {
+    if (strcmp(lang.c_str(), lang2enc[i].lang) == 0) {
       return lang2enc[i].num;
     }
   }
   return LANG_xx;
 }
 
 #ifndef OPENOFFICEORG
 #ifndef MOZILLA_CLIENT
-int initialize_utf_tbl() {
+void initialize_utf_tbl() {
   utf_tbl_count++;
   if (utf_tbl)
-    return 0;
-  utf_tbl = (unicode_info2*)malloc(CONTSIZE * sizeof(unicode_info2));
-  if (utf_tbl) {
-    size_t j;
-    for (j = 0; j < CONTSIZE; j++) {
-      utf_tbl[j].cletter = 0;
-      utf_tbl[j].clower = (unsigned short)j;
-      utf_tbl[j].cupper = (unsigned short)j;
-    }
-    for (j = 0; j < UTF_LST_LEN; j++) {
-      utf_tbl[utf_lst[j].c].cletter = 1;
-      utf_tbl[utf_lst[j].c].clower = utf_lst[j].clower;
-      utf_tbl[utf_lst[j].c].cupper = utf_lst[j].cupper;
-    }
-  } else
-    return 1;
-  return 0;
+    return;
+  utf_tbl = new unicode_info2[CONTSIZE];
+  for (size_t j = 0; j < CONTSIZE; ++j) {
+    utf_tbl[j].cletter = 0;
+    utf_tbl[j].clower = (unsigned short)j;
+    utf_tbl[j].cupper = (unsigned short)j;
+  }
+  for (size_t j = 0; j < UTF_LST_LEN; ++j) {
+    utf_tbl[utf_lst[j].c].cletter = 1;
+    utf_tbl[utf_lst[j].c].clower = utf_lst[j].clower;
+    utf_tbl[utf_lst[j].c].cupper = utf_lst[j].cupper;
+  }
 }
 #endif
 #endif
 
 void free_utf_tbl() {
   if (utf_tbl_count > 0)
     utf_tbl_count--;
   if (utf_tbl && (utf_tbl_count == 0)) {
-    free(utf_tbl);
+    delete[] utf_tbl;
     utf_tbl = NULL;
   }
 }
 
 unsigned short unicodetoupper(unsigned short c, int langnum) {
   // In Azeri and Turkish, I and i dictinct letters:
   // There are a dotless lower case i pair of upper `I',
   // and an upper I with dot pair of lower `i'.
@@ -2770,81 +2570,63 @@ size_t remove_ignored_chars_utf(std::str
       w2.push_back(w[i]);
     }
   }
 
   u16_u8(word, w2);
   return w2.size();
 }
 
-namespace {
-class is_any_of {
- public:
-  is_any_of(const std::string& in) : chars(in) {}
-
-  bool operator()(char c) { return chars.find(c) != std::string::npos; }
-
- private:
-  std::string chars;
-};
-}
-
 // strip all ignored characters in the string
 size_t remove_ignored_chars(std::string& word,
                             const std::string& ignored_chars) {
   word.erase(
       std::remove_if(word.begin(), word.end(), is_any_of(ignored_chars)),
       word.end());
   return word.size();
 }
 
-int parse_string(char* line, char** out, int ln) {
-  char* tp = line;
-  char* piece;
+bool parse_string(const std::string& line, std::string& out, int ln) {
+  if (!out.empty()) {
+    HUNSPELL_WARNING(stderr, "error: line %d: multiple definitions\n", ln);
+    return false;
+  }
   int i = 0;
   int np = 0;
-  if (*out) {
-    HUNSPELL_WARNING(stderr, "error: line %d: multiple definitions\n", ln);
-    return 1;
-  }
-  piece = mystrsep(&tp, 0);
-  while (piece) {
-    if (*piece != '\0') {
-      switch (i) {
-        case 0: {
-          np++;
-          break;
-        }
-        case 1: {
-          *out = mystrdup(piece);
-          if (!*out)
-            return 1;
-          np++;
-          break;
-        }
-        default:
-          break;
+  std::string::const_iterator iter = line.begin();
+  std::string::const_iterator start_piece = mystrsep(line, iter);
+  while (start_piece != line.end()) {
+    switch (i) {
+      case 0: {
+        np++;
+        break;
       }
-      i++;
+      case 1: {
+        out.assign(start_piece, iter);
+        np++;
+        break;
+      }
+      default:
+        break;
     }
-    // free(piece);
-    piece = mystrsep(&tp, 0);
+    ++i;
+     start_piece = mystrsep(line, iter);
   }
   if (np != 2) {
     HUNSPELL_WARNING(stderr, "error: line %d: missing data\n", ln);
-    return 1;
+    return false;
   }
-  return 0;
+  return true;
 }
 
-bool parse_array(char* line,
-                 char** out,
+bool parse_array(const std::string& line,
+                 std::string& out,
                  std::vector<w_char>& out_utf16,
                  int utf8,
                  int ln) {
-  if (parse_string(line, out, ln))
+  if (!parse_string(line, out, ln))
     return false;
   if (utf8) {
-    u8_u16(out_utf16, *out);
+    u8_u16(out_utf16, out);
     std::sort(out_utf16.begin(), out_utf16.end());
   }
   return true;
 }
--- a/extensions/spellcheck/hunspell/src/csutil.hxx
+++ b/extensions/spellcheck/hunspell/src/csutil.hxx
@@ -66,23 +66,24 @@
  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
-#ifndef __CSUTILHXX__
-#define __CSUTILHXX__
+#ifndef CSUTIL_HXX_
+#define CSUTIL_HXX_
 
 #include "hunvisapi.h"
 
 // First some base level utility routines
 
+#include <fstream>
 #include <string>
 #include <vector>
 #include <string.h>
 #include "w_char.hxx"
 #include "htypes.hxx"
 
 #ifdef MOZILLA_CLIENT
 #include "nscore.h"  // for mozalloc headers
@@ -122,96 +123,89 @@
 #define MSEP_REC '\n'
 #define MSEP_ALT '\v'
 
 // default flags
 #define DEFAULTFLAGS 65510
 #define FORBIDDENWORD 65510
 #define ONLYUPCASEFLAG 65511
 
-// fopen or optional _wfopen to fix long pathname problem of WIN32
-LIBHUNSPELL_DLL_EXPORTED FILE* myfopen(const char* path, const char* mode);
+// fix long pathname problem of WIN32 by using w_char std::fstream::open override
+LIBHUNSPELL_DLL_EXPORTED void myopen(std::ifstream& stream, const char* path,
+                                     std::ios_base::openmode mode);
 
 // convert UTF-16 characters to UTF-8
 LIBHUNSPELL_DLL_EXPORTED std::string& u16_u8(std::string& dest,
                                              const std::vector<w_char>& src);
 
 // convert UTF-8 characters to UTF-16
 LIBHUNSPELL_DLL_EXPORTED int u8_u16(std::vector<w_char>& dest,
                                     const std::string& src);
 
 // remove end of line char(s)
-LIBHUNSPELL_DLL_EXPORTED void mychomp(char* s);
+LIBHUNSPELL_DLL_EXPORTED void mychomp(std::string& s);
 
 // duplicate string
 LIBHUNSPELL_DLL_EXPORTED char* mystrdup(const char* s);
 
-// strcat for limited length destination string
-LIBHUNSPELL_DLL_EXPORTED char* mystrcat(char* dest, const char* st, int max);
-
 // parse into tokens with char delimiter
-LIBHUNSPELL_DLL_EXPORTED char* mystrsep(char** sptr, const char delim);
+LIBHUNSPELL_DLL_EXPORTED std::string::const_iterator mystrsep(const std::string &str,
+                                                              std::string::const_iterator& start);
 
 // replace pat by rep in word and return word
-LIBHUNSPELL_DLL_EXPORTED char* mystrrep(char* word,
-                                        const char* pat,
-                                        const char* rep);
 LIBHUNSPELL_DLL_EXPORTED std::string& mystrrep(std::string& str,
                                                const std::string& search,
                                                const std::string& replace);
 
 // append s to ends of every lines in text
 LIBHUNSPELL_DLL_EXPORTED std::string& strlinecat(std::string& str,
                                                  const std::string& apd);
 
 // tokenize into lines with new line
-LIBHUNSPELL_DLL_EXPORTED int line_tok(const char* text,
-                                      char*** lines,
-                                      char breakchar);
+LIBHUNSPELL_DLL_EXPORTED std::vector<std::string> line_tok(const std::string& text,
+                                                           char breakchar);
 
 // tokenize into lines with new line and uniq in place
-LIBHUNSPELL_DLL_EXPORTED char* line_uniq(char* text, char breakchar);
-LIBHUNSPELL_DLL_EXPORTED char* line_uniq_app(char** text, char breakchar);
+LIBHUNSPELL_DLL_EXPORTED void line_uniq(std::string& text, char breakchar);
+
+LIBHUNSPELL_DLL_EXPORTED void line_uniq_app(std::string& text, char breakchar);
 
 // reverse word
 LIBHUNSPELL_DLL_EXPORTED size_t reverseword(std::string& word);
 
 // reverse word
 LIBHUNSPELL_DLL_EXPORTED size_t reverseword_utf(std::string&);
 
 // remove duplicates
-LIBHUNSPELL_DLL_EXPORTED int uniqlist(char** list, int n);
-
-// free character array list
-LIBHUNSPELL_DLL_EXPORTED void freelist(char*** list, int n);
+LIBHUNSPELL_DLL_EXPORTED void uniqlist(std::vector<std::string>& list);
 
 // character encoding information
 struct cs_info {
   unsigned char ccase;
   unsigned char clower;
   unsigned char cupper;
 };
 
-LIBHUNSPELL_DLL_EXPORTED int initialize_utf_tbl();
+LIBHUNSPELL_DLL_EXPORTED void initialize_utf_tbl();
 LIBHUNSPELL_DLL_EXPORTED void free_utf_tbl();
 LIBHUNSPELL_DLL_EXPORTED unsigned short unicodetoupper(unsigned short c,
                                                        int langnum);
 LIBHUNSPELL_DLL_EXPORTED w_char upper_utf(w_char u, int langnum);
 LIBHUNSPELL_DLL_EXPORTED w_char lower_utf(w_char u, int langnum);
 LIBHUNSPELL_DLL_EXPORTED unsigned short unicodetolower(unsigned short c,
                                                        int langnum);
 LIBHUNSPELL_DLL_EXPORTED int unicodeisalpha(unsigned short c);
 
-LIBHUNSPELL_DLL_EXPORTED struct cs_info* get_current_cs(const char* es);
+LIBHUNSPELL_DLL_EXPORTED struct cs_info* get_current_cs(const std::string& es);
 
 // get language identifiers of language codes
-LIBHUNSPELL_DLL_EXPORTED int get_lang_num(const char* lang);
+LIBHUNSPELL_DLL_EXPORTED int get_lang_num(const std::string& lang);
 
 // get characters of the given 8bit encoding with lower- and uppercase forms
-LIBHUNSPELL_DLL_EXPORTED char* get_casechars(const char* enc);
+LIBHUNSPELL_DLL_EXPORTED std::string get_casechars(const char* enc);
 
 // convert std::string to all caps
 LIBHUNSPELL_DLL_EXPORTED std::string& mkallcap(std::string& s,
                                                const struct cs_info* csconv);
 
 // convert null terminated string to all little
 LIBHUNSPELL_DLL_EXPORTED std::string& mkallsmall(std::string& s,
                                                  const struct cs_info* csconv);
@@ -251,34 +245,32 @@ LIBHUNSPELL_DLL_EXPORTED size_t remove_i
     std::string& word,
     const std::vector<w_char>& ignored_chars);
 
 // strip all ignored characters in the string
 LIBHUNSPELL_DLL_EXPORTED size_t remove_ignored_chars(
     std::string& word,
     const std::string& ignored_chars);
 
-LIBHUNSPELL_DLL_EXPORTED int parse_string(char* line, char** out, int ln);
+LIBHUNSPELL_DLL_EXPORTED bool parse_string(const std::string& line,
+                                           std::string& out,
+                                           int ln);
 
-LIBHUNSPELL_DLL_EXPORTED bool parse_array(char* line,
-                                          char** out,
+LIBHUNSPELL_DLL_EXPORTED bool parse_array(const std::string& line,
+                                          std::string& out,
                                           std::vector<w_char>& out_utf16,
                                           int utf8,
                                           int ln);
 
 LIBHUNSPELL_DLL_EXPORTED int fieldlen(const char* r);
 
 LIBHUNSPELL_DLL_EXPORTED bool copy_field(std::string& dest,
                                          const std::string& morph,
                                          const std::string& var);
 
-LIBHUNSPELL_DLL_EXPORTED int morphcmp(const char* s, const char* t);
-
-LIBHUNSPELL_DLL_EXPORTED int get_sfxcount(const char* morph);
-
 // conversion function for protected memory
 LIBHUNSPELL_DLL_EXPORTED void store_pointer(char* dest, char* source);
 
 // conversion function for protected memory
 LIBHUNSPELL_DLL_EXPORTED char* get_stored_pointer(const char* s);
 
 // hash entry macros
 LIBHUNSPELL_DLL_EXPORTED inline char* HENTRY_DATA(struct hentry* h) {
--- a/extensions/spellcheck/hunspell/src/filemgr.cxx
+++ b/extensions/spellcheck/hunspell/src/filemgr.cxx
@@ -81,40 +81,40 @@
 int FileMgr::fail(const char* err, const char* par) {
   fprintf(stderr, err, par);
   return -1;
 }
 
 FileMgr::FileMgr(const char* file, const char* key) : hin(NULL), linenum(0) {
   in[0] = '\0';
 
-  fin = myfopen(file, "r");
-  if (!fin) {
+  myopen(fin, file, std::ios_base::in);
+  if (!fin.is_open()) {
     // check hzipped file
     std::string st(file);
     st.append(HZIP_EXTENSION);
     hin = new Hunzip(st.c_str(), key);
   }
-  if (!fin && !hin)
+  if (!fin.is_open() && !hin->is_open())
     fail(MSG_OPEN, file);
 }
 
 FileMgr::~FileMgr() {
-  if (fin)
-    fclose(fin);
-  if (hin)
-    delete hin;
+  delete hin;
 }
 
-char* FileMgr::getline() {
-  const char* l;
-  linenum++;
-  if (fin)
-    return fgets(in, BUFSIZE - 1, fin);
-  if (hin && ((l = hin->getline()) != NULL))
-    return strcpy(in, l);
-  linenum--;
-  return NULL;
+bool FileMgr::getline(std::string& dest) {
+  bool ret = false;
+  ++linenum;
+  if (fin.is_open()) {
+    ret = static_cast<bool>(std::getline(fin, dest));
+  } else if (hin->is_open()) {
+    ret = hin->getline(dest);
+  }
+  if (!ret) {
+    --linenum;
+  }
+  return ret;
 }
 
 int FileMgr::getlinenum() {
   return linenum;
 }
--- a/extensions/spellcheck/hunspell/src/filemgr.hxx
+++ b/extensions/spellcheck/hunspell/src/filemgr.hxx
@@ -67,35 +67,35 @@
  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 /* file manager class - read lines of files [filename] OR [filename.hz] */
-#ifndef _FILEMGR_HXX_
-#define _FILEMGR_HXX_
-
-#include "hunvisapi.h"
+#ifndef FILEMGR_HXX_
+#define FILEMGR_HXX_
 
 #include "hunzip.hxx"
 #include <stdio.h>
+#include <string>
+#include <fstream>
 
-class LIBHUNSPELL_DLL_EXPORTED FileMgr {
+class FileMgr {
  private:
   FileMgr(const FileMgr&);
   FileMgr& operator=(const FileMgr&);
 
  protected:
-  FILE* fin;
+  std::ifstream fin;
   Hunzip* hin;
   char in[BUFSIZE + 50];  // input buffer
   int fail(const char* err, const char* par);
   int linenum;
 
  public:
   FileMgr(const char* filename, const char* key = NULL);
   ~FileMgr();
-  char* getline();
+  bool getline(std::string&);
   int getlinenum();
 };
 #endif
--- a/extensions/spellcheck/hunspell/src/hashmgr.cxx
+++ b/extensions/spellcheck/hunspell/src/hashmgr.cxx
@@ -93,30 +93,29 @@ HashMgr::HashMgr(const char* tpath, cons
       forbiddenword(FORBIDDENWORD)  // forbidden word signing flag
       ,
       numaliasf(0),
       aliasf(NULL),
       aliasflen(0),
       numaliasm(0),
       aliasm(NULL) {
   langnum = 0;
-  lang = NULL;
-  enc = NULL;
   csconv = 0;
-  ignorechars = NULL;
   load_config(apath, key);
   int ec = load_tables(tpath, key);
   if (ec) {
     /* error condition - what should we do here */
     HUNSPELL_WARNING(stderr, "Hash Manager Error : %d\n", ec);
-    if (tableptr) {
-      free(tableptr);
-      tableptr = NULL;
+    free(tableptr);
+    //keep tablesize to 1 to fix possible division with zero
+    tablesize = 1;
+    tableptr = (struct hentry**)calloc(tablesize, sizeof(struct hentry*));
+    if (!tableptr) {
+      tablesize = 0;
     }
-    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++) {
@@ -154,24 +153,16 @@ HashMgr::~HashMgr() {
 
 #ifndef OPENOFFICEORG
 #ifndef MOZILLA_CLIENT
   if (utf8)
     free_utf_tbl();
 #endif
 #endif
 
-  if (enc)
-    free(enc);
-  if (lang)
-    free(lang);
-
-  if (ignorechars)
-    free(ignorechars);
-
 #ifdef MOZILLA_CLIENT
   delete[] csconv;
 #endif
 }
 
 // lookup a root word in the hashtable
 
 struct hentry* HashMgr::lookup(const char* word) const {
@@ -184,91 +175,91 @@ struct hentry* HashMgr::lookup(const cha
       if (strcmp(word, dp->word) == 0)
         return dp;
     }
   }
   return NULL;
 }
 
 // add a word to the hash table (private)
-int HashMgr::add_word(const char* word,
-                      int wbl,
+int HashMgr::add_word(const std::string& in_word,
                       int wcl,
                       unsigned short* aff,
                       int al,
-                      const char* desc,
+                      const std::string* in_desc,
                       bool onlyupcase) {
+  const std::string* word = &in_word;
+  const std::string* desc = in_desc;
 
   std::string *word_copy = NULL;
   std::string *desc_copy = NULL;
-  if (ignorechars || complexprefixes) {
-    word_copy = new std::string(word, wbl);
+  if (!ignorechars.empty() || complexprefixes) {
+    word_copy = new std::string(in_word);
 
-    if (ignorechars != NULL) {
+    if (!ignorechars.empty()) {
       if (utf8) {
         wcl = remove_ignored_chars_utf(*word_copy, ignorechars_utf16);
       } else {
         remove_ignored_chars(*word_copy, ignorechars);
       }
     }
 
     if (complexprefixes) {
       if (utf8)
         wcl = reverseword_utf(*word_copy);
       else
         reverseword(*word_copy);
 
-      if (desc && !aliasm) {
-        desc_copy = new std::string(desc);
+      if (in_desc && !aliasm) {
+        desc_copy = new std::string(*in_desc);
 
         if (complexprefixes) {
           if (utf8)
             reverseword_utf(*desc_copy);
           else
             reverseword(*desc_copy);
         }
-        desc = desc_copy->c_str();
+        desc = desc_copy;
       }
     }
 
-    wbl = word_copy->size();
-    word = word_copy->c_str();
+    word = word_copy;
   }
 
   bool upcasehomonym = false;
-  int descl = desc ? (aliasm ? sizeof(char*) : strlen(desc) + 1) : 0;
+  int descl = desc ? (aliasm ? sizeof(char*) : desc->size() + 1) : 0;
   // variable-length hash record with word and optional fields
   struct hentry* hp =
-      (struct hentry*)malloc(sizeof(struct hentry) + wbl + descl);
+      (struct hentry*)malloc(sizeof(struct hentry) + word->size() + descl);
   if (!hp) {
     delete desc_copy;
     delete word_copy;
     return 1;
   }
 
   char* hpw = hp->word;
-  strcpy(hpw, word);
+  strcpy(hpw, word->c_str());
 
   int i = hash(hpw);
 
-  hp->blen = (unsigned char)wbl;
+  hp->blen = (unsigned char)word->size();
   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)));
+      store_pointer(hpw + word->size() + 1, get_aliasm(atoi(desc->c_str())));
     } else {
-      strcpy(hpw + wbl + 1, desc);
+      strcpy(hpw + word->size() + 1, desc->c_str());
     }
     if (strstr(HENTRY_DATA(hp), MORPH_PHON))
       hp->var += H_OPT_PHON;
   } else
     hp->var = 0;
 
   struct hentry* dp = tableptr[i];
   if (!dp) {
@@ -329,17 +320,17 @@ int HashMgr::add_word(const char* word,
   delete word_copy;
   return 0;
 }
 
 int HashMgr::add_hidden_capitalized_word(const std::string& word,
                                          int wcl,
                                          unsigned short* flags,
                                          int flagslen,
-                                         char* dp,
+                                         const std::string* dp,
                                          int captype) {
   if (flags == NULL)
     flagslen = 0;
 
   // 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) ||
@@ -354,22 +345,22 @@ int HashMgr::add_hidden_capitalized_word
     flags2[flagslen] = ONLYUPCASEFLAG;
     if (utf8) {
       std::string st;
       std::vector<w_char> w;
       u8_u16(w, word);
       mkallsmall_utf(w, langnum);
       mkinitcap_utf(w, langnum);
       u16_u8(st, w);
-      return add_word(st.c_str(), st.size(), wcl, flags2, flagslen + 1, dp, true);
+      return add_word(st, wcl, flags2, flagslen + 1, dp, true);
     } else {
       std::string new_word(word);
       mkallsmall(new_word, csconv);
       mkinitcap(new_word, csconv);
-      int ret = add_word(new_word.c_str(), new_word.size(), wcl, flags2, flagslen + 1, dp, true);
+      int ret = add_word(new_word, wcl, flags2, flagslen + 1, dp, true);
       return ret;
     }
   }
   return 0;
 }
 
 // detect captype and modify word length for UTF-8 encoding
 int HashMgr::get_clen_and_captype(const std::string& word, int* captype) {
@@ -381,27 +372,28 @@ int HashMgr::get_clen_and_captype(const 
   } else {
     len = word.size();
     *captype = get_captype(word, csconv);
   }
   return len;
 }
 
 // remove word (personal dictionary function for standalone applications)
-int HashMgr::remove(const char* word) {
-  struct hentry* dp = lookup(word);
+int HashMgr::remove(const std::string& word) {
+  struct hentry* dp = lookup(word.c_str());
   while (dp) {
     if (dp->alen == 0 || !TESTAFF(dp->astr, forbiddenword, dp->alen)) {
       unsigned short* flags =
           (unsigned short*)malloc(sizeof(unsigned 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;
+      free(dp->astr);
       dp->astr = flags;
       dp->alen++;
       std::sort(flags, flags + dp->alen);
     }
     dp = dp->next_homonym;
   }
   return 0;
 }
@@ -421,56 +413,55 @@ int HashMgr::remove_forbidden_flag(const
         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--;
+        free(dp->astr);
         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 std::string& word) {
-  unsigned short* flags = NULL;
-  int al = 0;
   if (remove_forbidden_flag(word)) {
     int captype;
-    int wbl = word.size();
+    int al = 0;
+    unsigned short* flags = NULL;
     int wcl = get_clen_and_captype(word, &captype);
-    add_word(word.c_str(), wbl, wcl, flags, al, NULL, false);
+    add_word(word, wcl, flags, al, NULL, false);
     return add_hidden_capitalized_word(word, wcl, flags, al, NULL,
                                        captype);
   }
   return 0;
 }
 
-int HashMgr::add_with_affix(const char* word, const char* example) {
+int HashMgr::add_with_affix(const std::string& word, const std::string& example) {
   // detect captype and modify word length for UTF-8 encoding
-  struct hentry* dp = lookup(example);
+  struct hentry* dp = lookup(example.c_str());
   remove_forbidden_flag(word);
   if (dp && dp->astr) {
     int captype;
-    int wbl = strlen(word);
     int wcl = get_clen_and_captype(word, &captype);
     if (aliasf) {
-      add_word(word, wbl, wcl, dp->astr, dp->alen, NULL, false);
+      add_word(word, wcl, dp->astr, dp->alen, NULL, false);
     } else {
       unsigned short* flags =
           (unsigned short*)malloc(dp->alen * sizeof(unsigned short));
       if (flags) {
         memcpy((void*)flags, (void*)dp->astr,
                dp->alen * sizeof(unsigned short));
-        add_word(word, wbl, wcl, flags, dp->alen, NULL, false);
+        add_word(word, wcl, flags, dp->alen, NULL, false);
       } else
         return 1;
     }
     return add_hidden_capitalized_word(word, wcl, dp->astr,
                                        dp->alen, NULL, captype);
   }
   return 1;
 }
@@ -486,44 +477,36 @@ struct hentry* HashMgr::walk_hashtable(i
   }
   // null at end and reset to start
   col = -1;
   return NULL;
 }
 
 // load a munched word list and build a hash table on the fly
 int HashMgr::load_tables(const char* tpath, const char* key) {
-  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) {
+  std::string ts;
+  if (!dict->getline(ts)) {
     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
+  if (ts.compare(0, 3, "\xEF\xBB\xBF", 3) == 0) {
+    ts.erase(0, 3);
   }
 
-  tablesize = atoi(ts);
+  tablesize = atoi(ts.c_str());
 
   int nExtra = 5 + USERWORD;
 
   if (tablesize <= 0 ||
       (tablesize >= (std::numeric_limits<int>::max() - 1 - nExtra) /
                         int(sizeof(struct hentry*)))) {
     HUNSPELL_WARNING(
         stderr, "error: line 1: missing or bad word count in the dic file\n");
@@ -539,89 +522,93 @@ int HashMgr::load_tables(const char* tpa
   if (!tableptr) {
     delete dict;
     return 3;
   }
 
   // loop through all words on much list and add to hash
   // table and create word and affix strings
 
-  while ((ts = dict->getline()) != NULL) {
+  while (dict->getline(ts)) {
     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--)
+    size_t dp_pos = 0;
+    while ((dp_pos = ts.find(':', dp_pos)) != std::string::npos) {
+      if ((dp_pos > 3) && (ts[dp_pos - 3] == ' ' || ts[dp_pos - 3] == '\t')) {
+        for (dp_pos -= 3; dp_pos > 0 && (ts[dp_pos-1] == ' ' || ts[dp_pos-1] == '\t'); --dp_pos)
           ;
-        if (dp < ts) {  // missing word
-          dp = NULL;
+        if (dp_pos == 0) {  // missing word
+          dp_pos = std::string::npos;
         } else {
-          *(dp + 1) = '\0';
-          dp = dp + 2;
+          ++dp_pos;
         }
         break;
       }
-      dp++;
+      ++dp_pos;
     }
 
     // tabulator is the old morphological field separator
-    dp2 = strchr(ts, '\t');
-    if (dp2 && (!dp || dp2 < dp)) {
-      *dp2 = '\0';
-      dp = dp2 + 1;
+    size_t dp2_pos = ts.find('\t');
+    if (dp2_pos != std::string::npos && (dp_pos == std::string::npos || dp2_pos < dp_pos)) {
+      dp_pos = dp2_pos + 1;
+    }
+
+    std::string dp;
+    if (dp_pos != std::string::npos) {
+      dp.assign(ts.substr(dp_pos));
+      ts.resize(dp_pos - 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++;
+    size_t ap_pos = ts.find('/');
+    while (ap_pos != std::string::npos) {
+      if (ap_pos == 0) {
+        ++ap_pos;
         continue;
-      } else if (*(ap - 1) != '\\')
+      } else if (ts[ap_pos - 1] != '\\')
         break;
       // replace "\/" with "/"
-      for (char *sp = ap - 1; *sp; *sp = *(sp + 1), sp++)
-        ;
-      ap = strchr(ap, '/');
+      ts.erase(ap_pos - 1, 1);
+      ap_pos = ts.find('/', ap_pos);
     }
 
-    if (ap) {
-      *ap = '\0';
+    unsigned short* flags;
+    int al;
+    if (ap_pos != std::string::npos && ap_pos != ts.size()) {
+      std::string ap(ts.substr(ap_pos + 1));
+      ts.resize(ap_pos);
       if (aliasf) {
-        int index = atoi(ap + 1);
+        int index = atoi(ap.c_str());
         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);
+        al = decode_flags(&flags, ap.c_str(), dict);
         if (al == -1) {
           HUNSPELL_WARNING(stderr, "Can't allocate memory.\n");
           delete dict;
           return 6;
         }
         std::sort(flags, flags + al);
       }
     } else {
       al = 0;
-      ap = NULL;
       flags = NULL;
     }
 
     int captype;
-    int wbl = strlen(ts);
     int wcl = get_clen_and_captype(ts, &captype);
+    const std::string *dp_str = dp.empty() ? NULL : &dp;
     // 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, wcl, flags, al, dp, captype)) {
+    if (add_word(ts, wcl, flags, al, dp_str, false) ||
+        add_hidden_capitalized_word(ts, wcl, flags, al, dp_str, captype)) {
       delete dict;
       return 5;
     }
   }
 
   delete dict;
   return 0;
 }
@@ -634,69 +621,67 @@ int HashMgr::hash(const char* word) cons
     hv = (hv << 8) | (*word++);
   while (*word != 0) {
     ROTATE(hv, ROTATE_LEN);
     hv ^= (*word++);
   }
   return (unsigned long)hv % tablesize;
 }
 
-int HashMgr::decode_flags(unsigned short** result, char* flags, FileMgr* af) {
+int HashMgr::decode_flags(unsigned short** result, const std::string& flags, FileMgr* af) const {
   int len;
-  if (*flags == '\0') {
+  if (flags.empty()) {
     *result = NULL;
     return 0;
   }
   switch (flag_mode) {
     case FLAG_LONG: {  // two-character flags (1x2yZz -> 1x 2y Zz)
-      len = strlen(flags);
+      len = flags.size();
       if (len % 2 == 1)
         HUNSPELL_WARNING(stderr, "error: line %d: bad flagvector\n",
                          af->getlinenum());
       len /= 2;
       *result = (unsigned short*)malloc(len * sizeof(unsigned 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 == ',')
+      for (size_t i = 0; i < flags.size(); ++i) {
+        if (flags[i] == ',')
           len++;
       }
       *result = (unsigned short*)malloc(len * sizeof(unsigned short));
       if (!*result)
         return -1;
       dest = *result;
-      for (p = flags; *p; p++) {
+      const char* src = flags.c_str();
+      for (const char* p = src; *p; p++) {
         if (*p == ',') {
-          i = atoi(src);
+          int 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);
+      int 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());
@@ -709,31 +694,96 @@ int HashMgr::decode_flags(unsigned short
       *result = (unsigned short*)malloc(len * sizeof(unsigned short));
       if (!*result)
         return -1;
       memcpy(*result, &w[0], len * sizeof(short));
       break;
     }
     default: {  // Ispell's one-character flags (erfg -> e r f g)
       unsigned short* dest;
-      len = strlen(flags);
+      len = flags.size();
       *result = (unsigned short*)malloc(len * sizeof(unsigned short));
       if (!*result)
         return -1;
       dest = *result;
-      for (unsigned char* p = (unsigned char*)flags; *p; p++) {
-        *dest = (unsigned short)*p;
+      for (size_t i = 0; i < flags.size(); ++i) {
+        *dest = (unsigned char)flags[i];
         dest++;
       }
     }
   }
   return len;
 }
 
-unsigned short HashMgr::decode_flag(const char* f) {
+bool HashMgr::decode_flags(std::vector<unsigned short>& result, const std::string& flags, FileMgr* af) const {
+  if (flags.empty()) {
+    return false;
+  }
+  switch (flag_mode) {
+    case FLAG_LONG: {  // two-character flags (1x2yZz -> 1x 2y Zz)
+      size_t len = flags.size();
+      if (len % 2 == 1)
+        HUNSPELL_WARNING(stderr, "error: line %d: bad flagvector\n",
+                         af->getlinenum());
+      len /= 2;
+      result.reserve(result.size() + len);
+      for (size_t i = 0; i < len; ++i) {
+        result.push_back((((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)
+      const char* src = flags.c_str();
+      for (const char* p = src; *p; p++) {
+        if (*p == ',') {
+          int 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);
+          result.push_back((unsigned short)i);
+          if (result.back() == 0)
+            HUNSPELL_WARNING(stderr, "error: line %d: 0 is wrong flag id\n",
+                             af->getlinenum());
+          src = p + 1;
+        }
+      }
+      int 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);
+      result.push_back((unsigned short)i);
+      if (result.back() == 0)
+        HUNSPELL_WARNING(stderr, "error: line %d: 0 is wrong flag id\n",
+                         af->getlinenum());
+      break;
+    }
+    case FLAG_UNI: {  // UTF-8 characters
+      std::vector<w_char> w;
+      u8_u16(w, flags);
+      size_t len = w.size();
+      size_t origsize = result.size();
+      result.resize(origsize + len);
+      memcpy(&result[origsize], &w[0], len * sizeof(short));
+      break;
+    }
+    default: {  // Ispell's one-character flags (erfg -> e r f g)
+      result.reserve(flags.size());
+      for (size_t i = 0; i < flags.size(); ++i) {
+        result.push_back((unsigned char)flags[i]);
+      }
+    }
+  }
+  return true;
+}
+
+unsigned short HashMgr::decode_flag(const char* f) const {
   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);
@@ -745,24 +795,24 @@ unsigned short HashMgr::decode_flag(cons
     case FLAG_UNI: {
       std::vector<w_char> w;
       u8_u16(w, f);
       if (!w.empty())
           memcpy(&s, &w[0], 1 * sizeof(short));
       break;
     }
     default:
-      s = (unsigned short)*((unsigned char*)f);
+      s = *(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) {
+char* HashMgr::encode_flag(unsigned short f) const {
   if (f == 0)
     return mystrdup("(NULL)");
   std::string ch;
   if (flag_mode == FLAG_LONG) {
     ch.push_back((unsigned char)(f >> 8));
     ch.push_back((unsigned char)(f - ((f >> 8) << 8)));
   } else if (flag_mode == FLAG_NUM) {
     std::ostringstream stream;
@@ -775,373 +825,366 @@ char* HashMgr::encode_flag(unsigned shor
   } else {
     ch.push_back((unsigned char)(f));
   }
   return mystrdup(ch.c_str());
 }
 
 // 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
   FileMgr* afflst = new FileMgr(affpath, key);
   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) {
+  std::string line;
+  while (afflst->getline(line)) {
     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);
+      if (line.compare(0, 3, "\xEF\xBB\xBF", 3) == 0) {
+        line.erase(0, 3);
+      }
     }
 
     /* parse in the try string */
-    if ((strncmp(line, "FLAG", 4) == 0) && isspace(line[4])) {
+    if ((line.compare(0, 4, "FLAG", 4) == 0) && line.size() > 4 && 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"))
+      if (line.find("long") != std::string::npos)
         flag_mode = FLAG_LONG;
-      if (strstr(line, "num"))
+      if (line.find("num") != std::string::npos)
         flag_mode = FLAG_NUM;
-      if (strstr(line, "UTF-8"))
+      if (line.find("UTF-8") != std::string::npos)
         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())) {
+
+    if (line.compare(0, 13, "FORBIDDENWORD", 13) == 0) {
+      std::string st;
+      if (!parse_string(line, st, afflst->getlinenum())) {
         delete afflst;
         return 1;
       }
-      forbiddenword = decode_flag(st);
-      free(st);
+      forbiddenword = decode_flag(st.c_str());
     }
-    if (strncmp(line, "SET", 3) == 0) {
-      if (parse_string(line, &enc, afflst->getlinenum())) {
+
+    if (line.compare(0, 3, "SET", 3) == 0) {
+      if (!parse_string(line, enc, afflst->getlinenum())) {
         delete afflst;
         return 1;
       }
-      if (strcmp(enc, "UTF-8") == 0) {
+      if (enc == "UTF-8") {
         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())) {
+
+    if (line.compare(0, 4, "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,
+    if (line.compare(0, 6, "IGNORE", 6) == 0) {
+      if (!parse_array(line, ignorechars, ignorechars_utf16,
                        utf8, afflst->getlinenum())) {
         delete afflst;
         return 1;
       }
     }
 
-    if ((strncmp(line, "AF", 2) == 0) && isspace(line[2])) {
-      if (parse_aliasf(line, afflst)) {
+    if ((line.compare(0, 2, "AF", 2) == 0) && line.size() > 2 && 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)) {
+    if ((line.compare(0, 2, "AM", 2) == 0) && line.size() > 2 && isspace(line[2])) {
+      if (!parse_aliasm(line, afflst)) {
         delete afflst;
         return 1;
       }
     }
 
-    if (strncmp(line, "COMPLEXPREFIXES", 15) == 0)
+    if (line.compare(0, 15, "COMPLEXPREFIXES", 15) == 0)
       complexprefixes = 1;
-    if (((strncmp(line, "SFX", 3) == 0) || (strncmp(line, "PFX", 3) == 0)) &&
-        isspace(line[3]))
+
+    if (((line.compare(0, 3, "SFX", 3) == 0) ||
+         (line.compare(0, 3, "PFX", 3) == 0)) && line.size() > 3 && 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) {
+bool HashMgr::parse_aliasf(const std::string& line, FileMgr* af) {
   if (numaliasf != 0) {
     HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
                      af->getlinenum());
-    return 1;
+    return false;
   }
-  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;
+  std::string::const_iterator iter = line.begin();
+  std::string::const_iterator start_piece = mystrsep(line, iter);
+  while (start_piece != line.end()) {
+    switch (i) {
+      case 0: {
+        np++;
+        break;
+      }
+      case 1: {
+        numaliasf = atoi(std::string(start_piece, iter).c_str());
+        if (numaliasf < 1) {
+          numaliasf = 0;
+          aliasf = NULL;
+          aliasflen = NULL;
+          HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
+                           af->getlinenum());
+          return false;
         }
-        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(unsigned short));
-          if (!aliasf || !aliasflen) {
-            numaliasf = 0;
-            if (aliasf)
-              free(aliasf);
-            if (aliasflen)
-              free(aliasflen);
-            aliasf = NULL;
-            aliasflen = NULL;
-            return 1;
-          }
-          np++;
-          break;
+        aliasf =
+            (unsigned short**)malloc(numaliasf * sizeof(unsigned short*));
+        aliasflen =
+            (unsigned short*)malloc(numaliasf * sizeof(unsigned short));
+        if (!aliasf || !aliasflen) {
+          numaliasf = 0;
+          if (aliasf)
+            free(aliasf);
+          if (aliasflen)
+            free(aliasflen);
+          aliasf = NULL;
+          aliasflen = NULL;
+          return false;
         }
-        default:
-          break;
+        np++;
+        break;
       }
-      i++;
+      default:
+        break;
     }
-    piece = mystrsep(&tp, 0);
+    ++i;
+    start_piece = mystrsep(line, iter);
   }
   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;
+    return false;
   }
 
   /* 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;
+    std::string nl;
+    if (!af->getline(nl))
+      return false;
     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;
+    iter = nl.begin();
+    start_piece = mystrsep(nl, iter);
+    while (start_piece != nl.end()) {
+      switch (i) {
+        case 0: {
+          if (nl.compare(start_piece - nl.begin(), 2, "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 false;
           }
-          case 1: {
-            aliasflen[j] =
-                (unsigned short)decode_flags(&(aliasf[j]), piece, af);
-            std::sort(aliasf[j], aliasf[j] + aliasflen[j]);
-            break;
-          }
-          default:
-            break;
+          break;
         }
-        i++;
+        case 1: {
+          std::string piece(start_piece, iter);
+          aliasflen[j] =
+              (unsigned short)decode_flags(&(aliasf[j]), piece, af);
+          std::sort(aliasf[j], aliasf[j] + aliasflen[j]);
+          break;
+        }
+        default:
+          break;
       }
-      piece = mystrsep(&tp, 0);
+      ++i;
+      start_piece = mystrsep(nl, iter);
     }
     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 false;
     }
   }
-  return 0;
+  return true;
 }
 
-int HashMgr::is_aliasf() {
+int HashMgr::is_aliasf() const {
   return (aliasf != NULL);
 }
 
-int HashMgr::get_aliasf(int index, unsigned short** fvec, FileMgr* af) {
+int HashMgr::get_aliasf(int index, unsigned short** fvec, FileMgr* af) const {
   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) {
+bool HashMgr::parse_aliasm(const std::string& line, FileMgr* af) {
   if (numaliasm != 0) {
     HUNSPELL_WARNING(stderr, "error: line %d: multiple table definitions\n",
                      af->getlinenum());
-    return 1;
+    return false;
   }
-  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;
+  std::string::const_iterator iter = line.begin();
+  std::string::const_iterator start_piece = mystrsep(line, iter);
+  while (start_piece != line.end()) {
+    switch (i) {
+      case 0: {
+        np++;
+        break;
+      }
+      case 1: {
+        numaliasm = atoi(std::string(start_piece, iter).c_str());
+        if (numaliasm < 1) {
+          HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
+                           af->getlinenum());
+          return false;
         }
-        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;
+        aliasm = (char**)malloc(numaliasm * sizeof(char*));
+        if (!aliasm) {
+          numaliasm = 0;
+          return false;
         }
-        default:
-          break;
+        np++;
+        break;
       }
-      i++;
+      default:
+        break;
     }
-    piece = mystrsep(&tp, 0);
+    ++i;
+    start_piece = mystrsep(line, iter);
   }
   if (np != 2) {
     numaliasm = 0;
     free(aliasm);
     aliasm = NULL;
     HUNSPELL_WARNING(stderr, "error: line %d: missing data\n",
                      af->getlinenum());
-    return 1;
+    return false;
   }
 
   /* 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;
+    std::string nl;
+    if (!af->getline(nl))
+      return false;
     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;
+    iter = nl.begin();
+    i = 0;
+    start_piece = mystrsep(nl, iter);
+    while (start_piece != nl.end()) {
+      switch (i) {
+        case 0: {
+          if (nl.compare(start_piece - nl.begin(), 2, "AM", 2) != 0) {
+            HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
+                             af->getlinenum());
+            numaliasm = 0;
+            free(aliasm);
+            aliasm = NULL;
+            return false;
           }
-          case 1: {
-            // add the remaining of the line
-            if (*tp) {
-              *(tp - 1) = ' ';
-              tp = tp + strlen(tp);
-            }
-            std::string chunk(piece);
-            if (complexprefixes) {
-              if (utf8)
-                reverseword_utf(chunk);
-              else
-                reverseword(chunk);
-            }
-            aliasm[j] = mystrdup(chunk.c_str());
-            break;
+          break;
+        }
+        case 1: {
+          // add the remaining of the line
+          std::string::const_iterator end = nl.end();
+          std::string chunk(start_piece, end);
+          if (complexprefixes) {
+            if (utf8)
+              reverseword_utf(chunk);
+            else
+              reverseword(chunk);
           }
-          default:
-            break;
+          aliasm[j] = mystrdup(chunk.c_str());
+          break;
         }
-        i++;
+        default:
+          break;
       }
-      piece = mystrsep(&tp, ' ');
+      ++i;
+      start_piece = mystrsep(nl, iter);
     }
     if (!aliasm[j]) {
       numaliasm = 0;
       free(aliasm);
       aliasm = NULL;
       HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
                        af->getlinenum());
-      return 1;
+      return false;
     }
   }
-  return 0;
+  return true;
 }
 
-int HashMgr::is_aliasm() {
+int HashMgr::is_aliasm() const {
   return (aliasm != NULL);
 }
 
-char* HashMgr::get_aliasm(int index) {
+char* HashMgr::get_aliasm(int index) const {
   if ((index > 0) && (index <= numaliasm))
     return aliasm[index - 1];
   HUNSPELL_WARNING(stderr, "error: bad morph. alias index: %d\n", index);
   return NULL;
 }
--- a/extensions/spellcheck/hunspell/src/hashmgr.hxx
+++ b/extensions/spellcheck/hunspell/src/hashmgr.hxx
@@ -66,84 +66,82 @@
  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
-#ifndef _HASHMGR_HXX_
-#define _HASHMGR_HXX_
-
-#include "hunvisapi.h"
+#ifndef HASHMGR_HXX_
+#define HASHMGR_HXX_
 
 #include <stdio.h>
 #include <string>
 #include <vector>
 
 #include "htypes.hxx"
 #include "filemgr.hxx"
 #include "w_char.hxx"
 
 enum flag { FLAG_CHAR, FLAG_LONG, FLAG_NUM, FLAG_UNI };
 
-class LIBHUNSPELL_DLL_EXPORTED HashMgr {
+class HashMgr {
   int tablesize;
   struct hentry** tableptr;
   flag flag_mode;
   int complexprefixes;
   int utf8;
   unsigned short forbiddenword;
   int langnum;
-  char* enc;
-  char* lang;
+  std::string enc;
+  std::string lang;
   struct cs_info* csconv;
-  char* ignorechars;
+  std::string ignorechars;
   std::vector<w_char> ignorechars_utf16;
   int numaliasf;  // flag vector `compression' with aliases
   unsigned short** aliasf;
   unsigned short* aliasflen;
   int numaliasm;  // morphological desciption `compression' with aliases
   char** aliasm;
 
  public:
   HashMgr(const char* tpath, const char* apath, const char* key = NULL);
   ~HashMgr();
 
   struct hentry* lookup(const char*) const;
   int hash(const char*) const;
   struct hentry* walk_hashtable(int& col, struct hentry* hp) const;
 
   int add(const std::string& word);
-  int add_with_affix(const char* word, const char* pattern);
-  int remove(const char* word);
-  int decode_flags(unsigned short** result, char* flags, FileMgr* af);
-  unsigned short decode_flag(const char* flag);
-  char* encode_flag(unsigned short flag);
-  int is_aliasf();
-  int get_aliasf(int index, unsigned short** fvec, FileMgr* af);
-  int is_aliasm();
-  char* get_aliasm(int index);
+  int add_with_affix(const std::string& word, const std::string& pattern);
+  int remove(const std::string& word);
+  int decode_flags(unsigned short** result, const std::string& flags, FileMgr* af) const;
+  bool decode_flags(std::vector<unsigned short>& result, const std::string& flags, FileMgr* af) const;
+  unsigned short decode_flag(const char* flag) const;
+  char* encode_flag(unsigned short flag) const;
+  int is_aliasf() const;
+  int get_aliasf(int index, unsigned short** fvec, FileMgr* af) const;
+  int is_aliasm() const;
+  char* get_aliasm(int index) const;
 
  private:
   int get_clen_and_captype(const std::string& word, int* captype);
   int load_tables(const char* tpath, const char* key);
-  int add_word(const char* word,
-               int wbl,
+  int add_word(const std::string& word,
                int wcl,
                unsigned short* ap,
                int al,
-               const char* desc,
+               const std::string* desc,
                bool onlyupcase);
   int load_config(const char* affpath, const char* key);
-  int parse_aliasf(char* line, FileMgr* af);
+  bool parse_aliasf(const std::string& line, FileMgr* af);
   int add_hidden_capitalized_word(const std::string& word,
                                   int wcl,
                                   unsigned short* flags,
                                   int al,
-                                  char* dp,
+                                  const std::string* dp,
                                   int captype);
-  int parse_aliasm(char* line, FileMgr* af);
+  bool parse_aliasm(const std::string& line, FileMgr* af);
   int remove_forbidden_flag(const std::string& word);
 };
 
 #endif
--- a/extensions/spellcheck/hunspell/src/htypes.hxx
+++ b/extensions/spellcheck/hunspell/src/htypes.hxx
@@ -33,18 +33,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#ifndef _HTYPES_HXX_
-#define _HTYPES_HXX_
+#ifndef HTYPES_HXX_
+#define HTYPES_HXX_
 
 #define ROTATE_LEN 5
 
 #define ROTATE(v, q) \
   (v) = ((v) << (q)) | (((v) >> (32 - q)) & ((1 << (q)) - 1));
 
 // hentry options
 #define H_OPT (1 << 0)
--- a/extensions/spellcheck/hunspell/src/hunspell.cxx
+++ b/extensions/spellcheck/hunspell/src/hunspell.cxx
@@ -70,45 +70,109 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
 
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 
+#include "affixmgr.hxx"
 #include "hunspell.hxx"
+#include "suggestmgr.hxx"
 #include "hunspell.h"
-#ifndef MOZILLA_CLIENT
-#include "config.h"
-#endif
 #include "csutil.hxx"
 
 #include <limits>
 #include <string>
 
-#define MAXWORDLEN 176
 #define MAXWORDUTF8LEN (MAXWORDLEN * 3)
 
-Hunspell::Hunspell(const char* affpath, const char* dpath, const char* key) {
-  encoding = NULL;
+class HunspellImpl
+{
+public:
+  HunspellImpl(const char* affpath, const char* dpath, const char* key);
+  ~HunspellImpl();
+  int add_dic(const char* dpath, const char* key);
+  std::vector<std::string> suffix_suggest(const std::string& root_word);
+  std::vector<std::string> generate(const std::string& word, const std::vector<std::string>& pl);
+  std::vector<std::string> generate(const std::string& word, const std::string& pattern);
+  std::vector<std::string> stem(const std::string& word);
+  std::vector<std::string> stem(const std::vector<std::string>& morph);
+  std::vector<std::string> analyze(const std::string& word);
+  int get_langnum() const;
+  bool input_conv(const std::string& word, std::string& dest);
+  bool spell(const std::string& word, int* info = NULL, std::string* root = NULL);
+  std::vector<std::string> suggest(const std::string& word);
+  const std::string& get_wordchars() const;
+  const std::vector<w_char>& get_wordchars_utf16() const;
+  const std::string& get_dict_encoding() const;
+  int add(const std::string& word);
+  int add_with_affix(const std::string& word, const std::string& example);
+  int remove(const std::string& word);
+  const std::string& get_version() const;
+
+
+private:
+  AffixMgr* pAMgr;
+  std::vector<HashMgr*> m_HMgrs;
+  SuggestMgr* pSMgr;
+  char* affixpath;
+  std::string encoding;
+  struct cs_info* csconv;
+  int langnum;
+  int utf8;
+  int complexprefixes;
+  std::vector<std::string> wordbreak;
+
+private:
+  void cleanword(std::string& dest, const std::string&, int* pcaptype, int* pabbrev);
+  size_t cleanword2(std::string& dest,
+                    std::vector<w_char>& dest_u,
+                    const std::string& src,
+                    int* pcaptype,
+                    size_t* pabbrev);
+  void mkinitcap(std::string& u8);
+  int mkinitcap2(std::string& u8, std::vector<w_char>& u16);
+  int mkinitsmall2(std::string& u8, std::vector<w_char>& u16);
+  void mkallcap(std::string& u8);
+  int mkallsmall2(std::string& u8, std::vector<w_char>& u16);
+  struct hentry* checkword(const std::string& source, int* info, std::string* root);
+  std::string sharps_u8_l1(const std::string& source);
+  hentry*
+  spellsharps(std::string& base, size_t start_pos, int, int, int* info, std::string* root);
+  int is_keepcase(const hentry* rv);
+  void insert_sug(std::vector<std::string>& slst, const std::string& word);
+  void cat_result(std::string& result, const std::string& st);
+  std::vector<std::string> spellml(const std::string& word);
+  std::string get_xml_par(const char* par);
+  const char* get_xml_pos(const char* s, const char* attr);
+  std::vector<std::string> get_xml_list(const char* list, const char* tag);
+  int check_xml_par(const char* q, const char* attr, const char* value);
+private:
+  HunspellImpl(const HunspellImpl&);
+  HunspellImpl& operator=(const HunspellImpl&);
+};
+
+Hunspell::Hunspell(const char* affpath, const char* dpath, const char* key)
+  : m_Impl(new HunspellImpl(affpath, dpath, key)) {
+}
+
+HunspellImpl::HunspellImpl(const char* affpath, const char* dpath, const char* key) {
   csconv = NULL;
   utf8 = 0;
   complexprefixes = 0;
   affixpath = mystrdup(affpath);
-  maxdic = 0;
 
   /* first set up the hash manager */
-  pHMgr[0] = new HashMgr(dpath, affpath, key);
-  if (pHMgr[0])
-    maxdic = 1;
+  m_HMgrs.push_back(new HashMgr(dpath, affpath, key));
 
   /* next set up the affix manager */
   /* it needs access to the hash manager lookup methods */
-  pAMgr = new AffixMgr(affpath, pHMgr, &maxdic, key);
+  pAMgr = new AffixMgr(affpath, m_HMgrs, key);
 
   /* get the preferred try string and the dictionary */
   /* encoding from the Affix Manager for that dictionary */
   char* try_string = pAMgr->get_try_string();
   encoding = pAMgr->get_encoding();
   langnum = pAMgr->get_langnum();
   utf8 = pAMgr->get_utf8();
   if (!utf8)
@@ -118,64 +182,64 @@ Hunspell::Hunspell(const char* affpath, 
 
   /* and finally set up the suggestion manager */
   pSMgr = new SuggestMgr(try_string, MAXSUGGESTION, pAMgr);
   if (try_string)
     free(try_string);
 }
 
 Hunspell::~Hunspell() {
+  delete m_Impl;
+}
+
+HunspellImpl::~HunspellImpl() {
   delete pSMgr;
   delete pAMgr;
-  for (int i = 0; i < maxdic; i++)
-    delete pHMgr[i];
-  maxdic = 0;
+  for (size_t i = 0; i < m_HMgrs.size(); ++i)
+    delete m_HMgrs[i];
   pSMgr = NULL;
   pAMgr = NULL;
 #ifdef MOZILLA_CLIENT
   delete[] csconv;
 #endif
   csconv = NULL;
-  if (encoding)
-    free(encoding);
-  encoding = NULL;
   if (affixpath)
     free(affixpath);
   affixpath = NULL;
 }
 
 // load extra dictionaries
 int Hunspell::add_dic(const char* dpath, const char* key) {
-  if (maxdic == MAXDIC || !affixpath)
+  return m_Impl->add_dic(dpath, key);
+}
+
+// load extra dictionaries
+int HunspellImpl::add_dic(const char* dpath, const char* key) {
+  if (!affixpath)
     return 1;
-  pHMgr[maxdic] = new HashMgr(dpath, affixpath, key);
-  if (pHMgr[maxdic])
-    maxdic++;
-  else
-    return 1;
+  m_HMgrs.push_back(new HashMgr(dpath, affixpath, key));
   return 0;
 }
 
 // make a copy of src at destination while removing all leading
 // blanks and removing any trailing periods after recording
 // their presence with the abbreviation flag
 // also since already going through character by character,
 // set the capitalization type
 // return the length of the "cleaned" (and UTF-8 encoded) word
 
-size_t Hunspell::cleanword2(std::string& dest,
+size_t HunspellImpl::cleanword2(std::string& dest,
                          std::vector<w_char>& dest_utf,
-                         const char* src,
-                         int* nc,
+                         const std::string& src,
                          int* pcaptype,
                          size_t* pabbrev) {
   dest.clear();
   dest_utf.clear();
 
-  const char* q = src;
+  const char* q = src.c_str();
 
   // first skip over any leading blanks
   while ((*q != '\0') && (*q == ' '))
     q++;
 
   // now strip off any trailing periods (recording their presence)
   *pabbrev = 0;
   int nl = strlen(q);
@@ -188,31 +252,30 @@ size_t Hunspell::cleanword2(std::string&
   if (nl <= 0) {
     *pcaptype = NOCAP;
     return 0;
   }
 
   dest.append(q, nl);
   nl = dest.size();
   if (utf8) {
-    *nc = u8_u16(dest_utf, dest);
+    u8_u16(dest_utf, dest);
     *pcaptype = get_captype_utf8(dest_utf, langnum);
   } else {
     *pcaptype = get_captype(dest, csconv);
-    *nc = nl;
   }
   return nl;
 }
 
-void Hunspell::cleanword(std::string& dest,
-                        const char* src,
+void HunspellImpl::cleanword(std::string& dest,
+                        const std::string& src,
                         int* pcaptype,
                         int* pabbrev) {
   dest.clear();
-  const unsigned char* q = (const unsigned char*)src;
+  const unsigned char* q = (const unsigned char*)src.c_str();
   int firstcap = 0;
 
   // first skip over any leading blanks
   while ((*q != '\0') && (*q == ' '))
     q++;
 
   // now strip off any trailing periods (recording their presence)
   *pabbrev = 0;
@@ -272,145 +335,134 @@ void Hunspell::cleanword(std::string& de
     *pcaptype = ALLCAP;
   } else if ((ncap > 1) && firstcap) {
     *pcaptype = HUHINITCAP;
   } else {
     *pcaptype = HUHCAP;
   }
 }
 
-void Hunspell::mkallcap(std::string& u8) {
+void HunspellImpl::mkallcap(std::string& u8) {
   if (utf8) {
     std::vector<w_char> u16;
     u8_u16(u16, u8);
     ::mkallcap_utf(u16, langnum);
     u16_u8(u8, u16);
   } else {
     ::mkallcap(u8, csconv);
   }
 }
 
-int Hunspell::mkallsmall2(std::string& u8, std::vector<w_char>& u16) {
+int HunspellImpl::mkallsmall2(std::string& u8, std::vector<w_char>& u16) {
   if (utf8) {
     ::mkallsmall_utf(u16, langnum);
     u16_u8(u8, u16);
   } else {
     ::mkallsmall(u8, csconv);
   }
   return u8.size();
 }
 
 // convert UTF-8 sharp S codes to latin 1
-std::string Hunspell::sharps_u8_l1(const std::string& source) {
+std::string HunspellImpl::sharps_u8_l1(const std::string& source) {
   std::string dest(source);
   mystrrep(dest, "\xC3\x9F", "\xDF");
   return dest;
 }
 
 // recursive search for right ss - sharp s permutations
-hentry* Hunspell::spellsharps(std::string& base,
+hentry* HunspellImpl::spellsharps(std::string& base,
                               size_t n_pos,
                               int n,
                               int repnum,
                               int* info,
-                              char** root) {
+                              std::string* root) {
   size_t pos = base.find("ss", n_pos);
   if (pos != std::string::npos && (n < MAXSHARPS)) {
     base[pos] = '\xC3';
     base[pos + 1] = '\x9F';
     hentry* h = spellsharps(base, pos + 2, n + 1, repnum + 1, info, root);
     if (h)
       return h;
     base[pos] = 's';
     base[pos + 1] = 's';
     h = spellsharps(base, pos + 2, n + 1, repnum, info, root);
     if (h)
       return h;
   } else if (repnum > 0) {
     if (utf8)
-      return checkword(base.c_str(), info, root);
+      return checkword(base, info, root);
     std::string tmp(sharps_u8_l1(base));
-    return checkword(tmp.c_str(), info, root);
+    return checkword(tmp, info, root);
   }
   return NULL;
 }
 
-int Hunspell::is_keepcase(const hentry* rv) {
+int HunspellImpl::is_keepcase(const hentry* rv) {
   return pAMgr && rv->astr && pAMgr->get_keepcase() &&
          TESTAFF(rv->astr, pAMgr->get_keepcase(), rv->alen);
 }
 
-/* insert a word to the beginning of the suggestion array and return ns */
-int Hunspell::insert_sug(char*** slst, const char* word, int ns) {
-  if (!*slst)
-    return ns;
-  char* dup = mystrdup(word);
-  if (!dup)
-    return ns;
-  if (ns == MAXSUGGESTION) {
-    ns--;
-    free((*slst)[ns]);
-  }
-  for (int k = ns; k > 0; k--)
-    (*slst)[k] = (*slst)[k - 1];
-  (*slst)[0] = dup;
-  return ns + 1;
+/* insert a word to the beginning of the suggestion array */
+void HunspellImpl::insert_sug(std::vector<std::string>& slst, const std::string& word) {
+  slst.insert(slst.begin(), word);
 }
 
-int Hunspell::spell(const char* word, int* info, char** root) {
+bool Hunspell::spell(const std::string& word, int* info, std::string* root) {
+  return m_Impl->spell(word, info, root);
+}
+
+bool HunspellImpl::spell(const std::string& word, int* info, std::string* root) {
   struct hentry* rv = NULL;
 
   int info2 = 0;
   if (!info)
     info = &info2;
   else
     *info = 0;
 
   // Hunspell supports XML input of the simplified API (see manual)
-  if (strcmp(word, SPELL_XML) == 0)
-    return 1;
-  int nc = strlen(word);
+  if (word == SPELL_XML)
+    return true;
   if (utf8) {
-    if (nc >= MAXWORDUTF8LEN)
-      return 0;
+    if (word.size() >= MAXWORDUTF8LEN)
+      return false;
   } else {
-    if (nc >= MAXWORDLEN)
-      return 0;
+    if (word.size() >= MAXWORDLEN)
+      return false;
   }
   int captype = NOCAP;
   size_t abbv = 0;
   size_t wl = 0;
 
   std::string scw;
   std::vector<w_char> sunicw;
 
   // input conversion
-  RepList* rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL;
+  RepList* rl = pAMgr ? pAMgr->get_iconvtable() : NULL;
   {
     std::string wspace;
 
-    int convstatus = rl ? rl->conv(word, wspace) : 0;
-    if (convstatus < 0)
-      return 0;
-    else if (convstatus > 0)
-      wl = cleanword2(scw, sunicw, wspace.c_str(), &nc, &captype, &abbv);
+    bool convstatus = rl ? rl->conv(word, wspace) : false;
+    if (convstatus)
+      wl = cleanword2(scw, sunicw, wspace, &captype, &abbv);
     else
-      wl = cleanword2(scw, sunicw, word, &nc, &captype, &abbv);
+      wl = cleanword2(scw, sunicw, word, &captype, &abbv);
   }
 
 #ifdef MOZILLA_CLIENT
   // accept the abbreviated words without dots
   // workaround for the incomplete tokenization of Mozilla
   abbv = 1;
 #endif
 
-  if (wl == 0 || maxdic == 0)
-    return 1;
+  if (wl == 0 || m_HMgrs.empty())
+    return true;
   if (root)
-    *root = NULL;
+    root->clear();
 
   // allow numbers with dots, dashes and commas (but forbid double separators:
   // "..", "--" etc.)
   enum { NBEGIN, NNUM, NSEP };
   int nstate = NBEGIN;
   size_t i;
 
   for (i = 0; (i < wl); i++) {
@@ -419,41 +471,41 @@ int Hunspell::spell(const char* word, in
     } else if ((scw[i] == ',') || (scw[i] == '.') || (scw[i] == '-')) {
       if ((nstate == NSEP) || (i == 0))
         break;
       nstate = NSEP;
     } else
       break;
   }
   if ((i == wl) && (nstate == NNUM))
-    return 1;
+    return true;
 
   switch (captype) {
     case HUHCAP:
     /* FALLTHROUGH */
     case HUHINITCAP:
       *info += SPELL_ORIGCAP;
     /* FALLTHROUGH */
     case NOCAP:
-      rv = checkword(scw.c_str(), info, root);
+      rv = checkword(scw, info, root);
       if ((abbv) && !(rv)) {
         std::string u8buffer(scw);
         u8buffer.push_back('.');
-        rv = checkword(u8buffer.c_str(), info, root);
+        rv = checkword(u8buffer, info, root);
       }
       break;
     case ALLCAP: {
       *info += SPELL_ORIGCAP;
-      rv = checkword(scw.c_str(), info, root);
+      rv = checkword(scw, info, root);
       if (rv)
         break;
       if (abbv) {
         std::string u8buffer(scw);
         u8buffer.push_back('.');
-        rv = checkword(u8buffer.c_str(), info, root);
+        rv = checkword(u8buffer, info, root);
         if (rv)
           break;
       }
       // Spec. prefix handling for Catalan, French, Italian:
       // prefixes separated by apostrophe (SANT'ELIA -> Sant'+Elia).
       size_t apos = pAMgr ? scw.find('\'') : std::string::npos;
       if (apos != std::string::npos) {
         mkallsmall2(scw, sunicw);
@@ -465,28 +517,28 @@ int Hunspell::spell(const char* word, in
           if (utf8) {
             std::vector<w_char> part1u, part2u;
             u8_u16(part1u, part1);
             u8_u16(part2u, part2);
             mkinitcap2(part2, part2u);
             scw = part1 + part2;
             sunicw = part1u;
             sunicw.insert(sunicw.end(), part2u.begin(), part2u.end());
-            rv = checkword(scw.c_str(), info, root);
+            rv = checkword(scw, info, root);
             if (rv)
               break;
           } else {
             mkinitcap2(part2, sunicw);
             scw = part1 + part2;
-            rv = checkword(scw.c_str(), info, root);
+            rv = checkword(scw, info, root);
             if (rv)
               break;
           }
           mkinitcap2(scw, sunicw);
-          rv = checkword(scw.c_str(), info, root);
+          rv = checkword(scw, info, root);
           if (rv)
             break;
         }
       }
       if (pAMgr && pAMgr->get_checksharps() && scw.find("SS") != std::string::npos) {
 
         mkallsmall2(scw, sunicw);
         std::string u8buffer(scw);
@@ -511,41 +563,41 @@ int Hunspell::spell(const char* word, in
     case INITCAP: {
 
       *info += SPELL_ORIGCAP;
       mkallsmall2(scw, sunicw);
       std::string u8buffer(scw);
       mkinitcap2(scw, sunicw);
       if (captype == INITCAP)
         *info += SPELL_INITCAP;
-      rv = checkword(scw.c_str(), info, root);
+      rv = checkword(scw, info, root);
       if (captype == INITCAP)
         *info -= SPELL_INITCAP;
       // forbid bad capitalization
       // (for example, ijs -> Ijs instead of IJs in Dutch)
       // use explicit forms in dic: Ijs/F (F = FORBIDDENWORD flag)
       if (*info & SPELL_FORBIDDEN) {
         rv = NULL;
         break;
       }
       if (rv && is_keepcase(rv) && (captype == ALLCAP))
         rv = NULL;
       if (rv)
         break;
 
-      rv = checkword(u8buffer.c_str(), info, root);
+      rv = checkword(u8buffer, info, root);
       if (abbv && !rv) {
         u8buffer.push_back('.');
-        rv = checkword(u8buffer.c_str(), info, root);
+        rv = checkword(u8buffer, info, root);
         if (!rv) {
           u8buffer = scw;
           u8buffer.push_back('.');
           if (captype == INITCAP)
             *info += SPELL_INITCAP;
-          rv = checkword(u8buffer.c_str(), info, root);
+          rv = checkword(u8buffer, info, root);
           if (captype == INITCAP)
             *info -= SPELL_INITCAP;
           if (rv && is_keepcase(rv) && (captype == ALLCAP))
             rv = NULL;
           break;
         }
       }
       if (rv && is_keepcase(rv) &&
@@ -560,114 +612,112 @@ int Hunspell::spell(const char* word, in
     }
   }
 
   if (rv) {
     if (pAMgr && pAMgr->get_warn() && rv->astr &&
         TESTAFF(rv->astr, pAMgr->get_warn(), rv->alen)) {
       *info += SPELL_WARN;
       if (pAMgr->get_forbidwarn())
-        return 0;
-      return HUNSPELL_OK_WARN;
+        return false;
+      return true;
     }
-    return HUNSPELL_OK;
+    return true;
   }
 
   // recursive breaking at break points
-  if (wordbreak) {
+  if (!wordbreak.empty()) {
 
     int nbr = 0;
     wl = scw.size();
-    int numbreak = pAMgr ? pAMgr->get_numbreak() : 0;
 
     // calculate break points for recursion limit
-    for (int j = 0; j < numbreak; j++) {
-      size_t len = strlen(wordbreak[j]);
+    for (size_t j = 0; j < wordbreak.size(); ++j) {
       size_t pos = 0;
-      while ((pos = scw.find(wordbreak[j], pos, len)) != std::string::npos) {
+      while ((pos = scw.find(wordbreak[j], pos)) != std::string::npos) {
         ++nbr;
-        pos += len;
+        pos += wordbreak[j].size();
       }
     }
     if (nbr >= 10)
-      return 0;
+      return false;
 
     // check boundary patterns (^begin and end$)
-    for (int j = 0; j < numbreak; j++) {
-      size_t plen = strlen(wordbreak[j]);
+    for (size_t j = 0; j < wordbreak.size(); ++j) {
+      size_t plen = wordbreak[j].size();
       if (plen == 1 || plen > wl)
         continue;
 
       if (wordbreak[j][0] == '^' &&
-          scw.compare(0, plen - 1, wordbreak[j] + 1, plen -1) == 0 && spell(scw.c_str() + plen - 1))
-        return 1;
+          scw.compare(0, plen - 1, wordbreak[j], 1, plen -1) == 0 && spell(scw.substr(plen - 1)))
+        return true;
 
       if (wordbreak[j][plen - 1] == '$' &&
-          scw.compare(wl - plen + 1, plen - 1, wordbreak[j], plen - 1) == 0) {
-        char r = scw[wl - plen + 1];
-        scw[wl - plen + 1] = '\0';
-        if (spell(scw.c_str()))
-          return 1;
-        scw[wl - plen + 1] = r;
+          scw.compare(wl - plen + 1, plen - 1, wordbreak[j], 0, plen - 1) == 0) {
+        std::string suffix(scw.substr(wl - plen + 1));
+        scw.resize(wl - plen + 1);
+        if (spell(scw))
+          return true;
+        scw.append(suffix);
       }
     }
 
     // other patterns
-    for (int j = 0; j < numbreak; j++) {
-      size_t plen = strlen(wordbreak[j]);
+    for (size_t j = 0; j < wordbreak.size(); ++j) {
+      size_t plen = wordbreak[j].size();
       size_t found = scw.find(wordbreak[j]);
       if ((found > 0) && (found < wl - plen)) {
-        if (!spell(scw.c_str() + found + plen))
+        if (!spell(scw.substr(found + plen)))
           continue;
-        char r = scw[found];
-        scw[found] = '\0';
+        std::string suffix(scw.substr(found));
+        scw.resize(found);
         // examine 2 sides of the break point
-        if (spell(scw.c_str()))
-          return 1;
-        scw[found] = r;
+        if (spell(scw))
+          return true;
+        scw.append(suffix);
 
         // LANG_hu: spec. dash rule
-        if (langnum == LANG_hu && strcmp(wordbreak[j], "-") == 0) {
-          r = scw[found + 1];
-          scw[found + 1] = '\0';
-          if (spell(scw.c_str()))
-            return 1;  // check the first part with dash
-          scw[found + 1] = r;
+        if (langnum == LANG_hu && wordbreak[j] == "-") {
+          suffix = scw.substr(found + 1);
+          scw.resize(found + 1);
+          if (spell(scw))
+            return true;  // check the first part with dash
+          scw.append(suffix);
         }
         // end of LANG specific region
       }
     }
   }
 
-  return 0;
+  return false;
 }
 
-struct hentry* Hunspell::checkword(const char* w, int* info, char** root) {
-  struct hentry* he = NULL;
+struct hentry* HunspellImpl::checkword(const std::string& w, int* info, std::string* root) {
   bool usebuffer = false;
-  int len, i;
   std::string w2;
   const char* word;
+  int len;
 
-  char* ignoredchars = pAMgr ? pAMgr->get_ignore() : NULL;
+  const char* ignoredchars = pAMgr ? pAMgr->get_ignore() : NULL;
   if (ignoredchars != NULL) {
     w2.assign(w);
     if (utf8) {
       const std::vector<w_char>& ignoredchars_utf16 =
           pAMgr->get_ignore_utf16();
       remove_ignored_chars_utf(w2, ignoredchars_utf16);
     } else {
       remove_ignored_chars(w2, ignoredchars);
     }
     word = w2.c_str();
+    len = w2.size();
     usebuffer = true;
-  } else
-    word = w;
-
-  len = strlen(word);
+  } else {
+    word = w.c_str();
+    len = w.size();
+  }
 
   if (!len)
     return NULL;
 
   // word reversing wrapper for complex prefixes
   if (complexprefixes) {
     if (!usebuffer) {
       w2.assign(word);
@@ -679,18 +729,19 @@ struct hentry* Hunspell::checkword(const
       reverseword(w2);
   }
 
   if (usebuffer) {
     word = w2.c_str();
   }
 
   // look word in hash table
-  for (i = 0; (i < maxdic) && !he; i++) {
-    he = (pHMgr[i])->lookup(word);
+  struct hentry* he = NULL;
+  for (size_t i = 0; (i < m_HMgrs.size()) && !he; ++i) {
+    he = m_HMgrs[i]->lookup(word);
 
     // check forbidden and onlyincompound words
     if ((he) && (he->astr) && (pAMgr) &&
         TESTAFF(he->astr, pAMgr->get_forbiddenword(), he->alen)) {
       if (info)
         *info += SPELL_FORBIDDEN;
       // LANG_hu section: set dash information for suggestions
       if (langnum == LANG_hu) {
@@ -731,806 +782,767 @@ struct hentry* Hunspell::checkword(const
     if (he) {
       if ((he->astr) && (pAMgr) &&
           TESTAFF(he->astr, pAMgr->get_forbiddenword(), he->alen)) {
         if (info)
           *info += SPELL_FORBIDDEN;
         return NULL;
       }
       if (root) {
-        std::string word_root(he->word);
+        root->assign(he->word);
         if (complexprefixes) {
           if (utf8)
-            reverseword_utf(word_root);
+            reverseword_utf(*root);
           else
-            reverseword(word_root);
+            reverseword(*root);
         }
-        *root = mystrdup(word_root.c_str());
       }
       // try check compound word
     } else if (pAMgr->get_compound()) {
       struct hentry* rwords[100];  // buffer for COMPOUND pattern checking
-      he = pAMgr->compound_check(word, len, 0, 0, 100, 0, NULL, (hentry**)&rwords, 0, 0, info);
+      he = pAMgr->compound_check(word, 0, 0, 100, 0, NULL, (hentry**)&rwords, 0, 0, info);
       // LANG_hu section: `moving rule' with last dash
       if ((!he) && (langnum == LANG_hu) && (word[len - 1] == '-')) {
-        char* dup = mystrdup(word);
-        if (!dup)
-          return NULL;
-        dup[len - 1] = '\0';
-        he = pAMgr->compound_check(dup, len - 1, -5, 0, 100, 0, NULL, (hentry**)&rwords, 1, 0,
-                                   info);
-        free(dup);
+        std::string dup(word, len - 1);
+        he = pAMgr->compound_check(dup, -5, 0, 100, 0, NULL, (hentry**)&rwords, 1, 0, info);
       }
       // end of LANG specific region
       if (he) {
         if (root) {
-          std::string word_root(he->word);
+          root->assign(he->word);
           if (complexprefixes) {
             if (utf8)
-              reverseword_utf(word_root);
+              reverseword_utf(*root);
             else
-              reverseword(word_root);
+              reverseword(*root);
           }
-          *root = mystrdup(word_root.c_str());
         }
         if (info)
           *info += SPELL_COMPOUND;
       }
     }
   }
 
   return he;
 }
 
-int Hunspell::suggest(char*** slst, const char* word) {
+std::vector<std::string> Hunspell::suggest(const std::string& word) {
+  return m_Impl->suggest(word);
+}
+
+std::vector<std::string> HunspellImpl::suggest(const std::string& word) {
+  std::vector<std::string> slst;
+
   int onlycmpdsug = 0;
-  if (!pSMgr || maxdic == 0)
-    return 0;
-  *slst = NULL;
+  if (!pSMgr || m_HMgrs.empty())
+    return slst;
+
   // process XML input of the simplified API (see manual)
-  if (strncmp(word, SPELL_XML, sizeof(SPELL_XML) - 3) == 0) {
-    return spellml(slst, word);
+  if (word.compare(0, sizeof(SPELL_XML) - 3, SPELL_XML, sizeof(SPELL_XML) - 3) == 0) {
+    return spellml(word);
   }
-  int nc = strlen(word);
   if (utf8) {
-    if (nc >= MAXWORDUTF8LEN)
-      return 0;
+    if (word.size() >= MAXWORDUTF8LEN)
+      return slst;
   } else {
-    if (nc >= MAXWORDLEN)
-      return 0;
+    if (word.size() >= MAXWORDLEN)
+      return slst;
   }
   int captype = NOCAP;
   size_t abbv = 0;
   size_t wl = 0;
 
   std::string scw;
   std::vector<w_char> sunicw;
 
   // input conversion
   RepList* rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL;
   {
     std::string wspace;
 
-    int convstatus = rl ? rl->conv(word, wspace) : 0;
-    if (convstatus < 0)
-      return 0;
-    else if (convstatus > 0)
-      wl = cleanword2(scw, sunicw, wspace.c_str(), &nc, &captype, &abbv);
+    bool convstatus = rl ? rl->conv(word, wspace) : false;
+    if (convstatus)
+      wl = cleanword2(scw, sunicw, wspace, &captype, &abbv);
     else
-      wl = cleanword2(scw, sunicw, word, &nc, &captype, &abbv);
+      wl = cleanword2(scw, sunicw, word, &captype, &abbv);
 
     if (wl == 0)
-      return 0;
+      return slst;
   }
 
-  int ns = 0;
   int capwords = 0;
 
   // check capitalized form for FORCEUCASE
   if (pAMgr && captype == NOCAP && pAMgr->get_forceucase()) {
     int info = SPELL_ORIGCAP;
-    if (checkword(scw.c_str(), &info, NULL)) {
+    if (checkword(scw, &info, NULL)) {
       std::string form(scw);
       mkinitcap(form);
-
-      char** wlst = (char**)malloc(MAXSUGGESTION * sizeof(char*));
-      if (wlst == NULL)
-        return -1;
-      *slst = wlst;
-      wlst[0] = mystrdup(form.c_str());
-      for (int i = 1; i < MAXSUGGESTION; ++i) {
-        wlst[i] = NULL;
-      }
-
-      return 1;
+      slst.push_back(form);
+      return slst;
     }
   }
 
   switch (captype) {
     case NOCAP: {
-      ns = pSMgr->suggest(slst, scw.c_str(), ns, &onlycmpdsug);
+      pSMgr->suggest(slst, scw.c_str(), &onlycmpdsug);
       break;
     }
 
     case INITCAP: {
       capwords = 1;
-      ns = pSMgr->suggest(slst, scw.c_str(), ns, &onlycmpdsug);
-      if (ns == -1)
-        break;
+      pSMgr->suggest(slst, scw.c_str(), &onlycmpdsug);
       std::string wspace(scw);
       mkallsmall2(wspace, sunicw);
-      ns = pSMgr->suggest(slst, wspace.c_str(), ns, &onlycmpdsug);
+      pSMgr->suggest(slst, wspace.c_str(), &onlycmpdsug);
       break;
     }
     case HUHINITCAP:
       capwords = 1;
     case HUHCAP: {
-      ns = pSMgr->suggest(slst, scw.c_str(), ns, &onlycmpdsug);
-      if (ns != -1) {
-        // something.The -> something. The
-        size_t dot_pos = scw.find('.');
-        if (dot_pos != std::string::npos) {
-          std::string postdot = scw.substr(dot_pos + 1);
-          int captype_;
-          if (utf8) {
-            std::vector<w_char> postdotu;
-            u8_u16(postdotu, postdot);
-            captype_ = get_captype_utf8(postdotu, langnum);
-          } else {
-            captype_ = get_captype(postdot, csconv);
-          }
-          if (captype_ == INITCAP) {
-            std::string str(scw);
-            str.insert(dot_pos + 1, 1, ' ');
-            ns = insert_sug(slst, str.c_str(), ns);
-          }
+      pSMgr->suggest(slst, scw.c_str(), &onlycmpdsug);
+      // something.The -> something. The
+      size_t dot_pos = scw.find('.');
+      if (dot_pos != std::string::npos) {
+        std::string postdot = scw.substr(dot_pos + 1);
+        int captype_;
+        if (utf8) {
+          std::vector<w_char> postdotu;
+          u8_u16(postdotu, postdot);
+          captype_ = get_captype_utf8(postdotu, langnum);
+        } else {
+          captype_ = get_captype(postdot, csconv);
         }
-
-        std::string wspace;
+        if (captype_ == INITCAP) {
+          std::string str(scw);
+          str.insert(dot_pos + 1, 1, ' ');
+          insert_sug(slst, str);
+        }
+      }
 
-        if (captype == HUHINITCAP) {
-          // TheOpenOffice.org -> The OpenOffice.org
-          wspace = scw;
-          mkinitsmall2(wspace, sunicw);
-          ns = pSMgr->suggest(slst, wspace.c_str(), ns, &onlycmpdsug);
-        }
+      std::string wspace;
+
+      if (captype == HUHINITCAP) {
+        // TheOpenOffice.org -> The OpenOffice.org
         wspace = scw;
-        mkallsmall2(wspace, sunicw);
+        mkinitsmall2(wspace, sunicw);
+        pSMgr->suggest(slst, wspace.c_str(), &onlycmpdsug);
+      }
+      wspace = scw;
+      mkallsmall2(wspace, sunicw);
+      if (spell(wspace.c_str()))
+        insert_sug(slst, wspace);
+      size_t prevns = slst.size();
+      pSMgr->suggest(slst, wspace.c_str(), &onlycmpdsug);
+      if (captype == HUHINITCAP) {
+        mkinitcap2(wspace, sunicw);
         if (spell(wspace.c_str()))
-          ns = insert_sug(slst, wspace.c_str(), ns);
-        int prevns = ns;
-        ns = pSMgr->suggest(slst, wspace.c_str(), ns, &onlycmpdsug);
-        if (captype == HUHINITCAP) {
-          mkinitcap2(wspace, sunicw);
-          if (spell(wspace.c_str()))
-            ns = insert_sug(slst, wspace.c_str(), ns);
-          ns = pSMgr->suggest(slst, wspace.c_str(), ns, &onlycmpdsug);
-        }
-        // aNew -> "a New" (instead of "a new")
-        for (int j = prevns; j < ns; j++) {
-          char* space = strchr((*slst)[j], ' ');
-          if (space) {
-            size_t slen = strlen(space + 1);
-            // different case after space (need capitalisation)
-            if ((slen < wl) && strcmp(scw.c_str() + wl - slen, space + 1)) {
-              std::string first((*slst)[j], space + 1);
-              std::string second(space + 1);
-              std::vector<w_char> w;
-              if (utf8)
-                u8_u16(w, second);
-              mkinitcap2(second, w);
-              // set as first suggestion
-              char* r = (*slst)[j];
-              for (int k = j; k > 0; k--)
-                (*slst)[k] = (*slst)[k - 1];
-              free(r);
-              (*slst)[0] = mystrdup((first + second).c_str());
-            }
+          insert_sug(slst, wspace);
+        pSMgr->suggest(slst, wspace.c_str(), &onlycmpdsug);
+      }
+      // aNew -> "a New" (instead of "a new")
+      for (size_t j = prevns; j < slst.size(); ++j) {
+        const char* space = strchr(slst[j].c_str(), ' ');
+        if (space) {
+          size_t slen = strlen(space + 1);
+          // different case after space (need capitalisation)
+          if ((slen < wl) && strcmp(scw.c_str() + wl - slen, space + 1)) {
+            std::string first(slst[j].c_str(), space + 1);
+            std::string second(space + 1);
+            std::vector<w_char> w;
+            if (utf8)
+              u8_u16(w, second);
+            mkinitcap2(second, w);
+            // set as first suggestion
+            slst.erase(slst.begin() + j);
+            slst.insert(slst.begin(), first + second);
           }
         }
       }
       break;
     }
 
     case ALLCAP: {
       std::string wspace(scw);
       mkallsmall2(wspace, sunicw);
-      ns = pSMgr->suggest(slst, wspace.c_str(), ns, &onlycmpdsug);
-      if (ns == -1)
-        break;
+      pSMgr->suggest(slst, wspace.c_str(), &onlycmpdsug);
       if (pAMgr && pAMgr->get_keepcase() && spell(wspace.c_str()))
-        ns = insert_sug(slst, wspace.c_str(), ns);
+        insert_sug(slst, wspace);
       mkinitcap2(wspace, sunicw);
-      ns = pSMgr->suggest(slst, wspace.c_str(), ns, &onlycmpdsug);
-      for (int j = 0; j < ns; j++) {
-        std::string form((*slst)[j]);
-        mkallcap(form);
-
+      pSMgr->suggest(slst, wspace.c_str(), &onlycmpdsug);
+      for (size_t j = 0; j < slst.size(); ++j) {
+        mkallcap(slst[j]);
         if (pAMgr && pAMgr->get_checksharps()) {
           if (utf8) {
-            mystrrep(form, "\xC3\x9F", "SS");
+            mystrrep(slst[j], "\xC3\x9F", "SS");
           } else {
-            mystrrep(form, "\xDF", "SS");
+            mystrrep(slst[j], "\xDF", "SS");
           }
         }
-
-        free((*slst)[j]);
-        (*slst)[j] = mystrdup(form.c_str());
-
       }
       break;
     }
   }
 
   // LANG_hu section: replace '-' with ' ' in Hungarian
   if (langnum == LANG_hu) {
-    for (int j = 0; j < ns; j++) {
-      char* pos = strchr((*slst)[j], '-');
-      if (pos) {
+    for (size_t j = 0; j < slst.size(); ++j) {
+      size_t pos = slst[j].find('-');
+      if (pos != std::string::npos) {
         int info;
-        *pos = '\0';
-        std::string w((*slst)[j]);
-        w.append(pos + 1);
-        (void)spell(w.c_str(), &info, NULL);
+        std::string w(slst[j].substr(0, pos));
+        w.append(slst[j].substr(pos + 1));
+        (void)spell(w, &info, NULL);
         if ((info & SPELL_COMPOUND) && (info & SPELL_FORBIDDEN)) {
-          *pos = ' ';
+          slst[j][pos] = ' ';
         } else
-          *pos = '-';
+          slst[j][pos] = '-';
       }
     }
   }
   // END OF LANG_hu section
 
   // try ngram approach since found nothing or only compound words
-  if (pAMgr && (ns == 0 || onlycmpdsug) && (pAMgr->get_maxngramsugs() != 0) &&
-      (*slst)) {
+  if (pAMgr && (slst.empty() || onlycmpdsug) && (pAMgr->get_maxngramsugs() != 0)) {
     switch (captype) {
       case NOCAP: {
-        ns = pSMgr->ngsuggest(*slst, scw.c_str(), ns, pHMgr, maxdic);
+        pSMgr->ngsuggest(slst, scw.c_str(), m_HMgrs);
         break;
       }
       case HUHINITCAP:
         capwords = 1;
       case HUHCAP: {
         std::string wspace(scw);
         mkallsmall2(wspace, sunicw);
-        ns = pSMgr->ngsuggest(*slst, wspace.c_str(), ns, pHMgr, maxdic);
+        pSMgr->ngsuggest(slst, wspace.c_str(), m_HMgrs);
         break;
       }
       case INITCAP: {
         capwords = 1;
         std::string wspace(scw);
         mkallsmall2(wspace, sunicw);
-        ns = pSMgr->ngsuggest(*slst, wspace.c_str(), ns, pHMgr, maxdic);
+        pSMgr->ngsuggest(slst, wspace.c_str(), m_HMgrs);
         break;
       }
       case ALLCAP: {
         std::string wspace(scw);
         mkallsmall2(wspace, sunicw);
-        int oldns = ns;
-        ns = pSMgr->ngsuggest(*slst, wspace.c_str(), ns, pHMgr, maxdic);
-        for (int j = oldns; j < ns; j++) {
-          std::string form((*slst)[j]);
-          mkallcap(form);
-          free((*slst)[j]);
-          (*slst)[j] = mystrdup(form.c_str());
+        size_t oldns = slst.size();
+        pSMgr->ngsuggest(slst, wspace.c_str(), m_HMgrs);
+        for (size_t j = oldns; j < slst.size(); ++j) {
+          mkallcap(slst[j]);
         }
         break;
       }
     }
   }
 
   // try dash suggestion (Afo-American -> Afro-American)
   size_t dash_pos = scw.find('-');
   if (dash_pos != std::string::npos) {
     int nodashsug = 1;
-    for (int j = 0; j < ns && nodashsug == 1; j++) {
-      if (strchr((*slst)[j], '-'))
+    for (size_t j = 0; j < slst.size() && nodashsug == 1; ++j) {
+      if (slst[j].find('-') != std::string::npos)
         nodashsug = 0;
     }
 
     size_t prev_pos = 0;
     bool last = false;
 
     while (nodashsug && !last) {
       if (dash_pos == scw.size())
         last = 1;
       std::string chunk = scw.substr(prev_pos, dash_pos - prev_pos);
       if (!spell(chunk.c_str())) {
-        char** nlst = NULL;
-        int nn = suggest(&nlst, chunk.c_str());
-        for (int j = nn - 1; j >= 0; j--) {
+        std::vector<std::string> nlst = suggest(chunk.c_str());
+        for (std::vector<std::string>::reverse_iterator j = nlst.rbegin(); j != nlst.rend(); ++j) {
           std::string wspace = scw.substr(0, prev_pos);
-          wspace.append(nlst[j]);
+          wspace.append(*j);
           if (!last) {
             wspace.append("-");
             wspace.append(scw.substr(dash_pos + 1));
           }
-          ns = insert_sug(slst, wspace.c_str(), ns);
-          free(nlst[j]);
+          insert_sug(slst, wspace);
         }
-        if (nlst != NULL)
-          free(nlst);
         nodashsug = 0;
       }
       if (!last) {
         prev_pos = dash_pos + 1;
         dash_pos = scw.find('-', prev_pos);
       }
       if (dash_pos == std::string::npos)
         dash_pos = scw.size();
     }
   }
 
   // word reversing wrapper for complex prefixes
   if (complexprefixes) {
-    for (int j = 0; j < ns; j++) {
-      std::string root((*slst)[j]);
-      free((*slst)[j]);
+    for (size_t j = 0; j < slst.size(); ++j) {
       if (utf8)
-        reverseword_utf(root);
+        reverseword_utf(slst[j]);
       else
-        reverseword(root);
-      (*slst)[j] = mystrdup(root.c_str());
+        reverseword(slst[j]);
     }
   }
 
   // capitalize
   if (capwords)
-    for (int j = 0; j < ns; j++) {
-      std::string form((*slst)[j]);
-      free((*slst)[j]);
-      mkinitcap(form);
-      (*slst)[j] = mystrdup(form.c_str());
+    for (size_t j = 0; j < slst.size(); ++j) {
+      mkinitcap(slst[j]);
     }
 
   // expand suggestions with dot(s)
   if (abbv && pAMgr && pAMgr->get_sugswithdots()) {
-    for (int j = 0; j < ns; j++) {
-      (*slst)[j] = (char*)realloc((*slst)[j], strlen((*slst)[j]) + 1 + abbv);
-      strcat((*slst)[j], word + strlen(word) - abbv);
+    for (size_t j = 0; j < slst.size(); ++j) {
+      slst[j].append(word.substr(word.size() - abbv));
     }
   }
 
   // remove bad capitalized and forbidden forms
   if (pAMgr && (pAMgr->get_keepcase() || pAMgr->get_forbiddenword())) {
     switch (captype) {
       case INITCAP:
       case ALLCAP: {
-        int l = 0;
-        for (int j = 0; j < ns; j++) {
-          if (!strchr((*slst)[j], ' ') && !spell((*slst)[j])) {
+        size_t l = 0;
+        for (size_t j = 0; j < slst.size(); ++j) {
+          if (slst[j].find(' ') == std::string::npos && !spell(slst[j])) {
             std::string s;
             std::vector<w_char> w;
             if (utf8) {
-              u8_u16(w, (*slst)[j]);
+              u8_u16(w, slst[j]);
             } else {
-              s = (*slst)[j];
+              s = slst[j];
             }
             mkallsmall2(s, w);
-            free((*slst)[j]);
-            if (spell(s.c_str())) {
-              (*slst)[l] = mystrdup(s.c_str());
-              if ((*slst)[l])
-                l++;
+            if (spell(s)) {
+              slst[l] = s;
+              ++l;
             } else {
               mkinitcap2(s, w);
-              if (spell(s.c_str())) {
-                (*slst)[l] = mystrdup(s.c_str());
-                if ((*slst)[l])
-                  l++;
+              if (spell(s)) {
+                slst[l] = s;
+                ++l;
               }
             }
           } else {
-            (*slst)[l] = (*slst)[j];
-            l++;
+            slst[l] = slst[j];
+            ++l;
           }
         }
-        ns = l;
+        slst.resize(l);
       }
     }
   }
 
   // remove duplications
-  int l = 0;
-  for (int j = 0; j < ns; j++) {
-    (*slst)[l] = (*slst)[j];
-    for (int k = 0; k < l; k++) {
-      if (strcmp((*slst)[k], (*slst)[j]) == 0) {
-        free((*slst)[j]);
-        l--;
+  size_t l = 0;
+  for (size_t j = 0; j < slst.size(); ++j) {
+    slst[l] = slst[j];
+    for (size_t k = 0; k < l; ++k) {
+      if (slst[k] == slst[j]) {
+        --l;
         break;
       }
     }
-    l++;
+    ++l;
   }
-  ns = l;
+  slst.resize(l);
 
   // output conversion
   rl = (pAMgr) ? pAMgr->get_oconvtable() : NULL;
-  for (int j = 0; rl && j < ns; j++) {
+  for (size_t j = 0; rl && j < slst.size(); ++j) {
     std::string wspace;
-    if (rl->conv((*slst)[j], wspace) > 0) {
-      free((*slst)[j]);
-      (*slst)[j] = mystrdup(wspace.c_str());
+    if (rl->conv(slst[j], wspace)) {
+      slst[j] = wspace;
     }
   }
 
-  // if suggestions removed by nosuggest, onlyincompound parameters
-  if (l == 0 && *slst) {
-    free(*slst);
-    *slst = NULL;
-  }
-  return l;
+  return slst;
 }
 
-void Hunspell::free_list(char*** slst, int n) {
-  freelist(slst, n);
+const std::string& Hunspell::get_dict_encoding() const {
+  return m_Impl->get_dict_encoding();
 }
 
-char* Hunspell::get_dic_encoding() {
+const std::string& HunspellImpl::get_dict_encoding() const {
   return encoding;
 }
 
-int Hunspell::stem(char*** slst, char** desc, int n) {
+std::vector<std::string> Hunspell::stem(const std::vector<std::string>& desc) {
+  return m_Impl->stem(desc);
+}
+
+std::vector<std::string> HunspellImpl::stem(const std::vector<std::string>& desc) {
+  std::vector<std::string> slst;
 
   std::string result2;
-  *slst = NULL;
-  if (n == 0)
-    return 0;
-  for (int i = 0; i < n; i++) {
+  if (desc.empty())
+    return slst;
+  for (size_t i = 0; i < desc.size(); ++i) {
 
     std::string result;
 
     // add compound word parts (except the last one)
-    char* s = (char*)desc[i];
-    char* part = strstr(s, MORPH_PART);
+    const char* s = desc[i].c_str();
+    const char* part = strstr(s, MORPH_PART);
     if (part) {
-      char* nextpart = strstr(part + 1, MORPH_PART);
+      const char* nextpart = strstr(part + 1, MORPH_PART);
       while (nextpart) {
         std::string field;
         copy_field(field, part, MORPH_PART);
         result.append(field);
         part = nextpart;
         nextpart = strstr(part + 1, MORPH_PART);
       }
       s = part;
     }
 
-    char** pl;
     std::string tok(s);
     size_t alt = 0;
     while ((alt = tok.find(" | ", alt)) != std::string::npos) {
       tok[alt + 1] = MSEP_ALT;
     }
-    int pln = line_tok(tok.c_str(), &pl, MSEP_ALT);
-    for (int k = 0; k < pln; k++) {
+    std::vector<std::string> pl = line_tok(tok, MSEP_ALT);
+    for (size_t k = 0; k < pl.size(); ++k) {
       // add derivational suffixes
-      if (strstr(pl[k], MORPH_DERI_SFX)) {
+      if (pl[k].find(MORPH_DERI_SFX) != std::string::npos) {
         // remove inflectional suffixes
-        char* is = strstr(pl[k], MORPH_INFL_SFX);
-        if (is)
-          *is = '\0';
-        char* sg = pSMgr->suggest_gen(&(pl[k]), 1, pl[k]);
-        if (sg) {
-          char** gen;
-          int genl = line_tok(sg, &gen, MSEP_REC);
-          free(sg);
-          for (int j = 0; j < genl; j++) {
+        const size_t is = pl[k].find(MORPH_INFL_SFX);
+        if (is != std::string::npos)
+          pl[k].resize(is);
+        std::vector<std::string> singlepl;
+        singlepl.push_back(pl[k]);
+        std::string sg = pSMgr->suggest_gen(singlepl, pl[k]);
+        if (!sg.empty()) {
+          std::vector<std::string> gen = line_tok(sg, MSEP_REC);
+          for (size_t j = 0; j < gen.size(); ++j) {
             result2.push_back(MSEP_REC);
             result2.append(result);
             result2.append(gen[j]);
           }
-          freelist(&gen, genl);
         }
       } else {
         result2.push_back(MSEP_REC);
         result2.append(result);
-        if (strstr(pl[k], MORPH_SURF_PFX)) {
+        if (pl[k].find(MORPH_SURF_PFX) != std::string::npos) {
           std::string field;
           copy_field(field, pl[k], MORPH_SURF_PFX);
           result2.append(field);
         }
         std::string field;
         copy_field(field, pl[k], MORPH_STEM);
         result2.append(field);
       }
     }
-    freelist(&pl, pln);
   }
-  int sln = line_tok(result2.c_str(), slst, MSEP_REC);
-  return uniqlist(*slst, sln);
+  slst = line_tok(result2, MSEP_REC);
+  uniqlist(slst);
+  return slst;
+}
+
+std::vector<std::string> Hunspell::stem(const std::string& word) {
+  return m_Impl->stem(word);
 }
 
-int Hunspell::stem(char*** slst, const char* word) {
-  char** pl;
-  int pln = analyze(&pl, word);
-  int pln2 = stem(slst, pl, pln);
-  freelist(&pl, pln);
-  return pln2;
+std::vector<std::string> HunspellImpl::stem(const std::string& word) {
+  return stem(analyze(word));
 }
 
-const char* Hunspell::get_wordchars() {
+const std::string& Hunspell::get_wordchars() const {
+  return m_Impl->get_wordchars();
+}
+
+const std::string& HunspellImpl::get_wordchars() const {
   return pAMgr->get_wordchars();
 }
 
-const std::vector<w_char>& Hunspell::get_wordchars_utf16() {
+const std::vector<w_char>& Hunspell::get_wordchars_utf16() const {
+  return m_Impl->get_wordchars_utf16();
+}
+
+const std::vector<w_char>& HunspellImpl::get_wordchars_utf16() const {
   return pAMgr->get_wordchars_utf16();
 }
 
-void Hunspell::mkinitcap(std::string& u8) {
+void HunspellImpl::mkinitcap(std::string& u8) {
   if (utf8) {
     std::vector<w_char> u16;
     u8_u16(u16, u8);
     ::mkinitcap_utf(u16, langnum);
     u16_u8(u8, u16);
   } else {
     ::mkinitcap(u8, csconv);
   }
 }
 
-int Hunspell::mkinitcap2(std::string& u8, std::vector<w_char>& u16) {
+int HunspellImpl::mkinitcap2(std::string& u8, std::vector<w_char>& u16) {
   if (utf8) {
     ::mkinitcap_utf(u16, langnum);
     u16_u8(u8, u16);
   } else {
     ::mkinitcap(u8, csconv);
   }
   return u8.size();
 }