Merge m-i to m-c, a=merge
authorPhil Ringnalda <philringnalda@gmail.com>
Sat, 10 Dec 2016 08:27:52 -0800
changeset 325624 c51e7406d7b2e2246a1ece0d8989282ca752039f
parent 325580 5cc901aa30a2f8ce528082f8b5a4f06c34fef363 (current diff)
parent 325623 edb24e0ff1e147e44f042f8d0dccf59eac6f6de0 (diff)
child 325625 550922e8b2234ceb7bd8eb1e738c14ff8bff56ee
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewersmerge
milestone53.0a1
Merge m-i to m-c, a=merge MozReview-Commit-ID: BnSh8kutBaR
layout/base/nsLayoutUtils.cpp
media/webrtc/signaling/test/mediaconduit_unittests.cpp
mobile/android/chrome/content/browser.js
modules/libpref/init/all.js
toolkit/modules/FinderHighlighter.jsm
--- a/accessible/jsat/AccessFu.jsm
+++ b/accessible/jsat/AccessFu.jsm
@@ -28,18 +28,17 @@ this.AccessFu = { // jshint ignore:line
    * Initialize chrome-layer accessibility functionality.
    * If accessibility is enabled on the platform, then a special accessibility
    * mode is started.
    */
   attach: function attach(aWindow) {
     Utils.init(aWindow);
 
     try {
-      Services.androidBridge.handleGeckoMessage(
-          { type: 'Accessibility:Ready' });
+      Services.androidBridge.dispatch('Accessibility:Ready');
       Services.obs.addObserver(this, 'Accessibility:Settings', false);
     } catch (x) {
       // Not on Android
       if (aWindow.navigator.mozSettings) {
         let lock = aWindow.navigator.mozSettings.createLock();
         let req = lock.get(SCREENREADER_SETTING);
         req.addEventListener('success', () => {
           this._systemPref = req.result[SCREENREADER_SETTING];
@@ -597,17 +596,16 @@ var Output = {
     const ANDROID_VIEW_TEXT_CHANGED = 0x10;
     const ANDROID_VIEW_TEXT_SELECTION_CHANGED = 0x2000;
 
     if (!this.androidBridge) {
       return;
     }
 
     for (let androidEvent of aDetails) {
-      androidEvent.type = 'Accessibility:Event';
       if (androidEvent.bounds) {
         androidEvent.bounds = AccessFu.adjustContentBounds(
           androidEvent.bounds, aBrowser);
       }
 
       switch(androidEvent.eventType) {
         case ANDROID_VIEW_TEXT_CHANGED:
           androidEvent.brailleOutput = this.brailleState.adjustText(
@@ -617,17 +615,19 @@ var Output = {
           androidEvent.brailleOutput = this.brailleState.adjustSelection(
             androidEvent.brailleOutput);
           break;
         default:
           androidEvent.brailleOutput = this.brailleState.init(
             androidEvent.brailleOutput);
           break;
       }
-      this.androidBridge.handleGeckoMessage(androidEvent);
+      let win = Utils.win;
+      let view = win && win.QueryInterface(Ci.nsIAndroidView);
+      view.dispatch('Accessibility:Event', androidEvent);
     }
   },
 
   Braille: function Braille(aDetails) {
     Logger.debug('Braille output: ' + aDetails.output);
   }
 };
 
@@ -813,18 +813,19 @@ var Input = {
             return;
           } else {
             target.blur();
           }
         }
 
         if (Utils.MozBuildApp == 'mobile/android') {
           // Return focus to native Android browser chrome.
-          Services.androidBridge.handleGeckoMessage(
-              { type: 'ToggleChrome:Focus' });
+          let win = Utils.win;
+          let view = win && win.QueryInterface(Ci.nsIAndroidView);
+          view.dispatch('ToggleChrome:Focus');
         }
         break;
       case aEvent.DOM_VK_RETURN:
         if (this.editState.editing) {
           return;
         }
         this.activateCurrent();
         break;
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -5726,16 +5726,18 @@ nsDocShell::Create()
 }
 
 NS_IMETHODIMP
 nsDocShell::Destroy()
 {
   NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
                "Unexpected item type in docshell");
 
+  AssertOriginAttributesMatchPrivateBrowsing();
+
   if (!mIsBeingDestroyed) {
     nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
     if (serv) {
       const char* msg = mItemType == typeContent ?
         NS_WEBNAVIGATION_DESTROY : NS_CHROME_WEBNAVIGATION_DESTROY;
       serv->NotifyObservers(GetAsSupports(this), msg, nullptr);
     }
   }
@@ -14339,16 +14341,17 @@ nsDocShell::SetOriginAttributes(const Do
 
   bool isPrivate = mOriginAttributes.mPrivateBrowsingId > 0;
   // Chrome docshell can not contain OriginAttributes.mPrivateBrowsingId
   if (mItemType == typeChrome && isPrivate) {
     mOriginAttributes.mPrivateBrowsingId = 0;
   }
 
   SetPrivateBrowsing(isPrivate);
+  AssertOriginAttributesMatchPrivateBrowsing();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::SetOriginAttributesBeforeLoading(JS::Handle<JS::Value> aOriginAttributes)
 {
   if (!aOriginAttributes.isObject()) {
--- a/dom/base/DOMIntersectionObserver.cpp
+++ b/dom/base/DOMIntersectionObserver.cpp
@@ -42,16 +42,17 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOM
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMIntersectionObserver)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mQueuedEntries)
+  tmp->Disconnect();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMIntersectionObserver)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mQueuedEntries)
@@ -180,19 +181,20 @@ DOMIntersectionObserver::UnlinkTarget(El
 }
 
 void
 DOMIntersectionObserver::Connect()
 {
   if (mConnected) {
     return;
   }
+
+  mConnected = true;
   nsIDocument* document = mOwner->GetExtantDoc();
   document->AddIntersectionObserver(this);
-  mConnected = true;
 }
 
 void
 DOMIntersectionObserver::Disconnect()
 {
   if (!mConnected) {
     return;
   }
--- a/dom/base/DOMIntersectionObserver.h
+++ b/dom/base/DOMIntersectionObserver.h
@@ -96,19 +96,17 @@ protected:
 
 #define NS_DOM_INTERSECTION_OBSERVER_IID \
 { 0x8570a575, 0xe303, 0x4d18, \
   { 0xb6, 0xb1, 0x4d, 0x2b, 0x49, 0xd8, 0xef, 0x94 } }
 
 class DOMIntersectionObserver final : public nsISupports,
                                       public nsWrapperCache
 {
-  virtual ~DOMIntersectionObserver() {
-    Disconnect();
-  }
+  virtual ~DOMIntersectionObserver() { }
 
 public:
   DOMIntersectionObserver(already_AddRefed<nsPIDOMWindowInner>&& aOwner,
                           mozilla::dom::IntersectionCallback& aCb)
   : mOwner(aOwner), mCallback(&aCb), mConnected(false)
   {
   }
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -3864,54 +3864,54 @@ Element::ClearDataset()
 {
   nsDOMSlots *slots = GetExistingDOMSlots();
 
   MOZ_ASSERT(slots && slots->mDataset,
              "Slots should exist and dataset should not be null.");
   slots->mDataset = nullptr;
 }
 
-nsTArray<Element::nsDOMSlots::IntersectionObserverRegistration>*
+nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>*
 Element::RegisteredIntersectionObservers()
 {
   nsDOMSlots* slots = DOMSlots();
   return &slots->mRegisteredIntersectionObservers;
 }
 
 void
 Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver)
 {
-  RegisteredIntersectionObservers()->AppendElement(
-    nsDOMSlots::IntersectionObserverRegistration { aObserver, -1 });
+  nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
+    RegisteredIntersectionObservers();
+  if (observers->Contains(aObserver)) {
+    return;
+  }
+  RegisteredIntersectionObservers()->Put(aObserver, -1);
 }
 
 void
 Element::UnregisterIntersectionObserver(DOMIntersectionObserver* aObserver)
 {
-  nsTArray<nsDOMSlots::IntersectionObserverRegistration>* observers =
+  nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
     RegisteredIntersectionObservers();
-  for (uint32_t i = 0; i < observers->Length(); ++i) {
-    nsDOMSlots::IntersectionObserverRegistration reg = observers->ElementAt(i);
-    if (reg.observer == aObserver) {
-      observers->RemoveElementAt(i);
-      break;
-    }
-  }
+  observers->Remove(aObserver);
 }
 
 bool
 Element::UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32_t aThreshold)
 {
-  nsTArray<nsDOMSlots::IntersectionObserverRegistration>* observers =
+  nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
     RegisteredIntersectionObservers();
-  for (auto& reg : *observers) {
-    if (reg.observer == aObserver && reg.previousThreshold != aThreshold) {
-      reg.previousThreshold = aThreshold;
-      return true;
-    }
+  if (!observers->Contains(aObserver)) {
+    return false;
+  }
+  int32_t previousThreshold = observers->Get(aObserver);
+  if (previousThreshold != aThreshold) {
+    observers->Put(aObserver, aThreshold);
+    return true;
   }
   return false;
 }
 
 void
 Element::ClearServoData() {
 #ifdef MOZ_STYLO
   Servo_Element_ClearData(this);
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -1418,17 +1418,17 @@ protected:
    * the value of xlink:show, converted to a suitably equivalent named target
    * (e.g. _blank).
    */
   virtual void GetLinkTarget(nsAString& aTarget);
 
   nsDOMTokenList* GetTokenList(nsIAtom* aAtom,
                                const DOMTokenListSupportedTokenArray aSupportedTokens = nullptr);
 
-  nsTArray<nsDOMSlots::IntersectionObserverRegistration>* RegisteredIntersectionObservers();
+  nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t>* RegisteredIntersectionObservers();
 
 private:
   /**
    * Get this element's client area rect in app units.
    * @return the frame's client area
    */
   nsRect GetClientAreaRect();
 
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -16,16 +16,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsAttrAndChildArray.h"          // member
 #include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_*
 #include "nsIContent.h"                   // base class
 #include "nsIWeakReference.h"             // base class
 #include "nsNodeUtils.h"                  // class member nsNodeUtils::CloneNodeImpl
 #include "nsIHTMLCollection.h"
+#include "nsDataHashtable.h"
 
 class ContentUnbinder;
 class nsContentList;
 class nsDOMAttributeMap;
 class nsDOMTokenList;
 class nsIControllers;
 class nsICSSDeclaration;
 class nsIDocument;
@@ -342,22 +343,17 @@ public:
     /**
      * Web components custom element data.
      */
     RefPtr<CustomElementData> mCustomElementData;
 
     /**
      * Registered Intersection Observers on the element.
      */
-    struct IntersectionObserverRegistration {
-      DOMIntersectionObserver* observer;
-      int32_t previousThreshold;
-    };
-
-    nsTArray<IntersectionObserverRegistration> mRegisteredIntersectionObservers;
+    nsDataHashtable<nsPtrHashKey<DOMIntersectionObserver>, int32_t> mRegisteredIntersectionObservers;
   };
 
 protected:
   void GetMarkup(bool aIncludeSelf, nsAString& aMarkup);
   void SetInnerHTMLInternal(const nsAString& aInnerHTML, ErrorResult& aError);
 
   // Override from nsINode
   virtual nsINode::nsSlots* CreateSlots() override;
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -296,18 +296,19 @@ nsNodeUtils::LastRelease(nsINode* aNode)
                                          nsIMutationObserver,
                                          NodeWillBeDestroyed, (aNode));
     }
 
     if (aNode->IsElement()) {
       Element* elem = aNode->AsElement();
       FragmentOrElement::nsDOMSlots* domSlots =
         static_cast<FragmentOrElement::nsDOMSlots*>(slots);
-      for (auto& reg : domSlots->mRegisteredIntersectionObservers) {
-        reg.observer->UnlinkTarget(*elem);
+      for (auto iter = domSlots->mRegisteredIntersectionObservers.Iter(); !iter.Done(); iter.Next()) {
+        DOMIntersectionObserver* observer = iter.Key();
+        observer->UnlinkTarget(*elem);
       }
     }
 
     delete slots;
     aNode->mSlots = nullptr;
   }
 
   // Kill properties first since that may run external code, so we want to
--- a/dom/base/test/test_intersectionobservers.html
+++ b/dom/base/test/test_intersectionobservers.html
@@ -886,16 +886,29 @@ limitations under the License.
           expect(e.data).to.be.ok();
           win.close();
           done();
         };
 
         var win = window.open("intersectionobserver_window.html");
       });
 
+      it('triggers only once if observed multiple times (and does not crash when collected)', function(done) {
+        var spy = sinon.spy();
+        io = new IntersectionObserver(spy, {root: rootEl});
+        io.observe(targetEl1);
+        io.observe(targetEl1);
+        io.observe(targetEl1);
+
+        callDelayed(function () {
+          expect(spy.callCount).to.be(1);
+          done();
+        }, ASYNC_TIMEOUT);
+      });
+
     });
 
     describe('observe subframe', function () {
       
       it('should not trigger if target and root are not in the same document',
           function(done) {
 
         var spy = sinon.spy();
--- a/dom/events/test/pointerevents/mochitest_support_external.js
+++ b/dom/events/test/pointerevents/mochitest_support_external.js
@@ -30,94 +30,176 @@ function turnOnPointerEvents(callback) {
   SpecialPowers.pushPrefEnv({
     "set": [
       ["dom.w3c_pointer_events.enabled", true],
       ["layout.css.touch_action.enabled", true]
     ]
   }, callback);
 }
 
+// Mouse Event Helper Object
+var MouseEventHelper = (function() {
+  var utils = SpecialPowers.Ci.nsIDOMWindowUtils;
+
+  return {
+    // State
+    // TODO: Separate this to support mouse and pen simultaneously.
+    BUTTONS_STATE: utils.MOUSE_BUTTONS_NO_BUTTON,
+
+    // Button
+    BUTTON_NONE:   -1, // Used by test framework only. (replaced before sending)
+    BUTTON_LEFT:   utils.MOUSE_BUTTON_LEFT_BUTTON,
+    BUTTON_MIDDLE: utils.MOUSE_BUTTON_MIDDLE_BUTTON,
+    BUTTON_RIGHT:  utils.MOUSE_BUTTON_RIGHT_BUTTON,
+
+    // Buttons
+    BUTTONS_NONE:   utils.MOUSE_BUTTONS_NO_BUTTON,
+    BUTTONS_LEFT:   utils.MOUSE_BUTTONS_LEFT_BUTTON,
+    BUTTONS_MIDDLE: utils.MOUSE_BUTTONS_MIDDLE_BUTTON,
+    BUTTONS_RIGHT:  utils.MOUSE_BUTTONS_RIGHT_BUTTON,
+    BUTTONS_4TH:    utils.MOUSE_BUTTONS_4TH_BUTTON,
+    BUTTONS_5TH:    utils.MOUSE_BUTTONS_5TH_BUTTON,
+
+    // Utils
+    computeButtonsMaskFromButton: function(aButton) {
+      // Since the range of button values is 0 ~ 2 (see nsIDOMWindowUtils.idl),
+      // we can use an array to find out the desired mask.
+      var mask = [
+        this.BUTTONS_NONE,   // -1 (MouseEventHelper.BUTTON_NONE)
+        this.BUTTONS_LEFT,   // 0
+        this.BUTTONS_MIDDLE, // 1
+        this.BUTTONS_RIGHT   // 2
+      ][aButton + 1];
+
+      ok(mask !== undefined, "Unrecognized button value caught!");
+      return mask;
+    },
+
+    checkExitState: function() {
+      ok(!this.BUTTONS_STATE, "Mismatched mousedown/mouseup caught.");
+    }
+  };
+}) ();
+
 // Helper function to send MouseEvent with different parameters
 function sendMouseEvent(int_win, elemId, mouseEventType, params) {
   var elem = int_win.document.getElementById(elemId);
   if(!!elem) {
     var rect = elem.getBoundingClientRect();
     var eventObj = {type: mouseEventType};
-    if(params && "button" in params)
-      eventObj.button = params.button;
+
     if(params && "inputSource" in params)
       eventObj.inputSource = params.inputSource;
-    if(params && "buttons" in params)
-      eventObj.buttons = params.buttons;
+
+    // Check or generate a |button| value.
+    var isButtonEvent = mouseEventType === "mouseup" ||
+                        mouseEventType === "mousedown";
+
+    // Set |button| to the default value first.
+    eventObj.button = isButtonEvent ? MouseEventHelper.BUTTON_LEFT
+                                    : MouseEventHelper.BUTTON_NONE;
+
+    // |button| is passed, use and check it.
+    if (params && "button" in params) {
+      var hasButtonValue = (params.button !== MouseEventHelper.BUTTON_NONE);
+      ok(!isButtonEvent || hasButtonValue,
+         "Inappropriate |button| value caught.");
+      eventObj.button = params.button;
+    }
+
+    // Generate a |buttons| value and update buttons state
+    var buttonsMask = MouseEventHelper.computeButtonsMaskFromButton(eventObj.button);
+    switch(mouseEventType) {
+      case "mousedown":
+        MouseEventHelper.BUTTONS_STATE |= buttonsMask; // Set button flag.
+        break;
+      case "mouseup":
+        MouseEventHelper.BUTTONS_STATE &= ~buttonsMask; // Clear button flag.
+        break;
+    }
+    eventObj.buttons = MouseEventHelper.BUTTONS_STATE;
+
+    // Replace the button value for mousemove events.
+    // Since in widget level design, even when no button is pressed at all, the
+    // value of WidgetMouseEvent.button is still 0, which is the same value as
+    // the one for mouse left button.
+    if (mouseEventType === "mousemove") {
+      eventObj.button = MouseEventHelper.BUTTON_LEFT;
+    }
 
     // Default to the center of the target element but we can still send to a
     // position outside of the target element.
     var offsetX = params && "offsetX" in params ? params.offsetX : rect.width / 2;
     var offsetY = params && "offsetY" in params ? params.offsetY : rect.height / 2;
 
     console.log(elemId, eventObj);
     synthesizeMouse(elem, offsetX, offsetY, eventObj, int_win);
 
   } else {
     is(!!elem, true, "Document should have element with id: " + elemId);
   }
 }
 
+// Touch Event Helper Object
+var TouchEventHelper = {
+  // State
+  // TODO: Support multiple point scenarios.
+  TOUCH_STATE: false,
+
+  // Utils
+  checkExitState: function() {
+    ok(!this.TOUCH_STATE, "Mismatched touchstart/touchend caught.");
+  }
+}
+
 // Helper function to send TouchEvent with different parameters
 function sendTouchEvent(int_win, elemId, touchEventType, params) {
   var elem = int_win.document.getElementById(elemId);
   if(!!elem) {
     var rect = elem.getBoundingClientRect();
     var eventObj = {type: touchEventType};
 
+    // Update touch state
+    switch(touchEventType) {
+      case "touchstart":
+        TouchEventHelper.TOUCH_STATE = true; // Set touch flag.
+        break;
+      case "touchend":
+        TouchEventHelper.TOUCH_STATE = false; // Clear touch flag.
+        break;
+    }
+
     // Default to the center of the target element but we can still send to a
     // position outside of the target element.
     var offsetX = params && "offsetX" in params ? params.offsetX : rect.width / 2;
     var offsetY = params && "offsetY" in params ? params.offsetY : rect.height / 2;
 
     console.log(elemId, eventObj);
     synthesizeTouch(elem, offsetX, offsetY, eventObj, int_win);
   } else {
     is(!!elem, true, "Document should have element with id: " + elemId);
   }
 }
 
 // Helper function to run Point Event test in a new tab.
 function runTestInNewWindow(aFile) {
-  var w = window.open('', "_blank");
-  w.is = function(a, b, msg) { return is(a, b, aFile + " | " + msg); };
-  w.ok = function(cond, name, diag) { return ok(cond, aFile + " | " + name, diag); };
-  w.location = location.href.substring(0, location.href.lastIndexOf('/') + 1) + aFile;
-
-  w.testContext = {
-    result_callback: (aTestObj) => {
-      if(aTestObj["status"] != aTestObj["PASS"]) {
-        console.log(aTestObj["status"] + " = " + aTestObj["PASS"] + ". " + aTestObj["name"]);
-      }
-      is(aTestObj["status"], aTestObj["PASS"], aTestObj["name"]);
-    },
+  var testURL = location.href.substring(0, location.href.lastIndexOf('/') + 1) + aFile;
+  var testWindow = window.open(testURL, "_blank");
 
-    completion_callback: () => {
-      if (!!w.testContext.executionPromise) {
-        // We need to wait tests done and execute finished then we can close the window
-        w.testContext.executionPromise.then(() => {
-          w.close();
-          SimpleTest.finish();
-        });        
-      } else {
-        // execute may synchronous trigger tests done. In that case executionPromise
-        // is not yet assigned 
-        w.close();
+  window.addEventListener("message", function(aEvent) {
+    switch(aEvent.data.type) {
+      case "START":
+        turnOnPointerEvents(() => {
+          executeTest(testWindow);
+        });
+        return;
+      case "RESULT":
+        ok(aEvent.data.result, aEvent.data.message);
+        return;
+      case "FIN":
+        MouseEventHelper.checkExitState();
+        TouchEventHelper.checkExitState();
+        testWindow.close();
         SimpleTest.finish();
-      }
-    },
-
-    execute: (aWindow) => {
-      turnOnPointerEvents(() => {
-        w.testContext.executionPromise = new Promise((aResolve, aReject) => {
-          executeTest(aWindow);
-          aResolve();
-        });
-      });
+        return;
     }
-  };
-  return w;
+  });
 }
--- a/dom/events/test/pointerevents/mochitest_support_internal.js
+++ b/dom/events/test/pointerevents/mochitest_support_internal.js
@@ -1,27 +1,40 @@
 // This file supports translating W3C tests
 // to tests on auto MochiTest system with minimum changes.
 // Author: Maksim Lebedev <alessarik@gmail.com>
 
-// Function allows to prepare our tests after load document
-addEventListener("load", function(event) {
+const PARENT_ORIGIN = "http://mochi.test:8888/";
+
+addEventListener("load", function() {
+  // Setup environment.
   console.log("OnLoad internal document");
   addListeners(document.getElementById("target0"));
   addListeners(document.getElementById("target1"));
-  preExecute();
-}, false);
 
-// Function allows to initialize prerequisites before testing
-// and adds some callbacks to support mochitest system.
-function preExecute() {
-  add_result_callback(testContext.result_callback);
-  add_completion_callback(testContext.completion_callback);
-  testContext.execute(window);
-}
+  // Setup communication between mochitest_support_external.js.
+  // Function allows to initialize prerequisites before testing
+  // and adds some callbacks to support mochitest system.
+  add_result_callback((aTestObj) => {
+    var message = aTestObj["name"] + " (";
+    message += "Get: " + JSON.stringify(aTestObj["status"]) + ", ";
+    message += "Expect: " + JSON.stringify(aTestObj["PASS"]) + ")";
+    window.opener.postMessage({type: "RESULT",
+                               message: message,
+                               result: aTestObj["status"] === aTestObj["PASS"]},
+                              PARENT_ORIGIN);
+  });
+
+  add_completion_callback(() => {
+    window.opener.postMessage({type: "FIN"}, PARENT_ORIGIN);
+  });
+
+  // Start testing.
+  window.opener.postMessage({type: "START"}, PARENT_ORIGIN);
+});
 
 function addListeners(elem) {
   if(!elem)
     return;
   var All_Events = ["pointerdown","pointerup","pointercancel","pointermove","pointerover","pointerout",
                     "pointerenter","pointerleave","gotpointercapture","lostpointercapture"];
   All_Events.forEach(function(name) {
     elem.addEventListener(name, function(event) {
--- a/dom/events/test/pointerevents/test_pointerevent_attributes_mouse-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_attributes_mouse-manual.html
@@ -12,22 +12,20 @@ https://bugzilla.mozilla.org/show_bug.cg
     <script type="text/javascript" src="mochitest_support_external.js"></script>
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_attributes_mouse-manual.html");
       }
       function executeTest(int_win) {
-        sendMouseEvent(int_win, "square1", "mousemove", {button:-1});
-        sendMouseEvent(int_win, "square1", "mousedown", {button:0});
-        sendMouseEvent(int_win, "square1", "mouseup",   {button:0});
-        sendMouseEvent(int_win, "square1", "mousemove", {button:-1});
-        sendMouseEvent(int_win, "square1", "mousemove", {button:-1,
-                                                         offsetX: -1,
-                                                         offsetY: -1});
+        sendMouseEvent(int_win, "square1", "mousemove");
+        sendMouseEvent(int_win, "square1", "mousedown");
+        sendMouseEvent(int_win, "square1", "mouseup");
+        sendMouseEvent(int_win, "square1", "mousemove");
+        sendMouseEvent(int_win, "square1", "mousemove", {offsetX: -1, offSetY: -1});
       }
     </script>
   </head>
   <body>
   </body>
 </html>
 
--- a/dom/events/test/pointerevents/test_pointerevent_capture_mouse-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_capture_mouse-manual.html
@@ -15,17 +15,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_capture_mouse-manual.html");
       }
       function executeTest(int_win) {
         sendMouseEvent(int_win, "btnCapture", "mousemove");
         sendMouseEvent(int_win, "target0",    "mousemove");
         sendMouseEvent(int_win, "target1",    "mousemove");
-        sendMouseEvent(int_win, "btnCapture", "mousedown", {button:1});
+        sendMouseEvent(int_win, "btnCapture", "mousedown");
         sendMouseEvent(int_win, "target1",    "mousemove");
         sendMouseEvent(int_win, "target1",    "mouseup");
         sendMouseEvent(int_win, "target1",    "mousemove");
       }
     </script>
   </head>
   <body>
   </body>
--- a/dom/events/test/pointerevents/test_pointerevent_capture_suppressing_mouse-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_capture_suppressing_mouse-manual.html
@@ -14,17 +14,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_capture_suppressing_mouse-manual.html");
       }
       function executeTest(int_win) {
         sendMouseEvent(int_win, "target0",    "mousemove");
         sendMouseEvent(int_win, "target1",    "mousemove");
-        sendMouseEvent(int_win, "btnCapture", "mousedown", {button:1});
+        sendMouseEvent(int_win, "btnCapture", "mousedown");
         sendMouseEvent(int_win, "target1",    "mousemove");
         sendMouseEvent(int_win, "target0",    "mousemove");
         sendMouseEvent(int_win, "target1",    "mousemove");
         sendMouseEvent(int_win, "target1",    "mouseup");
         sendMouseEvent(int_win, "target1",    "mousemove");
       }
     </script>
   </head>
--- a/dom/events/test/pointerevents/test_pointerevent_element_haspointercapture-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_element_haspointercapture-manual.html
@@ -13,20 +13,20 @@ https://bugzilla.mozilla.org/show_bug.cg
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_element_haspointercapture-manual.html");
       }
       function executeTest(int_win) {
         sendMouseEvent(int_win, "target0", "mousemove");
-        sendMouseEvent(int_win, "target0", "mousedown", {button:0});
-        sendMouseEvent(int_win, "target0", "mousemove", {button:0});
-        sendMouseEvent(int_win, "target1", "mousemove", {button:0});
-        sendMouseEvent(int_win, "target1", "mouseup", {button:0});
-        sendMouseEvent(int_win, "target1", "mousedown", {button:0});
-        sendMouseEvent(int_win, "target1", "mouseup", {button:0});
+        sendMouseEvent(int_win, "target0", "mousedown");
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "target1", "mousemove");
+        sendMouseEvent(int_win, "target1", "mouseup");
+        sendMouseEvent(int_win, "target1", "mousedown");
+        sendMouseEvent(int_win, "target1", "mouseup");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_element_haspointercapture_release_pending_capture-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_element_haspointercapture_release_pending_capture-manual.html
@@ -13,18 +13,18 @@ https://bugzilla.mozilla.org/show_bug.cg
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_element_haspointercapture_release_pending_capture-manual.html");
       }
       function executeTest(int_win) {
         sendMouseEvent(int_win, "target0", "mousemove");
-        sendMouseEvent(int_win, "target0", "mousedown", {button:0});
-        sendMouseEvent(int_win, "target0", "mousemove", {button:0});
-        sendMouseEvent(int_win, "target1", "mousemove", {button:0});
-        sendMouseEvent(int_win, "target1", "mouseup", {button:0});
+        sendMouseEvent(int_win, "target0", "mousedown");
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "target1", "mousemove");
+        sendMouseEvent(int_win, "target1", "mouseup");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_gotpointercapture_before_first_pointerevent-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_gotpointercapture_before_first_pointerevent-manual.html
@@ -12,16 +12,16 @@ https://bugzilla.mozilla.org/show_bug.cg
     <script type="text/javascript" src="mochitest_support_external.js"></script>
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_gotpointercapture_before_first_pointerevent-manual.html");
       }
       function executeTest(int_win) {
-        sendMouseEvent(int_win, "target0", "mousedown", {button:0});
-        sendMouseEvent(int_win, "target0", "mouseup",   {button:0});
+        sendMouseEvent(int_win, "target0", "mousedown");
+        sendMouseEvent(int_win, "target0", "mouseup");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_lostpointercapture_for_disconnected_node-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_lostpointercapture_for_disconnected_node-manual.html
@@ -17,15 +17,16 @@ https://bugzilla.mozilla.org/show_bug.cg
       function startTest() {
         runTestInNewWindow("pointerevent_lostpointercapture_for_disconnected_node-manual.html");
       }
       function executeTest(int_win) {
         sendMouseEvent(int_win, "btnCapture", "mousedown");
         sendMouseEvent(int_win, "btnCapture", "mousemove");
         setTimeout(function() {
           sendMouseEvent(int_win, "target1", "mousemove");
+          sendMouseEvent(int_win, "target1", "mouseup");
         }, 500);
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_lostpointercapture_is_first-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_lostpointercapture_is_first-manual.html
@@ -12,17 +12,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     <script type="text/javascript" src="mochitest_support_external.js"></script>
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_lostpointercapture_is_first-manual.html");
       }
       function executeTest(int_win) {
-        sendMouseEvent(int_win, "btnCapture", "mousedown", {button:0});
-        sendMouseEvent(int_win, "btnCapture", "mouseup", {button:0});
+        sendMouseEvent(int_win, "btnCapture", "mousedown");
+        sendMouseEvent(int_win, "btnCapture", "mouseup");
         sendMouseEvent(int_win, "btnCapture", "mousemove");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_multiple_primary_pointers_boundary_events-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_multiple_primary_pointers_boundary_events-manual.html
@@ -16,16 +16,16 @@ https://bugzilla.mozilla.org/show_bug.cg
       function startTest() {
         runTestInNewWindow("pointerevent_multiple_primary_pointers_boundary_events-manual.html");
       }
       function executeTest(int_win) {
         sendMouseEvent(int_win, "target0", "mousemove");
         sendTouchEvent(int_win, "target1", "touchstart");
         sendTouchEvent(int_win, "target1", "touchend");
         sendMouseEvent(int_win, "target0", "mousemove");
-        sendMouseEvent(int_win, "done",    "mousedown", {button:0});
-        sendMouseEvent(int_win, "done",    "mouseup",   {button:0});
+        sendMouseEvent(int_win, "done",    "mousedown");
+        sendMouseEvent(int_win, "done",    "mouseup");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_pointercancel_touch-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_pointercancel_touch-manual.html
@@ -14,14 +14,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_pointercancel_touch-manual.html");
       }
       function executeTest(int_win) {
         sendTouchEvent(int_win, "target0", "touchstart");
         sendTouchEvent(int_win, "target0", "touchcancel");
+
+        // Need a touchend event to terminated the test gracefully.
+        sendTouchEvent(int_win, "target0", "touchend");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_pointerdown-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_pointerdown-manual.html
@@ -13,16 +13,16 @@ https://bugzilla.mozilla.org/show_bug.cg
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_pointerdown-manual.html");
       }
       function executeTest(int_win) {
         sendMouseEvent(int_win, "log",     "mousemove");
-        sendMouseEvent(int_win, "target0", "mousedown", {button:1});
+        sendMouseEvent(int_win, "target0", "mousedown");
         sendMouseEvent(int_win, "target0", "mouseup");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_pointerenter-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_pointerenter-manual.html
@@ -13,14 +13,15 @@ https://bugzilla.mozilla.org/show_bug.cg
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_pointerenter-manual.html");
       }
       function executeTest(int_win) {
         sendMouseEvent(int_win, "target0", "mousedown");
+        sendMouseEvent(int_win, "target0", "mouseup");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_pointerleave_after_pointercancel_touch-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_pointerleave_after_pointercancel_touch-manual.html
@@ -14,14 +14,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_pointerleave_after_pointercancel_touch-manual.html");
       }
       function executeTest(int_win) {
         sendTouchEvent(int_win, "target0", "touchstart");
         sendTouchEvent(int_win, "target0", "touchcancel");
+
+        // Need a touchend event to terminated the test gracefully.
+        sendTouchEvent(int_win, "target0", "touchend");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_pointermove-on-chorded-mouse-button.html
+++ b/dom/events/test/pointerevents/test_pointerevent_pointermove-on-chorded-mouse-button.html
@@ -13,25 +13,22 @@ https://bugzilla.mozilla.org/show_bug.cg
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_pointermove-on-chorded-mouse-button.html");
       }
 
       function executeTest(int_win) {
-        var utils = _getDOMWindowUtils(int_win);
-        sendMouseEvent(int_win, "target0", "mousemove", {button:0, buttons:utils.MOUSE_BUTTONS_NO_BUTTON});
-        sendMouseEvent(int_win, "target0", "mousedown", {button:0, buttons:utils.MOUSE_BUTTONS_LEFT_BUTTON});
-        sendMouseEvent(int_win, "target0", "mousemove", {button:0, buttons:utils.MOUSE_BUTTONS_LEFT_BUTTON});
-        sendMouseEvent(int_win, "target0", "mousedown", {button:1, buttons:utils.MOUSE_BUTTONS_LEFT_BUTTON |
-                                                                           utils.MOUSE_BUTTONS_MIDDLE_BUTTON});
-        sendMouseEvent(int_win, "target0", "mousemove", {button:1, buttons:utils.MOUSE_BUTTONS_LEFT_BUTTON |
-                                                                           utils.MOUSE_BUTTONS_MIDDLE_BUTTON});
-        sendMouseEvent(int_win, "target0", "mouseup", {button:1, buttons:utils.MOUSE_BUTTONS_LEFT_BUTTON});
-        sendMouseEvent(int_win, "target0", "mousemove", {button:1, buttons:utils.MOUSE_BUTTONS_LEFT_BUTTON});
-        sendMouseEvent(int_win, "target0", "mouseup", {button:0, buttons:utils.MOUSE_BUTTONS_NO_BUTTON});
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "target0", "mousedown", {button: MouseEventHelper.BUTTON_LEFT});
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "target0", "mousedown", {button: MouseEventHelper.BUTTON_MIDDLE});
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "target0", "mouseup", {button: MouseEventHelper.BUTTON_MIDDLE});
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "target0", "mouseup", {button: MouseEventHelper.BUTTON_LEFT});
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_pointermove_pointertype-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_pointermove_pointertype-manual.html
@@ -14,14 +14,15 @@ https://bugzilla.mozilla.org/show_bug.cg
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_pointermove_pointertype-manual.html");
       }
       function executeTest(int_win) {
         sendMouseEvent(int_win, "target0", "mousedown");
         sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "target0", "mouseup");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_pointerout_after_pointercancel_touch-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_pointerout_after_pointercancel_touch-manual.html
@@ -14,14 +14,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_pointerout_after_pointercancel_touch-manual.html");
       }
       function executeTest(int_win) {
         sendTouchEvent(int_win, "target0", "touchstart");
         sendTouchEvent(int_win, "target0", "touchcancel");
+
+        // Need a touchend event to terminated the test gracefully.
+        sendTouchEvent(int_win, "target0", "touchend");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_pointertype_mouse-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_pointertype_mouse-manual.html
@@ -12,16 +12,16 @@ https://bugzilla.mozilla.org/show_bug.cg
     <script type="text/javascript" src="mochitest_support_external.js"></script>
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_pointertype_mouse-manual.html");
       }
       function executeTest(int_win) {
-        sendMouseEvent(int_win, "target0", "mousedown", {button:0});
-        sendMouseEvent(int_win, "target0", "mouseup", {button:0});
+        sendMouseEvent(int_win, "target0", "mousedown");
+        sendMouseEvent(int_win, "target0", "mouseup");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_pointerup_isprimary_same_as_pointerdown-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_pointerup_isprimary_same_as_pointerdown-manual.html
@@ -12,16 +12,16 @@ https://bugzilla.mozilla.org/show_bug.cg
     <script type="text/javascript" src="mochitest_support_external.js"></script>
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_pointerup_isprimary_same_as_pointerdown-manual.html");
       }
       function executeTest(int_win) {
-        sendMouseEvent(int_win, "target0", "mousedown", {button:0});
-        sendMouseEvent(int_win, "target0", "mouseup", {button:0});
+        sendMouseEvent(int_win, "target0", "mousedown");
+        sendMouseEvent(int_win, "target0", "mouseup");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_releasepointercapture_invalid_pointerid-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_releasepointercapture_invalid_pointerid-manual.html
@@ -14,14 +14,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_releasepointercapture_invalid_pointerid-manual.html");
       }
       function executeTest(int_win) {
         sendTouchEvent(int_win, "target0", "touchstart");
         sendTouchEvent(int_win, "target0", "touchmove");
+
+        // Need a touchend event to terminated the test gracefully.
+        sendTouchEvent(int_win, "target0", "touchend");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_releasepointercapture_onpointercancel_touch-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_releasepointercapture_onpointercancel_touch-manual.html
@@ -14,14 +14,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_releasepointercapture_onpointercancel_touch-manual.html");
       }
       function executeTest(int_win) {
         sendTouchEvent(int_win, "target0", "touchstart");
         sendTouchEvent(int_win, "target0", "touchcancel");
+
+        // Need a touchend event to terminated the test gracefully.
+        sendTouchEvent(int_win, "target0", "touchend");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_releasepointercapture_release_right_after_capture-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_releasepointercapture_release_right_after_capture-manual.html
@@ -12,19 +12,19 @@ https://bugzilla.mozilla.org/show_bug.cg
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_releasepointercapture_release_right_after_capture-manual.html");
       }
       function executeTest(int_win) {
         sendMouseEvent(int_win, "target0", "mousemove");
-        sendMouseEvent(int_win, "target0", "mousedown", {button:0});
-        sendMouseEvent(int_win, "target0", "mousemove", {button:0});
-        sendMouseEvent(int_win, "target0", "mousemove", {button:0});
-        sendMouseEvent(int_win, "target0", "mousemove", {button:0});
-        sendMouseEvent(int_win, "target0", "mouseup", {button:0});
+        sendMouseEvent(int_win, "target0", "mousedown");
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "target0", "mouseup");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_setpointercapture_invalid_pointerid-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_setpointercapture_invalid_pointerid-manual.html
@@ -13,14 +13,15 @@ https://bugzilla.mozilla.org/show_bug.cg
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_setpointercapture_invalid_pointerid-manual.html");
       }
       function executeTest(int_win) {
         sendMouseEvent(int_win, "target0", "mousedown");
+        sendMouseEvent(int_win, "target0", "mouseup");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_setpointercapture_override_pending_capture_element-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_setpointercapture_override_pending_capture_element-manual.html
@@ -13,19 +13,19 @@ https://bugzilla.mozilla.org/show_bug.cg
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_setpointercapture_override_pending_capture_element-manual.html");
       }
       function executeTest(int_win) {
         sendMouseEvent(int_win, "target0", "mousemove");
-        sendMouseEvent(int_win, "target0", "mousedown", {button:0});
-        sendMouseEvent(int_win, "target0", "mousemove", {button:0});
-        sendMouseEvent(int_win, "target0", "mousemove", {button:0});
-        sendMouseEvent(int_win, "target0", "mousemove", {button:0});
-        sendMouseEvent(int_win, "target0", "mouseup", {button:0});
+        sendMouseEvent(int_win, "target0", "mousedown");
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "target0", "mouseup");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_setpointercapture_to_same_element_twice-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_setpointercapture_to_same_element_twice-manual.html
@@ -13,19 +13,19 @@ https://bugzilla.mozilla.org/show_bug.cg
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_setpointercapture_to_same_element_twice-manual.html");
       }
       function executeTest(int_win) {
         sendMouseEvent(int_win, "target0", "mousemove");
-        sendMouseEvent(int_win, "target0", "mousedown", {button:0});
-        sendMouseEvent(int_win, "target0", "mousemove", {button:0});
-        sendMouseEvent(int_win, "target0", "mousemove", {button:0});
-        sendMouseEvent(int_win, "target0", "mousemove", {button:0});
-        sendMouseEvent(int_win, "target0", "mouseup", {button:0});
+        sendMouseEvent(int_win, "target0", "mousedown");
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "target0", "mouseup");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_suppress_compat_events_on_click.html
+++ b/dom/events/test/pointerevents/test_pointerevent_suppress_compat_events_on_click.html
@@ -12,20 +12,20 @@ https://bugzilla.mozilla.org/show_bug.cg
     <script type="text/javascript" src="mochitest_support_external.js"></script>
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_suppress_compat_events_on_click.html");
       }
       function executeTest(int_win) {
-        sendMouseEvent(int_win, "target0", "mousedown", {button:0});
-        sendMouseEvent(int_win, "target0", "mouseup",   {button:0});
-        sendMouseEvent(int_win, "target1", "mousedown", {button:0});
-        sendMouseEvent(int_win, "target1", "mouseup",   {button:0});
-        sendMouseEvent(int_win, "done",    "mousedown", {button:0});
-        sendMouseEvent(int_win, "done",    "mouseup",   {button:0});
+        sendMouseEvent(int_win, "target0", "mousedown");
+        sendMouseEvent(int_win, "target0", "mouseup");
+        sendMouseEvent(int_win, "target1", "mousedown");
+        sendMouseEvent(int_win, "target1", "mouseup");
+        sendMouseEvent(int_win, "done",    "mousedown");
+        sendMouseEvent(int_win, "done",    "mouseup");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/events/test/pointerevents/test_pointerevent_suppress_compat_events_on_drag_mouse.html
+++ b/dom/events/test/pointerevents/test_pointerevent_suppress_compat_events_on_drag_mouse.html
@@ -12,22 +12,22 @@ https://bugzilla.mozilla.org/show_bug.cg
     <script type="text/javascript" src="mochitest_support_external.js"></script>
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_suppress_compat_events_on_drag_mouse.html");
       }
       function executeTest(int_win) {
-        sendMouseEvent(int_win, "target0", "mousedown", {button:0});
-        sendMouseEvent(int_win, "target0", "mousemove", {button:0});
-        sendMouseEvent(int_win, "target0", "mouseup",   {button:0});
-        sendMouseEvent(int_win, "target1", "mousedown", {button:0});
-        sendMouseEvent(int_win, "target1", "mousemove", {button:0});
-        sendMouseEvent(int_win, "target1", "mouseup",   {button:0});
-        sendMouseEvent(int_win, "done",    "mousedown", {button:0});
-        sendMouseEvent(int_win, "done",    "mouseup",   {button:0});
+        sendMouseEvent(int_win, "target0", "mousedown");
+        sendMouseEvent(int_win, "target0", "mousemove");
+        sendMouseEvent(int_win, "target0", "mouseup");
+        sendMouseEvent(int_win, "target1", "mousedown");
+        sendMouseEvent(int_win, "target1", "mousemove");
+        sendMouseEvent(int_win, "target1", "mouseup");
+        sendMouseEvent(int_win, "done",    "mousedown");
+        sendMouseEvent(int_win, "done",    "mouseup");
       }
     </script>
   </head>
   <body>
   </body>
 </html>
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -1968,16 +1968,22 @@ interface nsIDOMWindowUtils : nsISupport
    */
   void terminateGPUProcess();
 
   /**
     * Returns the GPU process pid, or -1 if there is no GPU process.
     */
   readonly attribute int32_t gpuProcessPid;
 
+  // Match WidgetMouseEventBase::buttonType.
+  const long MOUSE_BUTTON_LEFT_BUTTON   = 0;
+  const long MOUSE_BUTTON_MIDDLE_BUTTON = 1;
+  const long MOUSE_BUTTON_RIGHT_BUTTON  = 2;
+
+  // Match WidgetMouseEventBase::buttonsFlag.
   const long MOUSE_BUTTONS_NO_BUTTON = 0x00;
   const long MOUSE_BUTTONS_LEFT_BUTTON = 0x01;
   const long MOUSE_BUTTONS_RIGHT_BUTTON = 0x02;
   const long MOUSE_BUTTONS_MIDDLE_BUTTON = 0x04;
   // Typically, "back" button being left side of 5-button
   // mice, see "buttons" attribute document of DOM3 Events.
   const long MOUSE_BUTTONS_4TH_BUTTON = 0x08;
   // Typically, "forward" button being right side of 5-button
--- 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',
 ]
 
 FINAL_LIBRARY = 'xul'
 
--- 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.4
 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;
+    return false;
   }
   if (np == 2)
-    cpdvowels = mystrdup("aeiouAEIOU");
-  return 0;
+    cpdvowels = "AEIOUaeiou";
+  return true;
 }
 
 /* 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') {
+  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;
+        }
+        reptable.reserve(numrep);
+        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 numrep lines to read in the remainder of the table */
+  for (int j = 0; j < numrep; ++j) {
+    std::string nl;
+    if (!af->getline(nl))
+      return false;
+    mychomp(nl);
+    reptable.push_back(replentry());
+    iter = nl.begin();
+    i = 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: {
-          numrep = atoi(piece);
-          if (numrep < 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);
           }
-          reptable = (replentry*)malloc(numrep * sizeof(struct replentry));
-          if (!reptable)
-            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 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;
+  /* now parse the num lines to read in the remainder of the table */
+  for (int j = 0; j < numrl; j++) {
+    std::string nl;
+    if (!af->getline(nl))
+      return false;
     mychomp(nl);
-    tp = nl;
     i = 0;
-    reptable[j].pattern = NULL;
-    reptable[j].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, "REP", 3) != 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());
-              numrep = 0;
-              return 1;
+              delete *rl;
+              *rl = NULL;
+              return false;
             }
             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;
+            pattern.assign(start_piece, iter);
             break;
           }
           case 2: {
-            reptable[j].pattern2 = mystrrep(mystrdup(piece), "_", " ");
+            pattern2.assign(start_piece, iter);
             break;
           }
           default:
             break;
         }
-        i++;
+        ++i;
       }
-      piece = mystrsep(&tp, 0);
+      start_piece = mystrsep(nl, iter);
     }
-    if ((!(reptable[j].pattern)) || (!(reptable[j].pattern2))) {
+    if (pattern.empty() || pattern2.empty()) {
       HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
                        af->getlinenum());
-      numrep = 0;
-      return 1;
+      return false;
     }
+    (*rl)->add(pattern, pattern2);
   }
-  return 0;
+  return true;
 }
 
 /* parse in the typical fault correcting table */
-int AffixMgr::parse_convtable(char* line,
-                              FileMgr* af,
-                              RepList** rl,
-                              const char* keyword) {
-  if (*rl) {
+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;
-  int numrl = 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: {
-          numrl = atoi(piece);
-          if (numrl < 1) {
-            HUNSPELL_WARNING(stderr, "error: line %d: incorrect entry number\n",
-                             af->getlinenum());
-            return 1;
-          }
-          *rl = new RepList(numrl);
-          if (!*rl)
-            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 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;
+  /* now parse the phone->num lines to read in the remainder of the table */
+  for (int j = 0; j < num; ++j) {
+    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') {
+    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, keyword, strlen(keyword)) != 0) {
+            if (nl.compare(start_piece - nl.begin(), 5, "PHONE", 5) != 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), "_", " ");
+            phone->rules.push_back(std::string(start_piece, iter));
             break;
           }
           case 2: {
-            pattern2 = 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 (!pattern || !pattern2) {
-      if (pattern)
-        free(pattern);
-      if (pattern2)
-        free(pattern2);
+    if (phone->rules.size() != old_size + 2) {
       HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
                        af->getlinenum());
-      return 1;
+      phone->rules.clear();
+      return false;
     }
-    (*rl)->add(pattern, pattern2);
   }
-  return 0;
+  phone->rules.push_back("");
+  phone->rules.push_back("");
+  init_phonet_hash(*phone);
+  return true;
 }
 
-/* parse in the typical fault correcting table */
-int AffixMgr::parse_phonetable(char* line, FileMgr* af) {
-  if (phone) {
+/* parse in the checkcompoundpattern table */
+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: {
-          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;
+          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());
           }
-          phone->rules = (char**)malloc(2 * (phone->num + 1) * sizeof(char*));
-          if (!phone->rules) {
-            free(phone);
-            phone = NULL;
-            return 1;
+          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());
           }
-          np++;
+          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 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;
+  /* 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;
-    phone->rules[j * 2] = NULL;
-    phone->rules[j * 2 + 1] = NULL;
-    piece = mystrsep(&tp, 0);
-    while (piece) {
-      if (*piece != '\0') {
-        switch (i) {
-          case 0: {
-            if (strncmp(piece, "PHONE", 5) != 0) {
-              HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                               af->getlinenum());
-              phone->num = 0;
-              return 1;
-            }
-            break;
-          }
-          case 1: {
-            phone->rules[j * 2] = mystrrep(mystrdup(piece), "_", "");
-            break;
-          }
-          case 2: {
-            phone->rules[j * 2 + 1] = mystrrep(mystrdup(piece), "_", "");
-            break;
-          }
-          default:
-            break;
-        }
-        i++;
-      }
-      piece = mystrsep(&tp, 0);
-    }
-    if ((!(phone->rules[j * 2])) || (!(phone->rules[j * 2 + 1]))) {
-      HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
-                       af->getlinenum());
-      phone->num = 0;
-      return 1;
-    }
-  }
-  phone->rules[phone->num * 2] = mystrdup("");
-  phone->rules[phone->num * 2 + 1] = mystrdup("");
-  init_phonet_hash(*phone);
-  return 0;
-}
-
-/* parse in the checkcompoundpattern table */
-int AffixMgr::parse_checkcpdtable(char* line, FileMgr* af) {
-  if (numcheckcpd != 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++;
-          break;
-        }
-        case 1: {
-          numcheckcpd = atoi(piece);
-          if (numcheckcpd < 1) {
-            HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
+          if (nl.compare(start_piece - nl.begin(), 12, "COMPOUNDRULE", 12) != 0) {
+            HUNSPELL_WARNING(stderr, "error: line %d: table is corrupt\n",
                              af->getlinenum());
-            return 1;
+            numdefcpd = 0;
+            return false;
           }
-          checkcpdtable =
-              (patentry*)malloc(numcheckcpd * sizeof(struct patentry));
-          if (!checkcpdtable)
-            return 1;
-          np++;
           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 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;
-    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);
+        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);
+              }
             }
-            break;
-          }
-          case 3: {
-            checkcpdtable[j].pattern3 = mystrdup(piece);
-            simplifiedcpd = 1;
-            break;
+          } else {
+            pHMgr->decode_flags(defcpdtable.back(), std::string(start_piece, iter), af);
           }
-          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') {
-      switch (i) {
-        case 0: {
-          np++;
-          break;
-        }
-        case 1: {
-          numdefcpd = atoi(piece);
-          if (numdefcpd < 1) {
-            HUNSPELL_WARNING(stderr, "error: line %d: bad entry number\n",
-                             af->getlinenum());
-            return 1;
-          }
-          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,42 +33,42 @@
  * 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)
 static inline void HUNSPELL_WARNING(FILE*, const char*, ...) {}
 #endif
 #endif
 
 // HUNSTEM def.
 #define HUNSTEM
 
-#include "hashmgr.hxx"
 #include "w_char.hxx"
 #include <algorithm>
 #include <string>
+#include <vector>
 
 #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];
+        (*result)[i] = ((unsigned short)((unsigned char)flags[i * 2]) << 8) +
+                       (unsigned char)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,60 +694,125 @@ 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)((unsigned char)flags[i * 2]) << 8) +
+                         (unsigned char)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];
+      s = ((unsigned short)((unsigned char)f[0]) << 8) + (unsigned char)f[1];
       break;
     case FLAG_NUM:
       i = atoi(f);
       if (i >= DEFAULTFLAGS)
         HUNSPELL_WARNING(stderr, "error: flag id %d is too large (max: %d)\n",
                          i, DEFAULTFLAGS - 1);
       s = (unsigned short)i;
       break;
     case FLAG_UNI: {
       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,112 +70,180 @@
  * 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;
+  struct cs_info* get_csconv();
+  std::vector<char> dic_encoding_vec;
+
+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)
     csconv = get_current_cs(encoding);
   complexprefixes = pAMgr->get_complexprefixes();
   wordbreak = pAMgr->get_breaktable();
 
+  dic_encoding_vec.resize(encoding.size()+1);
+  strcpy(&dic_encoding_vec[0], encoding.c_str());
+
   /* 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;