Commits

Anonymous committed bb70299

Applied Michael K. Edwards' (medwards-debian at sane dot net) patches
with some amendments. The patches
- add debian build files (I added SKIP_SAX_INSTALL flag for Makefile.PL
and changed the patch so that it doesn't disable sax parser
registration completely by default, and rather made debian build
use this flag)
- general cleanup (use SV_nolen, etc.)
- SAX parsers cleanup
- general error reporting code cleanup/rewrite, try preventing possible
memory leaks
- recover(1) now triggers warnings (disable with $SIG{__WARN__}=sub {})
- slighlty more strict parse_string behavior (now same as when
parsing fh, etc): e.g. parse_string("<foo:bar>"), i.e prefix without
NS declaration, raises error unless recover(1) is used
- documentation fixes/updates
- slightly updated test set to reflect the new slightly more strict
parsing.
- I fixed default c14n XPath to include attributes and namespaces

Comments (0)

Files changed (24)

 use IO::Handle; # for FH reads called as methods
 
 
-$VERSION = "1.56";
+$VERSION = "1.57";
 require Exporter;
 require DynaLoader;
 
          and  $self->{XML_LIBXML_EXPAND_XINCLUDE} == 1 ) {
         $self->{_State_} = 1;
         eval { $self->processXIncludes($result); };
-	my $err = $@;
+        my $err = $@;
         $self->{_State_} = 0;
         if ($err) {
             $result = undef;
     if ( defined $self->{SAX} ) {
         my $string = shift;
         $self->{SAX_ELSTACK} = [];
-        eval {
-            $self->_parse_sax_string($string);
-        };
+        eval { $result = $self->_parse_sax_string($string); };
+
         my $err = $@;
         $self->{_State_} = 0;
         if ($err) {
     $doc->adoptNode( $self );
 }
 
-sub toStringC14N {
-    my $self = shift;
-    my ($comments, $xpath) = @_;
-
-    $comments = 0 unless defined $comments;
-    return $self->_toStringC14N( $comments, $xpath );
-}
-
 sub serialize_c14n {
     my $self = shift;
     return $self->toStringC14N( @_ );
 #  include <unistd.h>
 #endif
 
-/* get some infos about the environment libxml2 was configured for.
- */
+/* libxml2 configuration properties */
 #include <libxml/xmlversion.h>
 
 #define DEBUG_C14N
 #include <libxml/parserInternals.h>
 #include <libxml/HTMLparser.h>
 #include <libxml/HTMLtree.h>
-#if LIBXML_VERSION < 20600
 #include <libxml/DOCBparser.h>
-#endif
+#include <libxml/c14n.h>
 #include <libxml/tree.h>
 #include <libxml/xpath.h>
 #include <libxml/xmlIO.h>
 }
 #endif
 
-/*
+/* These globals are now declared in libxml2's globals.h */
+#if 0
 #ifdef VMS
 extern int xmlDoValidityCheckingDefaultVal;
 #define xmlDoValidityCheckingDefaultValue xmlDoValidityCheckingDefaultVal
 LIBXML_DLL_IMPORT extern int xmlKeepBlanksDefaultValue;
 LIBXML_DLL_IMPORT extern int xmlLoadExtDtdDefaultValue;
 LIBXML_DLL_IMPORT extern int xmlPedanticParserDefaultValue;
-*/
+#endif
 
 #define TEST_PERL_FLAG(flag) \
     SvTRUE(perl_get_sv(flag, FALSE)) ? 1 : 0
 static SV * LibXML_open_cb  = NULL;
 static SV * LibXML_close_cb = NULL;
 
-static SV * LibXML_error    = NULL;
-
-#define LibXML_init_error() if (LibXML_error == NULL || !SvOK(LibXML_error)) \
-                            LibXML_error = NEWSV(0,512); \
-                            sv_setpvn(LibXML_error, "", 0); \
-                            xmlSetGenericErrorFunc( NULL ,  \
-                                (xmlGenericErrorFunc)LibXML_error_handler);
-
-#define LibXML_croak_error() if ( SvCUR( LibXML_error ) > 0 ) { \
-                                 croak("%s",SvPV(LibXML_error, len)); \
-                             }
-
-#define LibXML_warn_error() if ( SvCUR( LibXML_error ) > 0 ) { \
-                                 warn("%s",SvPV(LibXML_error, len)); \
-                             }
-
-
 /* this should keep the default */
 static xmlExternalEntityLoader LibXML_old_ext_ent_loader = NULL;
 
  * Error handler
  * **************************************************************** */
 
+static SV * LibXML_error    = NULL;
+
 /* stores libxml errors into $@ */
 void
 LibXML_error_handler(void * ctxt, const char * msg, ...)
         sv_catsv(LibXML_error, sv); /* remember the last error */
     }
     else {
-       croak("%s",SvPV(sv, PL_na));
+       croak("%s", SvPV_nolen(sv));
     }
 
     SvREFCNT_dec(sv);
 {
     va_list args;
     SV * sv;
-    
+
     sv = NEWSV(0,512);
-    
+
     va_start(args, msg);
     sv_vsetpvfn(sv, msg, strlen(msg), &args, NULL, 0, NULL);
     va_end(args);
-    
+
     if (LibXML_error != NULL) {
         sv_catsv(LibXML_error, sv); /* remember the last error */
     }
     else {
-        croak("%s",SvPV(sv, PL_na));
+        croak("%s", SvPV_nolen(sv));
     }
     SvREFCNT_dec(sv);
 }
     STRLEN len;
     SV * sv;
     char * string = NULL;
-    
+
     sv = NEWSV(0,512);
-    
+
     va_start(args, msg);
     sv_vsetpvfn(sv, msg, strlen(msg), &args, NULL, 0, NULL);
     va_end(args);
-    
+
     string = SvPV(sv, len);
     if ( string != NULL ) {
         if ( len > 0 ) {
-             warn("validation error: '%s'" , string);
+            warn("validation error: '%s'" , string);
         }
         Safefree(string);
     }
     SvREFCNT_dec(sv);
 }
 
+static void
+LibXML_init_error(SV ** saved_errorp)
+{
+    *saved_errorp = LibXML_error;
+    LibXML_error = NEWSV(0, 512);
+    sv_setpvn(LibXML_error, "", 0);
+    xmlSetGenericErrorFunc(NULL, (xmlGenericErrorFunc) LibXML_error_handler);
+}
+
+static void
+LibXML_report_error(SV * saved_error, int recover)
+{
+    SV *my_error = sv_2mortal(LibXML_error);
+    LibXML_error = saved_error;
+    if ( SvCUR( my_error ) > 0 ) {
+        if ( recover ) {
+            warn("%s", SvPV_nolen(my_error));
+        } else {
+            croak("%s", SvPV_nolen(my_error));
+        }
+    }
+}
+
+static int
+LibXML_get_recover(HV * real_obj)
+{
+    SV** item = hv_fetch( real_obj, "XML_LIBXML_RECOVER", 18, 0 );
+    return ( item != NULL && SvTRUE(*item) ) ? 1 : 0;
+}
+
+static SV *
+LibXML_NodeToSv(HV * real_obj, xmlNodePtr real_doc)
+{
+    SV** item = hv_fetch( real_obj, "XML_LIBXML_GDOME", 16, 0 );
+
+    if ( item != NULL && SvTRUE(*item) ) {
+        return PmmNodeToGdomeSv(real_doc);
+    }
+    else {
+        return PmmNodeToSv(real_doc, NULL);
+    }
+}
+
 /* ****************************************************************
- * IO callbacks 
+ * IO callbacks
  * **************************************************************** */
 
 int
 LibXML_read_perl (SV * ioref, char * buffer, int len)
-{   
+{
     dTHX;
     dSP;
-    
+
     int cnt;
     SV * read_results;
     STRLEN read_length;
     char * chars;
     SV * tbuff = NEWSV(0,len);
     SV * tsize = newSViv(len);
-    
+
     ENTER;
     SAVETMPS;
-    
+
     PUSHMARK(SP);
     EXTEND(SP, 3);
     PUSHs(ioref);
     if (cnt != 1) {
         croak("read method call failed");
     }
-    
+
     if (SvTRUE(ERRSV)) {
-       STRLEN n_a;
-       croak("read on filehandle failed: %s", SvPV(ERRSV, n_a));
+       croak("read on filehandle failed: %s", SvPV_nolen(ERRSV));
        POPs ;
-    }                             
+    }
 
     read_results = POPs;
 
     return read_length;
 }
 
-int 
+int
 LibXML_input_match(char const * filename)
 {
     int results = 0;
         count = perl_call_sv(callback, G_SCALAR | G_EVAL);
 
         SPAGAIN;
-        
+
         if (count != 1) {
             croak("match callback must return a single value");
         }
-        
+
         if (SvTRUE(ERRSV)) {
-            STRLEN n_a;
-            croak("input match callback died: %s", SvPV(ERRSV, n_a));
+            croak("input match callback died: %s", SvPV_nolen(ERRSV));
             POPs ;
-        }                                 
+        }
 
         res = POPs;
 
         if (SvTRUE(res)) {
             results = 1;
         }
-        
+
         PUTBACK;
         FREETMPS;
         LEAVE;
     }
-    
+
     return results;
 }
 
-void * 
+void *
 LibXML_input_open(char const * filename)
 {
     SV * results;
         count = perl_call_sv(callback, G_SCALAR | G_EVAL);
 
         SPAGAIN;
-        
+
         if (count != 1) {
             croak("open callback must return a single value");
         }
 
         if (SvTRUE(ERRSV)) {
-            STRLEN n_a;
-            croak("input callback died: %s", SvPV(ERRSV, n_a));
+            croak("input callback died: %s", SvPV_nolen(ERRSV));
             POPs ;
-        } 
+        }
 
         results = POPs;
 
         FREETMPS;
         LEAVE;
     }
-    
+
     return (void *)results;
 }
 
-int 
+int
 LibXML_input_read(void * context, char * buffer, int len)
 {
-    SV * results = NULL;
     STRLEN res_len = 0;
     const char * output;
     SV * global_cb;
             && SvTRUE(global_cb)) {
         callback = global_cb;
     }
-    
+
     if (callback) {
         int count;
 
         count = perl_call_sv(callback, G_SCALAR | G_EVAL);
 
         SPAGAIN;
-        
+
         if (count != 1) {
             croak("read callback must return a single value");
         }
 
         if (SvTRUE(ERRSV)) {
-            STRLEN n_a;
-            croak("read callback died: %s", SvPV(ERRSV, n_a));
+            croak("read callback died: %s", SvPV_nolen(ERRSV));
             POPs ;
         }
 
                 buffer[0] = 0;
             }
         }
-        
+
         FREETMPS;
         LEAVE;
     }
-    
+
     /* warn("read, asked for: %d, returning: [%d] %s\n", len, res_len, buffer); */
     return res_len;
 }
 
-void 
+void
 LibXML_input_close(void * context)
 {
     SV * global_cb;
         SPAGAIN;
 
         SvREFCNT_dec(ctxt);
-        
+
         if (!count) {
             croak("close callback failed");
         }
 
         if (SvTRUE(ERRSV)) {
-            STRLEN n_a;
-            croak("close callback died: %s", SvPV(ERRSV, n_a));
+            croak("close callback died: %s", SvPV_nolen(ERRSV));
             POPs ;
         }
 
 
 int
 LibXML_output_write_handler(void * ioref, char * buffer, int len)
-{   
+{
     if ( buffer != NULL && len > 0) {
         dTHX;
         dSP;
 
-        int cnt; 
-        SV * read_results;
-        STRLEN read_length;
-        char * chars;
+        int cnt;
         SV * tbuff = newSVpv(buffer,len);
         SV * tsize = newSViv(len);
 
 
         ENTER;
         SAVETMPS;
-    
+
         PUSHMARK(SP);
         EXTEND(SP, 3);
         PUSHs((SV*)ioref);
         }
 
         if (SvTRUE(ERRSV)) {
-            STRLEN n_a;
-            croak("write method call died: %s", SvPV(ERRSV, n_a));
+            croak("write method call died: %s", SvPV_nolen(ERRSV));
             POPs ;
         }
 
     return len;
 }
 
-int 
+int
 LibXML_output_close_handler( void * handler )
 {
     return 1;
-} 
+}
 
 xmlParserInputPtr
 LibXML_load_external_entity(
-        const char * URL, 
-        const char * ID, 
+        const char * URL,
+        const char * ID,
         xmlParserCtxtPtr ctxt)
 {
     SV * self;
     if (ctxt->_private == NULL) {
         return xmlNewInputFromFile(ctxt, URL);
     }
-    
+
     if (URL == NULL) {
         URL = "";
     }
     if (ID == NULL) {
         ID = "";
     }
-    
+
     self = (SV *)ctxt->_private;
     real_obj = (HV *)SvRV(self);
     func = hv_fetch(real_obj, "ext_ent_handler", 15, 0);
-    
+
     if (func) {
         dTHX;
         dSP;
-        
+
         ENTER;
         SAVETMPS;
 
         XPUSHs(sv_2mortal(newSVpv((char*)URL, 0)));
         XPUSHs(sv_2mortal(newSVpv((char*)ID, 0)));
         PUTBACK;
-        
+
         count = perl_call_sv(*func, G_SCALAR | G_EVAL);
-        
-        SPAGAIN;       
+
+        SPAGAIN;
 
         if (!count) {
-            croak("external entity handler did not return a value"); 
-        }
-        
+            croak("external entity handler did not return a value");
+        }
+
         if (SvTRUE(ERRSV)) {
-            STRLEN n_a;
-            croak("external entity callback died: %s", SvPV(ERRSV, n_a));
+            croak("external entity callback died: %s", SvPV_nolen(ERRSV));
             POPs ;
         }
 
         results = POPs;
-        
+
         results_pv = SvPV(results, results_len);
         input_buf = xmlParserInputBufferCreateMem(
                         results_pv,
                         results_len,
                         XML_CHAR_ENCODING_NONE
                         );
-        
+
         FREETMPS;
         LEAVE;
-        
+
         return xmlNewIOInputStream(ctxt, input_buf, XML_CHAR_ENCODING_NONE);
     }
     else {
             return NULL;
         }
         return xmlNewInputFromFile(ctxt, URL);
-    }    
+    }
 }
 
 /* ****************************************************************
  * Helper functions
  * **************************************************************** */
 
-void
+HV*
 LibXML_init_parser( SV * self ) {
     /* we fetch all switches and callbacks from the hash */
+    HV* real_obj = NULL;
     SV** item    = NULL;
     SV*  item2   = NULL;
-
     xmlInitParser();    
     xmlGetWarningsDefaultValue = 0;
 
     if ( self != NULL ) {
         /* first fetch the values from the hash */
-        HV* real_obj = (HV *)SvRV(self);
-        SV * RETVAL  = NULL; /* dummy for the stupid macro */
-
-        LibXML_init_error();
+        real_obj = (HV *)SvRV(self);
 
         item = hv_fetch( real_obj, "XML_LIBXML_VALIDATION", 21, 0 );
-        if ( item != NULL && SvTRUE(*item) ) {  
+        if ( item != NULL && SvTRUE(*item) ) {
             xmlDoValidityCheckingDefaultValue = 1;
             xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
         }
             LibXML_read_cb= *item;
 
         item = hv_fetch( real_obj, "XML_LIBXML_MATCH_CB", 19, 0 );
-        if ( item != NULL  && SvTRUE(*item)) 
+        if ( item != NULL  && SvTRUE(*item))
             LibXML_match_cb= *item;
 
         item = hv_fetch( real_obj, "XML_LIBXML_OPEN_CB", 18, 0 );
-        if ( item != NULL  && SvTRUE(*item)) 
+        if ( item != NULL  && SvTRUE(*item))
             LibXML_open_cb = *item;
 
         item = hv_fetch( real_obj, "XML_LIBXML_CLOSE_CB", 19, 0 );
-        if ( item != NULL  && SvTRUE(*item)) 
+        if ( item != NULL  && SvTRUE(*item))
             LibXML_close_cb = *item;
 
         item = hv_fetch(real_obj, "ext_ent_handler", 15, 0);
         if ( item != NULL  && SvTRUE(*item)) {
-            LibXML_old_ext_ent_loader =  xmlGetExternalEntityLoader(); 
+            LibXML_old_ext_ent_loader =  xmlGetExternalEntityLoader();
             xmlSetExternalEntityLoader( (xmlExternalEntityLoader)LibXML_load_external_entity );
         }
         else {
 
     if ( LibXML_match_cb == NULL ) {
         item2 = perl_get_sv("XML::LibXML::MatchCB", 0);
-        if ( item != NULL  && SvTRUE(item2)) 
+        if ( item != NULL  && SvTRUE(item2))
             LibXML_match_cb= item2;
     }
     if ( LibXML_read_cb == NULL ) {
         item2 = perl_get_sv("XML::LibXML::ReadCB", 0);
-        if ( item2 != NULL  && SvTRUE(item2)) 
+        if ( item2 != NULL  && SvTRUE(item2))
             LibXML_read_cb= item2;
     }
     if ( LibXML_open_cb == NULL ) {
         item2 = perl_get_sv("XML::LibXML::OpenCB", 0);
-        if ( item2 != NULL  && SvTRUE(item2)) 
+        if ( item2 != NULL  && SvTRUE(item2))
             LibXML_open_cb= item2;
     }
     if ( LibXML_close_cb == NULL ) {
         item2 = perl_get_sv("XML::LibXML::CloseCB", 0);
-        if ( item2 != NULL  && SvTRUE(item2)) 
+        if ( item2 != NULL  && SvTRUE(item2))
             LibXML_close_cb= item2;
     }
 
                               (xmlInputOpenCallback) LibXML_input_open,
                               (xmlInputReadCallback) LibXML_input_read,
                               (xmlInputCloseCallback) LibXML_input_close);
-    
-    return; 
+
+    return real_obj;
 }
 
 void
 
 void
 LibXML_cleanup_callbacks() {
-    
+
     return;
 /*    xs_warn("      cleanup parser callbacks!\n"); */
 
 }
 
 
-int 
-LibXML_test_node_name( xmlChar * name ) 
+int
+LibXML_test_node_name( xmlChar * name )
 {
     xmlChar * cur = name;
     int tc  = 0;
-    int len = 0; 
+    int len = 0;
 
     if ( cur == NULL || *cur == 0 ) {
         /* warn("name is empty" ); */
         tc = 0;
         cur += len;
     }
-    
+
     /* warn("name is ok"); */
     return(1);
 }
 
-/* ****************************************************************
- * general parse functions 
- * **************************************************************** */
-
-xmlDocPtr
-LibXML_parse_stream(SV * self, SV * ioref, char * directory)
-{
-    xmlDocPtr doc = NULL;
-    xmlParserCtxtPtr ctxt;
-    int well_formed = 0;
-    int valid = 0;
-    char buffer[1024];
-    int read_length;
-    int ret = -1;
-    int encoding = 0;
-    char current_dir[512];
-    
-    if (directory == NULL) {
-        if (getcwd(current_dir, 512) != 0) {
-            directory = current_dir;
-        }
-        else {
-            warn("couldn't get current directory: %s\n", strerror(errno));
-        }
-    }
-    
-    read_length = LibXML_read_perl(ioref, buffer, 4);
-    if (read_length > 0) {
-        ctxt = xmlCreatePushParserCtxt(NULL, NULL, buffer, read_length, NULL);
-        if (ctxt == NULL) {
-            croak("Could not create push parser context: %s", strerror(errno));
-        }
-        ctxt->directory = directory;
-        ctxt->_private = (void*)self;
-        while(read_length = LibXML_read_perl(ioref, buffer, 1024)) {
-            xmlParseChunk(ctxt, buffer, read_length, 0);
-        }
-        ret = xmlParseChunk(ctxt, buffer, 0, 1);
-
-        ctxt->directory = NULL;
-
-        /* jsut being paranoid */
-        if ( ret == 0 ) {
-            doc = ctxt->myDoc;
-            well_formed = ctxt->wellFormed;
-            xmlFreeParserCtxt(ctxt);
-        }
-    }
-    else {
-        croak( "Empty Stream" );
-    }
-
-    if ( doc != NULL ) {
-        if (
-            !well_formed
-            || ( xmlDoValidityCheckingDefaultValue
-                 && !valid
-                 && (doc->intSubset
-                     || doc->extSubset) ) 
-            ) {
-            xmlFreeDoc(doc);
-            return NULL;
-        }
-
-        /* this should be done by libxml2 !? */
-        if (doc->encoding == NULL) {
-            /*  *LEAK NOTE* i am not shure if this is correct */
-            doc->encoding = xmlStrdup((const xmlChar*)"UTF-8");
-        }
-
-        if ( directory == NULL ) {
-            STRLEN len;
-            SV * newURI = sv_2mortal(newSVpvf("unknown-%12.12d", (void*)doc));
-            doc->URL = xmlStrdup((const xmlChar*)SvPV(newURI, len));
-        } else {
-            doc->URL = xmlStrdup((const xmlChar*)directory);
-        }
-    }
-
-    return doc;
-}
-
-void
-LibXML_parse_sax_stream(SV * self, SV * ioref, char * directory)
-{
-    xmlParserCtxtPtr ctxt;
-    char buffer[1024];
-    int read_length;
-    int ret = -1;
-    char current_dir[512];
-    
-    if (directory == NULL) {
-        if (getcwd(current_dir, 512) != 0) {
-            directory = current_dir;
-        }
-        else {
-            warn("couldn't get current directory: %s\n", strerror(errno));
-        }
-    }
-    
-    read_length = LibXML_read_perl(ioref, buffer, 4);
-    if (read_length > 0) {
-        xmlSAXHandlerPtr sax = PSaxGetHandler();
-        ctxt = xmlCreatePushParserCtxt(sax,
-                                       NULL,
-                                       buffer,
-                                       read_length,
-                                       NULL);
-        if (ctxt == NULL) {
-            croak("Could not create push parser context: %s", strerror(errno));
-        }
-        ctxt->directory = directory;
-        PmmSAXInitContext( ctxt, self );
-
-        while(read_length = LibXML_read_perl(ioref, buffer, 1024)) {
-            xmlParseChunk(ctxt, buffer, read_length, 0);
-        }
-        ret = xmlParseChunk(ctxt, buffer, 0, 1);
-
-        ctxt->directory = NULL;
-
-        xmlFree(ctxt->sax);
-        ctxt->sax = NULL;
-
-        xmlFree(sax);
-        PmmSAXCloseContext(ctxt);
-        xmlFreeParserCtxt(ctxt);
-
-    }
-    else {
-        croak( "Empty Stream" );
-    }
-
-}
-
-xmlDocPtr
-LibXML_parse_html_stream(SV * self, SV * ioref)
-{
-    xmlDocPtr doc = NULL;
-    htmlParserCtxtPtr ctxt;
-    int well_formed = 0;
-    char buffer[1024];
-    int read_length;
-    int ret = -1;
-    
-    read_length = LibXML_read_perl(ioref, buffer, 4);
-    if (read_length > 0) {
-        ctxt = htmlCreatePushParserCtxt(NULL, NULL, buffer, read_length,
-                                        NULL, XML_CHAR_ENCODING_NONE);
-        if (ctxt == NULL) {
-            croak("Could not create html push parser context: %s",
-                  strerror(errno));
-        }
-
-        ctxt->_private = (void*)self;
-
-        while(read_length = LibXML_read_perl(ioref, buffer, 1024)) {
-            ret = htmlParseChunk(ctxt, buffer, read_length, 0);
-            if ( ret != 0 ) {
-                break;
-            }   
-        }
-        ret = htmlParseChunk(ctxt, buffer, 0, 1);
-
-        if ( ret == 0 ) {
-            doc = ctxt->myDoc;
-            well_formed = ctxt->wellFormed;
-            htmlFreeParserCtxt(ctxt);
-        }
-    }
-    else {
-        croak( "Empty Stream" );
-    }
-    
-    if (!well_formed) {
-        xmlFreeDoc(doc);
-        return NULL;
-    }
-    
-    return doc;
-}
-
-
-xmlDocPtr
-LibXML_parse_sgml_stream(SV * self, SV * ioref, SV * enc )
-{
-    xmlDocPtr doc = NULL;
-    htmlParserCtxtPtr ctxt;
-    int well_formed = 0;
-    char buffer[1024];
-    int read_length;
-    int ret = -1;
-
-    const xmlChar * encoding = Sv2C( enc, NULL );
-
-    read_length = LibXML_read_perl(ioref, buffer, 4);
-    if (read_length > 0) {
-        ctxt = docbCreatePushParserCtxt(NULL, NULL, buffer, read_length,
-                                        NULL,
-                                        xmlParseCharEncoding( (const char*)encoding ));
-        if (ctxt == NULL) {
-            croak("Could not create sgml push parser context: %s",
-                  strerror(errno));
-        }
-
-        ctxt->_private = (void*)self;
-
-        while(read_length = LibXML_read_perl(ioref, buffer, 1024)) {
-            ret = docbParseChunk(ctxt, buffer, read_length, 0);
-            if ( ret != 0 ) {
-                break;
-            }   
-        }
-        ret = docbParseChunk(ctxt, buffer, 0, 1);
-
-        if ( ret == 0 ) {
-            doc = ctxt->myDoc;
-            well_formed = ctxt->wellFormed;
-            docbFreeParserCtxt(ctxt);
-        }
-    }
-    else {
-        croak( "Empty Stream" );
-    }
-    
-    if (!well_formed) {
-        xmlFreeDoc(doc);
-        return NULL;
-    }
-    
-    return doc;
-}
-
 MODULE = XML::LibXML         PACKAGE = XML::LibXML
 
 PROTOTYPES: DISABLE
                               (xmlInputReadCallback) LibXML_input_read,
                               (xmlInputCloseCallback) LibXML_input_close);
 
-    xmlSetGenericErrorFunc( NULL , 
+    xmlSetGenericErrorFunc( NULL ,
                            (xmlGenericErrorFunc)LibXML_error_handler);
     xmlDoValidityCheckingDefaultValue = 0;
     xmlSubstituteEntitiesDefaultValue = 1;
 
 char *
 get_last_error(CLASS)
-        SV * CLASS 
-    PREINIT: 
-        STRLEN len;
+        SV * CLASS
     CODE:
         RETVAL = NULL;
         if (LibXML_error != NULL) {
-            RETVAL = SvPV(LibXML_error, len);
+            RETVAL = SvPV_nolen(LibXML_error);
         }
     OUTPUT:
         RETVAL
         SV * string
         SV * dir
     PREINIT:
-        xmlParserCtxtPtr ctxt = NULL;
-        STRLEN len = 0;
-        char * ptr = NULL;
+        char * directory = NULL;
+        STRLEN len;
+        char * ptr;
+        SV * saved_error;
+        HV * real_obj;
         int well_formed;
         int valid;
-        int ret;
         xmlDocPtr real_doc;
-        HV* real_obj = (HV *)SvRV(self);
-        SV** item    = NULL;
-        int recover ;
-        char * directory = NULL;
+        int recover = 0;
+    INIT:
+        if (SvPOK(dir)) {
+            directory = SvPV(dir, len);
+            if (len <= 0) {
+                directory = NULL;
+            }
+        }
+        ptr = SvPV(string, len);
+        if (len <= 0) {
+            croak("Empty string");
+            XSRETURN_UNDEF;
+        }
     CODE:
-        ptr = SvPV(string, len);        
-        if (len == 0) {
-            croak("Empty string");
-        }
-  
-        LibXML_init_parser(self);
-        ctxt = xmlCreateMemoryParserCtxt((const char*)ptr, len);
-        if (ctxt == NULL) {
-            croak("Couldn't create memory parser context: %s", strerror(errno));
-        }
-
-        directory = (char*)Sv2C( dir, NULL );
-
-        xs_warn( "context created\n");
-
-        if ( directory != NULL ) {
-            ctxt->directory = directory;
-        }
-
-        ctxt->_private = (void*)self;
-
-        /* make libxml2-2.6 display line number on error */
-        if ( ctxt->input != NULL ) {
-          ctxt->input->filename = xmlStrdup((const xmlChar *) "");
-        }
-        
-        xs_warn( "context initialized \n");        
-
-        ret = xmlParseDocument(ctxt);
-        xs_warn( "document parsed \n");
-        ctxt->directory = NULL;
-
-        well_formed = ctxt->wellFormed;
-        valid = ctxt->valid;
-
-        real_doc = ctxt->myDoc;
-        xmlFreeParserCtxt(ctxt);
-
-        /* sv_2mortal(LibXML_error); */
-        
-        if ( real_doc == NULL ) {
-            LibXML_croak_error();
-            XSRETURN_UNDEF;
-        }
-
-  
-        if ( directory == NULL ) {
-            STRLEN len;
-            SV * newURI;
-
-            newURI = sv_2mortal(newSVpvf("unknown-%12.12d", (void*)real_doc));
-            real_doc->URL = xmlStrdup((const xmlChar*)SvPV(newURI, len));
-        } else {
-            real_doc->URL = xmlStrdup((const xmlChar*)directory);
-        }
-
-        item = hv_fetch( real_obj, "XML_LIBXML_RECOVER", 18, 0 );
-        recover = ( item != NULL && SvTRUE(*item) ) ? 1 : 0;
-        if ( ( !well_formed && !recover )
-               || (xmlDoValidityCheckingDefaultValue
-                    && valid == 0 && recover == 0 ) ) {
-            xmlFreeDoc(real_doc);
-            RETVAL = &PL_sv_undef;    
-            croak("%s",SvPV(LibXML_error, len));
-        }
-        else if (xmlDoValidityCheckingDefaultValue
-                 && (real_doc->intSubset || real_doc->extSubset) ) {
-            LibXML_croak_error();
-        }
-
-        item = hv_fetch( real_obj, "XML_LIBXML_GDOME", 16, 0 );
-
-        if ( item != NULL && SvTRUE(*item) ) {  
-            RETVAL = PmmNodeToGdomeSv( (xmlNodePtr)real_doc );
-        }
-        else {
-           RETVAL = PmmNodeToSv((xmlNodePtr)real_doc, NULL);
+        RETVAL = &PL_sv_undef;
+        LibXML_init_error(&saved_error);
+        real_obj = LibXML_init_parser(self);
+
+        {
+            xmlParserCtxtPtr ctxt = xmlCreateMemoryParserCtxt((const char*)ptr, len);
+            if (ctxt == NULL) {
+                LibXML_report_error(saved_error, 1);
+                croak("Couldn't create memory parser context: %s", strerror(errno));
+            }
+            xs_warn( "context created\n");
+
+            if ( directory != NULL ) {
+                ctxt->directory = directory;
+            }
+            ctxt->_private = (void*)self;
+
+            /* make libxml2-2.6 display line number on error */
+            if ( ctxt->input != NULL ) {
+                ctxt->input->filename = xmlStrdup((const xmlChar *) "");
+            }
+
+            xs_warn( "context initialized\n" );
+
+            {
+                xmlParseDocument(ctxt);
+                xs_warn( "document parsed \n");
+            }
+
+            ctxt->directory = NULL;
+            well_formed = ctxt->wellFormed;
+            valid = ctxt->valid;
+            real_doc = ctxt->myDoc;
+            ctxt->myDoc = NULL;
+            xmlFreeParserCtxt(ctxt);
+        }
+        if ( real_doc != NULL ) {
+            recover = LibXML_get_recover(real_obj);
+
+            if ( directory == NULL ) {
+                SV * newURI = sv_2mortal(newSVpvf("unknown-%12.12d", (void*)real_doc));
+                real_doc->URL = xmlStrdup((const xmlChar*)SvPV_nolen(newURI));
+            } else {
+                real_doc->URL = xmlStrdup((const xmlChar*)directory);
+            }
+            if ( recover || ( well_formed &&
+                              ( !xmlDoValidityCheckingDefaultValue
+                                || ( valid || ( real_doc->intSubset == NULL
+                                                && real_doc->extSubset == NULL ))))) {
+                RETVAL = LibXML_NodeToSv( real_obj, (xmlNodePtr) real_doc );
+            } else {
+                xmlFreeDoc(real_doc);
+            }
         }
 
         LibXML_cleanup_callbacks();
-        LibXML_cleanup_parser(); 
+        LibXML_cleanup_parser();
+        LibXML_report_error(saved_error, recover);
     OUTPUT:
         RETVAL
 
         SV * self
         SV * string
     PREINIT:
-        xmlParserCtxtPtr ctxt;
         STRLEN len;
         char * ptr;
-        int well_formed;
-        int ret;
-        xmlSAXHandlerPtr sax = NULL;
+        SV * saved_error;
+        HV * real_obj;
+        int recover = 0;
     INIT:
         ptr = SvPV(string, len);
-        if (len == 0) {
+        if (len <= 0) {
             croak("Empty string");
             XSRETURN_UNDEF;
         }
     CODE:
-        ctxt = xmlCreateMemoryParserCtxt(ptr, len);
-        LibXML_init_parser(self);
-        if (ctxt == NULL) {
-            croak("Couldn't create memory parser context: %s", strerror(errno));
-        }
-       
-        PmmSAXInitContext( ctxt, self );
-
-        RETVAL = xmlParseDocument(ctxt);
-
-        PmmSAXCloseContext(ctxt);
-        xmlFreeParserCtxt(ctxt);
-
-        /* sv_2mortal(LibXML_error); */
+        RETVAL = 0;
+        LibXML_init_error(&saved_error);
+        real_obj = LibXML_init_parser(self);
+        recover = LibXML_get_recover(real_obj);
+
+        {
+            xmlParserCtxtPtr ctxt = xmlCreateMemoryParserCtxt((const char*)ptr, len);
+            if (ctxt == NULL) {
+                LibXML_report_error(saved_error, 1);
+                croak("Couldn't create memory parser context: %s", strerror(errno));
+            }
+            xs_warn( "context created\n");
+
+            PmmSAXInitContext( ctxt, self );
+            xs_warn( "context initialized \n");
+
+            {
+                RETVAL = xmlParseDocument(ctxt);
+                xs_warn( "document parsed \n");
+            }
+
+            PmmSAXCloseContext(ctxt);
+            xmlFreeParserCtxt(ctxt);
+        }
+
         LibXML_cleanup_callbacks();
-        LibXML_cleanup_parser(); 
+        LibXML_cleanup_parser();
+        LibXML_report_error(saved_error, recover);
     OUTPUT:
         RETVAL
 
 SV*
-_parse_fh(self, fh, directory = NULL)
+_parse_fh(self, fh, dir = &PL_sv_undef)
         SV * self
         SV * fh
-        char * directory
+        SV * dir
     PREINIT:
         STRLEN len;
+        char * directory = NULL;
+        SV * saved_error;
+        HV * real_obj;
+        int well_formed;
+        int valid;
         xmlDocPtr real_doc;
-        HV* real_obj = (HV *)SvRV(self);
-        SV** item    = NULL;
         int recover = 0;
+    INIT:
+        if (SvPOK(dir)) {
+            directory = SvPV(dir, len);
+            if (len <= 0) {
+                directory = NULL;
+            }
+        }
     CODE:
-        LibXML_init_parser(self);
-        real_doc = LibXML_parse_stream(self, fh, directory);
-        
-        /* sv_2mortal(LibXML_error); */
-
-        item = hv_fetch( real_obj, "XML_LIBXML_RECOVER", 18, 0 );
-        recover = ( item != NULL && SvTRUE( *item ) ) ? 1 : 0;
-
-        if (real_doc == NULL) {
-            LibXML_croak_error();
-            XSRETURN_UNDEF;
-        }
-        else if (xmlDoValidityCheckingDefaultValue
-                 && recover == 0 ) {
-            LibXML_croak_error();
-        }
-        else {
-            /* LibXML_warn_error(); */ /* if the parser causes some noise */
-        }
-
-        item = hv_fetch( real_obj, "XML_LIBXML_GDOME", 16, 0 );
-
-        if ( item != NULL && SvTRUE(*item) ) {  
-            RETVAL = PmmNodeToGdomeSv( (xmlNodePtr)real_doc );
-        }
-        else {
-            RETVAL = PmmNodeToSv((xmlNodePtr)real_doc, NULL);
+        RETVAL = &PL_sv_undef;
+        LibXML_init_error(&saved_error);
+        real_obj = LibXML_init_parser(self);
+
+        {
+            int read_length;
+            char buffer[1024];
+            xmlParserCtxtPtr ctxt;
+
+            read_length = LibXML_read_perl(fh, buffer, 4);
+            if (read_length <= 0) {
+                croak( "Empty Stream" );
+            }
+
+            ctxt = xmlCreatePushParserCtxt(NULL, NULL, buffer, read_length, NULL);
+            if (ctxt == NULL) {
+                LibXML_report_error(saved_error, 1);
+                croak("Could not create xml push parser context: %s",
+                      strerror(errno));
+            }
+            xs_warn( "context created\n");
+
+            if ( directory != NULL ) {
+                ctxt->directory = directory;
+            }
+            ctxt->_private = (void*)self;
+            xs_warn( "context initialized \n");
+
+            {
+                int ret;
+                while ((read_length = LibXML_read_perl(fh, buffer, 1024))) {
+                    ret = xmlParseChunk(ctxt, buffer, read_length, 0);
+                    if ( ret != 0 ) {
+                        break;
+                    }
+                }
+                ret = xmlParseChunk(ctxt, buffer, 0, 1);
+                xs_warn( "document parsed \n");
+            }
+
+            ctxt->directory = NULL;
+            well_formed = ctxt->wellFormed;
+            valid = ctxt->valid;
+            real_doc = ctxt->myDoc;
+            ctxt->myDoc = NULL;
+            xmlFreeParserCtxt(ctxt);
+        }
+
+        if ( real_doc != NULL ) {
+            recover = LibXML_get_recover(real_obj);
+
+            if ( directory == NULL ) {
+                SV * newURI = sv_2mortal(newSVpvf("unknown-%12.12d", (void*)real_doc));
+                real_doc->URL = xmlStrdup((const xmlChar*)SvPV_nolen(newURI));
+            } else {
+                real_doc->URL = xmlStrdup((const xmlChar*)directory);
+            }
+
+            if ( recover || ( well_formed &&
+                              ( !xmlDoValidityCheckingDefaultValue
+                                || ( valid || ( real_doc->intSubset == NULL
+                                                && real_doc->extSubset == NULL ))))) {
+                RETVAL = LibXML_NodeToSv( real_obj, (xmlNodePtr) real_doc );
+            } else {
+                xmlFreeDoc(real_doc);
+            }
         }
 
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser();
+        LibXML_report_error(saved_error, recover);
     OUTPUT:
         RETVAL
 
 void
-_parse_sax_fh(self, fh, directory = NULL)
+_parse_sax_fh(self, fh, dir = &PL_sv_undef)
         SV * self
         SV * fh
-        char * directory
+        SV * dir
     PREINIT:
-    CODE:  
-        LibXML_init_parser(self);
-        LibXML_parse_sax_stream(self, fh, directory);
-        
-        /* sv_2mortal(LibXML_error); */
-        
+        STRLEN len;
+        char * directory = NULL;
+        SV * saved_error;
+        HV * real_obj;
+        int recover = 0;
+    INIT:
+        if (SvPOK(dir)) {
+            directory = SvPV(dir, len);
+            if (len <= 0) {
+                directory = NULL;
+            }
+        }
+    CODE:
+        LibXML_init_error(&saved_error);
+        real_obj = LibXML_init_parser(self);
+        recover = LibXML_get_recover(real_obj);
+
+        {
+            int read_length;
+            char buffer[1024];
+            xmlSAXHandlerPtr sax;
+            xmlParserCtxtPtr ctxt;
+
+            read_length = LibXML_read_perl(fh, buffer, 4);
+            if (read_length <= 0) {
+                croak( "Empty Stream" );
+            }
+
+            sax = PSaxGetHandler();
+            ctxt = xmlCreatePushParserCtxt(sax, NULL, buffer, read_length, NULL);
+            if (ctxt == NULL) {
+                LibXML_report_error(saved_error, 1);
+                croak("Could not create xml push parser context: %s",
+                      strerror(errno));
+            }
+            xs_warn( "context created\n");
+
+            if ( directory != NULL ) {
+                ctxt->directory = directory;
+            }
+            PmmSAXInitContext( ctxt, self );
+            xs_warn( "context initialized \n");
+
+            {
+                int ret;
+                while ((read_length = LibXML_read_perl(fh, buffer, 1024))) {
+                    ret = xmlParseChunk(ctxt, buffer, read_length, 0);
+                    if ( ret != 0 ) {
+                        break;
+                    }
+                }
+                ret = xmlParseChunk(ctxt, buffer, 0, 1);
+                xs_warn( "document parsed \n");
+            }
+
+            ctxt->directory = NULL;
+            xmlFree(ctxt->sax);
+            ctxt->sax = NULL;
+            xmlFree(sax);
+            PmmSAXCloseContext(ctxt);
+            xmlFreeParserCtxt(ctxt);
+        }
+
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser();
+        LibXML_report_error(saved_error, recover);
 
 SV*
-_parse_file(self, filename)
+_parse_file(self, filename_sv)
         SV * self
-        const char * filename
+        SV * filename_sv
     PREINIT:
-        xmlParserCtxtPtr ctxt;
-        int well_formed = 0;
-        int valid = 0;
         STRLEN len;
-        xmlDocPtr real_doc = NULL;
-        HV* real_obj = (HV *)SvRV(self);
-        SV** item    = NULL;
-        int recover;
+        char * filename;
+        SV * saved_error;
+        HV * real_obj;
+        int well_formed;
+        int valid;
+        xmlDocPtr real_doc;
+        int recover = 0;
+    INIT:
+        filename = SvPV(filename_sv, len);
+        if (len <= 0) {
+            croak("Empty filename");
+            XSRETURN_UNDEF;
+        }
     CODE:
-        LibXML_init_parser(self);
-        ctxt = xmlCreateFileParserCtxt(filename);
-
-        if (ctxt == NULL) {
-            croak("Could not create file parser context for file '%s' : %s", filename, strerror(errno));
-        }
-        ctxt->_private = (void*)self;
-        
-        xmlParseDocument(ctxt);
-
-        well_formed = ctxt->wellFormed;
-        valid       = ctxt->valid;
-
-        real_doc = ctxt->myDoc;
-        xmlFreeParserCtxt(ctxt);
-        
-        /* sv_2mortal(LibXML_error); */
-        
-        if ( real_doc == NULL ) {
-            LibXML_croak_error();
-            XSRETURN_UNDEF;
-        }
-
-        item = hv_fetch( real_obj, "XML_LIBXML_RECOVER", 18, 0 );
-        recover = ( item != NULL && SvTRUE(*item) ) ? 1 : 0;
-
-        if (  ( !well_formed && !recover )
-               || (xmlDoValidityCheckingDefaultValue
-                   && !recover 
-                   && !valid ) ) {
-            xmlFreeDoc(real_doc);
-            croak("'%s'",SvPV(LibXML_error, len));
-            XSRETURN_UNDEF;
-        }
-        else {
-            item = hv_fetch( real_obj, "XML_LIBXML_GDOME", 16, 0 );
-
-            if ( item != NULL && SvTRUE(*item) ) {  
-                RETVAL = PmmNodeToGdomeSv( (xmlNodePtr)real_doc );
+        RETVAL = &PL_sv_undef;
+        LibXML_init_error(&saved_error);
+        real_obj = LibXML_init_parser(self);
+
+        {
+            xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename);
+            if (ctxt == NULL) {
+                LibXML_report_error(saved_error, 1);
+                croak("Couldn't create file parser context for file \"%s\": %s",
+                      filename, strerror(errno));
             }
-            else {
-                RETVAL = PmmNodeToSv((xmlNodePtr)real_doc, NULL);
+            xs_warn( "context created\n");
+
+            ctxt->_private = (void*)self;
+            xs_warn( "context initialized \n");
+
+            {
+                xmlParseDocument(ctxt);
+                xs_warn( "document parsed \n");
             }
-        }
-        /* LibXML_warn_error(); */ /* if the parser causes some noise */  
+
+            well_formed = ctxt->wellFormed;
+            valid = ctxt->valid;
+            real_doc = ctxt->myDoc;
+            ctxt->myDoc = NULL;
+            xmlFreeParserCtxt(ctxt);
+        }
+
+        if ( real_doc != NULL ) {
+            recover = LibXML_get_recover(real_obj);
+
+            if ( recover || ( well_formed &&
+                              ( !xmlDoValidityCheckingDefaultValue
+                                || ( valid || ( real_doc->intSubset == NULL
+                                                && real_doc->extSubset == NULL ))))) {
+                RETVAL = LibXML_NodeToSv( real_obj, (xmlNodePtr) real_doc );
+            } else {
+                xmlFreeDoc(real_doc);
+            }
+        }
+
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser();
+        LibXML_report_error(saved_error, recover);
     OUTPUT:
         RETVAL
 
 void
-_parse_sax_file(self, filename)
+_parse_sax_file(self, filename_sv)
         SV * self
-        const char * filename
+        SV * filename_sv
     PREINIT:
-        xmlParserCtxtPtr ctxt;
         STRLEN len;
+        char * filename;
+        SV * saved_error;
+        HV * real_obj;
+        int recover = 0;
+    INIT:
+        filename = SvPV(filename_sv, len);
+        if (len <= 0) {
+            croak("Empty filename");
+            XSRETURN_UNDEF;
+        }
     CODE:
-        LibXML_init_parser(self);
-        ctxt = xmlCreateFileParserCtxt(filename);
-
-        if (ctxt == NULL) {
-            croak("Could not create file parser context for file '%s' : %s", filename, strerror(errno));
-        }
-
-        ctxt->sax = PSaxGetHandler();
-        PmmSAXInitContext( ctxt, self );
-        
-        xmlParseDocument(ctxt);
-
-        PmmSAXCloseContext(ctxt);
-        xmlFreeParserCtxt(ctxt);
-                
-        /* sv_2mortal(LibXML_error); */
-        
+        LibXML_init_error(&saved_error);
+        real_obj = LibXML_init_parser(self);
+        recover = LibXML_get_recover(real_obj);
+
+        {
+            xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename);
+            if (ctxt == NULL) {
+                LibXML_report_error(saved_error, 1);
+                croak("Couldn't create file parser context for file \"%s\": %s",
+                      filename, strerror(errno));
+            }
+            xs_warn( "context created\n");
+
+            ctxt->sax = PSaxGetHandler();
+            PmmSAXInitContext( ctxt, self );
+            xs_warn( "context initialized \n");
+
+            {
+                xmlParseDocument(ctxt);
+                xs_warn( "document parsed \n");
+            }
+
+            PmmSAXCloseContext(ctxt);
+            xmlFreeParserCtxt(ctxt);
+        }
+
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser();
+        LibXML_report_error(saved_error, recover);
 
 SV*
 parse_html_string(self, string)
         SV * self
         SV * string
     PREINIT:
-        htmlParserCtxtPtr ctxt;
         STRLEN len;
         char * ptr;
-        int well_formed;
-        int ret;
-        xmlDocPtr real_doc;
-        HV* real_obj = (HV *)SvRV(self);
-        SV** item    = NULL;
-        int recover;
+        SV * saved_error;
+        HV * real_obj;
+        htmlDocPtr real_doc;
+        int recover = 0;
+    INIT:
+        ptr = SvPV(string, len);
+        if (len <= 0) {
+            croak("Empty string");
+            XSRETURN_UNDEF;
+        }
     CODE:
-        ptr = SvPV(string, len);
-        if (len == 0) {
-            croak("Empty string");
-        }
-                
-        LibXML_init_parser(self);
+        RETVAL = &PL_sv_undef;
+        LibXML_init_error(&saved_error);
+        real_obj = LibXML_init_parser(self);
 
         real_doc = htmlParseDoc((xmlChar*)ptr, NULL);
+
+        if ( real_doc != NULL ) {
+            recover = LibXML_get_recover(real_obj);
+
+            {
+                SV * newURI = sv_2mortal(newSVpvf("unknown-%12.12d", (void*)real_doc));
+                real_doc->URL = xmlStrdup((const xmlChar*)SvPV_nolen(newURI));
+            }
+
+            /* This HTML memory parser doesn't use a ctxt; there is no "well-formed"
+             * distinction, and if it manages to parse the HTML, it returns non-null. */
+            RETVAL = LibXML_NodeToSv( real_obj, (xmlNodePtr) real_doc );
+        }
+
         LibXML_cleanup_callbacks();
-        LibXML_cleanup_parser();        
-
-        /* sv_2mortal(LibXML_error); */
-
-        if (real_doc == NULL) {
-            LibXML_croak_error();
-            XSRETURN_UNDEF;
-        }
-        else {
-            STRLEN n_a;
-            SV * newURI;
-
-            item = hv_fetch( real_obj, "XML_LIBXML_RECOVER", 18, 0 );
-            recover = ( item != NULL && SvTRUE( *item ) ) ? 1 : 0;
-            if (!recover) {
-                LibXML_croak_error();
-            }
-            else {
-                /* LibXML_warn_error(); */ /* if the parser causes some noise */
-            }
-
-            newURI = newSVpvf("unknown-%12.12d", real_doc);
-            real_doc->URL = xmlStrdup((const xmlChar*)SvPV(newURI, n_a));
-            SvREFCNT_dec(newURI);
-
-            item = hv_fetch( real_obj, "XML_LIBXML_GDOME", 16, 0 );            
-            if ( item != NULL && SvTRUE(*item) ) {  
-                RETVAL = PmmNodeToGdomeSv( (xmlNodePtr)real_doc );
-            }
-            else {
-                RETVAL = PmmNodeToSv((xmlNodePtr)real_doc, NULL);
-            }
-        }
+        LibXML_cleanup_parser();
+        LibXML_report_error(saved_error, recover);
     OUTPUT:
         RETVAL
 
         SV * self
         SV * fh
     PREINIT:
-        STRLEN len;
-        xmlDocPtr real_doc;
-        HV* real_obj = (HV *)SvRV(self);
-        SV** item    = NULL;
-        int recover;
-    CODE:        
-        LibXML_init_parser(self);
-        real_doc = LibXML_parse_html_stream(self, fh);
+        SV * saved_error;
+        HV * real_obj;
+        htmlDocPtr real_doc;
+        int well_formed;
+        int recover = 0;
+    CODE:
+        RETVAL = &PL_sv_undef;
+        LibXML_init_error(&saved_error);
+        real_obj = LibXML_init_parser(self);
+
+        {
+            int read_length;
+            char buffer[1024];
+            htmlParserCtxtPtr ctxt;
+
+            read_length = LibXML_read_perl(fh, buffer, 4);
+            if (read_length <= 0) {
+                croak( "Empty Stream" );
+            }
+
+            ctxt = htmlCreatePushParserCtxt(NULL, NULL, buffer, read_length,
+                                            NULL, XML_CHAR_ENCODING_NONE);
+            if (ctxt == NULL) {
+                LibXML_report_error(saved_error, 1);
+                croak("Could not create html push parser context: %s",
+                      strerror(errno));
+            }
+            xs_warn( "context created\n");
+
+            ctxt->_private = (void*)self;
+            xs_warn( "context initialized \n");
+
+            {
+                int ret;
+                while ((read_length = LibXML_read_perl(fh, buffer, 1024))) {
+                    ret = htmlParseChunk(ctxt, buffer, read_length, 0);
+                    if ( ret != 0 ) {
+                        break;
+                    }
+                }
+                ret = htmlParseChunk(ctxt, buffer, 0, 1);
+                xs_warn( "document parsed \n");
+            }
+
+            well_formed = ctxt->wellFormed;
+            real_doc = ctxt->myDoc;
+            ctxt->myDoc = NULL;
+            htmlFreeParserCtxt(ctxt);
+        }
+
+        if ( real_doc != NULL ) {
+            recover = LibXML_get_recover(real_obj);
+
+            {
+                SV * newURI = sv_2mortal(newSVpvf("unknown-%12.12d", (void*)real_doc));
+                real_doc->URL = xmlStrdup((const xmlChar*)SvPV_nolen(newURI));
+            }
+
+            if ( recover || well_formed ) {
+                RETVAL = LibXML_NodeToSv( real_obj, (xmlNodePtr) real_doc );
+            } else {
+                xmlFreeDoc(real_doc);
+            }
+        }
+
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser();
-        
-        /* sv_2mortal(LibXML_error); */
-        
-
-        if (real_doc == NULL) {
-            LibXML_croak_error();
-            XSRETURN_UNDEF;
-        } 
-        else {
-            STRLEN n_a;
-            SV * newURI;
-
-            item = hv_fetch( real_obj, "XML_LIBXML_RECOVER", 18, 0 );
-            recover = ( item != NULL && SvTRUE( *item ) ) ? 1 : 0;            
-            if (!recover){
-                LibXML_croak_error();
-            }
-            else {
-                /* LibXML_warn_error(); */ /* if the parser causes some noise */
-            }
-            newURI = newSVpvf("unknown-%12.12d", real_doc);
-            real_doc->URL = xmlStrdup((const xmlChar*)SvPV(newURI, n_a));
-            SvREFCNT_dec(newURI);
-            item = hv_fetch( real_obj, "XML_LIBXML_GDOME", 16, 0 );
-
-            if ( item != NULL && SvTRUE(*item) ) {  
-                RETVAL = PmmNodeToGdomeSv( (xmlNodePtr)real_doc );
-            }
-            else {
-                RETVAL = PmmNodeToSv((xmlNodePtr)real_doc, NULL);
-            }
-        }
+        LibXML_report_error(saved_error, recover);
     OUTPUT:
         RETVAL
-       
+
 SV*
-parse_html_file(self, filename)
+parse_html_file(self, filename_sv)
         SV * self
-        const char * filename
+        SV * filename_sv
     PREINIT:
         STRLEN len;
-        xmlDocPtr real_doc = NULL;
-        HV* real_obj = (HV *)SvRV(self);
-        SV** item    = NULL;
-        int recover;
+        char * filename;
+        SV * saved_error;
+        HV * real_obj;
+        htmlDocPtr real_doc;
+        int recover = 0;
+    INIT:
+        filename = SvPV(filename_sv, len);
+        if (len <= 0) {
+            croak("Empty filename");
+            XSRETURN_UNDEF;
+        }
     CODE:
-        LibXML_init_parser(self);
-        real_doc = htmlParseFile((char*)filename, NULL);
+        RETVAL = &PL_sv_undef;
+        LibXML_init_error(&saved_error);
+        real_obj = LibXML_init_parser(self);
+
+        real_doc = htmlParseFile((const char *)filename, NULL);
+
+        if ( real_doc != NULL ) {
+            recover = LibXML_get_recover(real_obj);
+
+            /* This HTML file parser doesn't use a ctxt; there is no "well-formed"
+             * distinction, and if it manages to parse the HTML, it returns non-null. */
+            RETVAL = LibXML_NodeToSv( real_obj, (xmlNodePtr) real_doc );
+        }
+
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser();
-
-        /* sv_2mortal(LibXML_error); */
-
-        if (real_doc == NULL) {
-            LibXML_croak_error();
-            XSRETURN_UNDEF;
-        }
-
-        item = hv_fetch( real_obj, "XML_LIBXML_RECOVER", 18, 0 );
-        recover = ( item != NULL && SvTRUE( *item ) ) ? 1 : 0;
-        if (!recover) {
-            LibXML_croak_error();
-        }
-        else {
-            /* LibXML_warn_error(); */ /* if the parser causes some noise */
-        }
-
-        item = hv_fetch( real_obj, "XML_LIBXML_GDOME", 16, 0 );
-
-        if ( item != NULL && SvTRUE(*item) ) {  
-            RETVAL = PmmNodeToGdomeSv( (xmlNodePtr)real_doc );
-        }
-        else {
-            RETVAL = PmmNodeToSv((xmlNodePtr)real_doc, NULL);
-        }
+        LibXML_report_error(saved_error, recover);
     OUTPUT:
         RETVAL
 
 SV*
-parse_sgml_fh(self, fh, encoding)
+parse_sgml_string(self, string, enc = &PL_sv_undef)
+        SV * self
+        SV * string
+        SV * enc
+    PREINIT:
+        STRLEN len;
+        char * ptr;
+        char * encoding = NULL;
+        SV * saved_error;
+        HV * real_obj;
+        docbDocPtr real_doc;
+        int recover = 0;
+    INIT:
+        ptr = SvPV(string, len);
+        if (len <= 0) {
+            croak("Empty string");
+            XSRETURN_UNDEF;
+        }
+        if (SvPOK(enc)) {
+            encoding = SvPV(enc, len);
+            if (len <= 0) {
+                encoding = NULL;
+            }
+        }
+    CODE:
+        RETVAL = &PL_sv_undef;
+        LibXML_init_error(&saved_error);
+        real_obj = LibXML_init_parser(self);
+
+        real_doc = docbParseDoc((xmlChar*)ptr, (const char *) encoding);
+
+        if ( real_doc != NULL ) {
+            recover = LibXML_get_recover(real_obj);
+
+            {
+                SV * newURI = sv_2mortal(newSVpvf("unknown-%12.12d", (void*)real_doc));
+                real_doc->URL = xmlStrdup((const xmlChar*)SvPV_nolen(newURI));
+            }
+
+            /* This SGML memory parser doesn't use a ctxt; there is no "well-formed"
+             * distinction, and if it manages to parse the SGML, it returns non-null. */
+            RETVAL = LibXML_NodeToSv( real_obj, (xmlNodePtr) real_doc );
+        }
+
+        LibXML_cleanup_callbacks();
+        LibXML_cleanup_parser();
+        LibXML_report_error(saved_error, recover);
+    OUTPUT:
+        RETVAL
+
+SV*
+parse_sgml_fh(self, fh, enc = &PL_sv_undef)
         SV * self
         SV * fh
-        SV * encoding
+        SV * enc
     PREINIT:
         STRLEN len;
-        xmlDocPtr real_doc;
-        HV* real_obj = (HV *)SvRV(self);
-        SV** item    = NULL;
-        STRLEN n_a;
-        SV * newURI;
-        int recover;
+        char * encoding = NULL;
+        SV * saved_error;
+        HV * real_obj;
+        docbDocPtr real_doc;
+        int well_formed;
+        int recover = 0;
+    INIT:
+        if (SvPOK(enc)) {
+            encoding = SvPV(enc, len);
+            if (len <= 0) {
+                encoding = NULL;
+            }
+        }
     CODE:
-        LibXML_error = NEWSV(0, 512);
-        sv_setpvn(LibXML_error, "", 0);
-        
-        LibXML_init_parser(self);
-        real_doc = LibXML_parse_sgml_stream(self, fh, encoding);
+        RETVAL = &PL_sv_undef;
+        LibXML_init_error(&saved_error);
+        real_obj = LibXML_init_parser(self);
+
+        {
+            int read_length;
+            char buffer[1024];
+            docbParserCtxtPtr ctxt;
+
+            read_length = LibXML_read_perl(fh, buffer, 4);
+            if (read_length <= 0) {
+                croak( "Empty Stream" );
+            }
+
+            ctxt = docbCreatePushParserCtxt(NULL, NULL, buffer, read_length, NULL,
+                                            xmlParseCharEncoding((const char*)encoding));
+            if (ctxt == NULL) {
+                LibXML_report_error(saved_error, 1);
+                croak("Could not create docbook SGML push parser context: %s",
+                      strerror(errno));
+            }
+            xs_warn( "context created\n");
+
+            ctxt->_private = (void*)self;
+            xs_warn( "context initialized \n");
+
+            {
+                int ret;
+                while ((read_length = LibXML_read_perl(fh, buffer, 1024))) {
+                    ret = docbParseChunk(ctxt, buffer, read_length, 0);
+                    if ( ret != 0 ) {
+                        break;
+                    }
+                }
+                ret = docbParseChunk(ctxt, buffer, 0, 1);
+                xs_warn( "document parsed \n");
+            }
+
+            well_formed = ctxt->wellFormed;
+            real_doc = ctxt->myDoc;
+            ctxt->myDoc = NULL;
+            docbFreeParserCtxt(ctxt);
+        }
+
+        if ( real_doc != NULL ) {
+            recover = LibXML_get_recover(real_obj);
+
+            {
+                SV * newURI = sv_2mortal(newSVpvf("unknown-%12.12d", (void*)real_doc));
+                real_doc->URL = xmlStrdup((const xmlChar*)SvPV_nolen(newURI));
+            }
+
+            if ( recover || well_formed ) {
+                RETVAL = LibXML_NodeToSv( real_obj, (xmlNodePtr) real_doc );
+            } else {
+                xmlFreeDoc(real_doc);
+            }
+        }
+
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser();
-        
-        /* sv_2mortal(LibXML_error); */
-        
-        if (real_doc == NULL) {
-            LibXML_croak_error();
-            XSRETURN_UNDEF;
-        }
-
-        item = hv_fetch( real_obj, "XML_LIBXML_RECOVER", 18, 0 );
-        recover = ( item != NULL && SvTRUE( *item ) ) ? 1 : 0;
-        if (!recover) {
-            LibXML_croak_error();
-        }
-        else {
-            /* LibXML_warn_error(); */ /* if the parser causes some noise */
-        }
-
-        newURI = newSVpvf("unknown-%12.12d", real_doc);
-        real_doc->URL = xmlStrdup((const xmlChar*)SvPV(newURI, n_a));
-        SvREFCNT_dec(newURI);
-        item = hv_fetch( real_obj, "XML_LIBXML_GDOME", 16, 0 );
-
-        if ( item != NULL && SvTRUE(*item) ) {  
-            RETVAL = PmmNodeToGdomeSv( (xmlNodePtr)real_doc );
-        }
-        else {
-            RETVAL = PmmNodeToSv((xmlNodePtr)real_doc, NULL);
-        }
+        LibXML_report_error(saved_error, recover);
     OUTPUT:
         RETVAL
 
 SV*
-parse_sgml_string(self, string, encoding)
+parse_sgml_file(self, filename_sv, enc = &PL_sv_undef)
         SV * self
-        SV * string
-        SV * encoding
+        SV * filename_sv
+        SV * enc
     PREINIT:
-        htmlParserCtxtPtr ctxt;
         STRLEN len;
-        char * ptr;
-        int well_formed;
-        int ret;
-        xmlDocPtr real_doc;
-        HV* real_obj = (HV *)SvRV(self);
-        SV** item    = NULL;
-        STRLEN n_a;
-        SV * newURI;
-        int recover;
+        char * filename;
+        char * encoding = NULL;
+        SV * saved_error;
+        HV * real_obj;
+        docbDocPtr real_doc;
+        int recover = 0;
+    INIT:
+        filename = SvPV(filename_sv, len);
+        if (len <= 0) {
+            croak("Empty filename");
+            XSRETURN_UNDEF;
+        }
+        if (SvPOK(enc)) {
+            encoding = SvPV(enc, len);
+            if (len <= 0) {
+                encoding = NULL;
+            }
+        }
     CODE:
-        ptr = SvPV(string, len);
-        if (len == 0) {
-            croak("Empty string");
-        }
-        
-        LibXML_init_parser(self);
-        real_doc = (xmlDocPtr) docbParseDoc((xmlChar *)ptr,
-                                            (const char *)Sv2C(encoding, NULL));
+        RETVAL = &PL_sv_undef;
+        LibXML_init_error(&saved_error);
+        real_obj = LibXML_init_parser(self);
+
+        real_doc = docbParseFile((const char *)filename, (const char *) encoding);
+
+        if ( real_doc != NULL ) {
+            recover = LibXML_get_recover(real_obj);
+
+            /* This SGML file parser doesn't use a ctxt; there is no "well-formed"
+             * distinction, and if it manages to parse the SGML, it returns non-null. */
+            RETVAL = LibXML_NodeToSv( real_obj, (xmlNodePtr) real_doc );
+        }
 
         LibXML_cleanup_callbacks();
-        LibXML_cleanup_parser();        
-
-        /* sv_2mortal(LibXML_error); */
-
-        if (real_doc == NULL) {
-            LibXML_croak_error();
-            XSRETURN_UNDEF;
-        }
-
-        item = hv_fetch( real_obj, "XML_LIBXML_RECOVER", 18, 0 );
-        recover = ( item != NULL && SvTRUE( *item ) ) ? 1 : 0;
-        if (!recover) {
-            LibXML_croak_error();
-        }
-        else {
-            /* LibXML_warn_error(); */ /* if the parser causes some noise */
-        }
-
-        newURI = newSVpvf("unknown-%12.12d", real_doc);
-        real_doc->URL = xmlStrdup((const xmlChar*)SvPV(newURI, n_a));
-        SvREFCNT_dec(newURI);
-
-        item = hv_fetch( real_obj, "XML_LIBXML_GDOME", 16, 0 );            
-        if ( item != NULL && SvTRUE(*item) ) {  
-            RETVAL = PmmNodeToGdomeSv( (xmlNodePtr)real_doc );
-        }
-        else {
-            RETVAL = PmmNodeToSv((xmlNodePtr)real_doc, NULL);
-        }
+        LibXML_cleanup_parser();
+        LibXML_report_error(saved_error, recover);
     OUTPUT:
         RETVAL
 
-SV*
-parse_sgml_file(self, fn, encoding)
+void
+_parse_sax_sgml_file(self, filename_sv, enc = &PL_sv_undef)
         SV * self
-        SV * fn
-        SV * encoding
+        SV * filename_sv
+        SV * enc
     PREINIT:
-        const char * filename = (const char*)Sv2C( fn, NULL );
         STRLEN len;
-        xmlDocPtr real_doc;
-        HV* real_obj = (HV *)SvRV(self);
-        SV** item    = NULL;
-        int recover;
+        char * filename;
+        char * encoding = NULL;
+        SV * saved_error;
+        HV * real_obj;
+        int recover = 0;
+    INIT:
+        filename = SvPV(filename_sv, len);
+        if (len <= 0) {
+            croak("Empty filename");
+            XSRETURN_UNDEF;
+        }
+        if (SvPOK(enc)) {
+            encoding = SvPV(enc, len);
+            if (len <= 0) {
+                encoding = NULL;
+            }
+        }
     CODE:
-        LibXML_init_parser(self);
-        real_doc = (xmlDocPtr) docbParseFile(filename,
-                                             (const char *) Sv2C(encoding, NULL));
+        LibXML_init_error(&saved_error);
+        real_obj = LibXML_init_parser(self);
+        recover = LibXML_get_recover(real_obj);
+
+        {
+            docbParserCtxtPtr ctxt = docbCreateFileParserCtxt(filename, encoding);
+            if (ctxt == NULL) {
+                LibXML_report_error(saved_error, 1);
+                croak("Couldn't create file parser context for file \"%s\": %s",
+                      filename, strerror(errno));
+            }
+            xs_warn( "context created\n");
+
+            ctxt->sax = PSaxGetHandler();
+            PmmSAXInitContext( ctxt, self );
+            xs_warn( "context initialized \n");
+
+            {
+                docbParseDocument(ctxt);
+                xs_warn( "document parsed \n");
+            }
+
+            PmmSAXCloseContext(ctxt);
+            docbFreeParserCtxt(ctxt);
+        }
+
         LibXML_cleanup_callbacks();
         LibXML_cleanup_parser();
-
-        /* sv_2mortal(LibXML_error); */
-        
-        if (real_doc == NULL) {
-            LibXML_croak_error();
-            XSRETURN_UNDEF;
-        }
-        else {
-            item = hv_fetch( real_obj, "XML_LIBXML_RECOVER", 18, 0 );
-            recover = ( item != NULL && SvTRUE( *item ) ) ? 1 : 0;
-            if (!recover) {
-                LibXML_croak_error();
-            }
-            else {
-                /* LibXML_warn_error(); */ /* if the parser causes some noise */
-            }
-            
-            item = hv_fetch( real_obj, "XML_LIBXML_GDOME", 16, 0 );
-
-            if ( item != NULL && SvTRUE(*item) ) {  
-                RETVAL = PmmNodeToGdomeSv( (xmlNodePtr)real_doc );
-            }
-            else {
-                RETVAL = PmmNodeToSv((xmlNodePtr)real_doc, NULL);
-            }
-        }
-    OUTPUT:
-        RETVAL
-
-
-void
-parse_sax_sgml_file(self, fn, enc )
+        LibXML_report_error(saved_error, recover);
+
+SV*
+_parse_xml_chunk(self, svchunk, enc = &PL_sv_undef)
         SV * self
-        SV * fn
+        SV * svchunk
         SV * enc
     PREINIT:
-        const char * filename = (const char *)Sv2C(fn, NULL);  
-        const char * encoding = (const char *)Sv2C(enc, NULL);
-        xmlParserCtxtPtr ctxt;
         STRLEN len;
+        char * encoding = "UTF-8";
+        SV * saved_error;
+        HV * real_obj;
+        int recover = 0;
+        xmlChar * chunk;
+        xmlNodePtr rv = NULL;
+    INIT:
+        if (SvPOK(enc)) {
+            encoding = SvPV(enc, len);
+            if (len <= 0) {
+                encoding = "UTF-8";
+            }
+        }
     CODE:
-        LibXML_init_parser(self);
-        ctxt = (xmlParserCtxtPtr) docbCreateFileParserCtxt(filename, encoding);
-
-        if (ctxt == NULL) {
-            croak("Could not create file parser context for file '%s' : %s", filename, strerror(errno));
-        }