adding xmlMemBlocks() work on generator of an automatic API regression

* xmlmemory.c include/libxml/xmlmemory.h: adding xmlMemBlocks()
* Makefile.am gentest.py testapi.c: work on generator of an
  automatic API regression test tool.
* SAX2.c nanoftp.c parser.c parserInternals.c tree.c xmlIO.c
  xmlstring.c: various API hardeing changes as a result of running
  teh first set of automatic API regression tests.
* test/slashdot16.xml: apparently missing from CVS, commited it
Daniel
diff --git a/ChangeLog b/ChangeLog
index f3cd904..491d988 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+Tue Nov  2 15:49:34 CET 2004 Daniel Veillard <daniel@veillard.com>
+
+	* xmlmemory.c include/libxml/xmlmemory.h: adding xmlMemBlocks()
+	* Makefile.am gentest.py testapi.c: work on generator of an
+	  automatic API regression test tool.
+	* SAX2.c nanoftp.c parser.c parserInternals.c tree.c xmlIO.c
+	  xmlstring.c: various API hardeing changes as a result of running
+	  teh first set of automatic API regression tests.
+	* test/slashdot16.xml: apparently missing from CVS, commited it
+
 Mon Nov  1 15:54:18 CET 2004 Daniel Veillard <daniel@veillard.com>
 
 	* xpath.c: fixed an UTF-8 parsing bug reported by Markus Bertheau
diff --git a/HTMLtree.c b/HTMLtree.c
index 9a5d35f..dc0b0f5 100644
--- a/HTMLtree.c
+++ b/HTMLtree.c
@@ -1053,6 +1053,9 @@
     const char *encoding;
     int ret;
 
+    if ((cur == NULL) || (filename == NULL))
+        return(-1);
+       
     xmlInitParser();
 
     encoding = (const char *) htmlGetMetaEncoding(cur);
@@ -1113,6 +1116,9 @@
     xmlCharEncodingHandlerPtr handler = NULL;
     int ret;
 
+    if ((cur == NULL) || (filename == NULL))
+        return(-1);
+       
     xmlInitParser();
 
     if (encoding != NULL) {
diff --git a/Makefile.am b/Makefile.am
index 583e812..a6115bd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,7 +8,7 @@
 
 noinst_PROGRAMS=testSchemas testRelax testSAX testHTML testXPath testURI \
                 testThreads testC14N testAutomata testRegexp \
-		testReader
+		testReader testapi
 
 bin_PROGRAMS = xmllint xmlcatalog
 
@@ -113,6 +113,14 @@
 testReader_DEPENDENCIES = $(DEPS)
 testReader_LDADD= $(LDADDS)
 
+testapi.c: gentest.py doc/libxml2-api.xml
+	-@(if [ "$(PYTHON)" != "" ] ; then $(PYTHON) gentest.py ; fi )
+
+testapi_SOURCES=testapi.c
+testapi_LDFLAGS = 
+testapi_DEPENDENCIES = $(DEPS)
+testapi_LDADD= $(LDADDS)
+
 #testOOM_SOURCES=testOOM.c testOOMlib.h testOOMlib.c
 #testOOM_LDFLAGS = 
 #testOOM_DEPENDENCIES = $(DEPS)
diff --git a/SAX2.c b/SAX2.c
index af36df9..f392660 100644
--- a/SAX2.c
+++ b/SAX2.c
@@ -890,7 +890,9 @@
 	ctxt->myDoc->encoding = ctxt->encoding;
 	ctxt->encoding = NULL;
     }
-    if ((ctxt->inputTab[0]->encoding != NULL) && (ctxt->myDoc != NULL) &&
+    if ((ctxt->inputTab != NULL) &&
+        (ctxt->inputNr > 0) && (ctxt->inputTab[0] != NULL) &&
+        (ctxt->inputTab[0]->encoding != NULL) && (ctxt->myDoc != NULL) &&
 	(ctxt->myDoc->encoding == NULL)) {
 	ctxt->myDoc->encoding = xmlStrdup(ctxt->inputTab[0]->encoding);
     }
diff --git a/gentest.py b/gentest.py
new file mode 100755
index 0000000..7732d16
--- /dev/null
+++ b/gentest.py
@@ -0,0 +1,556 @@
+#!/usr/bin/python -u
+#
+# generate a tester program for the API
+#
+import sys
+import string
+try:
+    import libxml2
+except:
+    print "libxml2 python bindings not available, skipping testapi.c generation"
+    sys.exit(0)
+
+#
+# Modules we don't want skip in API test
+#
+skipped_modules = [ "SAX", "SAX2", "xlink", "threads", "globals",
+  "xpathInternals", "xmlunicode", "parserInternals", "xmlmemory",
+  "xmlversion", "debugXML" ]
+
+#
+# Some function really need to be skipped for the tests.
+#
+skipped_functions = [ "xmlFdRead", "xmlReadFd", "xmlCtxtReadFd",
+                      "xmlCleanupParser" ]
+
+#
+# Those functions have side effect on the global state
+# and hence generate errors on memory allocation tests
+#
+skipped_memcheck = [ "xmlLoadCatalog", "xmlAddEncodingAlias",
+   "xmlSchemaInitTypes", "xmlNanoFTPProxy", "xmlNanoFTPScanProxy",
+   "xmlNanoHTTPScanProxy", "xmlResetLastError", "xmlCatalogConvert",
+   "xmlCatalogRemove", "xmlLoadCatalogs", "xmlCleanupCharEncodingHandlers",
+   "xmlInitCharEncodingHandlers" ]
+
+modules = []
+
+def is_skipped_module(name):
+    for mod in skipped_modules:
+        if mod == name:
+	    return 1
+    return 0
+
+def is_skipped_function(name):
+    for fun in skipped_functions:
+        if fun == name:
+	    return 1
+    # Do not test destructors
+    if string.find(name, 'Free') != -1:
+        return 1
+    return 0
+
+def is_skipped_memcheck(name):
+    for fun in skipped_memcheck:
+        if fun == name:
+	    return 1
+    return 0
+
+missing_types = {}
+def add_missing_type(name, func):
+    try:
+        list = missing_types[name]
+	list.append(func)
+    except:
+        missing_types[name] = [func]
+
+#
+# Open the input API description and the C test program result
+#
+doc = libxml2.readFile('doc/libxml2-api.xml', None, 0)
+if doc == None:
+    print "Failed to load doc/libxml2-api.xml"
+    sys.exit(1)
+test = open('testapi.c', 'w')
+ctxt = doc.xpathNewContext()
+headers = ctxt.xpathEval("/api/files/file")
+
+#
+# Generate the test header
+#
+test.write("""/*
+ * testapi.c: libxml2 API tester program.
+ *
+ * Automatically generated by gentest.py from libxml2-api.xml
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ */
+
+#include <stdio.h>
+#include <libxml/xmlerror.h>
+
+static int testlibxml2(void);
+
+static int generic_errors = 0;
+static int call_tests = 0;
+
+static void
+structured_errors(void *userData ATTRIBUTE_UNUSED,
+                  xmlErrorPtr error ATTRIBUTE_UNUSED) {
+    generic_errors++;
+}
+
+int main(void) {
+    int ret;
+    int blocks, mem;
+
+    LIBXML_TEST_VERSION
+
+    xmlSetStructuredErrorFunc(NULL, structured_errors);
+
+    ret = testlibxml2();
+
+    xmlCleanupParser();
+    blocks = xmlMemBlocks();
+    mem = xmlMemUsed();
+    if ((blocks != 0) || (mem != 0)) {
+        printf("testapi leaked %d bytes in %d blocks\\n", mem, blocks);
+    }
+    xmlMemoryDump();
+
+    return (ret != 0);
+}
+
+""");
+
+#
+# Load the interfaces
+# 
+for file in headers:
+    name = file.xpathEval('string(@name)')
+    if (name == None) or (name == ''):
+        continue
+
+    #
+    # do not test deprecated APIs
+    #
+    desc = file.xpathEval('string(description)')
+    if string.find(desc, 'DEPRECATED') != -1:
+        print "Skipping deprecated interface %s" % name
+	continue;
+
+    #
+    # Some module may be skipped because they don't really consists
+    # of user callable APIs
+    #
+    if is_skipped_module(name):
+        continue
+
+    test.write("#include <libxml/%s.h>\n" % name)
+    modules.append(name)
+        
+#
+# Generate the callers signatures
+# 
+for module in modules:
+    test.write("static int test_%s(void);\n" % module);
+
+#
+# Provide the type generators and destructors for the parameters
+#
+
+def type_convert(str, name, info, module, function):
+    res = string.replace(str, " *", "_ptr")
+    res = string.replace(res, " ", "_")
+    if res == 'const_char_ptr':
+        if string.find(name, "file") != -1 or \
+           string.find(name, "uri") != -1 or \
+           string.find(name, "URI") != -1 or \
+           string.find(info, "filename") != -1 or \
+           string.find(info, "URI") != -1 or \
+           string.find(info, "URL") != -1:
+	    if string.find(function, "Save") != -1:
+	        return('fileoutput')
+	    return('filepath')
+    if res == 'void_ptr':
+        if module == 'nanoftp' and name == 'ctx':
+	    return('xmlNanoFTPCtxtPtr')
+        if module == 'nanohttp' and name == 'ctx':
+	    return('xmlNanoHTTPCtxtPtr')
+        
+    return res
+
+known_param_types = [ "int", "const_char_ptr", "const_xmlChar_ptr",
+   "xmlParserCtxtPtr", "xmlDocPtr", "filepath", "fileoutput" ];
+
+def is_known_param_type(name):
+    for type in known_param_types:
+        if type == name:
+	    return 1
+    return 0
+
+test.write("""
+#define gen_nb_int 4
+
+static int gen_int(int no) {
+    if (no == 0) return(0);
+    if (no == 1) return(1);
+    if (no == 2) return(122);
+    return(-1);
+}
+
+static void des_int(int no ATTRIBUTE_UNUSED, int val ATTRIBUTE_UNUSED) {
+}
+
+#define gen_nb_const_char_ptr 4
+
+static const char *gen_const_char_ptr(int no) {
+    if (no == 0) return("foo");
+    if (no == 1) return("<foo/>");
+    if (no == 2) return("test/ent2");
+    return(NULL);
+}
+static void des_const_char_ptr(int no ATTRIBUTE_UNUSED, const char *val ATTRIBUTE_UNUSED) {
+}
+
+#define gen_nb_const_xmlChar_ptr 5
+
+static const xmlChar *gen_const_xmlChar_ptr(int no) {
+    if (no == 0) return((const xmlChar *) "foo");
+    if (no == 1) return((const xmlChar *) "<foo/>");
+    if (no == 2) return((const xmlChar *) "nøne");
+    if (no == 3) return((const xmlChar *) " 2ab ");
+    return(NULL);
+}
+static void des_const_xmlChar_ptr(int no ATTRIBUTE_UNUSED, const xmlChar *val ATTRIBUTE_UNUSED) {
+}
+
+#define gen_nb_filepath 8
+
+static const char *gen_filepath(int no) {
+    if (no == 0) return("missing.xml");
+    if (no == 1) return("<foo/>");
+    if (no == 2) return("test/ent2");
+    if (no == 3) return("test/valid/REC-xml-19980210.xml");
+    if (no == 4) return("test/valid/xhtml1-strict.dtd");
+    if (no == 5) return("http://missing.example.org/");
+    if (no == 6) return("http://missing. example.org/");
+    return(NULL);
+}
+static void des_filepath(int no ATTRIBUTE_UNUSED, const char *val ATTRIBUTE_UNUSED) {
+}
+
+#define gen_nb_fileoutput 6
+
+static const char *gen_fileoutput(int no) {
+    if (no == 0) return("/missing.xml");
+    if (no == 1) return("<foo/>");
+    if (no == 2) return("ftp://missing.example.org/foo");
+    if (no == 3) return("http://missing.example.org/");
+    if (no == 4) return("http://missing. example.org/");
+    return(NULL);
+}
+static void des_fileoutput(int no ATTRIBUTE_UNUSED, const char *val ATTRIBUTE_UNUSED) {
+}
+
+#define gen_nb_xmlParserCtxtPtr 2
+static xmlParserCtxtPtr gen_xmlParserCtxtPtr(int no) {
+    if (no == 0) return(xmlNewParserCtxt());
+    return(NULL);
+}
+static void des_xmlParserCtxtPtr(int no ATTRIBUTE_UNUSED, xmlParserCtxtPtr val) {
+    if (val != NULL)
+        xmlFreeParserCtxt(val);
+}
+
+#define gen_nb_xmlDocPtr 2
+static xmlDocPtr gen_xmlDocPtr(int no) {
+    if (no == 0) return(xmlNewDoc(BAD_CAST "1.0"));
+    return(NULL);
+}
+static void des_xmlDocPtr(int no ATTRIBUTE_UNUSED, xmlDocPtr val) {
+    if (val != NULL)
+        xmlFreeDoc(val);
+}
+
+""");
+
+#
+# Provide the type destructors for the return values
+#
+
+known_return_types = [ "int", "const_char_ptr", "xmlDocPtr", "xmlNodePtr" ];
+
+def is_known_return_type(name):
+    for type in known_return_types:
+        if type == name:
+	    return 1
+    return 0
+
+test.write("""
+static void desret_int(int val ATTRIBUTE_UNUSED) {
+}
+static void desret_const_char_ptr(const char *val ATTRIBUTE_UNUSED) {
+}
+static void desret_xmlDocPtr(xmlDocPtr val) {
+    xmlFreeDoc(val);
+}
+static void desret_xmlNodePtr(xmlNodePtr val) {
+    xmlUnlinkNode(val);
+    xmlFreeNode(val);
+}
+""");
+
+#
+# Generate the top caller
+# 
+
+test.write("""
+/**
+ * testlibxml2:
+ *
+ * Main entry point of the tester for the full libxml2 module,
+ * it calls all the tester entry point for each module.
+ *
+ * Returns the number of error found
+ */
+static int
+testlibxml2(void)
+{
+    int ret = 0;
+
+""")
+
+for module in modules:
+    test.write("    ret += test_%s();\n" % module)
+
+test.write("""
+    printf("Total: %d tests, %d errors\\n", call_tests, ret);
+    return(ret);
+}
+
+""")
+
+#
+# How to handle a function
+# 
+nb_tests = 0
+
+def generate_test(module, node):
+    global test
+    global nb_tests
+    nb_cond = 0
+    no_gen = 0
+
+    name = node.xpathEval('string(@name)')
+    if is_skipped_function(name):
+        return
+
+    test.write("""
+static int
+test_%s(void) {
+    int ret = 0;
+
+""" % (name))
+
+    #
+    # check we know how to handle the args and return values
+    # and store the informations for the generation
+    #
+    try:
+	args = node.xpathEval("arg")
+    except:
+        args = []
+    t_args = []
+    for arg in args:
+        rtype = arg.xpathEval("string(@type)")
+	if rtype == 'void':
+	    break;
+	info = arg.xpathEval("string(@info)")
+	nam = arg.xpathEval("string(@name)")
+        type = type_convert(rtype, nam, info, module, name)
+	if is_known_param_type(type) == 0:
+	    add_missing_type(type, name);
+	    no_gen = 1
+	t_args.append((nam, type, rtype, info))
+    
+    try:
+	rets = node.xpathEval("return")
+    except:
+        rets = []
+    t_ret = None
+    for ret in rets:
+        rtype = ret.xpathEval("string(@type)")
+	info = ret.xpathEval("string(@info)")
+        type = type_convert(rtype, 'return', info, module, name)
+	if rtype == 'void':
+	    break
+	if is_known_return_type(type) == 0:
+	    add_missing_type(type, name);
+	    no_gen = 1
+	t_ret = (type, rtype, info)
+	break
+
+    if no_gen == 1:
+	test.write("""
+    /* missing type support */
+    return(ret);
+}
+
+""")
+        return
+
+    try:
+	conds = node.xpathEval("cond")
+	for cond in conds:
+	    test.write("#ifdef %s\n" % (cond.get_content()))
+	    nb_cond = nb_cond + 1
+    except:
+        pass
+    
+    # Declare the memory usage counter
+    no_mem = is_skipped_memcheck(name)
+    if no_mem == 0:
+	test.write("    int mem_base;\n");
+
+    # Declare the return value
+    if t_ret != None:
+        test.write("    %s ret_val;\n" % (t_ret[1]))
+
+    # Declare the arguments
+    for arg in t_args:
+        (nam, type, rtype, info) = arg;
+	# add declaration
+	test.write("    %s %s; /* %s */\n" % (rtype, nam, info))
+	test.write("    int n_%s;\n" % (nam))
+    test.write("\n")
+
+    # Cascade loop on of each argument list of values
+    for arg in t_args:
+        (nam, type, rtype, info) = arg;
+	#
+	test.write("    for (n_%s = 0;n_%s < gen_nb_%s;n_%s++) {\n" % (
+	           nam, nam, type, nam))
+    
+    # log the memory usage
+    if no_mem == 0:
+	test.write("        mem_base = xmlMemBlocks();\n");
+
+    # prepare the call
+    for arg in t_args:
+        (nam, type, rtype, info) = arg;
+	#
+	test.write("        %s = gen_%s(n_%s);\n" % (nam, type, nam))
+
+    # do the call, and clanup the result
+    if t_ret != None:
+	test.write("\n        ret_val = %s(" % (name))
+	need = 0
+	for arg in t_args:
+	    (nam, type, rtype, info) = arg
+	    if need:
+	        test.write(", ")
+	    else:
+	        need = 1
+	    test.write("%s" % nam);
+	test.write(");\n        desret_%s(ret_val);\n" % t_ret[0])
+    else:
+	test.write("\n        %s(" % (name));
+	need = 0;
+	for arg in t_args:
+	    (nam, type, rtype, info) = arg;
+	    if need:
+	        test.write(", ")
+	    else:
+	        need = 1
+	    test.write("%s" % nam)
+	test.write(");\n")
+    test.write("        call_tests++;\n");
+
+    # Free the arguments
+    for arg in t_args:
+        (nam, type, rtype, info) = arg;
+	#
+	test.write("        des_%s(n_%s, %s);\n" % (type, nam, nam))
+
+    test.write("        xmlResetLastError();\n");
+    # Check the memory usage
+    if no_mem == 0:
+	test.write("""        if (mem_base != xmlMemBlocks()) {
+            printf("Leak of %%d blocks found in %s\\n",
+	           xmlMemBlocks() - mem_base);
+	    ret++;
+        }
+""" % (name));
+
+    for arg in t_args:
+	test.write("    }\n")
+
+    #
+    # end of conditional
+    #
+    while nb_cond > 0:
+        test.write("#endif\n")
+	nb_cond = nb_cond -1
+
+    nb_tests = nb_tests + 1;
+
+    test.write("""
+    return(ret);
+}
+
+""")
+    
+#
+# Generate all module callers
+#
+for module in modules:
+    # gather all the functions exported by that module
+    try:
+	functions = ctxt.xpathEval("/api/symbols/function[@file='%s']" % (module))
+    except:
+        print "Failed to gather functions from module %s" % (module)
+	continue;
+
+    # iterate over all functions in the module generating the test
+    for function in functions:
+        generate_test(module, function);
+
+    # header
+    test.write("""static int
+test_%s(void) {
+    int ret = 0;
+
+    printf("Testing %s ...\\n");
+""" % (module, module))
+
+    # iterate over all functions in the module generating the call
+    for function in functions:
+        name = function.xpathEval('string(@name)')
+	if is_skipped_function(name):
+	    continue
+	test.write("    ret += test_%s();\n" % (name))
+
+    # footer
+    test.write("""
+    if (ret != 0)
+	printf("Module %s: %%d errors\\n", ret);
+    return(ret);
+}
+""" % (module))
+
+print "Generated test for %d modules and %d functions" %(len(modules), nb_tests)
+nr = 0
+miss = 'none'
+for missing in missing_types.keys():
+    n = len(missing_types[missing])
+    if n > nr:
+        miss = missing
+	nr = n
+
+if nr > 0:
+    print "most needed type support: %s %d times" % (miss, nr)
+
+
diff --git a/include/libxml/xmlmemory.h b/include/libxml/xmlmemory.h
index 0e6a767..235721c 100644
--- a/include/libxml/xmlmemory.h
+++ b/include/libxml/xmlmemory.h
@@ -139,6 +139,8 @@
  */
 XMLPUBFUN int XMLCALL	
 	xmlMemUsed	(void);
+XMLPUBFUN int XMLCALL	
+	xmlMemBlocks	(void);
 XMLPUBFUN void XMLCALL	
 	xmlMemDisplay	(FILE *fp);
 XMLPUBFUN void XMLCALL	
diff --git a/nanoftp.c b/nanoftp.c
index 16e6242..30d143f 100644
--- a/nanoftp.c
+++ b/nanoftp.c
@@ -260,12 +260,18 @@
 void
 xmlNanoFTPProxy(const char *host, int port, const char *user,
 	        const char *passwd, int type) {
-    if (proxy != NULL)
+    if (proxy != NULL) {
 	xmlFree(proxy);
-    if (proxyUser != NULL)
+	proxy = NULL;
+    }
+    if (proxyUser != NULL) {
 	xmlFree(proxyUser);
-    if (proxyPasswd != NULL)
+	proxyUser = NULL;
+    }
+    if (proxyPasswd != NULL) {
 	xmlFree(proxyPasswd);
+	proxyPasswd = NULL;
+    }
     if (host)
 	proxy = xmlMemStrdup(host);
     if (user)
diff --git a/parser.c b/parser.c
index 8a03b0c..7a51c05 100644
--- a/parser.c
+++ b/parser.c
@@ -949,6 +949,8 @@
 int
 inputPush(xmlParserCtxtPtr ctxt, xmlParserInputPtr value)
 {
+    if ((ctxt == NULL) || (value == NULL))
+        return(0);
     if (ctxt->inputNr >= ctxt->inputMax) {
         ctxt->inputMax *= 2;
         ctxt->inputTab =
@@ -977,6 +979,8 @@
 {
     xmlParserInputPtr ret;
 
+    if (ctxt == NULL)
+        return(NULL);
     if (ctxt->inputNr <= 0)
         return (0);
     ctxt->inputNr--;
@@ -8541,6 +8545,9 @@
 
     xmlInitParser();
 
+    if ((ctxt == NULL) || (ctxt->input == NULL))
+        return(-1);
+
     GROW;
 
     /*
@@ -8700,6 +8707,9 @@
     xmlChar start[4];
     xmlCharEncoding enc;
 
+    if ((ctxt == NULL) || (ctxt->input == NULL))
+        return(-1);
+
     xmlDefaultSAXHandlerInit();
 
     xmlDetectSAX2(ctxt);
@@ -8942,6 +8952,9 @@
     xmlChar cur, next;
     const xmlChar *lastlt, *lastgt;
 
+    if (ctxt->input == NULL)
+        return(0);
+
 #ifdef DEBUG_PUSH
     switch (ctxt->instate) {
 	case XML_PARSER_EOF:
@@ -9801,6 +9814,8 @@
 int
 xmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size,
               int terminate) {
+    if (ctxt == NULL)
+        return(XML_ERR_INTERNAL_ERROR);
     if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1))
         return(ctxt->errNo);
     if (ctxt->instate == XML_PARSER_START)
@@ -9849,13 +9864,16 @@
 	/*
 	 * Check for termination
 	 */
-	    int avail = 0;
+	int avail = 0;
+
+	if (ctxt->input != NULL) {
 	    if (ctxt->input->buf == NULL)
-                avail = ctxt->input->length -
-		        (ctxt->input->cur - ctxt->input->base);
-            else
-                avail = ctxt->input->buf->buffer->use -
-		        (ctxt->input->cur - ctxt->input->base);
+		avail = ctxt->input->length -
+			(ctxt->input->cur - ctxt->input->base);
+	    else
+		avail = ctxt->input->buf->buffer->use -
+			(ctxt->input->cur - ctxt->input->base);
+	}
 			    
 	if ((ctxt->instate != XML_PARSER_EOF) &&
 	    (ctxt->instate != XML_PARSER_EPILOG)) {
@@ -11638,10 +11656,13 @@
 {
     xmlParserInputPtr input;
 
+    if ((ctxt == NULL) || (buffer == NULL))
+        return;
+
     input = xmlNewInputStream(ctxt);
     if (input == NULL) {
         xmlErrMemory(NULL, "parsing new buffer: out of memory\n");
-        xmlFree(ctxt);
+        xmlClearParserCtxt(ctxt);
         return;
     }
   
@@ -12094,6 +12115,9 @@
 #ifdef LIBXML_OUTPUT_ENABLED
     xmlCleanupOutputCallbacks();
 #endif
+#ifdef LIBXML_SCHEMAS_ENABLED
+    xmlSchemaCleanupTypes();
+#endif
     xmlCleanupGlobals();
     xmlResetLastError();
     xmlCleanupThreads(); /* must be last if called not from the main thread */
@@ -12129,7 +12153,12 @@
 xmlCtxtReset(xmlParserCtxtPtr ctxt)
 {
     xmlParserInputPtr input;
-    xmlDictPtr dict = ctxt->dict;
+    xmlDictPtr dict;
+    
+    if (ctxt == NULL)
+        return;
+
+    dict = ctxt->dict;
 
     while ((input = inputPop(ctxt)) != NULL) { /* Non consuming */
         xmlFreeInputStream(input);
@@ -12325,6 +12354,8 @@
 int
 xmlCtxtUseOptions(xmlParserCtxtPtr ctxt, int options)
 {
+    if (ctxt == NULL)
+        return(-1);
     if (options & XML_PARSE_RECOVER) {
         ctxt->recovery = 1;
         options -= XML_PARSE_RECOVER;
diff --git a/parserInternals.c b/parserInternals.c
index 42db411..c338a53 100644
--- a/parserInternals.c
+++ b/parserInternals.c
@@ -1520,12 +1520,14 @@
 
     xmlDefaultSAXHandlerInit();
 
-    ctxt->dict = xmlDictCreate();
+    if (ctxt->dict == NULL)
+	ctxt->dict = xmlDictCreate();
     if (ctxt->dict == NULL) {
         xmlErrMemory(NULL, "cannot initialize parser context\n");
 	return(-1);
     }
-    ctxt->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
+    if (ctxt->sax == NULL)
+	ctxt->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
     if (ctxt->sax == NULL) {
         xmlErrMemory(NULL, "cannot initialize parser context\n");
 	return(-1);
@@ -1536,8 +1538,11 @@
     ctxt->maxatts = 0;
     ctxt->atts = NULL;
     /* Allocate the Input stack */
-    ctxt->inputTab = (xmlParserInputPtr *)
-	        xmlMalloc(5 * sizeof(xmlParserInputPtr));
+    if (ctxt->inputTab == NULL) {
+	ctxt->inputTab = (xmlParserInputPtr *)
+		    xmlMalloc(5 * sizeof(xmlParserInputPtr));
+	ctxt->inputMax = 5;
+    }
     if (ctxt->inputTab == NULL) {
         xmlErrMemory(NULL, "cannot initialize parser context\n");
 	ctxt->inputNr = 0;
@@ -1546,7 +1551,6 @@
 	return(-1);
     }
     ctxt->inputNr = 0;
-    ctxt->inputMax = 5;
     ctxt->input = NULL;
 
     ctxt->version = NULL;
@@ -1561,7 +1565,10 @@
     ctxt->directory = NULL;
 
     /* Allocate the Node stack */
-    ctxt->nodeTab = (xmlNodePtr *) xmlMalloc(10 * sizeof(xmlNodePtr));
+    if (ctxt->nodeTab == NULL) {
+	ctxt->nodeTab = (xmlNodePtr *) xmlMalloc(10 * sizeof(xmlNodePtr));
+	ctxt->nodeMax = 10;
+    }
     if (ctxt->nodeTab == NULL) {
         xmlErrMemory(NULL, "cannot initialize parser context\n");
 	ctxt->nodeNr = 0;
@@ -1573,11 +1580,13 @@
 	return(-1);
     }
     ctxt->nodeNr = 0;
-    ctxt->nodeMax = 10;
     ctxt->node = NULL;
 
     /* Allocate the Name stack */
-    ctxt->nameTab = (const xmlChar **) xmlMalloc(10 * sizeof(xmlChar *));
+    if (ctxt->nameTab == NULL) {
+	ctxt->nameTab = (const xmlChar **) xmlMalloc(10 * sizeof(xmlChar *));
+	ctxt->nameMax = 10;
+    }
     if (ctxt->nameTab == NULL) {
         xmlErrMemory(NULL, "cannot initialize parser context\n");
 	ctxt->nodeNr = 0;
@@ -1592,11 +1601,13 @@
 	return(-1);
     }
     ctxt->nameNr = 0;
-    ctxt->nameMax = 10;
     ctxt->name = NULL;
 
     /* Allocate the space stack */
-    ctxt->spaceTab = (int *) xmlMalloc(10 * sizeof(int));
+    if (ctxt->spaceTab == NULL) {
+	ctxt->spaceTab = (int *) xmlMalloc(10 * sizeof(int));
+	ctxt->spaceMax = 10;
+    }
     if (ctxt->spaceTab == NULL) {
         xmlErrMemory(NULL, "cannot initialize parser context\n");
 	ctxt->nodeNr = 0;
@@ -1784,7 +1795,7 @@
   if (ctxt==NULL)
     return;
   xmlClearNodeInfoSeq(&ctxt->node_seq);
-  xmlInitParserCtxt(ctxt);
+  xmlCtxtReset(ctxt);
 }
 
 /**
diff --git a/test/slashdot16.xml b/test/slashdot16.xml
new file mode 100644
index 0000000..f6a7f2a
--- /dev/null
+++ b/test/slashdot16.xml
Binary files differ
diff --git a/tree.c b/tree.c
index 9de498d..1eea268 100644
--- a/tree.c
+++ b/tree.c
@@ -345,6 +345,9 @@
     const xmlChar *cur = value;
     int c,l;
 
+    if (value == NULL)
+        return(-1);
+
     /*
      * First quick algorithm for ASCII range
      */
@@ -416,6 +419,8 @@
     const xmlChar *cur = value;
     int c,l;
 
+    if (value == NULL)
+        return(-1);
     /*
      * First quick algorithm for ASCII range
      */
@@ -512,6 +517,8 @@
     const xmlChar *cur = value;
     int c,l;
 
+    if (value == NULL)
+        return(-1);
     /*
      * First quick algorithm for ASCII range
      */
@@ -579,6 +586,8 @@
     const xmlChar *cur = value;
     int c,l;
 
+    if (value == NULL)
+        return(-1);
     /*
      * First quick algorithm for ASCII range
      */
@@ -2503,6 +2512,9 @@
 xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
     xmlNodePtr cur;
 
+    if (name == NULL)
+        return(NULL);
+
     /*
      * Allocate a new node and fill the fields.
      */
@@ -2544,6 +2556,9 @@
     xmlNodePtr cur;
     xmlEntityPtr ent;
 
+    if (name == NULL)
+        return(NULL);
+
     /*
      * Allocate a new node and fill the fields.
      */
diff --git a/xmlIO.c b/xmlIO.c
index 198fb15..f33d355 100644
--- a/xmlIO.c
+++ b/xmlIO.c
@@ -551,6 +551,9 @@
 int
 xmlCheckFilename (const char *path)
 {
+    if (path == NULL)
+        return(0);
+
 #ifdef HAVE_STAT
     struct stat stat_buffer;
 
diff --git a/xmlmemory.c b/xmlmemory.c
index 821e3b9..69de28d 100644
--- a/xmlmemory.c
+++ b/xmlmemory.c
@@ -50,6 +50,7 @@
 
 static int xmlMemInitialized = 0;
 static unsigned long  debugMemSize = 0;
+static unsigned long  debugMemBlocks = 0;
 static unsigned long  debugMaxMemSize = 0;
 static xmlMutexPtr xmlMemMutex = NULL;
 
@@ -186,6 +187,7 @@
     xmlMutexLock(xmlMemMutex);
     p->mh_number = ++block;
     debugMemSize += size;
+    debugMemBlocks++;
     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
 #ifdef MEM_LIST
     debugmem_list_add(p);
@@ -253,6 +255,7 @@
     xmlMutexLock(xmlMemMutex);
     p->mh_number = ++block;
     debugMemSize += size;
+    debugMemBlocks++;
     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
 #ifdef MEM_LIST
     debugmem_list_add(p);
@@ -329,6 +332,7 @@
     p->mh_tag = ~MEMTAG;
     xmlMutexLock(xmlMemMutex);
     debugMemSize -= p->mh_size;
+    debugMemBlocks--;
 #ifdef DEBUG_MEMORY
     oldsize = p->mh_size;
 #endif
@@ -355,6 +359,7 @@
     p->mh_line = line;
     xmlMutexLock(xmlMemMutex);
     debugMemSize += size;
+    debugMemBlocks++;
     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
 #ifdef MEM_LIST
     debugmem_list_add(p);
@@ -428,6 +433,7 @@
     memset(target, -1, p->mh_size);
     xmlMutexLock(xmlMemMutex);
     debugMemSize -= p->mh_size;
+    debugMemBlocks--;
 #ifdef DEBUG_MEMORY
     size = p->mh_size;
 #endif
@@ -487,6 +493,7 @@
     xmlMutexLock(xmlMemMutex);
     p->mh_number = ++block;
     debugMemSize += size;
+    debugMemBlocks++;
     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
 #ifdef MEM_LIST
     debugmem_list_add(p);
@@ -543,6 +550,19 @@
      return(debugMemSize);
 }
 
+/**
+ * xmlMemBlocks:
+ *
+ * Provides the number of memory areas currently allocated
+ *
+ * Returns an int representing the number of blocks
+ */
+
+int
+xmlMemBlocks(void) {
+     return(debugMemBlocks);
+}
+
 #ifdef MEM_LIST
 /**
  * xmlMemContentShow:
diff --git a/xmlstring.c b/xmlstring.c
index af4e5c8..15ca76c 100644
--- a/xmlstring.c
+++ b/xmlstring.c
@@ -807,7 +807,6 @@
  *
  * Returns the storage size of
  * the first 'len' characters of ARRAY
- *
  */
 
 int
@@ -815,6 +814,9 @@
     const xmlChar   *ptr=utf;
     xmlChar         ch;
 
+    if (utf == NULL)
+        return(0);
+
     if (len <= 0)
         return(0);