diff --git a/HTMLparser.c b/HTMLparser.c
index 070c9c1d..02ab081e 100644
--- a/HTMLparser.c
+++ b/HTMLparser.c
@@ -5927,13 +5927,7 @@ htmlCtxtParseDocument(htmlParserCtxtPtr ctxt, xmlParserInputPtr input)
ctxt->html = INSERT_INITIAL;
htmlParseDocument(ctxt);
- if (ctxt->errNo != XML_ERR_NO_MEMORY) {
- ret = ctxt->myDoc;
- } else {
- ret = NULL;
- xmlFreeDoc(ctxt->myDoc);
- }
- ctxt->myDoc = NULL;
+ ret = xmlCtxtGetDocument(ctxt);
/* assert(ctxt->inputNr == 1); */
while (ctxt->inputNr > 0)
diff --git a/doc/libxml2-api.xml b/doc/libxml2-api.xml
index 58eee541..fb95c15d 100644
--- a/doc/libxml2-api.xml
+++ b/doc/libxml2-api.xml
@@ -690,11 +690,16 @@
+
+
+
+
+
@@ -713,6 +718,7 @@
+
@@ -8451,6 +8457,11 @@ crash if you try to modify the tree)'/>
+
+ Available since 2.14.0.
+
+
+
Get the last parsing error registered.
@@ -8466,6 +8477,11 @@ crash if you try to modify the tree)'/>
+
+ Available since 2.14.0.
+
+
+
Available since 2.14.0.
@@ -8476,11 +8492,26 @@ crash if you try to modify the tree)'/>
+
+ Available since 2.14.0.
+
+
+
Available since 2.14.0.
+
+ Available since 2.14.0.
+
+
+
+
+ Available since 2.14.0.
+
+
+
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.
@@ -8632,6 +8663,12 @@ crash if you try to modify the tree)'/>
+
+ Available since 2.14.0. Set the SAX handler struct to a copy of @sax.
+
+
+
+
DEPRECATED: Use xmlCtxtSetOptions. Applies the options to the parser context. The following options are never cleared and can only be enabled: XML_PARSE_NOERROR XML_PARSE_NOWARNING XML_PARSE_NONET XML_PARSE_NSCLEAN XML_PARSE_NOCDATA XML_PARSE_COMPACT XML_PARSE_OLD10 XML_PARSE_HUGE XML_PARSE_OLDSAX XML_PARSE_IGNORE_ENC XML_PARSE_BIG_LINES
diff --git a/include/libxml/parser.h b/include/libxml/parser.h
index b5c74429..d78304cb 100644
--- a/include/libxml/parser.h
+++ b/include/libxml/parser.h
@@ -1405,6 +1405,19 @@ XMLPUBFUN xmlDictPtr
XMLPUBFUN void
xmlCtxtSetDict (xmlParserCtxtPtr ctxt,
xmlDictPtr);
+XMLPUBFUN xmlSAXHandler *
+ xmlCtxtGetSaxHandler (xmlParserCtxtPtr ctxt);
+XMLPUBFUN int
+ xmlCtxtSetSaxHandler (xmlParserCtxtPtr ctxt,
+ const xmlSAXHandler *sax);
+XMLPUBFUN xmlDocPtr
+ xmlCtxtGetDocument (xmlParserCtxtPtr ctxt);
+XMLPUBFUN int
+ xmlCtxtIsHtml (xmlParserCtxtPtr ctxt);
+XMLPUBFUN int
+ xmlCtxtIsStopped (xmlParserCtxtPtr ctxt);
+XMLPUBFUN xmlValidCtxtPtr
+ xmlCtxtGetValidCtxt (xmlParserCtxtPtr ctxt);
XMLPUBFUN const xmlChar *
xmlCtxtGetVersion (xmlParserCtxtPtr ctxt);
XMLPUBFUN const xmlChar *
diff --git a/parser.c b/parser.c
index 10f1d6a4..283539ac 100644
--- a/parser.c
+++ b/parser.c
@@ -13816,17 +13816,9 @@ xmlCtxtParseDocument(xmlParserCtxtPtr ctxt, xmlParserInputPtr input)
xmlParseDocument(ctxt);
- if ((ctxt->wellFormed) ||
- ((ctxt->recovery) && (!xmlCtxtIsCatastrophicError(ctxt)))) {
- ret = ctxt->myDoc;
- } else {
- if (ctxt->errNo == XML_ERR_OK)
- xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, "unknown error\n");
-
- ret = NULL;
- xmlFreeDoc(ctxt->myDoc);
- }
- ctxt->myDoc = NULL;
+ ret = xmlCtxtGetDocument(ctxt);
+ if ((ret == NULL) && (ctxt->errNo == XML_ERR_OK))
+ xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, "unknown error\n");
/* assert(ctxt->inputNr == 1); */
while (ctxt->inputNr > 0)
diff --git a/parserInternals.c b/parserInternals.c
index effd566c..5c80694c 100644
--- a/parserInternals.c
+++ b/parserInternals.c
@@ -3162,6 +3162,130 @@ xmlCtxtSetDict(xmlParserCtxtPtr ctxt, xmlDictPtr dict) {
ctxt->dict = dict;
}
+/**
+ * xmlCtxtGetSaxHandler:
+ * @ctxt: parser context
+ *
+ * Available since 2.14.0.
+ *
+ * Returns the SAX handler struct. This is not a copy and must not
+ * be freed. Handlers can be updated.
+ */
+xmlSAXHandler *
+xmlCtxtGetSaxHandler(xmlParserCtxtPtr ctxt) {
+ if (ctxt == NULL)
+ return(NULL);
+
+ return(ctxt->sax);
+}
+
+/**
+ * xmlCtxtSetSaxHandler:
+ * @ctxt: parser context
+ * @sax: SAX handler
+ *
+ * Available since 2.14.0.
+ *
+ * Set the SAX handler struct to a copy of @sax.
+ *
+ * Returns 0 on success or -1 if arguments are invalid or a memory
+ * allocation failed.
+ */
+int
+xmlCtxtSetSaxHandler(xmlParserCtxtPtr ctxt, const xmlSAXHandler *sax) {
+ xmlSAXHandler *copy;
+
+ if ((ctxt == NULL) || (sax == NULL))
+ return(-1);
+
+ copy = xmlMalloc(sizeof(*copy));
+ if (copy == NULL)
+ return(-1);
+
+ memcpy(copy, sax, sizeof(*copy));
+ ctxt->sax = copy;
+
+ return(0);
+}
+
+/**
+ * xmlCtxtGetDocument:
+ * @ctxt: parser context
+ *
+ * Available since 2.14.0.
+ *
+ * Returns the parsed document or NULL if a fatal error occurred when
+ * parsing. The document must be freed by the caller. Resets the
+ * context's document to NULL.
+ */
+xmlDocPtr
+xmlCtxtGetDocument(xmlParserCtxtPtr ctxt) {
+ xmlDocPtr doc;
+
+ if (ctxt == NULL)
+ return(NULL);
+
+ if ((ctxt->wellFormed) ||
+ (((ctxt->recovery) || (ctxt->html)) &&
+ (!xmlCtxtIsCatastrophicError(ctxt)))) {
+ doc = ctxt->myDoc;
+ } else {
+ doc = NULL;
+ xmlFreeDoc(ctxt->myDoc);
+ }
+ ctxt->myDoc = NULL;
+
+ return(doc);
+}
+
+/**
+ * xmlCtxtIsHtml:
+ * @ctxt: parser context
+ *
+ * Available since 2.14.0.
+ *
+ * Returns 1 if this is a HTML parser context, 0 otherwise.
+ */
+int
+xmlCtxtIsHtml(xmlParserCtxtPtr ctxt) {
+ if (ctxt == NULL)
+ return(0);
+
+ return(ctxt->html ? 1 : 0);
+}
+
+/**
+ * xmlCtxtIsStopped:
+ * @ctxt: parser context
+ *
+ * Available since 2.14.0.
+ *
+ * Returns 1 if the parser is stopped, 0 otherwise.
+ */
+int
+xmlCtxtIsStopped(xmlParserCtxtPtr ctxt) {
+ if (ctxt == NULL)
+ return(0);
+
+ return(PARSER_STOPPED(ctxt));
+}
+
+/**
+ * xmlCtxtGetValidCtxt:
+ * @ctxt: parser context
+ *
+ * Available since 2.14.0.
+ *
+ * Returns the validation context.
+ */
+xmlValidCtxtPtr
+xmlCtxtGetValidCtxt(xmlParserCtxtPtr ctxt) {
+ if (ctxt == NULL)
+ return(NULL);
+
+ return(&ctxt->vctxt);
+}
+
/************************************************************************
* *
* Handling of node information *
diff --git a/testapi.c b/testapi.c
index 4828da0c..72d82a77 100644
--- a/testapi.c
+++ b/testapi.c
@@ -11937,6 +11937,38 @@ test_xmlCtxtGetDeclaredEncoding(void) {
}
+static int
+test_xmlCtxtGetDocument(void) {
+ int test_ret = 0;
+
+ int mem_base;
+ xmlDocPtr ret_val;
+ xmlParserCtxtPtr ctxt; /* parser context */
+ int n_ctxt;
+
+ for (n_ctxt = 0;n_ctxt < gen_nb_xmlParserCtxtPtr;n_ctxt++) {
+ mem_base = xmlMemBlocks();
+ ctxt = gen_xmlParserCtxtPtr(n_ctxt, 0);
+
+ ret_val = xmlCtxtGetDocument(ctxt);
+ desret_xmlDocPtr(ret_val);
+ call_tests++;
+ des_xmlParserCtxtPtr(n_ctxt, ctxt, 0);
+ xmlResetLastError();
+ if (mem_base != xmlMemBlocks()) {
+ printf("Leak of %d blocks found in xmlCtxtGetDocument",
+ xmlMemBlocks() - mem_base);
+ test_ret++;
+ printf(" %d", n_ctxt);
+ printf("\n");
+ }
+ }
+ function_tests++;
+
+ return(test_ret);
+}
+
+
static int
test_xmlCtxtGetOptions(void) {
int test_ret = 0;
@@ -12001,6 +12033,16 @@ test_xmlCtxtGetPrivate(void) {
}
+static int
+test_xmlCtxtGetSaxHandler(void) {
+ int test_ret = 0;
+
+
+ /* missing type support */
+ return(test_ret);
+}
+
+
static int
test_xmlCtxtGetStandalone(void) {
int test_ret = 0;
@@ -12069,6 +12111,16 @@ test_xmlCtxtGetStatus(void) {
}
+static int
+test_xmlCtxtGetValidCtxt(void) {
+ int test_ret = 0;
+
+
+ /* missing type support */
+ return(test_ret);
+}
+
+
static int
test_xmlCtxtGetVersion(void) {
int test_ret = 0;
@@ -12101,6 +12153,70 @@ test_xmlCtxtGetVersion(void) {
}
+static int
+test_xmlCtxtIsHtml(void) {
+ int test_ret = 0;
+
+ int mem_base;
+ int ret_val;
+ xmlParserCtxtPtr ctxt; /* parser context */
+ int n_ctxt;
+
+ for (n_ctxt = 0;n_ctxt < gen_nb_xmlParserCtxtPtr;n_ctxt++) {
+ mem_base = xmlMemBlocks();
+ ctxt = gen_xmlParserCtxtPtr(n_ctxt, 0);
+
+ ret_val = xmlCtxtIsHtml(ctxt);
+ desret_int(ret_val);
+ call_tests++;
+ des_xmlParserCtxtPtr(n_ctxt, ctxt, 0);
+ xmlResetLastError();
+ if (mem_base != xmlMemBlocks()) {
+ printf("Leak of %d blocks found in xmlCtxtIsHtml",
+ xmlMemBlocks() - mem_base);
+ test_ret++;
+ printf(" %d", n_ctxt);
+ printf("\n");
+ }
+ }
+ function_tests++;
+
+ return(test_ret);
+}
+
+
+static int
+test_xmlCtxtIsStopped(void) {
+ int test_ret = 0;
+
+ int mem_base;
+ int ret_val;
+ xmlParserCtxtPtr ctxt; /* parser context */
+ int n_ctxt;
+
+ for (n_ctxt = 0;n_ctxt < gen_nb_xmlParserCtxtPtr;n_ctxt++) {
+ mem_base = xmlMemBlocks();
+ ctxt = gen_xmlParserCtxtPtr(n_ctxt, 0);
+
+ ret_val = xmlCtxtIsStopped(ctxt);
+ desret_int(ret_val);
+ call_tests++;
+ des_xmlParserCtxtPtr(n_ctxt, ctxt, 0);
+ xmlResetLastError();
+ if (mem_base != xmlMemBlocks()) {
+ printf("Leak of %d blocks found in xmlCtxtIsStopped",
+ xmlMemBlocks() - mem_base);
+ test_ret++;
+ printf(" %d", n_ctxt);
+ printf("\n");
+ }
+ }
+ function_tests++;
+
+ return(test_ret);
+}
+
+
static int
test_xmlCtxtParseContent(void) {
int test_ret = 0;
@@ -12714,6 +12830,49 @@ test_xmlCtxtSetResourceLoader(void) {
}
+#define gen_nb_const_xmlSAXHandler_ptr 1
+#define gen_const_xmlSAXHandler_ptr(no, nr) NULL
+#define des_const_xmlSAXHandler_ptr(no, val, nr)
+
+static int
+test_xmlCtxtSetSaxHandler(void) {
+ int test_ret = 0;
+
+ int mem_base;
+ int ret_val;
+ xmlParserCtxtPtr ctxt; /* parser context */
+ int n_ctxt;
+ const xmlSAXHandler * sax; /* SAX handler */
+ int n_sax;
+
+ for (n_ctxt = 0;n_ctxt < gen_nb_xmlParserCtxtPtr;n_ctxt++) {
+ for (n_sax = 0;n_sax < gen_nb_const_xmlSAXHandler_ptr;n_sax++) {
+ mem_base = xmlMemBlocks();
+ ctxt = gen_xmlParserCtxtPtr(n_ctxt, 0);
+ sax = gen_const_xmlSAXHandler_ptr(n_sax, 1);
+
+ ret_val = xmlCtxtSetSaxHandler(ctxt, sax);
+ desret_int(ret_val);
+ call_tests++;
+ des_xmlParserCtxtPtr(n_ctxt, ctxt, 0);
+ des_const_xmlSAXHandler_ptr(n_sax, sax, 1);
+ xmlResetLastError();
+ if (mem_base != xmlMemBlocks()) {
+ printf("Leak of %d blocks found in xmlCtxtSetSaxHandler",
+ xmlMemBlocks() - mem_base);
+ test_ret++;
+ printf(" %d", n_ctxt);
+ printf(" %d", n_sax);
+ printf("\n");
+ }
+ }
+ }
+ function_tests++;
+
+ return(test_ret);
+}
+
+
static int
test_xmlCtxtUseOptions(void) {
int test_ret = 0;
@@ -13415,10 +13574,6 @@ test_xmlNewParserCtxt(void) {
}
-#define gen_nb_const_xmlSAXHandler_ptr 1
-#define gen_const_xmlSAXHandler_ptr(no, nr) NULL
-#define des_const_xmlSAXHandler_ptr(no, val, nr)
-
static int
test_xmlNewSAXParserCtxt(void) {
int test_ret = 0;
@@ -15489,7 +15644,7 @@ static int
test_parser(void) {
int test_ret = 0;
- if (quiet == 0) printf("Testing parser : 88 of 104 functions ...\n");
+ if (quiet == 0) printf("Testing parser : 92 of 110 functions ...\n");
test_ret += test_xmlByteConsumed();
test_ret += test_xmlCleanupGlobals();
test_ret += test_xmlClearNodeInfoSeq();
@@ -15498,11 +15653,16 @@ test_parser(void) {
test_ret += test_xmlCreatePushParserCtxt();
test_ret += test_xmlCtxtGetCatalogs();
test_ret += test_xmlCtxtGetDeclaredEncoding();
+ test_ret += test_xmlCtxtGetDocument();
test_ret += test_xmlCtxtGetOptions();
test_ret += test_xmlCtxtGetPrivate();
+ test_ret += test_xmlCtxtGetSaxHandler();
test_ret += test_xmlCtxtGetStandalone();
test_ret += test_xmlCtxtGetStatus();
+ test_ret += test_xmlCtxtGetValidCtxt();
test_ret += test_xmlCtxtGetVersion();
+ test_ret += test_xmlCtxtIsHtml();
+ test_ret += test_xmlCtxtIsStopped();
test_ret += test_xmlCtxtParseContent();
test_ret += test_xmlCtxtParseDocument();
test_ret += test_xmlCtxtParseDtd();
@@ -15519,6 +15679,7 @@ test_parser(void) {
test_ret += test_xmlCtxtSetOptions();
test_ret += test_xmlCtxtSetPrivate();
test_ret += test_xmlCtxtSetResourceLoader();
+ test_ret += test_xmlCtxtSetSaxHandler();
test_ret += test_xmlCtxtUseOptions();
test_ret += test_xmlCtxtValidateDocument();
test_ret += test_xmlCtxtValidateDtd();