diff --git a/ext/dom/xml_serializer.c b/ext/dom/xml_serializer.c index 0c5f12023aa..3d7363b86ef 100644 --- a/ext/dom/xml_serializer.c +++ b/ext/dom/xml_serializer.c @@ -66,9 +66,13 @@ typedef struct { const xmlChar *prefix, *name; } dom_qname_pair; +typedef struct dom_xml_serialize_ctx { + xmlSaveCtxtPtr ctxt; + xmlOutputBufferPtr out; +} dom_xml_serialize_ctx; + static int dom_xml_serialization_algorithm( - xmlSaveCtxtPtr ctxt, - xmlOutputBufferPtr out, + dom_xml_serialize_ctx *ctx, dom_xml_ns_prefix_map *namespace_prefix_map, xmlNodePtr node, const xmlChar *namespace, @@ -895,8 +899,7 @@ static int dom_xml_output_indents(xmlOutputBufferPtr out, int indent) /* https://w3c.github.io/DOM-Parsing/#dfn-xml-serializing-an-element-node */ static int dom_xml_serialize_element_node( - xmlSaveCtxtPtr ctxt, - xmlOutputBufferPtr out, + dom_xml_serialize_ctx *ctx, const xmlChar *namespace, dom_xml_ns_prefix_map *namespace_prefix_map, xmlNodePtr element, @@ -916,7 +919,7 @@ static int dom_xml_serialize_element_node( bool should_format = indent >= 0 && element->children != NULL && dom_xml_should_format_element(element); /* 2. Let markup be the string "<" (U+003C LESS-THAN SIGN). */ - TRY(xmlOutputBufferWriteLit(out, "<")); + TRY(xmlOutputBufferWriteLit(ctx->out, "<")); /* 3. Let qualified name be an empty string. * => We're going to do it a bit differently. @@ -966,7 +969,7 @@ static int dom_xml_serialize_element_node( } /* 11.4. Append the value of qualified name to markup. */ - TRY_OR_CLEANUP(dom_xml_output_qname(out, &qualified_name)); + TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name)); } /* 12. Otherwise, inherited ns is not equal to ns */ else { @@ -1011,7 +1014,7 @@ static int dom_xml_serialize_element_node( } /* 12.4.3. Append the value of qualified name to markup. */ - TRY_OR_CLEANUP(dom_xml_output_qname(out, &qualified_name)); + TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name)); } /* 12.5. Otherwise, if prefix is not null, then: */ else if (prefix != NULL) { @@ -1033,14 +1036,14 @@ static int dom_xml_serialize_element_node( qualified_name.name = element->name; /* 12.5.4. Append the value of qualified name to markup. */ - TRY_OR_CLEANUP(dom_xml_output_qname(out, &qualified_name)); + TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name)); /* 12.5.5. Append the following to markup, in the order listed: ... */ - TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, " xmlns:")); /* 12.5.5.1 - 12.5.5.2 */ - TRY_OR_CLEANUP(xmlOutputBufferWriteString(out, (const char *) prefix)); - TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, "=\"")); - TRY_OR_CLEANUP(dom_xml_common_text_serialization(out, (const char *) ns, true)); - TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, "\"")); + TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, " xmlns:")); /* 12.5.5.1 - 12.5.5.2 */ + TRY_OR_CLEANUP(xmlOutputBufferWriteString(ctx->out, (const char *) prefix)); + TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, "=\"")); + TRY_OR_CLEANUP(dom_xml_common_text_serialization(ctx->out, (const char *) ns, true)); + TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, "\"")); /* 12.5.6. If local default namespace is not null ... (editorial numbering error: https://github.com/w3c/DOM-Parsing/issues/43) */ if (local_default_namespace != NULL) { @@ -1064,24 +1067,24 @@ static int dom_xml_serialize_element_node( inherited_ns = ns; /* 12.6.4. Append the value of qualified name to markup. */ - TRY_OR_CLEANUP(dom_xml_output_qname(out, &qualified_name)); + TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name)); /* 12.6.5. Append the following to markup, in the order listed: ... */ - TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, " xmlns=\"")); /* 12.6.5.1 - 12.6.5.2 */ - TRY_OR_CLEANUP(dom_xml_common_text_serialization(out, (const char *) ns, true)); - TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, "\"")); + TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, " xmlns=\"")); /* 12.6.5.1 - 12.6.5.2 */ + TRY_OR_CLEANUP(dom_xml_common_text_serialization(ctx->out, (const char *) ns, true)); + TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, "\"")); } /* 12.7. Otherwise, the node has a local default namespace that matches ns ... */ else { qualified_name.name = element->name; inherited_ns = ns; - TRY_OR_CLEANUP(dom_xml_output_qname(out, &qualified_name)); + TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name)); } } /* 13. Append to markup the result of the XML serialization of node's attributes given map, prefix index, * local prefixes map, ignore namespace definition attribute flag, and require well-formed flag. */ - TRY_OR_CLEANUP(dom_xml_serialize_attributes(out, element, &map, &local_prefixes_map, prefix_index, ignore_namespace_definition_attribute, require_well_formed)); + TRY_OR_CLEANUP(dom_xml_serialize_attributes(ctx->out, element, &map, &local_prefixes_map, prefix_index, ignore_namespace_definition_attribute, require_well_formed)); /* 14. If ns is the HTML namespace, and the node's list of children is empty, and the node's localName matches * any one of the following void elements: ... */ @@ -1109,19 +1112,19 @@ static int dom_xml_serialize_element_node( || dom_local_name_compare_ex(element, "source", strlen("source"), name_length) || dom_local_name_compare_ex(element, "track", strlen("track"), name_length) || dom_local_name_compare_ex(element, "wbr", strlen("wbr"), name_length)) { - TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, " /")); + TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, " /")); skip_end_tag = true; } } else { /* 15. If ns is not the HTML namespace, and the node's list of children is empty, * then append "/" (U+002F SOLIDUS) to markup and set the skip end tag flag to true. */ - TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, "/")); + TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, "/")); skip_end_tag = true; } } /* 16. Append ">" (U+003E GREATER-THAN SIGN) to markup. */ - TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, ">")); + TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, ">")); /* 17. If the value of skip end tag is true, then return the value of markup and skip the remaining steps. */ if (!skip_end_tag) { @@ -1136,20 +1139,20 @@ static int dom_xml_serialize_element_node( /* 19. Otherwise, append to markup the result of running the XML serialization algorithm on each of node's children. */ for (xmlNodePtr child = element->children; child != NULL; child = child->next) { if (should_format) { - TRY_OR_CLEANUP(dom_xml_output_indents(out, indent)); + TRY_OR_CLEANUP(dom_xml_output_indents(ctx->out, indent)); } - TRY_OR_CLEANUP(dom_xml_serialization_algorithm(ctxt, out, &map, child, inherited_ns, prefix_index, indent, require_well_formed)); + TRY_OR_CLEANUP(dom_xml_serialization_algorithm(ctx, &map, child, inherited_ns, prefix_index, indent, require_well_formed)); } if (should_format) { indent--; - TRY_OR_CLEANUP(dom_xml_output_indents(out, indent)); + TRY_OR_CLEANUP(dom_xml_output_indents(ctx->out, indent)); } /* 20. Append the following to markup, in the order listed: */ - TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, "")); + TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, "out, &qualified_name)); + TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, ">")); } /* 21. Return the value of markup. @@ -1166,8 +1169,7 @@ cleanup: /* https://w3c.github.io/DOM-Parsing/#xml-serializing-a-documentfragment-node */ static int dom_xml_serializing_a_document_fragment_node( - xmlSaveCtxtPtr ctxt, - xmlOutputBufferPtr out, + dom_xml_serialize_ctx *ctx, dom_xml_ns_prefix_map *namespace_prefix_map, xmlNodePtr node, const xmlChar *namespace, @@ -1182,7 +1184,7 @@ static int dom_xml_serializing_a_document_fragment_node( /* 2. For each child child of node, in tree order, run the XML serialization algorithm on the child ... */ xmlNodePtr child = node->children; while (child != NULL) { - TRY(dom_xml_serialization_algorithm(ctxt, out, namespace_prefix_map, child, namespace, prefix_index, indent, require_well_formed)); + TRY(dom_xml_serialization_algorithm(ctx, namespace_prefix_map, child, namespace, prefix_index, indent, require_well_formed)); child = child->next; } @@ -1193,8 +1195,7 @@ static int dom_xml_serializing_a_document_fragment_node( /* https://w3c.github.io/DOM-Parsing/#dfn-xml-serializing-a-document-node */ static int dom_xml_serializing_a_document_node( - xmlSaveCtxtPtr ctxt, - xmlOutputBufferPtr out, + dom_xml_serialize_ctx *ctx, dom_xml_ns_prefix_map *namespace_prefix_map, xmlNodePtr node, const xmlChar *namespace, @@ -1210,16 +1211,16 @@ static int dom_xml_serializing_a_document_node( node->children = NULL; /* https://github.com/w3c/DOM-Parsing/issues/50 */ - TRY(xmlOutputBufferFlush(out)); - TRY(xmlSaveDoc(ctxt, (xmlDocPtr) node)); - TRY(xmlSaveFlush(ctxt)); + TRY(xmlOutputBufferFlush(ctx->out)); + TRY(xmlSaveDoc(ctx->ctxt, (xmlDocPtr) node)); + TRY(xmlSaveFlush(ctx->ctxt)); node->children = child; /* 2. For each child child of node, in tree order, run the XML serialization algorithm on the child passing along the provided arguments, * and append the result to serialized document. */ while (child != NULL) { - TRY(dom_xml_serialization_algorithm(ctxt, out, namespace_prefix_map, child, namespace, prefix_index, indent, require_well_formed)); + TRY(dom_xml_serialization_algorithm(ctx, namespace_prefix_map, child, namespace, prefix_index, indent, require_well_formed)); child = child->next; } @@ -1230,8 +1231,7 @@ static int dom_xml_serializing_a_document_node( /* https://w3c.github.io/DOM-Parsing/#dfn-xml-serialization-algorithm */ static int dom_xml_serialization_algorithm( - xmlSaveCtxtPtr ctxt, - xmlOutputBufferPtr out, + dom_xml_serialize_ctx *ctx, dom_xml_ns_prefix_map *namespace_prefix_map, xmlNodePtr node, const xmlChar *namespace, @@ -1243,36 +1243,36 @@ static int dom_xml_serialization_algorithm( /* If node's interface is: */ switch (node->type) { case XML_ELEMENT_NODE: - return dom_xml_serialize_element_node(ctxt, out, namespace, namespace_prefix_map, node, prefix_index, indent, require_well_formed); + return dom_xml_serialize_element_node(ctx, namespace, namespace_prefix_map, node, prefix_index, indent, require_well_formed); case XML_DOCUMENT_FRAG_NODE: - return dom_xml_serializing_a_document_fragment_node(ctxt, out, namespace_prefix_map, node, namespace, prefix_index, indent, require_well_formed); + return dom_xml_serializing_a_document_fragment_node(ctx, namespace_prefix_map, node, namespace, prefix_index, indent, require_well_formed); case XML_HTML_DOCUMENT_NODE: case XML_DOCUMENT_NODE: - return dom_xml_serializing_a_document_node(ctxt, out, namespace_prefix_map, node, namespace, prefix_index, indent, require_well_formed); + return dom_xml_serializing_a_document_node(ctx, namespace_prefix_map, node, namespace, prefix_index, indent, require_well_formed); case XML_TEXT_NODE: - return dom_xml_serialize_text_node(out, node, require_well_formed); + return dom_xml_serialize_text_node(ctx->out, node, require_well_formed); case XML_COMMENT_NODE: - return dom_xml_serialize_comment_node(out, node, require_well_formed); + return dom_xml_serialize_comment_node(ctx->out, node, require_well_formed); case XML_PI_NODE: - return dom_xml_serialize_processing_instruction(out, node, require_well_formed); + return dom_xml_serialize_processing_instruction(ctx->out, node, require_well_formed); case XML_CDATA_SECTION_NODE: - return dom_xml_serialize_cdata_section_node(out, node); + return dom_xml_serialize_cdata_section_node(ctx->out, node); case XML_ATTRIBUTE_NODE: - return dom_xml_serialize_attribute_node(out, node); + return dom_xml_serialize_attribute_node(ctx->out, node); default: - TRY(xmlOutputBufferFlush(out)); - TRY(xmlSaveTree(ctxt, node)); - TRY(xmlSaveFlush(ctxt)); + TRY(xmlOutputBufferFlush(ctx->out)); + TRY(xmlSaveTree(ctx->ctxt, node)); + TRY(xmlSaveFlush(ctx->ctxt)); if (node->type == XML_DTD_NODE) { - return xmlOutputBufferWriteLit(out, "\n"); + return xmlOutputBufferWriteLit(ctx->out, "\n"); } return 0; } @@ -1297,8 +1297,11 @@ int dom_xml_serialize(xmlSaveCtxtPtr ctxt, xmlOutputBufferPtr out, xmlNodePtr no unsigned int prefix_index = 1; /* 5. Return the result of running the XML serialization algorithm ... */ + dom_xml_serialize_ctx ctx; + ctx.out = out; + ctx.ctxt = ctxt; int indent = format ? 0 : -1; - int result = dom_xml_serialization_algorithm(ctxt, out, &namespace_prefix_map, node, namespace, &prefix_index, indent, require_well_formed); + int result = dom_xml_serialization_algorithm(&ctx, &namespace_prefix_map, node, namespace, &prefix_index, indent, require_well_formed); dom_xml_ns_prefix_map_dtor(&namespace_prefix_map);