1. Shlomi Fish
  2. perl-XML-LibXML

Commits

ph...@9ae0c189-cd1f-4510-a509-f4891f5cf20d  committed 1fd6105

Modified Files:
LibXML.xs LibXML.pm dom.h dom.c
+ document destruction memory leaks fixed (no segfaulting, no attenpts
of freeing uninitialized scalars)
+ Element::getAttributes() added
+ Element::getAttributesNS(URI) added
+ Element::setAttributeNode() finished
+ dom.c/dom.h: domSetAttributeNode() added
+ some security fixes

  • Participants
  • Parent commits 4a865c2
  • Branches default

Comments (0)

Files changed (4)

File LibXML.pm

View file
 use vars qw($VERSION @ISA @EXPORT);
 use Carp;
 
-$VERSION = "0.92";
+$VERSION = "0.94";
 require Exporter;
 require DynaLoader;
 
 @XML::LibXML::NoGCDocument::ISA = 'XML::LibXML::Document';
 @XML::LibXML::Attr::ISA         = 'XML::LibXML::Node';
 
-sub XML::LibXML::NoGCDocument::DESTROY () { }
+# sub XML::LibXML::NoGCDocument::DESTROY () { }
 
 sub XML::LibXML::Node::iterator {
     my $self = shift;

File LibXML.xs

View file
             croak(SvPV(LibXML_error, len));
         }
         else {
-            if (real_dom->encoding == NULL) {
-                real_dom->encoding = "UTF-8";
-            }
+            #xmlFreeDoc(real_dom);
+            #RETVAL = &PL_sv_undef;    
+            #croak(SvPV(LibXML_error, len));
 
             proxy = make_proxy_node( (xmlNodePtr)real_dom ); 
 
             croak(SvPV(LibXML_error, len));
         }
         else {
-            if (real_dom->encoding == NULL) {
-                real_dom->encoding = xmlStrdup("UTF-8");
-            }
-       
             proxy = make_proxy_node( (xmlNodePtr)real_dom ); 
 
             RETVAL = sv_newmortal();
             croak(SvPV(LibXML_error, len));
         }
         else {
-            if (real_dom->encoding == NULL) {
-                real_dom->encoding = xmlStrdup("UTF-8");
-            }
-
             proxy = make_proxy_node( (xmlNodePtr)real_dom ); 
 
             RETVAL = sv_newmortal();
     PREINIT:
         xmlDocPtr real_node;
     CODE:
-       
-   
+        if ( self->object != NULL ) {
+            xmlFreeDoc((xmlDocPtr)self->object);
+            # warn( "REAL DOCUMENT DROP SUCCEEDS" );
+        }        
+        self->object = NULL;
+        Safefree( self );
 
 SV *
 toString(self, format=0)
         int format
     PREINIT:
         xmlDocPtr real_dom;
-        xmlChar *result;
-        int len;
+        xmlChar *result=NULL;
+        int len=0;
     CODE:
         real_dom = (xmlDocPtr)self->object;
         if ( format <= 0 ) {
+            # warn( "use no formated toString!" );
             xmlDocDumpMemory(real_dom, &result, &len);
         }
         else {
             int t_indent_var = xmlIndentTreeOutput;
+            # warn( "use formated toString!" );
             xmlIndentTreeOutput = 1;
             xmlDocDumpFormatMemory( real_dom, &result, &len, format ); 
             xmlIndentTreeOutput = t_indent_var;
 	        # warn("Failed to convert doc to string");           
             RETVAL = &PL_sv_undef;
     	} else {
-            # warn(result);
+            # warn("%s, %d\n",result, len);
             RETVAL = newSVpvn((char *)result, (STRLEN)len);
             xmlFree(result);
         }
-        xmlReconciliateNs(real_dom,xmlDocGetRootElement(real_dom));
     OUTPUT:
         RETVAL
 
         real_dom = (xmlDocPtr)((ProxyObject*)SvIV((SV*)SvRV(dom)))->object;
         SvREFCNT_dec(proxy->extra);
         elem = (xmlNodePtr)proxy->object;
-        domSetDocumentElement( real_dom, elem );
-        proxy->extra = dom;
-        SvREFCNT_inc(dom);
+        # please correct me if i am wrong: the document element HAS to be
+        # an ELEMENT NODE
+        if ( elem->type == XML_ELEMENT_NODE ) {
+            domSetDocumentElement( real_dom, elem );
+            proxy->extra = dom;
+            SvREFCNT_inc(dom);
+        }
 
 ProxyObject *
 getDocumentElement( dom )
         if (node == NULL) {
            XSRETURN_UNDEF;
         }
-        real_node = node->object;
-        if (node->extra != NULL) {
-            SvREFCNT_dec(node->extra);
+        real_node = (xmlNodePtr)node->object;
+        if ( node->extra != NULL
+             && real_node != NULL ){
+            if ( SvREFCNT( node->extra ) > 0 ){
+                SvREFCNT_dec(node->extra);
+            }
+            if ( real_node->type != XML_DOCUMENT_NODE ) {
+                Safefree(node);
+            }
         }
-     
-        if ( real_node != NULL ) {
-            if ( real_node->type == XML_DOCUMENT_NODE ){
-                if ( node->extra == NULL ) {
-                    xmlFreeDoc((xmlDocPtr)node->object);
-                }
-                else {
-                    node->extra  = NULL;
-                }
-            }
+        else if ( real_node == NULL ) {
             Safefree(node);
-        } 
+        }     
  
 int 
 getType( node ) 
         ProxyObject* elem
     CODE:
         RETVAL = elem->extra;
+        SvREFCNT_inc( RETVAL );
     OUTPUT:
         RETVAL
 
             qname  = domEncodeString( elem->doc->encoding, qname );
             value = domEncodeString( elem->doc->encoding, value );
         }
-
+    
         if ( nsURI != NULL && strlen(nsURI) != 0 ) {
             lname = xmlSplitQName2(qname, &prefix);
         
             xmlSetProp( elem, qname, value );
         }
 
-# this is a dummy!
 ProxyObject *
 setAttributeNode( elem, attrnode ) 
         ProxyObject* elem
     PREINIT:
         const char * CLASS = "XML::LibXML::Attr";
     CODE:
-        RETVAL = NULL;        
+        RETVAL = make_proxy_node( (xmlNodePtr)domSetAttributeNode( (xmlNodePtr) elem->object, (xmlAttrPtr) attrnode->object ) );
+        if ( elem->extra != NULL ) {
+            RETVAL->extra = elem->extra;
+            SvREFCNT_inc(elem->extra);
+        }
     OUTPUT:
         RETVAL
 
         xmlNodePtr elem
         char * name
     PREINIT:
-        xmlAttrPtr att;
+        xmlAttrPtr att = NULL;
     CODE:
         /**
          * xmlHasProp() returns the attribute node, which is not exactly what 
         char * nsURI
         char * name
     PREINIT:
-        xmlAttrPtr att;
+        xmlAttrPtr att = NULL;
     CODE:
         /**
          * domHasNsProp() returns the attribute node, which is not exactly what 
         ProxyObject* elem
         char * name 
     PREINIT:
-	    char * content;
+	    char * content = NULL;
     CODE:
         content = xmlGetProp( elem->object, name );
-        if( ((xmlNodePtr)elem->object)->doc != NULL ){
+        if ( ((xmlNodePtr)elem->object)->doc != NULL ){
             content = domDecodeString( ((xmlNodePtr)elem->object)->doc->encoding, content );
         }
+
         if ( content != NULL ) {
             RETVAL  = newSVpvn( content, xmlStrlen( content ) );
         }
         char * name 
     PREINIT:
         xmlAttrPtr att;
-	    char * content;
+	    char * content = NULL;
     CODE:
         att = domHasNsProp( elem->object, name, nsURI );
         if ( att != NULL && att->children != NULL ) {
             content = att->children->content;
         }
 
-        if( ((xmlNodePtr)elem->object)->doc != NULL ){
+        if ( ((xmlNodePtr)elem->object)->doc != NULL ){
             content = domDecodeString( ((xmlNodePtr)elem->object)->doc->encoding, content );
         }
 
     PREINIT:
         const char * CLASS = "XML::LibXML::Attr";
         xmlNodePtr elem = (xmlNodePtr) elemobj->object;
-        xmlAttrPtr attrnode;
+        xmlAttrPtr attrnode = NULL;
     CODE:
+        RETVAL = NULL;
         attrnode = xmlHasProp( elem, name );
         if ( attrnode != NULL ) {
             RETVAL = make_proxy_node((xmlNodePtr)attrnode);
                 SvREFCNT_inc(elemobj->extra);
             }
         }
-        else {
-            RETVAL = NULL;
-        }
     OUTPUT:
         RETVAL
 
     PREINIT:
         const char * CLASS = "XML::LibXML::Attr";
         xmlNodePtr elem = (xmlNodePtr) elemobj->object;
-        xmlAttrPtr attrnode;
+        xmlAttrPtr attrnode = NULL;
     CODE:
+        RETVAL = NULL;
         attrnode = domHasNsProp( elem, name, nsURI );
         if ( attrnode != NULL ) {
             RETVAL = make_proxy_node((xmlNodePtr)attrnode);
                 SvREFCNT_inc(elemobj->extra);
             }
         }
-        else {
-            RETVAL = NULL;
-        }
     OUTPUT:
         RETVAL
 
+SV*
+getAttributes( node )
+        ProxyObject* node
+    PREINIT:
+        xmlAttrPtr attr = NULL;
+        xmlNodePtr real_node = NULL;
+        SV * element;
+        int len=0;
+        const char * CLASS = "XML::LibXML::Attr";
+    PPCODE:
+        real_node = (xmlNodePtr) node->object;
+
+        attr      = real_node->properties;
+        while ( attr != NULL ) {
+            ProxyObject * proxy=NULL;
+            element = sv_newmortal();   
+            proxy = make_proxy_node((xmlNodePtr)attr);
+            if ( node->extra != NULL ) {
+                proxy->extra = node->extra;
+                SvREFCNT_inc(node->extra);
+            }
+            XPUSHs( sv_setref_pv( element, (char *)CLASS, (void*)proxy ) );
+            attr = attr->next;
+            len++;
+         }
+        XSRETURN(len);
+
+SV*
+getAttributesNS( node,nsURI )
+        ProxyObject* node
+        char * nsURI
+    PREINIT:
+        xmlAttrPtr attr = NULL;
+        xmlNodePtr real_node = NULL;
+        SV * element;
+        int len = 0;
+        const char * CLASS = "XML::LibXML::Attr";
+    PPCODE:
+        real_node = (xmlNodePtr) node->object;
+
+        attr      = real_node->properties;
+        while ( attr != NULL ) {
+            if( attr->ns != NULL && xmlStrcmp( nsURI, attr->ns->href ) == 0 ){ 
+                ProxyObject * proxy;
+                element = sv_newmortal();
+                
+                proxy = make_proxy_node((xmlNodePtr)attr);
+                if ( node->extra != NULL ) {
+                    proxy->extra = node->extra;
+                    SvREFCNT_inc(node->extra);
+                }
+                XPUSHs( sv_setref_pv( element, (char *)CLASS, (void*)proxy ) );
+                len++;
+            }
+            attr = attr->next;
+        }
+        XSRETURN(len);
+
 void
 removeAttribute( elem, name ) 	
         xmlNodePtr elem

File dom.c

View file
+/* $Id$ */
 #include <libxml/tree.h>
 #include <libxml/encoding.h>
 #include <libxml/xmlmemory.h>
 xmlNodePtr
 domUnbindNode( xmlNodePtr self ) {
   if ( (self != NULL) && (self->parent != NULL) ) { 
+    if( self->parent!=NULL ) {
+      if( self->parent->properties == (xmlAttrPtr) self ) 
+        self->parent->properties = (xmlAttrPtr)self->next;
+      if ( self == self->parent->last ) 
+        self->parent->last = self->prev;
+      if ( self == self->parent->children ) 
+        self->parent->children = self->next;
+    }
     if ( self->next != NULL )
       self->next->prev = self->prev;
     if ( self->prev != NULL )
       self->prev->next = self->next;
-    if ( self == self->parent->last ) 
-      self->parent->last = self->prev;
-    if ( self == self->parent->children ) 
-      self->parent->children = self->next;
 
     self->parent = NULL;
     self->next   = NULL;
     case XML_ATTRIBUTE_NODE:
       name = "XML::LibXML::Attr"; 
       break;
+    case XML_DOCUMENT_NODE:
+      name = "XML::LibXML::Document";
+      break;
     default:
       name = "XML::LibXML::Node";
       break;
 domImportNode( xmlDocPtr doc, xmlNodePtr node, int move ) {
   xmlNodePtr return_node = node;
 
-  if ( !doc ) {
-    return_node = node;
-  }
-  else if ( node && node->doc != doc ) {
+  if ( node && node->doc != doc ) {
     if ( move ) {
       return_node = domUnbindNode( node );
     }
 
 xmlNodePtr
 domSetOwnerDocument( xmlNodePtr self, xmlDocPtr newDoc ) {
-    if ( newDoc == NULL ) {
-        return NULL;
-    }
+    if ( self != NULL ) {
+        xmlNodePtr cNode = self->children;
+        xmlNodePtr pNode = (xmlNodePtr)self->properties;
+        
+        self->doc = newDoc;
+        while ( cNode != NULL ) {
+            domSetOwnerDocument( cNode, newDoc );
+            cNode = cNode->next;
+        }
 
-    if ( self != NULL ) {
-        xmlNodePtr pNode = self->children;
-
-        self->doc = newDoc;
         while ( pNode != NULL ) {
-            domSetOwnerDocument( pNode, newDoc );
-            pNode = pNode->next;
+          domSetOwnerDocument( cNode, newDoc );
+          pNode = pNode->next;
         }
     }
 
   }
   return(NULL);
 }
+
+xmlAttrPtr 
+domSetAttributeNode( xmlNodePtr node, xmlAttrPtr attr ) {
+  if ( attr != NULL && attr->type != XML_ATTRIBUTE_NODE )
+    return NULL;
+  if ( node == NULL || attr == NULL ) {
+    return attr;
+  }
+  if ( node == attr->parent ) {
+    return attr; /* attribute is allready part of the node */
+  }  
+  if ( attr->doc != node->doc ){
+    attr = (xmlAttrPtr) domImportNode( node->doc, (xmlNodePtr) attr, 1 ); 
+  } 
+  else {
+    attr = (xmlAttrPtr)domUnbindNode( (xmlNodePtr) attr );
+  }
+
+  /* stolen from libxml2 */
+  if ( attr != NULL ) {
+    if (node->properties == NULL) {
+      node->properties = attr;
+    } else {
+      xmlAttrPtr prev = node->properties;
+      
+      while (prev->next != NULL) prev = prev->next;
+      prev->next = attr;
+      attr->prev = prev;
+    }
+  }
+
+  return attr;
+}

File dom.h

View file
 /* dom.h
+ * $Id$
  * Author: Christian Glahn (2001)
  * 
  * This header file provides some definitions for wrapper functions.
 
 xmlAttrPtr
 domHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *namespace);
+
+xmlAttrPtr
+domSetAttributeNode( xmlNodePtr node , xmlAttrPtr attr );
+
 #endif