mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-03-27 18:50:07 +03:00
parser: Implement xmlCtxtParseContent
This implements xmlCtxtParseContent, a better alternative to xmlParseInNodeContext or xmlParseBalancedChunkMemory. It accepts a parser context and a parser input, making it a lot more versatile. xmlParseInNodeContext is now implemented in terms of xmlCtxtParseContent. This makes sure that xmlParseInNodeContext never modifies the target document, improving thread safety. xmlParseInNodeContext is also more lenient now with regard to undeclared entities. Fixes #727.
This commit is contained in:
parent
673ca0edaf
commit
4f329dc524
54
HTMLparser.c
54
HTMLparser.c
@ -4716,18 +4716,50 @@ htmlParseContentInternal(htmlParserCtxtPtr ctxt) {
|
||||
if (currentNode != NULL) xmlFree(currentNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* htmlParseContent:
|
||||
* @ctxt: an HTML parser context
|
||||
*
|
||||
* Parse a content: comment, sub-element, reference or text.
|
||||
* This is the entry point when called from parser.c
|
||||
*/
|
||||
xmlNodePtr
|
||||
htmlCtxtParseContentInternal(htmlParserCtxtPtr ctxt, xmlParserInputPtr input) {
|
||||
xmlNodePtr root;
|
||||
xmlNodePtr list = NULL;
|
||||
xmlChar *rootName = BAD_CAST "#root";
|
||||
|
||||
void
|
||||
__htmlParseContent(void *ctxt) {
|
||||
if (ctxt != NULL)
|
||||
htmlParseContentInternal((htmlParserCtxtPtr) ctxt);
|
||||
root = xmlNewDocNode(ctxt->myDoc, NULL, rootName, NULL);
|
||||
if (root == NULL) {
|
||||
htmlErrMemory(ctxt);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
if (xmlPushInput(ctxt, input) < 0) {
|
||||
xmlFreeNode(root);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
htmlnamePush(ctxt, rootName);
|
||||
nodePush(ctxt, root);
|
||||
|
||||
htmlParseContentInternal(ctxt);
|
||||
|
||||
/* TODO: Use xmlCtxtIsCatastrophicError */
|
||||
if (ctxt->errNo != XML_ERR_NO_MEMORY) {
|
||||
xmlNodePtr cur;
|
||||
|
||||
/*
|
||||
* Unlink newly created node list.
|
||||
*/
|
||||
list = root->children;
|
||||
root->children = NULL;
|
||||
root->last = NULL;
|
||||
for (cur = list; cur != NULL; cur = cur->next)
|
||||
cur->parent = NULL;
|
||||
}
|
||||
|
||||
nodePop(ctxt);
|
||||
htmlnamePop(ctxt);
|
||||
|
||||
/* xmlPopInput would free the stream */
|
||||
inputPop(ctxt);
|
||||
|
||||
xmlFreeNode(root);
|
||||
return(list);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -691,6 +691,7 @@
|
||||
<exports symbol='xmlCtxtGetStandalone' type='function'/>
|
||||
<exports symbol='xmlCtxtGetStatus' type='function'/>
|
||||
<exports symbol='xmlCtxtGetVersion' type='function'/>
|
||||
<exports symbol='xmlCtxtParseContent' type='function'/>
|
||||
<exports symbol='xmlCtxtParseDocument' type='function'/>
|
||||
<exports symbol='xmlCtxtReadDoc' type='function'/>
|
||||
<exports symbol='xmlCtxtReadFd' type='function'/>
|
||||
@ -8714,6 +8715,14 @@ crash if you try to modify the tree)'/>
|
||||
<return type='const xmlChar *' info='the version from the XML declaration.'/>
|
||||
<arg name='ctxt' type='xmlParserCtxtPtr' info=''/>
|
||||
</function>
|
||||
<function name='xmlCtxtParseContent' file='parser' module='parser'>
|
||||
<info>Parse a well-balanced chunk of XML matching the 'content' production. Namespaces in scope of @node and entities of @node's document are recognized. When validating, the DTD of @node's document is used. Always consumes @input even in error case. Available since 2.14.0.</info>
|
||||
<return type='xmlNodePtr' info='a node list or NULL in case of error.'/>
|
||||
<arg name='ctxt' type='xmlParserCtxtPtr' info='parser context'/>
|
||||
<arg name='input' type='xmlParserInputPtr' info='parser input'/>
|
||||
<arg name='node' type='xmlNodePtr' info='target node or document'/>
|
||||
<arg name='hasTextDecl' type='int' info='whether to parse text declaration'/>
|
||||
</function>
|
||||
<function name='xmlCtxtParseDocument' file='parser' module='parser'>
|
||||
<info>Parse an XML document and return the resulting document tree. Takes ownership of the input object. Available since 2.13.0.</info>
|
||||
<return type='xmlDocPtr' info='the resulting document tree or NULL'/>
|
||||
@ -11314,7 +11323,7 @@ crash if you try to modify the tree)'/>
|
||||
<arg name='ctxt' type='xmlParserCtxtPtr' info='an XML parser context'/>
|
||||
</function>
|
||||
<function name='xmlParseContent' file='parserInternals' module='parser'>
|
||||
<info>Parse XML element content. This is useful if you're only interested in custom SAX callbacks. If you want a node list, use xmlParseInNodeContext.</info>
|
||||
<info>Parse XML element content. This is useful if you're only interested in custom SAX callbacks. If you want a node list, use xmlCtxtParseContent.</info>
|
||||
<return type='void'/>
|
||||
<arg name='ctxt' type='xmlParserCtxtPtr' info='an XML parser context'/>
|
||||
</function>
|
||||
@ -11471,13 +11480,13 @@ crash if you try to modify the tree)'/>
|
||||
<arg name='filename' type='const char *' info='the filename'/>
|
||||
</function>
|
||||
<function name='xmlParseInNodeContext' file='parser' module='parser'>
|
||||
<info>Parse a well-balanced chunk of an XML document within the context (DTD, namespaces, etc ...) of the given node. The allowed sequence for the data is a Well Balanced Chunk defined by the content production in the XML grammar: [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*</info>
|
||||
<info>Parse a well-balanced chunk of an XML document within the context (DTD, namespaces, etc ...) of the given node. The allowed sequence for the data is a Well Balanced Chunk defined by the content production in the XML grammar: [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* This function assumes the encoding of @node's document which is typically not what you want. A better alternative is xmlCtxtParseContent.</info>
|
||||
<return type='xmlParserErrors' info='XML_ERR_OK if the chunk is well balanced, and the parser error code otherwise'/>
|
||||
<arg name='node' type='xmlNodePtr' info='the context node'/>
|
||||
<arg name='data' type='const char *' info='the input string'/>
|
||||
<arg name='datalen' type='int' info='the input string length in bytes'/>
|
||||
<arg name='options' type='int' info='a combination of xmlParserOption'/>
|
||||
<arg name='lst' type='xmlNodePtr *' info='the return value for the set of parsed nodes'/>
|
||||
<arg name='listOut' type='xmlNodePtr *' info='the return value for the set of parsed nodes'/>
|
||||
</function>
|
||||
<function name='xmlParseMarkupDecl' file='parserInternals' module='parser'>
|
||||
<info>DEPRECATED: Internal function, don't use. Parse markup declarations. Always consumes '<!' or '<?'. [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl | NotationDecl | PI | Comment [ VC: Proper Declaration/PE Nesting ] Parameter-entity replacement text must be properly nested with markup declarations. That is to say, if either the first character or the last character of a markup declaration (markupdecl above) is contained in the replacement text for a parameter-entity reference, both must be contained in the same replacement text. [ WFC: PEs in Internal Subset ] In the internal DTD subset, parameter-entity references can occur only where markup declarations can occur, not within markup declarations. (This does not apply to references that occur in external parameter entities or to the external subset.)</info>
|
||||
|
@ -1480,6 +1480,11 @@ XMLPUBFUN xmlDocPtr
|
||||
XMLPUBFUN xmlDocPtr
|
||||
xmlCtxtParseDocument (xmlParserCtxtPtr ctxt,
|
||||
xmlParserInputPtr input);
|
||||
XMLPUBFUN xmlNodePtr
|
||||
xmlCtxtParseContent (xmlParserCtxtPtr ctxt,
|
||||
xmlParserInputPtr input,
|
||||
xmlNodePtr node,
|
||||
int hasTextDecl);
|
||||
XMLPUBFUN xmlDocPtr
|
||||
xmlCtxtReadDoc (xmlParserCtxtPtr ctxt,
|
||||
const xmlChar *cur,
|
||||
|
@ -5,8 +5,8 @@
|
||||
|
||||
#ifdef LIBXML_HTML_ENABLED
|
||||
|
||||
XML_HIDDEN void
|
||||
__htmlParseContent(void *ctx);
|
||||
XML_HIDDEN xmlNodePtr
|
||||
htmlCtxtParseContentInternal(xmlParserCtxtPtr ctxt, xmlParserInputPtr input);
|
||||
|
||||
#endif /* LIBXML_HTML_ENABLED */
|
||||
|
||||
|
389
parser.c
389
parser.c
@ -7573,7 +7573,7 @@ xmlHandleUndeclaredEntity(xmlParserCtxtPtr ctxt, const xmlChar *name) {
|
||||
*/
|
||||
xmlValidityError(ctxt, XML_ERR_UNDECLARED_ENTITY,
|
||||
"Entity '%s' not defined\n", name, NULL);
|
||||
} else if ((ctxt->loadsubset) ||
|
||||
} else if ((ctxt->loadsubset & ~XML_SKIP_IDS) ||
|
||||
((ctxt->replaceEntities) &&
|
||||
((ctxt->options & XML_PARSE_NO_XXE) == 0))) {
|
||||
/*
|
||||
@ -9774,7 +9774,7 @@ xmlParseContentInternal(xmlParserCtxtPtr ctxt) {
|
||||
*
|
||||
* Parse XML element content. This is useful if you're only interested
|
||||
* in custom SAX callbacks. If you want a node list, use
|
||||
* xmlParseInNodeContext.
|
||||
* xmlCtxtParseContent.
|
||||
*/
|
||||
void
|
||||
xmlParseContent(xmlParserCtxtPtr ctxt) {
|
||||
@ -12000,8 +12000,8 @@ xmlParseDTD(const xmlChar *ExternalID, const xmlChar *SystemID) {
|
||||
************************************************************************/
|
||||
|
||||
static xmlNodePtr
|
||||
xmlCtxtParseContent(xmlParserCtxtPtr ctxt, xmlParserInputPtr input,
|
||||
int hasTextDecl, int buildTree) {
|
||||
xmlCtxtParseContentInternal(xmlParserCtxtPtr ctxt, xmlParserInputPtr input,
|
||||
int hasTextDecl, int buildTree) {
|
||||
xmlNodePtr root = NULL;
|
||||
xmlNodePtr list = NULL;
|
||||
xmlChar *rootName = BAD_CAST "#root";
|
||||
@ -12056,17 +12056,13 @@ xmlCtxtParseContent(xmlParserCtxtPtr ctxt, xmlParserInputPtr input,
|
||||
xmlNodePtr cur;
|
||||
|
||||
/*
|
||||
* Return the newly created nodeset after unlinking it from
|
||||
* its pseudo parent.
|
||||
* Unlink newly created node list.
|
||||
*/
|
||||
cur = root->children;
|
||||
list = cur;
|
||||
while (cur != NULL) {
|
||||
cur->parent = NULL;
|
||||
cur = cur->next;
|
||||
}
|
||||
list = root->children;
|
||||
root->children = NULL;
|
||||
root->last = NULL;
|
||||
for (cur = list; cur != NULL; cur = cur->next)
|
||||
cur->parent = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -12143,7 +12139,7 @@ xmlCtxtParseEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr ent) {
|
||||
*
|
||||
* This initiates a recursive call chain:
|
||||
*
|
||||
* - xmlCtxtParseContent
|
||||
* - xmlCtxtParseContentInternal
|
||||
* - xmlParseContentInternal
|
||||
* - xmlParseReference
|
||||
* - xmlCtxtParseEntity
|
||||
@ -12157,7 +12153,7 @@ xmlCtxtParseEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr ent) {
|
||||
|
||||
ent->flags |= XML_ENT_EXPANDING;
|
||||
|
||||
list = xmlCtxtParseContent(ctxt, input, isExternal, buildTree);
|
||||
list = xmlCtxtParseContentInternal(ctxt, input, isExternal, buildTree);
|
||||
|
||||
ent->flags &= ~XML_ENT_EXPANDING;
|
||||
|
||||
@ -12232,7 +12228,7 @@ xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctxt, const xmlChar *URL,
|
||||
|
||||
xmlCtxtInitializeLate(ctxt);
|
||||
|
||||
list = xmlCtxtParseContent(ctxt, input, /* hasTextDecl */ 1, 1);
|
||||
list = xmlCtxtParseContentInternal(ctxt, input, /* hasTextDecl */ 1, 1);
|
||||
if (listOut != NULL)
|
||||
*listOut = list;
|
||||
else
|
||||
@ -12317,13 +12313,164 @@ xmlParseBalancedChunkMemory(xmlDocPtr doc, xmlSAXHandlerPtr sax,
|
||||
}
|
||||
#endif /* LIBXML_SAX1_ENABLED */
|
||||
|
||||
/**
|
||||
* xmlCtxtParseContent:
|
||||
* @ctxt: parser context
|
||||
* @input: parser input
|
||||
* @node: target node or document
|
||||
* @hasTextDecl: whether to parse text declaration
|
||||
*
|
||||
* Parse a well-balanced chunk of XML matching the 'content' production.
|
||||
*
|
||||
* Namespaces in scope of @node and entities of @node's document are
|
||||
* recognized. When validating, the DTD of @node's document is used.
|
||||
*
|
||||
* Always consumes @input even in error case.
|
||||
*
|
||||
* Available since 2.14.0.
|
||||
*
|
||||
* Returns a node list or NULL in case of error.
|
||||
*/
|
||||
xmlNodePtr
|
||||
xmlCtxtParseContent(xmlParserCtxtPtr ctxt, xmlParserInputPtr input,
|
||||
xmlNodePtr node, int hasTextDecl) {
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr cur, list = NULL;
|
||||
int nsnr = 0;
|
||||
xmlDictPtr oldDict;
|
||||
int oldOptions, oldDictNames, oldLoadSubset;
|
||||
|
||||
if ((ctxt == NULL) || (input == NULL) || (node == NULL)) {
|
||||
xmlFatalErr(ctxt, XML_ERR_ARGUMENT, NULL);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
doc = node->doc;
|
||||
if (doc == NULL) {
|
||||
xmlFatalErr(ctxt, XML_ERR_ARGUMENT, NULL);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
switch (node->type) {
|
||||
case XML_ELEMENT_NODE:
|
||||
case XML_DOCUMENT_NODE:
|
||||
case XML_HTML_DOCUMENT_NODE:
|
||||
break;
|
||||
|
||||
case XML_ATTRIBUTE_NODE:
|
||||
case XML_TEXT_NODE:
|
||||
case XML_CDATA_SECTION_NODE:
|
||||
case XML_ENTITY_REF_NODE:
|
||||
case XML_PI_NODE:
|
||||
case XML_COMMENT_NODE:
|
||||
for (cur = node->parent; cur != NULL; cur = node->parent) {
|
||||
if ((cur->type == XML_ELEMENT_NODE) ||
|
||||
(cur->type == XML_DOCUMENT_NODE) ||
|
||||
(cur->type == XML_HTML_DOCUMENT_NODE)) {
|
||||
node = cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
xmlFatalErr(ctxt, XML_ERR_ARGUMENT, NULL);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
#ifdef LIBXML_HTML_ENABLED
|
||||
if (ctxt->html)
|
||||
htmlCtxtReset(ctxt);
|
||||
else
|
||||
#endif
|
||||
xmlCtxtReset(ctxt);
|
||||
|
||||
oldDict = ctxt->dict;
|
||||
oldOptions = ctxt->options;
|
||||
oldDictNames = ctxt->dictNames;
|
||||
oldLoadSubset = ctxt->loadsubset;
|
||||
|
||||
/*
|
||||
* Use input doc's dict if present, else assure XML_PARSE_NODICT is set.
|
||||
*/
|
||||
if (doc->dict != NULL) {
|
||||
ctxt->dict = doc->dict;
|
||||
} else {
|
||||
ctxt->options |= XML_PARSE_NODICT;
|
||||
ctxt->dictNames = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable IDs
|
||||
*/
|
||||
ctxt->loadsubset |= XML_SKIP_IDS;
|
||||
|
||||
ctxt->myDoc = doc;
|
||||
|
||||
#ifdef LIBXML_HTML_ENABLED
|
||||
if (ctxt->html) {
|
||||
/*
|
||||
* When parsing in context, it makes no sense to add implied
|
||||
* elements like html/body/etc...
|
||||
*/
|
||||
ctxt->options |= HTML_PARSE_NOIMPLIED;
|
||||
|
||||
list = htmlCtxtParseContentInternal(ctxt, input);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
xmlCtxtInitializeLate(ctxt);
|
||||
|
||||
/*
|
||||
* This hack lowers the error level of undeclared entities
|
||||
* from XML_ERR_FATAL (well-formedness error) to XML_ERR_ERROR
|
||||
* or XML_ERR_WARNING.
|
||||
*/
|
||||
ctxt->hasExternalSubset = 1;
|
||||
|
||||
/*
|
||||
* initialize the SAX2 namespaces stack
|
||||
*/
|
||||
cur = node;
|
||||
while ((cur != NULL) && (cur->type == XML_ELEMENT_NODE)) {
|
||||
xmlNsPtr ns = cur->nsDef;
|
||||
xmlHashedString hprefix, huri;
|
||||
|
||||
while (ns != NULL) {
|
||||
hprefix = xmlDictLookupHashed(ctxt->dict, ns->prefix, -1);
|
||||
huri = xmlDictLookupHashed(ctxt->dict, ns->href, -1);
|
||||
if (xmlParserNsPush(ctxt, &hprefix, &huri, ns, 1) > 0)
|
||||
nsnr++;
|
||||
ns = ns->next;
|
||||
}
|
||||
cur = cur->parent;
|
||||
}
|
||||
|
||||
list = xmlCtxtParseContentInternal(ctxt, input, hasTextDecl, 1);
|
||||
|
||||
if (nsnr > 0)
|
||||
xmlParserNsPop(ctxt, nsnr);
|
||||
}
|
||||
|
||||
ctxt->dict = oldDict;
|
||||
ctxt->options = oldOptions;
|
||||
ctxt->dictNames = oldDictNames;
|
||||
ctxt->loadsubset = oldLoadSubset;
|
||||
ctxt->myDoc = NULL;
|
||||
ctxt->node = NULL;
|
||||
|
||||
exit:
|
||||
xmlFreeInputStream(input);
|
||||
return(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlParseInNodeContext:
|
||||
* @node: the context node
|
||||
* @data: the input string
|
||||
* @datalen: the input string length in bytes
|
||||
* @options: a combination of xmlParserOption
|
||||
* @lst: the return value for the set of parsed nodes
|
||||
* @listOut: the return value for the set of parsed nodes
|
||||
*
|
||||
* Parse a well-balanced chunk of an XML document
|
||||
* within the context (DTD, namespaces, etc ...) of the given node.
|
||||
@ -12333,188 +12480,65 @@ xmlParseBalancedChunkMemory(xmlDocPtr doc, xmlSAXHandlerPtr sax,
|
||||
*
|
||||
* [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
|
||||
*
|
||||
* This function assumes the encoding of @node's document which is
|
||||
* typically not what you want. A better alternative is
|
||||
* xmlCtxtParseContent.
|
||||
*
|
||||
* Returns XML_ERR_OK if the chunk is well balanced, and the parser
|
||||
* error code otherwise
|
||||
*/
|
||||
xmlParserErrors
|
||||
xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen,
|
||||
int options, xmlNodePtr *lst) {
|
||||
int options, xmlNodePtr *listOut) {
|
||||
xmlParserCtxtPtr ctxt;
|
||||
xmlDocPtr doc = NULL;
|
||||
xmlNodePtr fake, cur;
|
||||
int nsnr = 0;
|
||||
xmlParserInputPtr input;
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr list;
|
||||
xmlParserErrors ret;
|
||||
|
||||
xmlParserErrors ret = XML_ERR_OK;
|
||||
|
||||
/*
|
||||
* check all input parameters, grab the document
|
||||
*/
|
||||
if ((lst == NULL) || (node == NULL) || (data == NULL) || (datalen < 0))
|
||||
return(XML_ERR_ARGUMENT);
|
||||
switch (node->type) {
|
||||
case XML_ELEMENT_NODE:
|
||||
case XML_ATTRIBUTE_NODE:
|
||||
case XML_TEXT_NODE:
|
||||
case XML_CDATA_SECTION_NODE:
|
||||
case XML_ENTITY_REF_NODE:
|
||||
case XML_PI_NODE:
|
||||
case XML_COMMENT_NODE:
|
||||
case XML_DOCUMENT_NODE:
|
||||
case XML_HTML_DOCUMENT_NODE:
|
||||
break;
|
||||
default:
|
||||
return(XML_ERR_INTERNAL_ERROR);
|
||||
|
||||
}
|
||||
while ((node != NULL) && (node->type != XML_ELEMENT_NODE) &&
|
||||
(node->type != XML_DOCUMENT_NODE) &&
|
||||
(node->type != XML_HTML_DOCUMENT_NODE))
|
||||
node = node->parent;
|
||||
if (node == NULL)
|
||||
return(XML_ERR_INTERNAL_ERROR);
|
||||
if (node->type == XML_ELEMENT_NODE)
|
||||
doc = node->doc;
|
||||
else
|
||||
doc = (xmlDocPtr) node;
|
||||
if (doc == NULL)
|
||||
return(XML_ERR_INTERNAL_ERROR);
|
||||
|
||||
/*
|
||||
* allocate a context and set-up everything not related to the
|
||||
* node position in the tree
|
||||
*/
|
||||
if (doc->type == XML_DOCUMENT_NODE)
|
||||
ctxt = xmlCreateMemoryParserCtxt((char *) data, datalen);
|
||||
#ifdef LIBXML_HTML_ENABLED
|
||||
else if (doc->type == XML_HTML_DOCUMENT_NODE) {
|
||||
ctxt = htmlCreateMemoryParserCtxt((char *) data, datalen);
|
||||
/*
|
||||
* When parsing in context, it makes no sense to add implied
|
||||
* elements like html/body/etc...
|
||||
*/
|
||||
options |= HTML_PARSE_NOIMPLIED;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
if (listOut == NULL)
|
||||
return(XML_ERR_INTERNAL_ERROR);
|
||||
*listOut = NULL;
|
||||
|
||||
if ((node == NULL) || (data == NULL) || (datalen < 0))
|
||||
return(XML_ERR_INTERNAL_ERROR);
|
||||
|
||||
doc = node->doc;
|
||||
if (doc == NULL)
|
||||
return(XML_ERR_INTERNAL_ERROR);
|
||||
|
||||
#ifdef LIBXML_HTML_ENABLED
|
||||
if (doc->type == XML_HTML_DOCUMENT_NODE) {
|
||||
ctxt = htmlNewParserCtxt();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
ctxt = xmlNewParserCtxt();
|
||||
|
||||
if (ctxt == NULL)
|
||||
return(XML_ERR_NO_MEMORY);
|
||||
|
||||
/*
|
||||
* Use input doc's dict if present, else assure XML_PARSE_NODICT is set.
|
||||
* We need a dictionary for xmlCtxtInitializeLate, so if there's no doc dict
|
||||
* we must wait until the last moment to free the original one.
|
||||
*/
|
||||
if (doc->dict != NULL) {
|
||||
if (ctxt->dict != NULL)
|
||||
xmlDictFree(ctxt->dict);
|
||||
ctxt->dict = doc->dict;
|
||||
} else {
|
||||
options |= XML_PARSE_NODICT;
|
||||
ctxt->dictNames = 0;
|
||||
input = xmlNewInputMemory(ctxt, NULL, data, datalen,
|
||||
(const char *) doc->encoding,
|
||||
XML_INPUT_BUF_STATIC);
|
||||
if (input == NULL) {
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
return(XML_ERR_NO_MEMORY);
|
||||
}
|
||||
|
||||
if (doc->encoding != NULL)
|
||||
xmlSwitchEncodingName(ctxt, (const char *) doc->encoding);
|
||||
|
||||
xmlCtxtUseOptions(ctxt, options);
|
||||
xmlCtxtInitializeLate(ctxt);
|
||||
ctxt->myDoc = doc;
|
||||
/* parsing in context, i.e. as within existing content */
|
||||
ctxt->input_id = 2;
|
||||
|
||||
/*
|
||||
* TODO: Use xmlCtxtParseContent
|
||||
*/
|
||||
list = xmlCtxtParseContent(ctxt, input, node, /* hasTextDecl */ 0);
|
||||
|
||||
fake = xmlNewDocComment(node->doc, NULL);
|
||||
if (fake == NULL) {
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
return(XML_ERR_NO_MEMORY);
|
||||
}
|
||||
xmlAddChild(node, fake);
|
||||
|
||||
if (node->type == XML_ELEMENT_NODE)
|
||||
nodePush(ctxt, node);
|
||||
|
||||
if ((ctxt->html == 0) && (node->type == XML_ELEMENT_NODE)) {
|
||||
/*
|
||||
* initialize the SAX2 namespaces stack
|
||||
*/
|
||||
cur = node;
|
||||
while ((cur != NULL) && (cur->type == XML_ELEMENT_NODE)) {
|
||||
xmlNsPtr ns = cur->nsDef;
|
||||
xmlHashedString hprefix, huri;
|
||||
|
||||
while (ns != NULL) {
|
||||
hprefix = xmlDictLookupHashed(ctxt->dict, ns->prefix, -1);
|
||||
huri = xmlDictLookupHashed(ctxt->dict, ns->href, -1);
|
||||
if (xmlParserNsPush(ctxt, &hprefix, &huri, ns, 1) > 0)
|
||||
nsnr++;
|
||||
ns = ns->next;
|
||||
}
|
||||
cur = cur->parent;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ctxt->validate) || (ctxt->replaceEntities != 0)) {
|
||||
/*
|
||||
* ID/IDREF registration will be done in xmlValidateElement below
|
||||
*/
|
||||
ctxt->loadsubset |= XML_SKIP_IDS;
|
||||
}
|
||||
|
||||
#ifdef LIBXML_HTML_ENABLED
|
||||
if (doc->type == XML_HTML_DOCUMENT_NODE)
|
||||
__htmlParseContent(ctxt);
|
||||
else
|
||||
#endif
|
||||
xmlParseContentInternal(ctxt);
|
||||
|
||||
if (ctxt->input->cur < ctxt->input->end)
|
||||
xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL);
|
||||
|
||||
xmlParserNsPop(ctxt, nsnr);
|
||||
|
||||
if ((ctxt->wellFormed) ||
|
||||
((ctxt->recovery) && (ctxt->errNo != XML_ERR_NO_MEMORY))) {
|
||||
ret = XML_ERR_OK;
|
||||
if (list == NULL) {
|
||||
ret = ctxt->errNo;
|
||||
if (ret == XML_ERR_ARGUMENT)
|
||||
ret = XML_ERR_INTERNAL_ERROR;
|
||||
} else {
|
||||
ret = (xmlParserErrors) ctxt->errNo;
|
||||
ret = XML_ERR_OK;
|
||||
*listOut = list;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the newly created nodeset after unlinking it from
|
||||
* the pseudo sibling.
|
||||
*/
|
||||
|
||||
cur = fake->next;
|
||||
fake->next = NULL;
|
||||
node->last = fake;
|
||||
|
||||
if (cur != NULL) {
|
||||
cur->prev = NULL;
|
||||
}
|
||||
|
||||
*lst = cur;
|
||||
|
||||
while (cur != NULL) {
|
||||
cur->parent = NULL;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
xmlUnlinkNode(fake);
|
||||
xmlFreeNode(fake);
|
||||
|
||||
|
||||
if (ret != XML_ERR_OK) {
|
||||
xmlFreeNodeList(*lst);
|
||||
*lst = NULL;
|
||||
}
|
||||
|
||||
if (doc->dict != NULL)
|
||||
ctxt->dict = NULL;
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
|
||||
return(ret);
|
||||
@ -12574,10 +12598,12 @@ xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax,
|
||||
}
|
||||
|
||||
input = xmlNewStringInputStream(ctxt, string);
|
||||
if (input == NULL)
|
||||
return(ctxt->errNo);
|
||||
if (input == NULL) {
|
||||
ret = ctxt->errNo;
|
||||
goto error;
|
||||
}
|
||||
|
||||
list = xmlCtxtParseContent(ctxt, input, /* hasTextDecl */ 0, 1);
|
||||
list = xmlCtxtParseContentInternal(ctxt, input, /* hasTextDecl */ 0, 1);
|
||||
if (listOut != NULL)
|
||||
*listOut = list;
|
||||
else
|
||||
@ -12588,6 +12614,7 @@ xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax,
|
||||
else
|
||||
ret = XML_ERR_OK;
|
||||
|
||||
error:
|
||||
xmlFreeInputStream(input);
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
return(ret);
|
||||
|
@ -319,6 +319,9 @@ xmlCtxtVErr(xmlParserCtxtPtr ctxt, xmlNodePtr node, xmlErrorDomain domain,
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctxt == NULL)
|
||||
return;
|
||||
|
||||
if (PARSER_STOPPED(ctxt))
|
||||
return;
|
||||
|
||||
|
134
runtest.c
134
runtest.c
@ -33,6 +33,7 @@
|
||||
#include <libxml/tree.h>
|
||||
#include <libxml/uri.h>
|
||||
#include <libxml/encoding.h>
|
||||
#include <libxml/xmlsave.h>
|
||||
|
||||
#ifdef LIBXML_OUTPUT_ENABLED
|
||||
#ifdef LIBXML_READER_ENABLED
|
||||
@ -2060,6 +2061,78 @@ pushBoundaryTest(const char *filename, const char *result,
|
||||
}
|
||||
#endif
|
||||
|
||||
static char *
|
||||
dumpNodeList(xmlNodePtr list) {
|
||||
xmlBufferPtr buffer;
|
||||
xmlSaveCtxtPtr save;
|
||||
xmlNodePtr cur;
|
||||
char *ret;
|
||||
|
||||
buffer = xmlBufferCreate();
|
||||
save = xmlSaveToBuffer(buffer, "UTF-8", 0);
|
||||
for (cur = list; cur != NULL; cur = cur->next)
|
||||
xmlSaveTree(save, cur);
|
||||
xmlSaveClose(save);
|
||||
|
||||
ret = (char *) xmlBufferDetach(buffer);
|
||||
xmlBufferFree(buffer);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static int
|
||||
testParseContent(xmlParserCtxtPtr ctxt, xmlDocPtr doc, const char *filename) {
|
||||
xmlParserInputPtr input;
|
||||
xmlNodePtr root = NULL, list;
|
||||
char *content, *roundTrip;
|
||||
int ret = 0;
|
||||
|
||||
if (ctxt->html) {
|
||||
xmlNodePtr cur;
|
||||
|
||||
if (doc == NULL || doc->children == NULL)
|
||||
return 0;
|
||||
for (cur = doc->children->children; cur != NULL; cur = cur->next) {
|
||||
if (xmlStrEqual(cur->name, BAD_CAST "body")) {
|
||||
root = cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
root = xmlDocGetRootElement(doc);
|
||||
}
|
||||
if (root == NULL)
|
||||
return 0;
|
||||
|
||||
content = dumpNodeList(root->children);
|
||||
|
||||
input = xmlInputCreateString(NULL, content, XML_INPUT_BUF_STATIC);
|
||||
list = xmlCtxtParseContent(ctxt, input, root, 0);
|
||||
roundTrip = dumpNodeList(list);
|
||||
if (strcmp(content, roundTrip) != 0) {
|
||||
fprintf(stderr, "xmlCtxtParseContent failed for %s\n", filename);
|
||||
ret = -1;
|
||||
}
|
||||
xmlFree(roundTrip);
|
||||
xmlFreeNodeList(list);
|
||||
|
||||
/* xmlParseInNodeContext uses the document's encoding. */
|
||||
xmlFree((xmlChar *) doc->encoding);
|
||||
doc->encoding = (const xmlChar *) xmlStrdup(BAD_CAST "UTF-8");
|
||||
xmlParseInNodeContext(root, content, strlen(content),
|
||||
ctxt->options | XML_PARSE_NOERROR,
|
||||
&list);
|
||||
roundTrip = dumpNodeList(list);
|
||||
if (strcmp(content, roundTrip) != 0) {
|
||||
fprintf(stderr, "xmlParseInNodeContext failed for %s\n", filename);
|
||||
ret = -1;
|
||||
}
|
||||
xmlFree(roundTrip);
|
||||
xmlFreeNodeList(list);
|
||||
|
||||
xmlFree(content);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* memParseTest:
|
||||
* @filename: the file to parse
|
||||
@ -2075,10 +2148,14 @@ pushBoundaryTest(const char *filename, const char *result,
|
||||
static int
|
||||
memParseTest(const char *filename, const char *result,
|
||||
const char *err ATTRIBUTE_UNUSED,
|
||||
int options ATTRIBUTE_UNUSED) {
|
||||
int options) {
|
||||
xmlParserCtxtPtr ctxt;
|
||||
xmlDocPtr doc;
|
||||
const char *base;
|
||||
int size, res;
|
||||
int ret = 0;
|
||||
|
||||
options |= XML_PARSE_NOWARNING;
|
||||
|
||||
nb_tests++;
|
||||
/*
|
||||
@ -2089,22 +2166,26 @@ memParseTest(const char *filename, const char *result,
|
||||
return(-1);
|
||||
}
|
||||
|
||||
doc = xmlReadMemory(base, size, filename, NULL, XML_PARSE_NOWARNING);
|
||||
ctxt = xmlNewParserCtxt();
|
||||
doc = xmlCtxtReadMemory(ctxt, base, size, filename, NULL, options);
|
||||
unloadMem(base);
|
||||
if (doc == NULL) {
|
||||
return(1);
|
||||
}
|
||||
xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
|
||||
xmlFreeDoc(doc);
|
||||
res = compareFileMem(result, base, size);
|
||||
if ((base == NULL) || (res != 0)) {
|
||||
if (base != NULL)
|
||||
xmlFree((char *)base);
|
||||
fprintf(stderr, "Result for %s failed in %s\n", filename, result);
|
||||
return(-1);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (testParseContent(ctxt, doc, filename) < 0)
|
||||
ret = -1;
|
||||
|
||||
xmlFreeDoc(doc);
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
xmlFree((char *)base);
|
||||
return(0);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2181,8 +2262,8 @@ errParseTest(const char *filename, const char *result, const char *err,
|
||||
int options) {
|
||||
xmlParserCtxtPtr ctxt;
|
||||
xmlDocPtr doc;
|
||||
const char *base = NULL;
|
||||
int size, res = 0;
|
||||
int ret = 0;
|
||||
|
||||
nb_tests++;
|
||||
#ifdef LIBXML_HTML_ENABLED
|
||||
@ -2190,14 +2271,12 @@ errParseTest(const char *filename, const char *result, const char *err,
|
||||
ctxt = htmlNewParserCtxt();
|
||||
xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
|
||||
doc = htmlCtxtReadFile(ctxt, filename, NULL, options);
|
||||
htmlFreeParserCtxt(ctxt);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ctxt = xmlNewParserCtxt();
|
||||
xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
|
||||
doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
#ifdef LIBXML_XINCLUDE_ENABLED
|
||||
if (options & XML_PARSE_XINCLUDE) {
|
||||
xmlXIncludeCtxtPtr xinc = NULL;
|
||||
@ -2215,40 +2294,45 @@ errParseTest(const char *filename, const char *result, const char *err,
|
||||
#endif
|
||||
}
|
||||
if (result) {
|
||||
xmlChar *base = NULL;
|
||||
|
||||
if (doc == NULL) {
|
||||
base = "";
|
||||
base = xmlStrdup(BAD_CAST "");
|
||||
size = 0;
|
||||
} else {
|
||||
#ifdef LIBXML_HTML_ENABLED
|
||||
if (options & XML_PARSE_HTML) {
|
||||
htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
|
||||
htmlDocDumpMemory(doc, &base, &size);
|
||||
} else
|
||||
#endif
|
||||
xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
|
||||
xmlDocDumpMemory(doc, &base, &size);
|
||||
}
|
||||
res = compareFileMem(result, base, size);
|
||||
}
|
||||
if (doc != NULL) {
|
||||
if (base != NULL)
|
||||
xmlFree((char *)base);
|
||||
xmlFreeDoc(doc);
|
||||
res = compareFileMem(result, (char *) base, size);
|
||||
xmlFree(base);
|
||||
}
|
||||
|
||||
if (res != 0) {
|
||||
fprintf(stderr, "Result for %s failed in %s\n", filename, result);
|
||||
return(-1);
|
||||
}
|
||||
if (err != NULL) {
|
||||
ret = -1;
|
||||
} else if (err != NULL) {
|
||||
res = compareFileMem(err, testErrors, testErrorsSize);
|
||||
if (res != 0) {
|
||||
fprintf(stderr, "Error for %s failed\n", filename);
|
||||
return(-1);
|
||||
ret = -1;
|
||||
}
|
||||
} else if (options & XML_PARSE_DTDVALID) {
|
||||
if (testErrorsSize != 0)
|
||||
if (testErrorsSize != 0) {
|
||||
fprintf(stderr, "Validation for %s failed\n", filename);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
if (testParseContent(ctxt, doc, filename) < 0)
|
||||
ret = -1;
|
||||
|
||||
xmlFreeDoc(doc);
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_HTML_ENABLED)
|
||||
|
70
testapi.c
70
testapi.c
@ -12059,6 +12059,59 @@ test_xmlCtxtGetVersion(void) {
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
test_xmlCtxtParseContent(void) {
|
||||
int test_ret = 0;
|
||||
|
||||
int mem_base;
|
||||
xmlNodePtr ret_val;
|
||||
xmlParserCtxtPtr ctxt; /* parser context */
|
||||
int n_ctxt;
|
||||
xmlParserInputPtr input; /* parser input */
|
||||
int n_input;
|
||||
xmlNodePtr node; /* target node or document */
|
||||
int n_node;
|
||||
int hasTextDecl; /* whether to parse text declaration */
|
||||
int n_hasTextDecl;
|
||||
|
||||
for (n_ctxt = 0;n_ctxt < gen_nb_xmlParserCtxtPtr;n_ctxt++) {
|
||||
for (n_input = 0;n_input < gen_nb_xmlParserInputPtr;n_input++) {
|
||||
for (n_node = 0;n_node < gen_nb_xmlNodePtr;n_node++) {
|
||||
for (n_hasTextDecl = 0;n_hasTextDecl < gen_nb_int;n_hasTextDecl++) {
|
||||
mem_base = xmlMemBlocks();
|
||||
ctxt = gen_xmlParserCtxtPtr(n_ctxt, 0);
|
||||
input = gen_xmlParserInputPtr(n_input, 1);
|
||||
node = gen_xmlNodePtr(n_node, 2);
|
||||
hasTextDecl = gen_int(n_hasTextDecl, 3);
|
||||
|
||||
ret_val = xmlCtxtParseContent(ctxt, input, node, hasTextDecl);
|
||||
desret_xmlNodePtr(ret_val);
|
||||
call_tests++;
|
||||
des_xmlParserCtxtPtr(n_ctxt, ctxt, 0);
|
||||
des_xmlParserInputPtr(n_input, input, 1);
|
||||
des_xmlNodePtr(n_node, node, 2);
|
||||
des_int(n_hasTextDecl, hasTextDecl, 3);
|
||||
xmlResetLastError();
|
||||
if (mem_base != xmlMemBlocks()) {
|
||||
printf("Leak of %d blocks found in xmlCtxtParseContent",
|
||||
xmlMemBlocks() - mem_base);
|
||||
test_ret++;
|
||||
printf(" %d", n_ctxt);
|
||||
printf(" %d", n_input);
|
||||
printf(" %d", n_node);
|
||||
printf(" %d", n_hasTextDecl);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function_tests++;
|
||||
|
||||
return(test_ret);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
test_xmlCtxtParseDocument(void) {
|
||||
int test_ret = 0;
|
||||
@ -13602,29 +13655,29 @@ test_xmlParseInNodeContext(void) {
|
||||
int n_datalen;
|
||||
int options; /* a combination of xmlParserOption */
|
||||
int n_options;
|
||||
xmlNodePtr * lst; /* the return value for the set of parsed nodes */
|
||||
int n_lst;
|
||||
xmlNodePtr * listOut; /* the return value for the set of parsed nodes */
|
||||
int n_listOut;
|
||||
|
||||
for (n_node = 0;n_node < gen_nb_xmlNodePtr;n_node++) {
|
||||
for (n_data = 0;n_data < gen_nb_const_char_ptr;n_data++) {
|
||||
for (n_datalen = 0;n_datalen < gen_nb_int;n_datalen++) {
|
||||
for (n_options = 0;n_options < gen_nb_parseroptions;n_options++) {
|
||||
for (n_lst = 0;n_lst < gen_nb_xmlNodePtr_ptr;n_lst++) {
|
||||
for (n_listOut = 0;n_listOut < gen_nb_xmlNodePtr_ptr;n_listOut++) {
|
||||
mem_base = xmlMemBlocks();
|
||||
node = gen_xmlNodePtr(n_node, 0);
|
||||
data = gen_const_char_ptr(n_data, 1);
|
||||
datalen = gen_int(n_datalen, 2);
|
||||
options = gen_parseroptions(n_options, 3);
|
||||
lst = gen_xmlNodePtr_ptr(n_lst, 4);
|
||||
listOut = gen_xmlNodePtr_ptr(n_listOut, 4);
|
||||
|
||||
ret_val = xmlParseInNodeContext(node, data, datalen, options, lst);
|
||||
ret_val = xmlParseInNodeContext(node, data, datalen, options, listOut);
|
||||
desret_xmlParserErrors(ret_val);
|
||||
call_tests++;
|
||||
des_xmlNodePtr(n_node, node, 0);
|
||||
des_const_char_ptr(n_data, data, 1);
|
||||
des_int(n_datalen, datalen, 2);
|
||||
des_parseroptions(n_options, options, 3);
|
||||
des_xmlNodePtr_ptr(n_lst, lst, 4);
|
||||
des_xmlNodePtr_ptr(n_listOut, listOut, 4);
|
||||
xmlResetLastError();
|
||||
if (mem_base != xmlMemBlocks()) {
|
||||
printf("Leak of %d blocks found in xmlParseInNodeContext",
|
||||
@ -13634,7 +13687,7 @@ test_xmlParseInNodeContext(void) {
|
||||
printf(" %d", n_data);
|
||||
printf(" %d", n_datalen);
|
||||
printf(" %d", n_options);
|
||||
printf(" %d", n_lst);
|
||||
printf(" %d", n_listOut);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
@ -15081,7 +15134,7 @@ static int
|
||||
test_parser(void) {
|
||||
int test_ret = 0;
|
||||
|
||||
if (quiet == 0) printf("Testing parser : 81 of 95 functions ...\n");
|
||||
if (quiet == 0) printf("Testing parser : 82 of 96 functions ...\n");
|
||||
test_ret += test_xmlByteConsumed();
|
||||
test_ret += test_xmlCleanupGlobals();
|
||||
test_ret += test_xmlClearNodeInfoSeq();
|
||||
@ -15095,6 +15148,7 @@ test_parser(void) {
|
||||
test_ret += test_xmlCtxtGetStandalone();
|
||||
test_ret += test_xmlCtxtGetStatus();
|
||||
test_ret += test_xmlCtxtGetVersion();
|
||||
test_ret += test_xmlCtxtParseContent();
|
||||
test_ret += test_xmlCtxtParseDocument();
|
||||
test_ret += test_xmlCtxtReadDoc();
|
||||
test_ret += test_xmlCtxtReadFile();
|
||||
|
83
testparser.c
83
testparser.c
@ -8,8 +8,10 @@
|
||||
|
||||
#include "libxml.h"
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/parserInternals.h>
|
||||
#include <libxml/uri.h>
|
||||
#include <libxml/xmlreader.h>
|
||||
#include <libxml/xmlsave.h>
|
||||
#include <libxml/xmlwriter.h>
|
||||
#include <libxml/HTMLparser.h>
|
||||
|
||||
@ -126,6 +128,84 @@ testCFileIO(void) {
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef LIBXML_OUTPUT_ENABLED
|
||||
static xmlChar *
|
||||
dumpNodeList(xmlNodePtr list) {
|
||||
xmlBufferPtr buffer;
|
||||
xmlSaveCtxtPtr save;
|
||||
xmlNodePtr cur;
|
||||
xmlChar *ret;
|
||||
|
||||
buffer = xmlBufferCreate();
|
||||
save = xmlSaveToBuffer(buffer, "UTF-8", 0);
|
||||
for (cur = list; cur != NULL; cur = cur->next)
|
||||
xmlSaveTree(save, cur);
|
||||
xmlSaveClose(save);
|
||||
|
||||
ret = xmlBufferDetach(buffer);
|
||||
xmlBufferFree(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
testCtxtParseContent(void) {
|
||||
xmlParserCtxtPtr ctxt;
|
||||
xmlParserInputPtr input;
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr node, list;
|
||||
const char *content;
|
||||
xmlChar *output;
|
||||
int i, j;
|
||||
int err = 0;
|
||||
|
||||
static const char *const tests[] = {
|
||||
"<!-- c -->\xF0\x9F\x98\x84<a/><b/>end",
|
||||
"text<a:foo><b:foo/></a:foo>text<!-- c -->"
|
||||
};
|
||||
|
||||
doc = xmlReadDoc(BAD_CAST "<doc xmlns:a='a'><elem xmlns:b='b'/></doc>",
|
||||
NULL, NULL, 0);
|
||||
node = doc->children->children;
|
||||
|
||||
ctxt = xmlNewParserCtxt();
|
||||
|
||||
for (i = 0; (size_t) i < sizeof(tests) / sizeof(tests[0]); i++) {
|
||||
content = tests[i];
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
if (j == 0) {
|
||||
input = xmlInputCreateString(NULL, content,
|
||||
XML_INPUT_BUF_STATIC);
|
||||
list = xmlCtxtParseContent(ctxt, input, node, 0);
|
||||
} else {
|
||||
xmlParseInNodeContext(node, content, strlen(content), 0,
|
||||
&list);
|
||||
}
|
||||
|
||||
output = dumpNodeList(list);
|
||||
|
||||
if ((j == 0 && ctxt->nsWellFormed == 0) ||
|
||||
strcmp((char *) output, content) != 0) {
|
||||
fprintf(stderr, "%s failed test %d, got:\n%s\n",
|
||||
j == 0 ?
|
||||
"xmlCtxtParseContent" :
|
||||
"xmlParseInNodeContext",
|
||||
i, output);
|
||||
err = 1;
|
||||
}
|
||||
|
||||
xmlFree(output);
|
||||
xmlFreeNodeList(list);
|
||||
}
|
||||
}
|
||||
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
xmlFreeDoc(doc);
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif /* LIBXML_OUTPUT_ENABLED */
|
||||
|
||||
#ifdef LIBXML_SAX1_ENABLED
|
||||
static int
|
||||
testBalancedChunk(void) {
|
||||
@ -681,6 +761,9 @@ main(void) {
|
||||
err |= testUnsupportedEncoding();
|
||||
err |= testNodeGetContent();
|
||||
err |= testCFileIO();
|
||||
#ifdef LIBXML_OUTPUT_ENABLED
|
||||
err |= testCtxtParseContent();
|
||||
#endif
|
||||
#ifdef LIBXML_SAX1_ENABLED
|
||||
err |= testBalancedChunk();
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user