back out change by mitch@convergence.de and apply patch in bug id #52067
authorCEST 2001 Paolo Molaro <lupus@ximian.com>
Thu, 24 May 2001 19:30:40 +0000 (19:30 +0000)
committerPaolo Molaro <lupus@src.gnome.org>
Thu, 24 May 2001 19:30:40 +0000 (19:30 +0000)
Thu May 24 21:24:16 CEST 2001 Paolo Molaro <lupus@ximian.com>

* gmarkup.c: back out change by mitch@convergence.de and apply patch in
bug id #52067 that fixes the same problem in a more complete manner.
This fixes also a segfault for a malformed XML file and adds a new
test case.

ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-12
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
glib/gmarkup.c
gmarkup.c
tests/markups/valid-3.gmarkup [new file with mode: 0644]

index ffde3ab..9656ae2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Thu May 24 21:24:16 CEST 2001 Paolo Molaro <lupus@ximian.com>
+
+       * gmarkup.c: back out change by mitch@convergence.de and apply patch in
+       bug id #52067 that fixes the same problem in a more complete manner.
+       This fixes also a segfault for a malformed XML file and adds a new
+       test case.
+
 2001-05-24  Hans Breuer  <hans@breuer.org>
 
        * grel.c : reflect renaming of g_string_sprintfa to g_string_printfa
index ffde3ab..9656ae2 100644 (file)
@@ -1,3 +1,10 @@
+Thu May 24 21:24:16 CEST 2001 Paolo Molaro <lupus@ximian.com>
+
+       * gmarkup.c: back out change by mitch@convergence.de and apply patch in
+       bug id #52067 that fixes the same problem in a more complete manner.
+       This fixes also a segfault for a malformed XML file and adds a new
+       test case.
+
 2001-05-24  Hans Breuer  <hans@breuer.org>
 
        * grel.c : reflect renaming of g_string_sprintfa to g_string_printfa
index ffde3ab..9656ae2 100644 (file)
@@ -1,3 +1,10 @@
+Thu May 24 21:24:16 CEST 2001 Paolo Molaro <lupus@ximian.com>
+
+       * gmarkup.c: back out change by mitch@convergence.de and apply patch in
+       bug id #52067 that fixes the same problem in a more complete manner.
+       This fixes also a segfault for a malformed XML file and adds a new
+       test case.
+
 2001-05-24  Hans Breuer  <hans@breuer.org>
 
        * grel.c : reflect renaming of g_string_sprintfa to g_string_printfa
index ffde3ab..9656ae2 100644 (file)
@@ -1,3 +1,10 @@
+Thu May 24 21:24:16 CEST 2001 Paolo Molaro <lupus@ximian.com>
+
+       * gmarkup.c: back out change by mitch@convergence.de and apply patch in
+       bug id #52067 that fixes the same problem in a more complete manner.
+       This fixes also a segfault for a malformed XML file and adds a new
+       test case.
+
 2001-05-24  Hans Breuer  <hans@breuer.org>
 
        * grel.c : reflect renaming of g_string_sprintfa to g_string_printfa
index ffde3ab..9656ae2 100644 (file)
@@ -1,3 +1,10 @@
+Thu May 24 21:24:16 CEST 2001 Paolo Molaro <lupus@ximian.com>
+
+       * gmarkup.c: back out change by mitch@convergence.de and apply patch in
+       bug id #52067 that fixes the same problem in a more complete manner.
+       This fixes also a segfault for a malformed XML file and adds a new
+       test case.
+
 2001-05-24  Hans Breuer  <hans@breuer.org>
 
        * grel.c : reflect renaming of g_string_sprintfa to g_string_printfa
index ffde3ab..9656ae2 100644 (file)
@@ -1,3 +1,10 @@
+Thu May 24 21:24:16 CEST 2001 Paolo Molaro <lupus@ximian.com>
+
+       * gmarkup.c: back out change by mitch@convergence.de and apply patch in
+       bug id #52067 that fixes the same problem in a more complete manner.
+       This fixes also a segfault for a malformed XML file and adds a new
+       test case.
+
 2001-05-24  Hans Breuer  <hans@breuer.org>
 
        * grel.c : reflect renaming of g_string_sprintfa to g_string_printfa
index ffde3ab..9656ae2 100644 (file)
@@ -1,3 +1,10 @@
+Thu May 24 21:24:16 CEST 2001 Paolo Molaro <lupus@ximian.com>
+
+       * gmarkup.c: back out change by mitch@convergence.de and apply patch in
+       bug id #52067 that fixes the same problem in a more complete manner.
+       This fixes also a segfault for a malformed XML file and adds a new
+       test case.
+
 2001-05-24  Hans Breuer  <hans@breuer.org>
 
        * grel.c : reflect renaming of g_string_sprintfa to g_string_printfa
index ffde3ab..9656ae2 100644 (file)
@@ -1,3 +1,10 @@
+Thu May 24 21:24:16 CEST 2001 Paolo Molaro <lupus@ximian.com>
+
+       * gmarkup.c: back out change by mitch@convergence.de and apply patch in
+       bug id #52067 that fixes the same problem in a more complete manner.
+       This fixes also a segfault for a malformed XML file and adds a new
+       test case.
+
 2001-05-24  Hans Breuer  <hans@breuer.org>
 
        * grel.c : reflect renaming of g_string_sprintfa to g_string_printfa
index 87d6091..e141db6 100644 (file)
@@ -38,36 +38,6 @@ g_markup_error_quark ()
   return error_quark;
 }
 
-typedef struct _GMarkupAttribute GMarkupAttribute;
-
-struct _GMarkupAttribute
-{
-  gchar *name;
-  gchar *value;
-};
-
-static GMarkupAttribute*
-attribute_new (const gchar *name, const gchar *value)
-{
-  GMarkupAttribute *attr;
-
-  attr = g_new (GMarkupAttribute, 1);
-
-  /* name/value are allowed to be NULL */
-  attr->name = g_strdup (name);
-  attr->value = g_strdup (value);
-
-  return attr;
-}
-
-static void
-attribute_free (GMarkupAttribute *attr)
-{
-  g_free (attr->name);
-  g_free (attr->value);
-  g_free (attr);
-}
-
 typedef enum
 {
   STATE_START,
@@ -106,7 +76,10 @@ struct _GMarkupParseContext
 
   GMarkupParseState state;
   GSList *tag_stack;
-  GSList *attributes;
+  gchar **attr_names;
+  gchar **attr_values;
+  gint cur_attr;
+  gint alloc_attrs;
 
   const gchar *current_text;
   gint         current_text_len;
@@ -162,7 +135,10 @@ g_markup_parse_context_new (const GMarkupParser *parser,
 
   context->state = STATE_START;
   context->tag_stack = NULL;
-  context->attributes = NULL;
+  context->attr_names = NULL;
+  context->attr_values = NULL;
+  context->cur_attr = -1;
+  context->alloc_attrs = 0;
 
   context->current_text = NULL;
   context->current_text_len = -1;
@@ -195,8 +171,8 @@ g_markup_parse_context_free (GMarkupParseContext *context)
   if (context->dnotify)
     (* context->dnotify) (context->user_data);
 
-  g_slist_foreach (context->attributes, (GFunc)attribute_free, NULL);
-  g_slist_free (context->attributes);
+  g_strfreev (context->attr_names);
+  g_strfreev (context->attr_values);
 
   g_slist_foreach (context->tag_stack, (GFunc)g_free, NULL);
   g_slist_free (context->tag_stack);
@@ -211,68 +187,6 @@ g_markup_parse_context_free (GMarkupParseContext *context)
 }
 
 static void
-attribute_list_to_arrays (GSList  *attributes,
-                          gchar ***namesp,
-                          gchar ***valuesp,
-                          gint    *n_attributes)
-{
-  GSList *tmp_list;
-  gint len;
-  gchar **names;
-  gchar **values;
-  gint i;
-
-  len = g_slist_length (attributes);
-
-  if (namesp)
-    {
-      names = g_new (gchar*, len + 1);
-      names[len] = NULL;
-    }
-  else
-    names = NULL;
-
-  if (valuesp)
-    {
-      values = g_new (gchar*, len + 1);
-      values[len] = NULL;
-    }
-  else
-    values = NULL;
-
-  /* We want to reverse the list, since it's
-   * backward from the order the attributes appeared
-   * in the file.
-   */
-  i = len - 1;
-  tmp_list = attributes;
-  while (tmp_list)
-    {
-      GMarkupAttribute *attr = tmp_list->data;
-
-      g_assert (i >= 0);
-
-      if (namesp)
-        names[i] = attr->name;
-
-      if (valuesp)
-        values[i] = attr->value;
-
-      tmp_list = g_slist_next (tmp_list);
-      --i;
-    }
-
-  if (n_attributes)
-    *n_attributes = len;
-
-  if (namesp)
-    *namesp = names;
-
-  if (valuesp)
-    *valuesp = values;
-}
-
-static void
 mark_error (GMarkupParseContext *context,
             GError              *error)
 {
@@ -748,12 +662,11 @@ add_to_partial (GMarkupParseContext *context,
 }
 
 static void
-free_partial (GMarkupParseContext *context)
+truncate_partial (GMarkupParseContext *context)
 {
   if (context->partial_chunk != NULL)
     {
-      g_string_free (context->partial_chunk, TRUE);
-      context->partial_chunk = NULL;
+      context->partial_chunk = g_string_truncate (context->partial_chunk, 0);
     }
 }
 
@@ -766,7 +679,8 @@ current_element (GMarkupParseContext *context)
 static const gchar*
 current_attribute (GMarkupParseContext *context)
 {
-  return ((GMarkupAttribute*)context->attributes->data)->name;
+  g_assert (context->cur_attr >= 0);
+  return context->attr_names[context->cur_attr];
 }
 
 static void
@@ -806,6 +720,21 @@ find_current_text_end (GMarkupParseContext *context)
     }
 }
 
+static void
+add_attribute (GMarkupParseContext *context, char *name)
+{
+  if (context->cur_attr + 2 >= context->alloc_attrs)
+    {
+      context->alloc_attrs += 5; /* silly magic number */
+      context->attr_names = g_realloc (context->attr_names, sizeof(char*)*context->alloc_attrs);
+      context->attr_values = g_realloc (context->attr_values, sizeof(char*)*context->alloc_attrs);
+    }
+  context->cur_attr++;
+  context->attr_names[context->cur_attr] = name;
+  context->attr_values[context->cur_attr] = NULL;
+  context->attr_names[context->cur_attr+1] = NULL;
+}
+
 /**
  * g_markup_parse_context_parse:
  * @context: a #GMarkupParseContext
@@ -1073,10 +1002,6 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                                                 context->user_data,
                                                 &tmp_error);
           
-            g_free (context->tag_stack->data);
-            context->tag_stack = g_slist_delete_link (context->tag_stack,
-                                                      context->tag_stack);
-
             if (tmp_error)
               {
                 mark_error (context, tmp_error);
@@ -1102,6 +1027,10 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                                current_element (context));
                   }
               }
+
+            g_free (context->tag_stack->data);
+            context->tag_stack = g_slist_delete_link (context->tag_stack,
+                                                      context->tag_stack);
           }
           break;
 
@@ -1161,20 +1090,13 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
               /* The name has ended. Combine it with the partial chunk
                * if any; push it on the stack; enter next state.
                */
-              GMarkupAttribute *attr;
               add_to_partial (context, context->start, context->iter);
 
-              attr = attribute_new (NULL, NULL);
-
-              attr->name = g_string_free (context->partial_chunk,
-                                          FALSE);
+              add_attribute (context, g_string_free (context->partial_chunk, FALSE));
 
               context->partial_chunk = NULL;
               context->start = NULL;
 
-              context->attributes =
-                g_slist_prepend (context->attributes, attr);
-
               if (*context->iter == '=')
                 {
                   advance_char (context);
@@ -1189,7 +1111,7 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                              _("Odd character '%s', expected a '=' after "
                                "attribute name '%s' of element '%s'"),
                              utf8_str (context->iter, buf),
-                             attr->name,
+                             current_attribute (context),
                              current_element (context));
 
                 }
@@ -1243,17 +1165,20 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                   context->state == STATE_AFTER_CLOSE_ANGLE)
                 {
                   const gchar *start_name;
-                  gchar **attr_names = NULL;
-                  gchar **attr_values = NULL;
+                 /* Ugly, but the current code expects an empty array instead of NULL */
+                 const gchar *empty = NULL;
+                  const gchar **attr_names =  &empty;
+                  const gchar **attr_values = &empty;
                   GError *tmp_error;
 
                   /* Call user callback for element start */
                   start_name = current_element (context);
 
-                  attribute_list_to_arrays (context->attributes,
-                                            &attr_names,
-                                            &attr_values,
-                                            NULL);
+                 if (context->cur_attr >= 0)
+                   {
+                     attr_names = (const gchar**)context->attr_names;
+                     attr_values = (const gchar**)context->attr_values;
+                   }
 
                   tmp_error = NULL;
                   if (context->parser->start_element)
@@ -1264,17 +1189,15 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                                                         context->user_data,
                                                         &tmp_error);
 
-                 /* Free only the string arrays, as we didn't g_strdup() the attribute
-                  * list's strings
-                  */
-                  g_free (attr_names);
-                  g_free (attr_values);
-
-                  /* Go ahead and free this. */
-                  g_slist_foreach (context->attributes, (GFunc)attribute_free,
-                                   NULL);
-                  g_slist_free (context->attributes);
-                  context->attributes = NULL;
+                  /* Go ahead and free the attributes. */
+                 for (; context->cur_attr >= 0; context->cur_attr--)
+                   {
+                     int pos = context->cur_attr;
+                     g_free (context->attr_names[pos]);
+                     g_free (context->attr_values[pos]);
+                     context->attr_names[pos] = context->attr_values[pos] = NULL;
+                   }
+                  context->cur_attr = -1;
 
                   if (tmp_error != NULL)
                     {
@@ -1330,17 +1253,15 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                * with the partial chunk if any; set it for the current
                * attribute.
                */
-              GMarkupAttribute *attr;
-
               add_to_partial (context, context->start, context->iter);
 
-              attr = context->attributes->data;
+              g_assert (context->cur_attr >= 0);
               
               if (unescape_text (context,
                                  context->partial_chunk->str,
                                  context->partial_chunk->str +
                                  context->partial_chunk->len,
-                                 &attr->value,
+                                 &context->attr_values[context->cur_attr],
                                  error))
                 {
                   /* success, advance past quote and set state. */
@@ -1349,7 +1270,7 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                   context->start = NULL;
                 }
               
-              free_partial (context);
+              truncate_partial (context);
             }
           break;
 
@@ -1409,7 +1330,7 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                     }
                 }
 
-              free_partial (context);
+              truncate_partial (context);
             }
           break;
 
@@ -1558,7 +1479,7 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                                                  context->user_data,
                                                  &tmp_error);
                   
-              free_partial (context);
+              truncate_partial (context);
 
               if (tmp_error == NULL)
                 {
@@ -1609,6 +1530,12 @@ g_markup_parse_context_end_parse (GMarkupParseContext *context,
   g_return_val_if_fail (!context->parsing, FALSE);
   g_return_val_if_fail (context->state != STATE_ERROR, FALSE);
 
+  if (context->partial_chunk != NULL)
+    {
+      g_string_free (context->partial_chunk, TRUE);
+      context->partial_chunk = NULL;
+    }
+
   if (context->document_empty)
     {
       set_error (context, error, G_MARKUP_ERROR_EMPTY,
index 87d6091..e141db6 100644 (file)
--- a/gmarkup.c
+++ b/gmarkup.c
@@ -38,36 +38,6 @@ g_markup_error_quark ()
   return error_quark;
 }
 
-typedef struct _GMarkupAttribute GMarkupAttribute;
-
-struct _GMarkupAttribute
-{
-  gchar *name;
-  gchar *value;
-};
-
-static GMarkupAttribute*
-attribute_new (const gchar *name, const gchar *value)
-{
-  GMarkupAttribute *attr;
-
-  attr = g_new (GMarkupAttribute, 1);
-
-  /* name/value are allowed to be NULL */
-  attr->name = g_strdup (name);
-  attr->value = g_strdup (value);
-
-  return attr;
-}
-
-static void
-attribute_free (GMarkupAttribute *attr)
-{
-  g_free (attr->name);
-  g_free (attr->value);
-  g_free (attr);
-}
-
 typedef enum
 {
   STATE_START,
@@ -106,7 +76,10 @@ struct _GMarkupParseContext
 
   GMarkupParseState state;
   GSList *tag_stack;
-  GSList *attributes;
+  gchar **attr_names;
+  gchar **attr_values;
+  gint cur_attr;
+  gint alloc_attrs;
 
   const gchar *current_text;
   gint         current_text_len;
@@ -162,7 +135,10 @@ g_markup_parse_context_new (const GMarkupParser *parser,
 
   context->state = STATE_START;
   context->tag_stack = NULL;
-  context->attributes = NULL;
+  context->attr_names = NULL;
+  context->attr_values = NULL;
+  context->cur_attr = -1;
+  context->alloc_attrs = 0;
 
   context->current_text = NULL;
   context->current_text_len = -1;
@@ -195,8 +171,8 @@ g_markup_parse_context_free (GMarkupParseContext *context)
   if (context->dnotify)
     (* context->dnotify) (context->user_data);
 
-  g_slist_foreach (context->attributes, (GFunc)attribute_free, NULL);
-  g_slist_free (context->attributes);
+  g_strfreev (context->attr_names);
+  g_strfreev (context->attr_values);
 
   g_slist_foreach (context->tag_stack, (GFunc)g_free, NULL);
   g_slist_free (context->tag_stack);
@@ -211,68 +187,6 @@ g_markup_parse_context_free (GMarkupParseContext *context)
 }
 
 static void
-attribute_list_to_arrays (GSList  *attributes,
-                          gchar ***namesp,
-                          gchar ***valuesp,
-                          gint    *n_attributes)
-{
-  GSList *tmp_list;
-  gint len;
-  gchar **names;
-  gchar **values;
-  gint i;
-
-  len = g_slist_length (attributes);
-
-  if (namesp)
-    {
-      names = g_new (gchar*, len + 1);
-      names[len] = NULL;
-    }
-  else
-    names = NULL;
-
-  if (valuesp)
-    {
-      values = g_new (gchar*, len + 1);
-      values[len] = NULL;
-    }
-  else
-    values = NULL;
-
-  /* We want to reverse the list, since it's
-   * backward from the order the attributes appeared
-   * in the file.
-   */
-  i = len - 1;
-  tmp_list = attributes;
-  while (tmp_list)
-    {
-      GMarkupAttribute *attr = tmp_list->data;
-
-      g_assert (i >= 0);
-
-      if (namesp)
-        names[i] = attr->name;
-
-      if (valuesp)
-        values[i] = attr->value;
-
-      tmp_list = g_slist_next (tmp_list);
-      --i;
-    }
-
-  if (n_attributes)
-    *n_attributes = len;
-
-  if (namesp)
-    *namesp = names;
-
-  if (valuesp)
-    *valuesp = values;
-}
-
-static void
 mark_error (GMarkupParseContext *context,
             GError              *error)
 {
@@ -748,12 +662,11 @@ add_to_partial (GMarkupParseContext *context,
 }
 
 static void
-free_partial (GMarkupParseContext *context)
+truncate_partial (GMarkupParseContext *context)
 {
   if (context->partial_chunk != NULL)
     {
-      g_string_free (context->partial_chunk, TRUE);
-      context->partial_chunk = NULL;
+      context->partial_chunk = g_string_truncate (context->partial_chunk, 0);
     }
 }
 
@@ -766,7 +679,8 @@ current_element (GMarkupParseContext *context)
 static const gchar*
 current_attribute (GMarkupParseContext *context)
 {
-  return ((GMarkupAttribute*)context->attributes->data)->name;
+  g_assert (context->cur_attr >= 0);
+  return context->attr_names[context->cur_attr];
 }
 
 static void
@@ -806,6 +720,21 @@ find_current_text_end (GMarkupParseContext *context)
     }
 }
 
+static void
+add_attribute (GMarkupParseContext *context, char *name)
+{
+  if (context->cur_attr + 2 >= context->alloc_attrs)
+    {
+      context->alloc_attrs += 5; /* silly magic number */
+      context->attr_names = g_realloc (context->attr_names, sizeof(char*)*context->alloc_attrs);
+      context->attr_values = g_realloc (context->attr_values, sizeof(char*)*context->alloc_attrs);
+    }
+  context->cur_attr++;
+  context->attr_names[context->cur_attr] = name;
+  context->attr_values[context->cur_attr] = NULL;
+  context->attr_names[context->cur_attr+1] = NULL;
+}
+
 /**
  * g_markup_parse_context_parse:
  * @context: a #GMarkupParseContext
@@ -1073,10 +1002,6 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                                                 context->user_data,
                                                 &tmp_error);
           
-            g_free (context->tag_stack->data);
-            context->tag_stack = g_slist_delete_link (context->tag_stack,
-                                                      context->tag_stack);
-
             if (tmp_error)
               {
                 mark_error (context, tmp_error);
@@ -1102,6 +1027,10 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                                current_element (context));
                   }
               }
+
+            g_free (context->tag_stack->data);
+            context->tag_stack = g_slist_delete_link (context->tag_stack,
+                                                      context->tag_stack);
           }
           break;
 
@@ -1161,20 +1090,13 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
               /* The name has ended. Combine it with the partial chunk
                * if any; push it on the stack; enter next state.
                */
-              GMarkupAttribute *attr;
               add_to_partial (context, context->start, context->iter);
 
-              attr = attribute_new (NULL, NULL);
-
-              attr->name = g_string_free (context->partial_chunk,
-                                          FALSE);
+              add_attribute (context, g_string_free (context->partial_chunk, FALSE));
 
               context->partial_chunk = NULL;
               context->start = NULL;
 
-              context->attributes =
-                g_slist_prepend (context->attributes, attr);
-
               if (*context->iter == '=')
                 {
                   advance_char (context);
@@ -1189,7 +1111,7 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                              _("Odd character '%s', expected a '=' after "
                                "attribute name '%s' of element '%s'"),
                              utf8_str (context->iter, buf),
-                             attr->name,
+                             current_attribute (context),
                              current_element (context));
 
                 }
@@ -1243,17 +1165,20 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                   context->state == STATE_AFTER_CLOSE_ANGLE)
                 {
                   const gchar *start_name;
-                  gchar **attr_names = NULL;
-                  gchar **attr_values = NULL;
+                 /* Ugly, but the current code expects an empty array instead of NULL */
+                 const gchar *empty = NULL;
+                  const gchar **attr_names =  &empty;
+                  const gchar **attr_values = &empty;
                   GError *tmp_error;
 
                   /* Call user callback for element start */
                   start_name = current_element (context);
 
-                  attribute_list_to_arrays (context->attributes,
-                                            &attr_names,
-                                            &attr_values,
-                                            NULL);
+                 if (context->cur_attr >= 0)
+                   {
+                     attr_names = (const gchar**)context->attr_names;
+                     attr_values = (const gchar**)context->attr_values;
+                   }
 
                   tmp_error = NULL;
                   if (context->parser->start_element)
@@ -1264,17 +1189,15 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                                                         context->user_data,
                                                         &tmp_error);
 
-                 /* Free only the string arrays, as we didn't g_strdup() the attribute
-                  * list's strings
-                  */
-                  g_free (attr_names);
-                  g_free (attr_values);
-
-                  /* Go ahead and free this. */
-                  g_slist_foreach (context->attributes, (GFunc)attribute_free,
-                                   NULL);
-                  g_slist_free (context->attributes);
-                  context->attributes = NULL;
+                  /* Go ahead and free the attributes. */
+                 for (; context->cur_attr >= 0; context->cur_attr--)
+                   {
+                     int pos = context->cur_attr;
+                     g_free (context->attr_names[pos]);
+                     g_free (context->attr_values[pos]);
+                     context->attr_names[pos] = context->attr_values[pos] = NULL;
+                   }
+                  context->cur_attr = -1;
 
                   if (tmp_error != NULL)
                     {
@@ -1330,17 +1253,15 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                * with the partial chunk if any; set it for the current
                * attribute.
                */
-              GMarkupAttribute *attr;
-
               add_to_partial (context, context->start, context->iter);
 
-              attr = context->attributes->data;
+              g_assert (context->cur_attr >= 0);
               
               if (unescape_text (context,
                                  context->partial_chunk->str,
                                  context->partial_chunk->str +
                                  context->partial_chunk->len,
-                                 &attr->value,
+                                 &context->attr_values[context->cur_attr],
                                  error))
                 {
                   /* success, advance past quote and set state. */
@@ -1349,7 +1270,7 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                   context->start = NULL;
                 }
               
-              free_partial (context);
+              truncate_partial (context);
             }
           break;
 
@@ -1409,7 +1330,7 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                     }
                 }
 
-              free_partial (context);
+              truncate_partial (context);
             }
           break;
 
@@ -1558,7 +1479,7 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                                                  context->user_data,
                                                  &tmp_error);
                   
-              free_partial (context);
+              truncate_partial (context);
 
               if (tmp_error == NULL)
                 {
@@ -1609,6 +1530,12 @@ g_markup_parse_context_end_parse (GMarkupParseContext *context,
   g_return_val_if_fail (!context->parsing, FALSE);
   g_return_val_if_fail (context->state != STATE_ERROR, FALSE);
 
+  if (context->partial_chunk != NULL)
+    {
+      g_string_free (context->partial_chunk, TRUE);
+      context->partial_chunk = NULL;
+    }
+
   if (context->document_empty)
     {
       set_error (context, error, G_MARKUP_ERROR_EMPTY,
diff --git a/tests/markups/valid-3.gmarkup b/tests/markups/valid-3.gmarkup
new file mode 100644 (file)
index 0000000..aed984e
--- /dev/null
@@ -0,0 +1,10 @@
+<foo>
+<bar a="1"/>
+<bar a="1" b="2"/>
+<bar a="1" b="2" c="3"/>
+<bar a="1" b="2" c="3" d="4"/>
+<bar a="1" b="2" c="3" d="4" e="5"/>
+<bar a="1" b="2" c="3" d="4" e="5" f="6"/>
+<bar a="1" b="2" c="3"/>
+<bar a="1"/>
+</foo>