mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2026-01-26 21:41:34 +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:
54
HTMLparser.c
54
HTMLparser.c
@@ -4716,18 +4716,50 @@ htmlParseContentInternal(htmlParserCtxtPtr ctxt) {
|
|||||||
if (currentNode != NULL) xmlFree(currentNode);
|
if (currentNode != NULL) xmlFree(currentNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
xmlNodePtr
|
||||||
* htmlParseContent:
|
htmlCtxtParseContentInternal(htmlParserCtxtPtr ctxt, xmlParserInputPtr input) {
|
||||||
* @ctxt: an HTML parser context
|
xmlNodePtr root;
|
||||||
*
|
xmlNodePtr list = NULL;
|
||||||
* Parse a content: comment, sub-element, reference or text.
|
xmlChar *rootName = BAD_CAST "#root";
|
||||||
* This is the entry point when called from parser.c
|
|
||||||
*/
|
|
||||||
|
|
||||||
void
|
root = xmlNewDocNode(ctxt->myDoc, NULL, rootName, NULL);
|
||||||
__htmlParseContent(void *ctxt) {
|
if (root == NULL) {
|
||||||
if (ctxt != NULL)
|
htmlErrMemory(ctxt);
|
||||||
htmlParseContentInternal((htmlParserCtxtPtr) 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='xmlCtxtGetStandalone' type='function'/>
|
||||||
<exports symbol='xmlCtxtGetStatus' type='function'/>
|
<exports symbol='xmlCtxtGetStatus' type='function'/>
|
||||||
<exports symbol='xmlCtxtGetVersion' type='function'/>
|
<exports symbol='xmlCtxtGetVersion' type='function'/>
|
||||||
|
<exports symbol='xmlCtxtParseContent' type='function'/>
|
||||||
<exports symbol='xmlCtxtParseDocument' type='function'/>
|
<exports symbol='xmlCtxtParseDocument' type='function'/>
|
||||||
<exports symbol='xmlCtxtReadDoc' type='function'/>
|
<exports symbol='xmlCtxtReadDoc' type='function'/>
|
||||||
<exports symbol='xmlCtxtReadFd' 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.'/>
|
<return type='const xmlChar *' info='the version from the XML declaration.'/>
|
||||||
<arg name='ctxt' type='xmlParserCtxtPtr' info=''/>
|
<arg name='ctxt' type='xmlParserCtxtPtr' info=''/>
|
||||||
</function>
|
</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'>
|
<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>
|
<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'/>
|
<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'/>
|
<arg name='ctxt' type='xmlParserCtxtPtr' info='an XML parser context'/>
|
||||||
</function>
|
</function>
|
||||||
<function name='xmlParseContent' file='parserInternals' module='parser'>
|
<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'/>
|
<return type='void'/>
|
||||||
<arg name='ctxt' type='xmlParserCtxtPtr' info='an XML parser context'/>
|
<arg name='ctxt' type='xmlParserCtxtPtr' info='an XML parser context'/>
|
||||||
</function>
|
</function>
|
||||||
@@ -11471,13 +11480,13 @@ crash if you try to modify the tree)'/>
|
|||||||
<arg name='filename' type='const char *' info='the filename'/>
|
<arg name='filename' type='const char *' info='the filename'/>
|
||||||
</function>
|
</function>
|
||||||
<function name='xmlParseInNodeContext' file='parser' module='parser'>
|
<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'/>
|
<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='node' type='xmlNodePtr' info='the context node'/>
|
||||||
<arg name='data' type='const char *' info='the input string'/>
|
<arg name='data' type='const char *' info='the input string'/>
|
||||||
<arg name='datalen' type='int' info='the input string length in bytes'/>
|
<arg name='datalen' type='int' info='the input string length in bytes'/>
|
||||||
<arg name='options' type='int' info='a combination of xmlParserOption'/>
|
<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>
|
||||||
<function name='xmlParseMarkupDecl' file='parserInternals' module='parser'>
|
<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>
|
<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
|
XMLPUBFUN xmlDocPtr
|
||||||
xmlCtxtParseDocument (xmlParserCtxtPtr ctxt,
|
xmlCtxtParseDocument (xmlParserCtxtPtr ctxt,
|
||||||
xmlParserInputPtr input);
|
xmlParserInputPtr input);
|
||||||
|
XMLPUBFUN xmlNodePtr
|
||||||
|
xmlCtxtParseContent (xmlParserCtxtPtr ctxt,
|
||||||
|
xmlParserInputPtr input,
|
||||||
|
xmlNodePtr node,
|
||||||
|
int hasTextDecl);
|
||||||
XMLPUBFUN xmlDocPtr
|
XMLPUBFUN xmlDocPtr
|
||||||
xmlCtxtReadDoc (xmlParserCtxtPtr ctxt,
|
xmlCtxtReadDoc (xmlParserCtxtPtr ctxt,
|
||||||
const xmlChar *cur,
|
const xmlChar *cur,
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
#ifdef LIBXML_HTML_ENABLED
|
#ifdef LIBXML_HTML_ENABLED
|
||||||
|
|
||||||
XML_HIDDEN void
|
XML_HIDDEN xmlNodePtr
|
||||||
__htmlParseContent(void *ctx);
|
htmlCtxtParseContentInternal(xmlParserCtxtPtr ctxt, xmlParserInputPtr input);
|
||||||
|
|
||||||
#endif /* LIBXML_HTML_ENABLED */
|
#endif /* LIBXML_HTML_ENABLED */
|
||||||
|
|
||||||
|
|||||||
329
parser.c
329
parser.c
@@ -7573,7 +7573,7 @@ xmlHandleUndeclaredEntity(xmlParserCtxtPtr ctxt, const xmlChar *name) {
|
|||||||
*/
|
*/
|
||||||
xmlValidityError(ctxt, XML_ERR_UNDECLARED_ENTITY,
|
xmlValidityError(ctxt, XML_ERR_UNDECLARED_ENTITY,
|
||||||
"Entity '%s' not defined\n", name, NULL);
|
"Entity '%s' not defined\n", name, NULL);
|
||||||
} else if ((ctxt->loadsubset) ||
|
} else if ((ctxt->loadsubset & ~XML_SKIP_IDS) ||
|
||||||
((ctxt->replaceEntities) &&
|
((ctxt->replaceEntities) &&
|
||||||
((ctxt->options & XML_PARSE_NO_XXE) == 0))) {
|
((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
|
* Parse XML element content. This is useful if you're only interested
|
||||||
* in custom SAX callbacks. If you want a node list, use
|
* in custom SAX callbacks. If you want a node list, use
|
||||||
* xmlParseInNodeContext.
|
* xmlCtxtParseContent.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
xmlParseContent(xmlParserCtxtPtr ctxt) {
|
xmlParseContent(xmlParserCtxtPtr ctxt) {
|
||||||
@@ -12000,7 +12000,7 @@ xmlParseDTD(const xmlChar *ExternalID, const xmlChar *SystemID) {
|
|||||||
************************************************************************/
|
************************************************************************/
|
||||||
|
|
||||||
static xmlNodePtr
|
static xmlNodePtr
|
||||||
xmlCtxtParseContent(xmlParserCtxtPtr ctxt, xmlParserInputPtr input,
|
xmlCtxtParseContentInternal(xmlParserCtxtPtr ctxt, xmlParserInputPtr input,
|
||||||
int hasTextDecl, int buildTree) {
|
int hasTextDecl, int buildTree) {
|
||||||
xmlNodePtr root = NULL;
|
xmlNodePtr root = NULL;
|
||||||
xmlNodePtr list = NULL;
|
xmlNodePtr list = NULL;
|
||||||
@@ -12056,17 +12056,13 @@ xmlCtxtParseContent(xmlParserCtxtPtr ctxt, xmlParserInputPtr input,
|
|||||||
xmlNodePtr cur;
|
xmlNodePtr cur;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the newly created nodeset after unlinking it from
|
* Unlink newly created node list.
|
||||||
* its pseudo parent.
|
|
||||||
*/
|
*/
|
||||||
cur = root->children;
|
list = root->children;
|
||||||
list = cur;
|
|
||||||
while (cur != NULL) {
|
|
||||||
cur->parent = NULL;
|
|
||||||
cur = cur->next;
|
|
||||||
}
|
|
||||||
root->children = NULL;
|
root->children = NULL;
|
||||||
root->last = 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:
|
* This initiates a recursive call chain:
|
||||||
*
|
*
|
||||||
* - xmlCtxtParseContent
|
* - xmlCtxtParseContentInternal
|
||||||
* - xmlParseContentInternal
|
* - xmlParseContentInternal
|
||||||
* - xmlParseReference
|
* - xmlParseReference
|
||||||
* - xmlCtxtParseEntity
|
* - xmlCtxtParseEntity
|
||||||
@@ -12157,7 +12153,7 @@ xmlCtxtParseEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr ent) {
|
|||||||
|
|
||||||
ent->flags |= XML_ENT_EXPANDING;
|
ent->flags |= XML_ENT_EXPANDING;
|
||||||
|
|
||||||
list = xmlCtxtParseContent(ctxt, input, isExternal, buildTree);
|
list = xmlCtxtParseContentInternal(ctxt, input, isExternal, buildTree);
|
||||||
|
|
||||||
ent->flags &= ~XML_ENT_EXPANDING;
|
ent->flags &= ~XML_ENT_EXPANDING;
|
||||||
|
|
||||||
@@ -12232,7 +12228,7 @@ xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctxt, const xmlChar *URL,
|
|||||||
|
|
||||||
xmlCtxtInitializeLate(ctxt);
|
xmlCtxtInitializeLate(ctxt);
|
||||||
|
|
||||||
list = xmlCtxtParseContent(ctxt, input, /* hasTextDecl */ 1, 1);
|
list = xmlCtxtParseContentInternal(ctxt, input, /* hasTextDecl */ 1, 1);
|
||||||
if (listOut != NULL)
|
if (listOut != NULL)
|
||||||
*listOut = list;
|
*listOut = list;
|
||||||
else
|
else
|
||||||
@@ -12318,127 +12314,120 @@ xmlParseBalancedChunkMemory(xmlDocPtr doc, xmlSAXHandlerPtr sax,
|
|||||||
#endif /* LIBXML_SAX1_ENABLED */
|
#endif /* LIBXML_SAX1_ENABLED */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* xmlParseInNodeContext:
|
* xmlCtxtParseContent:
|
||||||
* @node: the context node
|
* @ctxt: parser context
|
||||||
* @data: the input string
|
* @input: parser input
|
||||||
* @datalen: the input string length in bytes
|
* @node: target node or document
|
||||||
* @options: a combination of xmlParserOption
|
* @hasTextDecl: whether to parse text declaration
|
||||||
* @lst: the return value for the set of parsed nodes
|
|
||||||
*
|
*
|
||||||
* Parse a well-balanced chunk of an XML document
|
* Parse a well-balanced chunk of XML matching the 'content' production.
|
||||||
* within the context (DTD, namespaces, etc ...) of the given node.
|
|
||||||
*
|
*
|
||||||
* The allowed sequence for the data is a Well Balanced Chunk defined by
|
* Namespaces in scope of @node and entities of @node's document are
|
||||||
* the content production in the XML grammar:
|
* recognized. When validating, the DTD of @node's document is used.
|
||||||
*
|
*
|
||||||
* [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
|
* Always consumes @input even in error case.
|
||||||
*
|
*
|
||||||
* Returns XML_ERR_OK if the chunk is well balanced, and the parser
|
* Available since 2.14.0.
|
||||||
* error code otherwise
|
*
|
||||||
|
* Returns a node list or NULL in case of error.
|
||||||
*/
|
*/
|
||||||
xmlParserErrors
|
xmlNodePtr
|
||||||
xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen,
|
xmlCtxtParseContent(xmlParserCtxtPtr ctxt, xmlParserInputPtr input,
|
||||||
int options, xmlNodePtr *lst) {
|
xmlNodePtr node, int hasTextDecl) {
|
||||||
xmlParserCtxtPtr ctxt;
|
xmlDocPtr doc;
|
||||||
xmlDocPtr doc = NULL;
|
xmlNodePtr cur, list = NULL;
|
||||||
xmlNodePtr fake, cur;
|
|
||||||
int nsnr = 0;
|
int nsnr = 0;
|
||||||
|
xmlDictPtr oldDict;
|
||||||
|
int oldOptions, oldDictNames, oldLoadSubset;
|
||||||
|
|
||||||
xmlParserErrors ret = XML_ERR_OK;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* check all input parameters, grab the document
|
|
||||||
*/
|
|
||||||
if ((lst == NULL) || (node == NULL) || (data == NULL) || (datalen < 0))
|
|
||||||
return(XML_ERR_ARGUMENT);
|
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case XML_ELEMENT_NODE:
|
case XML_ELEMENT_NODE:
|
||||||
|
case XML_DOCUMENT_NODE:
|
||||||
|
case XML_HTML_DOCUMENT_NODE:
|
||||||
|
break;
|
||||||
|
|
||||||
case XML_ATTRIBUTE_NODE:
|
case XML_ATTRIBUTE_NODE:
|
||||||
case XML_TEXT_NODE:
|
case XML_TEXT_NODE:
|
||||||
case XML_CDATA_SECTION_NODE:
|
case XML_CDATA_SECTION_NODE:
|
||||||
case XML_ENTITY_REF_NODE:
|
case XML_ENTITY_REF_NODE:
|
||||||
case XML_PI_NODE:
|
case XML_PI_NODE:
|
||||||
case XML_COMMENT_NODE:
|
case XML_COMMENT_NODE:
|
||||||
case XML_DOCUMENT_NODE:
|
for (cur = node->parent; cur != NULL; cur = node->parent) {
|
||||||
case XML_HTML_DOCUMENT_NODE:
|
if ((cur->type == XML_ELEMENT_NODE) ||
|
||||||
|
(cur->type == XML_DOCUMENT_NODE) ||
|
||||||
|
(cur->type == XML_HTML_DOCUMENT_NODE)) {
|
||||||
|
node = cur;
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
return(XML_ERR_INTERNAL_ERROR);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
while ((node != NULL) && (node->type != XML_ELEMENT_NODE) &&
|
}
|
||||||
(node->type != XML_DOCUMENT_NODE) &&
|
break;
|
||||||
(node->type != XML_HTML_DOCUMENT_NODE))
|
|
||||||
node = node->parent;
|
default:
|
||||||
if (node == NULL)
|
xmlFatalErr(ctxt, XML_ERR_ARGUMENT, NULL);
|
||||||
return(XML_ERR_INTERNAL_ERROR);
|
goto exit;
|
||||||
if (node->type == XML_ELEMENT_NODE)
|
}
|
||||||
doc = node->doc;
|
|
||||||
|
#ifdef LIBXML_HTML_ENABLED
|
||||||
|
if (ctxt->html)
|
||||||
|
htmlCtxtReset(ctxt);
|
||||||
else
|
else
|
||||||
doc = (xmlDocPtr) node;
|
#endif
|
||||||
if (doc == NULL)
|
xmlCtxtReset(ctxt);
|
||||||
return(XML_ERR_INTERNAL_ERROR);
|
|
||||||
|
oldDict = ctxt->dict;
|
||||||
|
oldOptions = ctxt->options;
|
||||||
|
oldDictNames = ctxt->dictNames;
|
||||||
|
oldLoadSubset = ctxt->loadsubset;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* allocate a context and set-up everything not related to the
|
* Use input doc's dict if present, else assure XML_PARSE_NODICT is set.
|
||||||
* node position in the tree
|
|
||||||
*/
|
*/
|
||||||
if (doc->type == XML_DOCUMENT_NODE)
|
if (doc->dict != NULL) {
|
||||||
ctxt = xmlCreateMemoryParserCtxt((char *) data, datalen);
|
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
|
#ifdef LIBXML_HTML_ENABLED
|
||||||
else if (doc->type == XML_HTML_DOCUMENT_NODE) {
|
if (ctxt->html) {
|
||||||
ctxt = htmlCreateMemoryParserCtxt((char *) data, datalen);
|
|
||||||
/*
|
/*
|
||||||
* When parsing in context, it makes no sense to add implied
|
* When parsing in context, it makes no sense to add implied
|
||||||
* elements like html/body/etc...
|
* elements like html/body/etc...
|
||||||
*/
|
*/
|
||||||
options |= HTML_PARSE_NOIMPLIED;
|
ctxt->options |= HTML_PARSE_NOIMPLIED;
|
||||||
}
|
|
||||||
|
list = htmlCtxtParseContentInternal(ctxt, input);
|
||||||
|
} else
|
||||||
#endif
|
#endif
|
||||||
else
|
{
|
||||||
return(XML_ERR_INTERNAL_ERROR);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doc->encoding != NULL)
|
|
||||||
xmlSwitchEncodingName(ctxt, (const char *) doc->encoding);
|
|
||||||
|
|
||||||
xmlCtxtUseOptions(ctxt, options);
|
|
||||||
xmlCtxtInitializeLate(ctxt);
|
xmlCtxtInitializeLate(ctxt);
|
||||||
ctxt->myDoc = doc;
|
|
||||||
/* parsing in context, i.e. as within existing content */
|
|
||||||
ctxt->input_id = 2;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: Use xmlCtxtParseContent
|
* 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;
|
||||||
|
|
||||||
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
|
* initialize the SAX2 namespaces stack
|
||||||
*/
|
*/
|
||||||
@@ -12456,65 +12445,100 @@ xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen,
|
|||||||
}
|
}
|
||||||
cur = cur->parent;
|
cur = cur->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list = xmlCtxtParseContentInternal(ctxt, input, hasTextDecl, 1);
|
||||||
|
|
||||||
|
if (nsnr > 0)
|
||||||
|
xmlParserNsPop(ctxt, nsnr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ctxt->validate) || (ctxt->replaceEntities != 0)) {
|
ctxt->dict = oldDict;
|
||||||
/*
|
ctxt->options = oldOptions;
|
||||||
* ID/IDREF registration will be done in xmlValidateElement below
|
ctxt->dictNames = oldDictNames;
|
||||||
*/
|
ctxt->loadsubset = oldLoadSubset;
|
||||||
ctxt->loadsubset |= XML_SKIP_IDS;
|
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
|
||||||
|
* @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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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 *listOut) {
|
||||||
|
xmlParserCtxtPtr ctxt;
|
||||||
|
xmlParserInputPtr input;
|
||||||
|
xmlDocPtr doc;
|
||||||
|
xmlNodePtr list;
|
||||||
|
xmlParserErrors ret;
|
||||||
|
|
||||||
|
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
|
#ifdef LIBXML_HTML_ENABLED
|
||||||
if (doc->type == XML_HTML_DOCUMENT_NODE)
|
if (doc->type == XML_HTML_DOCUMENT_NODE) {
|
||||||
__htmlParseContent(ctxt);
|
ctxt = htmlNewParserCtxt();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
xmlParseContentInternal(ctxt);
|
ctxt = xmlNewParserCtxt();
|
||||||
|
|
||||||
if (ctxt->input->cur < ctxt->input->end)
|
if (ctxt == NULL)
|
||||||
xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL);
|
return(XML_ERR_NO_MEMORY);
|
||||||
|
|
||||||
xmlParserNsPop(ctxt, nsnr);
|
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 ((ctxt->wellFormed) ||
|
xmlCtxtUseOptions(ctxt, options);
|
||||||
((ctxt->recovery) && (ctxt->errNo != XML_ERR_NO_MEMORY))) {
|
|
||||||
ret = XML_ERR_OK;
|
list = xmlCtxtParseContent(ctxt, input, node, /* hasTextDecl */ 0);
|
||||||
|
|
||||||
|
if (list == NULL) {
|
||||||
|
ret = ctxt->errNo;
|
||||||
|
if (ret == XML_ERR_ARGUMENT)
|
||||||
|
ret = XML_ERR_INTERNAL_ERROR;
|
||||||
} else {
|
} 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);
|
xmlFreeParserCtxt(ctxt);
|
||||||
|
|
||||||
return(ret);
|
return(ret);
|
||||||
@@ -12574,10 +12598,12 @@ xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax,
|
|||||||
}
|
}
|
||||||
|
|
||||||
input = xmlNewStringInputStream(ctxt, string);
|
input = xmlNewStringInputStream(ctxt, string);
|
||||||
if (input == NULL)
|
if (input == NULL) {
|
||||||
return(ctxt->errNo);
|
ret = ctxt->errNo;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
list = xmlCtxtParseContent(ctxt, input, /* hasTextDecl */ 0, 1);
|
list = xmlCtxtParseContentInternal(ctxt, input, /* hasTextDecl */ 0, 1);
|
||||||
if (listOut != NULL)
|
if (listOut != NULL)
|
||||||
*listOut = list;
|
*listOut = list;
|
||||||
else
|
else
|
||||||
@@ -12588,6 +12614,7 @@ xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax,
|
|||||||
else
|
else
|
||||||
ret = XML_ERR_OK;
|
ret = XML_ERR_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
xmlFreeInputStream(input);
|
xmlFreeInputStream(input);
|
||||||
xmlFreeParserCtxt(ctxt);
|
xmlFreeParserCtxt(ctxt);
|
||||||
return(ret);
|
return(ret);
|
||||||
|
|||||||
@@ -319,6 +319,9 @@ xmlCtxtVErr(xmlParserCtxtPtr ctxt, xmlNodePtr node, xmlErrorDomain domain,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctxt == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
if (PARSER_STOPPED(ctxt))
|
if (PARSER_STOPPED(ctxt))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
134
runtest.c
134
runtest.c
@@ -33,6 +33,7 @@
|
|||||||
#include <libxml/tree.h>
|
#include <libxml/tree.h>
|
||||||
#include <libxml/uri.h>
|
#include <libxml/uri.h>
|
||||||
#include <libxml/encoding.h>
|
#include <libxml/encoding.h>
|
||||||
|
#include <libxml/xmlsave.h>
|
||||||
|
|
||||||
#ifdef LIBXML_OUTPUT_ENABLED
|
#ifdef LIBXML_OUTPUT_ENABLED
|
||||||
#ifdef LIBXML_READER_ENABLED
|
#ifdef LIBXML_READER_ENABLED
|
||||||
@@ -2060,6 +2061,78 @@ pushBoundaryTest(const char *filename, const char *result,
|
|||||||
}
|
}
|
||||||
#endif
|
#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:
|
* memParseTest:
|
||||||
* @filename: the file to parse
|
* @filename: the file to parse
|
||||||
@@ -2075,10 +2148,14 @@ pushBoundaryTest(const char *filename, const char *result,
|
|||||||
static int
|
static int
|
||||||
memParseTest(const char *filename, const char *result,
|
memParseTest(const char *filename, const char *result,
|
||||||
const char *err ATTRIBUTE_UNUSED,
|
const char *err ATTRIBUTE_UNUSED,
|
||||||
int options ATTRIBUTE_UNUSED) {
|
int options) {
|
||||||
|
xmlParserCtxtPtr ctxt;
|
||||||
xmlDocPtr doc;
|
xmlDocPtr doc;
|
||||||
const char *base;
|
const char *base;
|
||||||
int size, res;
|
int size, res;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
options |= XML_PARSE_NOWARNING;
|
||||||
|
|
||||||
nb_tests++;
|
nb_tests++;
|
||||||
/*
|
/*
|
||||||
@@ -2089,22 +2166,26 @@ memParseTest(const char *filename, const char *result,
|
|||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
doc = xmlReadMemory(base, size, filename, NULL, XML_PARSE_NOWARNING);
|
ctxt = xmlNewParserCtxt();
|
||||||
|
doc = xmlCtxtReadMemory(ctxt, base, size, filename, NULL, options);
|
||||||
unloadMem(base);
|
unloadMem(base);
|
||||||
if (doc == NULL) {
|
if (doc == NULL) {
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
|
xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
|
||||||
xmlFreeDoc(doc);
|
|
||||||
res = compareFileMem(result, base, size);
|
res = compareFileMem(result, base, size);
|
||||||
if ((base == NULL) || (res != 0)) {
|
if ((base == NULL) || (res != 0)) {
|
||||||
if (base != NULL)
|
|
||||||
xmlFree((char *)base);
|
|
||||||
fprintf(stderr, "Result for %s failed in %s\n", filename, result);
|
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);
|
xmlFree((char *)base);
|
||||||
return(0);
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2181,8 +2262,8 @@ errParseTest(const char *filename, const char *result, const char *err,
|
|||||||
int options) {
|
int options) {
|
||||||
xmlParserCtxtPtr ctxt;
|
xmlParserCtxtPtr ctxt;
|
||||||
xmlDocPtr doc;
|
xmlDocPtr doc;
|
||||||
const char *base = NULL;
|
|
||||||
int size, res = 0;
|
int size, res = 0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
nb_tests++;
|
nb_tests++;
|
||||||
#ifdef LIBXML_HTML_ENABLED
|
#ifdef LIBXML_HTML_ENABLED
|
||||||
@@ -2190,14 +2271,12 @@ errParseTest(const char *filename, const char *result, const char *err,
|
|||||||
ctxt = htmlNewParserCtxt();
|
ctxt = htmlNewParserCtxt();
|
||||||
xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
|
xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
|
||||||
doc = htmlCtxtReadFile(ctxt, filename, NULL, options);
|
doc = htmlCtxtReadFile(ctxt, filename, NULL, options);
|
||||||
htmlFreeParserCtxt(ctxt);
|
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
ctxt = xmlNewParserCtxt();
|
ctxt = xmlNewParserCtxt();
|
||||||
xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
|
xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
|
||||||
doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
|
doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
|
||||||
xmlFreeParserCtxt(ctxt);
|
|
||||||
#ifdef LIBXML_XINCLUDE_ENABLED
|
#ifdef LIBXML_XINCLUDE_ENABLED
|
||||||
if (options & XML_PARSE_XINCLUDE) {
|
if (options & XML_PARSE_XINCLUDE) {
|
||||||
xmlXIncludeCtxtPtr xinc = NULL;
|
xmlXIncludeCtxtPtr xinc = NULL;
|
||||||
@@ -2215,40 +2294,45 @@ errParseTest(const char *filename, const char *result, const char *err,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (result) {
|
if (result) {
|
||||||
|
xmlChar *base = NULL;
|
||||||
|
|
||||||
if (doc == NULL) {
|
if (doc == NULL) {
|
||||||
base = "";
|
base = xmlStrdup(BAD_CAST "");
|
||||||
size = 0;
|
size = 0;
|
||||||
} else {
|
} else {
|
||||||
#ifdef LIBXML_HTML_ENABLED
|
#ifdef LIBXML_HTML_ENABLED
|
||||||
if (options & XML_PARSE_HTML) {
|
if (options & XML_PARSE_HTML) {
|
||||||
htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
|
htmlDocDumpMemory(doc, &base, &size);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
|
xmlDocDumpMemory(doc, &base, &size);
|
||||||
}
|
}
|
||||||
res = compareFileMem(result, base, size);
|
res = compareFileMem(result, (char *) base, size);
|
||||||
}
|
xmlFree(base);
|
||||||
if (doc != NULL) {
|
|
||||||
if (base != NULL)
|
|
||||||
xmlFree((char *)base);
|
|
||||||
xmlFreeDoc(doc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
fprintf(stderr, "Result for %s failed in %s\n", filename, result);
|
fprintf(stderr, "Result for %s failed in %s\n", filename, result);
|
||||||
return(-1);
|
ret = -1;
|
||||||
}
|
} else if (err != NULL) {
|
||||||
if (err != NULL) {
|
|
||||||
res = compareFileMem(err, testErrors, testErrorsSize);
|
res = compareFileMem(err, testErrors, testErrorsSize);
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
fprintf(stderr, "Error for %s failed\n", filename);
|
fprintf(stderr, "Error for %s failed\n", filename);
|
||||||
return(-1);
|
ret = -1;
|
||||||
}
|
}
|
||||||
} else if (options & XML_PARSE_DTDVALID) {
|
} else if (options & XML_PARSE_DTDVALID) {
|
||||||
if (testErrorsSize != 0)
|
if (testErrorsSize != 0) {
|
||||||
fprintf(stderr, "Validation for %s failed\n", filename);
|
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)
|
#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
|
static int
|
||||||
test_xmlCtxtParseDocument(void) {
|
test_xmlCtxtParseDocument(void) {
|
||||||
int test_ret = 0;
|
int test_ret = 0;
|
||||||
@@ -13602,29 +13655,29 @@ test_xmlParseInNodeContext(void) {
|
|||||||
int n_datalen;
|
int n_datalen;
|
||||||
int options; /* a combination of xmlParserOption */
|
int options; /* a combination of xmlParserOption */
|
||||||
int n_options;
|
int n_options;
|
||||||
xmlNodePtr * lst; /* the return value for the set of parsed nodes */
|
xmlNodePtr * listOut; /* the return value for the set of parsed nodes */
|
||||||
int n_lst;
|
int n_listOut;
|
||||||
|
|
||||||
for (n_node = 0;n_node < gen_nb_xmlNodePtr;n_node++) {
|
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_data = 0;n_data < gen_nb_const_char_ptr;n_data++) {
|
||||||
for (n_datalen = 0;n_datalen < gen_nb_int;n_datalen++) {
|
for (n_datalen = 0;n_datalen < gen_nb_int;n_datalen++) {
|
||||||
for (n_options = 0;n_options < gen_nb_parseroptions;n_options++) {
|
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();
|
mem_base = xmlMemBlocks();
|
||||||
node = gen_xmlNodePtr(n_node, 0);
|
node = gen_xmlNodePtr(n_node, 0);
|
||||||
data = gen_const_char_ptr(n_data, 1);
|
data = gen_const_char_ptr(n_data, 1);
|
||||||
datalen = gen_int(n_datalen, 2);
|
datalen = gen_int(n_datalen, 2);
|
||||||
options = gen_parseroptions(n_options, 3);
|
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);
|
desret_xmlParserErrors(ret_val);
|
||||||
call_tests++;
|
call_tests++;
|
||||||
des_xmlNodePtr(n_node, node, 0);
|
des_xmlNodePtr(n_node, node, 0);
|
||||||
des_const_char_ptr(n_data, data, 1);
|
des_const_char_ptr(n_data, data, 1);
|
||||||
des_int(n_datalen, datalen, 2);
|
des_int(n_datalen, datalen, 2);
|
||||||
des_parseroptions(n_options, options, 3);
|
des_parseroptions(n_options, options, 3);
|
||||||
des_xmlNodePtr_ptr(n_lst, lst, 4);
|
des_xmlNodePtr_ptr(n_listOut, listOut, 4);
|
||||||
xmlResetLastError();
|
xmlResetLastError();
|
||||||
if (mem_base != xmlMemBlocks()) {
|
if (mem_base != xmlMemBlocks()) {
|
||||||
printf("Leak of %d blocks found in xmlParseInNodeContext",
|
printf("Leak of %d blocks found in xmlParseInNodeContext",
|
||||||
@@ -13634,7 +13687,7 @@ test_xmlParseInNodeContext(void) {
|
|||||||
printf(" %d", n_data);
|
printf(" %d", n_data);
|
||||||
printf(" %d", n_datalen);
|
printf(" %d", n_datalen);
|
||||||
printf(" %d", n_options);
|
printf(" %d", n_options);
|
||||||
printf(" %d", n_lst);
|
printf(" %d", n_listOut);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15081,7 +15134,7 @@ static int
|
|||||||
test_parser(void) {
|
test_parser(void) {
|
||||||
int test_ret = 0;
|
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_xmlByteConsumed();
|
||||||
test_ret += test_xmlCleanupGlobals();
|
test_ret += test_xmlCleanupGlobals();
|
||||||
test_ret += test_xmlClearNodeInfoSeq();
|
test_ret += test_xmlClearNodeInfoSeq();
|
||||||
@@ -15095,6 +15148,7 @@ test_parser(void) {
|
|||||||
test_ret += test_xmlCtxtGetStandalone();
|
test_ret += test_xmlCtxtGetStandalone();
|
||||||
test_ret += test_xmlCtxtGetStatus();
|
test_ret += test_xmlCtxtGetStatus();
|
||||||
test_ret += test_xmlCtxtGetVersion();
|
test_ret += test_xmlCtxtGetVersion();
|
||||||
|
test_ret += test_xmlCtxtParseContent();
|
||||||
test_ret += test_xmlCtxtParseDocument();
|
test_ret += test_xmlCtxtParseDocument();
|
||||||
test_ret += test_xmlCtxtReadDoc();
|
test_ret += test_xmlCtxtReadDoc();
|
||||||
test_ret += test_xmlCtxtReadFile();
|
test_ret += test_xmlCtxtReadFile();
|
||||||
|
|||||||
83
testparser.c
83
testparser.c
@@ -8,8 +8,10 @@
|
|||||||
|
|
||||||
#include "libxml.h"
|
#include "libxml.h"
|
||||||
#include <libxml/parser.h>
|
#include <libxml/parser.h>
|
||||||
|
#include <libxml/parserInternals.h>
|
||||||
#include <libxml/uri.h>
|
#include <libxml/uri.h>
|
||||||
#include <libxml/xmlreader.h>
|
#include <libxml/xmlreader.h>
|
||||||
|
#include <libxml/xmlsave.h>
|
||||||
#include <libxml/xmlwriter.h>
|
#include <libxml/xmlwriter.h>
|
||||||
#include <libxml/HTMLparser.h>
|
#include <libxml/HTMLparser.h>
|
||||||
|
|
||||||
@@ -126,6 +128,84 @@ testCFileIO(void) {
|
|||||||
return err;
|
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
|
#ifdef LIBXML_SAX1_ENABLED
|
||||||
static int
|
static int
|
||||||
testBalancedChunk(void) {
|
testBalancedChunk(void) {
|
||||||
@@ -681,6 +761,9 @@ main(void) {
|
|||||||
err |= testUnsupportedEncoding();
|
err |= testUnsupportedEncoding();
|
||||||
err |= testNodeGetContent();
|
err |= testNodeGetContent();
|
||||||
err |= testCFileIO();
|
err |= testCFileIO();
|
||||||
|
#ifdef LIBXML_OUTPUT_ENABLED
|
||||||
|
err |= testCtxtParseContent();
|
||||||
|
#endif
|
||||||
#ifdef LIBXML_SAX1_ENABLED
|
#ifdef LIBXML_SAX1_ENABLED
|
||||||
err |= testBalancedChunk();
|
err |= testBalancedChunk();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user