* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.86 2009/04/08 21:51:38 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.87 2009/05/12 20:17:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
                }
                appendStringInfoString(&buf, str + len);
 
-               if (version)
-                       xmlFree(version);
                pfree(str);
 
                return buf.data;
                if (!version)
                        global_version_no_value = true;
                else if (!global_version)
-                       global_version = xmlStrdup(version);
+                       global_version = version;
                else if (xmlStrcmp(version, global_version) != 0)
                        global_version_no_value = true;
 
                        || xmlIsCombiningQ(c) \
                        || xmlIsExtender_ch(c))
 
+/* pnstrdup, but deal with xmlChar not char; len is measured in xmlChars */
+static xmlChar *
+xml_pnstrdup(const xmlChar *str, size_t len)
+{
+       xmlChar    *result;
+
+       result = (xmlChar *) palloc((len + 1) * sizeof(xmlChar));
+       memcpy(result, str, len * sizeof(xmlChar));
+       result[len] = 0;
+       return result;
+}
+
+/*
+ * str is the null-terminated input string.  Remaining arguments are
+ * output arguments; each can be NULL if value is not wanted.
+ * version and encoding are returned as locally-palloc'd strings.
+ * Result is 0 if OK, an error code if not.
+ */
 static int
 parse_xml_decl(const xmlChar * str, size_t *lenp,
                           xmlChar ** version, xmlChar ** encoding, int *standalone)
 
        xml_init();
 
+       /* Initialize output arguments to "not present" */
        if (version)
                *version = NULL;
        if (encoding)
                        return XML_ERR_VERSION_MISSING;
 
                if (version)
-                       *version = xmlStrndup(p + 1, q - p - 1);
+                       *version = xml_pnstrdup(p + 1, q - p - 1);
                p = q + 1;
        }
        else
                                return XML_ERR_MISSING_ENCODING;
 
                        if (encoding)
-                               *encoding = xmlStrndup(p + 1, q - p - 1);
+                               *encoding = xml_pnstrdup(p + 1, q - p - 1);
                        p = q + 1;
                }
                else
                xmlChar    *version = NULL;
                int                     standalone = -1;
 
-               doc = xmlNewDoc(NULL);
-
                res_code = parse_xml_decl(utf8string,
                                                                  &count, &version, NULL, &standalone);
                if (res_code != 0)
                                                                "invalid XML content: invalid XML declaration",
                                                                res_code);
 
+               doc = xmlNewDoc(version);
+               Assert(doc->encoding == NULL);
+               doc->encoding = xmlStrdup((const xmlChar *) "UTF-8");
+               doc->standalone = standalone;
+
                res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0,
                                                                                           utf8string + count, NULL);
                if (res_code != 0)
                        xml_ereport(ERROR, ERRCODE_INVALID_XML_CONTENT,
                                                "invalid XML content");
-
-               doc->version = xmlStrdup(version);
-               doc->encoding = xmlStrdup((xmlChar *) "UTF-8");
-               doc->standalone = standalone;
        }
 
        xmlFreeParserCtxt(ctxt);