From e562e556902192fe8d4fd87610101bc996f8928c Mon Sep 17 00:00:00 2001
From: Michael R Sweet <michaelrsweet@users.noreply.github.com>
Date: Sat, 11 Jun 2016 20:51:49 +0000
Subject: [PATCH 1/2] mxmlDelete used a recursive algorithm which could require
 large amounts of stack space depending on the file (Bug #549)

Bump version to 2.10.
---
 CHANGES                      |   8 ++-
 configure                    |  54 +++++++++-------
 configure.in => configure.ac |   8 +--
 mxml-node.c                  | 148 +++++++++++++++++++++++++++++--------------
 4 files changed, 144 insertions(+), 74 deletions(-)
 rename configure.in => configure.ac (97%)

Index: mxml-2.5/mxml-node.c
===================================================================
--- mxml-2.5.orig/mxml-node.c	2017-03-10 12:22:21.868432973 +0100
+++ mxml-2.5/mxml-node.c	2017-03-10 12:22:23.860433914 +0100
@@ -46,6 +46,7 @@
  * Local functions...
  */
 
+static void		mxml_free(mxml_node_t *node);
 static mxml_node_t	*mxml_new(mxml_node_t *parent, mxml_type_t type);
 
 
@@ -197,7 +198,8 @@ mxmlAdd(mxml_node_t *parent,		/* I - Par
 void
 mxmlDelete(mxml_node_t *node)		/* I - Node to delete */
 {
-  int	i;				/* Looping var */
+  mxml_node_t	*current,		/* Current node */
+		*next;			/* Next node */
 
 
 #ifdef DEBUG
@@ -221,60 +223,50 @@ mxmlDelete(mxml_node_t *node)		/* I - No
   * Delete children...
   */
 
-  while (node->child)
-    mxmlDelete(node->child);
+  for (current = node->child; current; current = next)
+  {
+   /*
+    * Get the next node...
+    */
 
- /*
-  * Now delete any node data...
-  */
+    if ((next = current->child) != NULL)
+    {
+     /*
+      * Free parent nodes after child nodes have been freed...
+      */
 
-  switch (node->type)
-  {
-    case MXML_ELEMENT :
-        if (node->value.element.name)
-	  free(node->value.element.name);
+      current->child = NULL;
+      continue;
+    }
 
-	if (node->value.element.num_attrs)
-	{
-	  for (i = 0; i < node->value.element.num_attrs; i ++)
-	  {
-	    if (node->value.element.attrs[i].name)
-	      free(node->value.element.attrs[i].name);
-	    if (node->value.element.attrs[i].value)
-	      free(node->value.element.attrs[i].value);
-	  }
+    if ((next = current->next) == NULL)
+    {
+      mxml_node_t *temp = current->parent;
+					/* Pointer to parent node */
 
-          free(node->value.element.attrs);
-	}
-        break;
-    case MXML_INTEGER :
-       /* Nothing to do */
-        break;
-    case MXML_OPAQUE :
-        if (node->value.opaque)
-	  free(node->value.opaque);
-        break;
-    case MXML_REAL :
-       /* Nothing to do */
-        break;
-    case MXML_TEXT :
-        if (node->value.text.string)
-	  free(node->value.text.string);
-        break;
-    case MXML_CUSTOM :
-        if (node->value.custom.data &&
-	    node->value.custom.destroy)
-	  (*(node->value.custom.destroy))(node->value.custom.data);
-	break;
-    default :
-        break;
+      if (temp == node)
+      {
+       /*
+        * Got back to the top node...
+        */
+
+        next = NULL;
+      }
+      else if ((next = temp->next) == NULL)
+      {
+	if ((next = temp->parent) == node)
+	  next = NULL;
+      }
+    }
+
+    mxml_free(current);
   }
 
  /*
-  * Free this node...
+  * Then free the memory used by this node...
   */
 
-  free(node);
+  mxml_free(node);
 }
 
 
@@ -721,6 +713,68 @@ mxmlRetain(mxml_node_t *node)		/* I - No
 }
 
 
+/*
+ * 'mxml_free()' - Free the memory used by a node.
+ *
+ * Note: Does not free child nodes, does not remove from parent.
+ */
+
+static void
+mxml_free(mxml_node_t *node)		/* I - Node */
+{
+  int	i;				/* Looping var */
+
+
+  switch (node->type)
+  {
+    case MXML_ELEMENT :
+        if (node->value.element.name)
+	  free(node->value.element.name);
+
+	if (node->value.element.num_attrs)
+	{
+	  for (i = 0; i < node->value.element.num_attrs; i ++)
+	  {
+	    if (node->value.element.attrs[i].name)
+	      free(node->value.element.attrs[i].name);
+	    if (node->value.element.attrs[i].value)
+	      free(node->value.element.attrs[i].value);
+	  }
+
+          free(node->value.element.attrs);
+	}
+        break;
+    case MXML_INTEGER :
+       /* Nothing to do */
+        break;
+    case MXML_OPAQUE :
+        if (node->value.opaque)
+	  free(node->value.opaque);
+        break;
+    case MXML_REAL :
+       /* Nothing to do */
+        break;
+    case MXML_TEXT :
+        if (node->value.text.string)
+	  free(node->value.text.string);
+        break;
+    case MXML_CUSTOM :
+        if (node->value.custom.data &&
+	    node->value.custom.destroy)
+	  (*(node->value.custom.destroy))(node->value.custom.data);
+	break;
+    default :
+        break;
+  }
+
+ /*
+  * Free this node...
+  */
+
+  free(node);
+}
+
+
 /*
  * 'mxml_new()' - Create a new node.
  */
