Convert from NULL macro to nullptr.
[shibboleth/cpp-xmltooling.git] / xmltooling / io / AbstractXMLObjectMarshaller.cpp
index 4822fbe..c28bcbf 100644 (file)
@@ -1,5 +1,5 @@
 /*
-*  Copyright 2001-2006 Internet2
+*  Copyright 2001-2010 Internet2
  * 
 * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
 #include "exceptions.h"
 #include "io/AbstractXMLObjectMarshaller.h"
 #ifndef XMLTOOLING_NO_XMLSEC
+    #include "security/Credential.h"
     #include "signature/Signature.h"
 #endif
 #include "util/NDC.h"
 #include <algorithm>
 #include <functional>
 #include <xercesc/util/XMLUniDefs.hpp>
-#include <log4cpp/Category.hh>
 
 #ifndef XMLTOOLING_NO_XMLSEC
     using namespace xmlsignature;
 #endif
 using namespace xmlconstants;
 using namespace xmltooling;
-using namespace log4cpp;
+using namespace xercesc;
 using namespace std;
 
-#define XT_log (*static_cast<Category*>(m_log))
+AbstractXMLObjectMarshaller::AbstractXMLObjectMarshaller()
+{
+}
+
+AbstractXMLObjectMarshaller::~AbstractXMLObjectMarshaller()
+{
+}
+
+void AbstractXMLObjectMarshaller::setDocumentElement(DOMDocument* document, DOMElement* element) const
+{
+    DOMElement* documentRoot = document->getDocumentElement();
+    if (documentRoot)
+        document->replaceChild(element, documentRoot);
+    else
+        document->appendChild(element);
+}
 
 DOMElement* AbstractXMLObjectMarshaller::marshall(
     DOMDocument* document
 #ifndef XMLTOOLING_NO_XMLSEC
-    ,const std::vector<xmlsignature::Signature*>* sigs
+    ,const vector<Signature*>* sigs
+    ,const Credential* credential
 #endif
     ) const
 {
@@ -56,14 +72,14 @@ DOMElement* AbstractXMLObjectMarshaller::marshall(
     xmltooling::NDC ndc("marshall");
 #endif
 
-    if (XT_log.isDebugEnabled()) {
-        XT_log.debug("starting to marshal %s", getElementQName().toString().c_str());
+    if (m_log.isDebugEnabled()) {
+        m_log.debug("starting to marshal %s", getElementQName().toString().c_str());
     }
 
     DOMElement* cachedDOM=getDOM();
     if (cachedDOM) {
         if (!document || document==cachedDOM->getOwnerDocument()) {
-            XT_log.debug("XMLObject has a usable cached DOM, reusing it");
+            m_log.debug("XMLObject has a usable cached DOM, reusing it");
             if (document)
                 setDocumentElement(cachedDOM->getOwnerDocument(),cachedDOM);
             releaseParentDOM(true);
@@ -83,24 +99,24 @@ DOMElement* AbstractXMLObjectMarshaller::marshall(
     // We may need to create our own document.
     bool bindDocument=false;
     if (!document) {
-        document=DOMImplementationRegistry::getDOMImplementation(NULL)->createDocument();
+        document=DOMImplementationRegistry::getDOMImplementation(nullptr)->createDocument();
         bindDocument=true;
     }
     
-    XercesJanitor<DOMDocument> janitor(bindDocument ? document : NULL);
+    XercesJanitor<DOMDocument> janitor(bindDocument ? document : nullptr);
 
-    XT_log.debug("creating root element to marshall");
+    m_log.debug("creating root element to marshall");
     DOMElement* domElement = document->createElementNS(
         getElementQName().getNamespaceURI(), getElementQName().getLocalPart()
         );
     setDocumentElement(document, domElement);
 #ifndef XMLTOOLING_NO_XMLSEC
-    marshallInto(domElement, sigs);
+    marshallInto(domElement, sigs, credential);
 #else
     marshallInto(domElement);
 #endif
     //Recache the DOM.
-    XT_log.debug("caching DOM for XMLObject (document is %sbound)", bindDocument ? "" : "not ");
+    m_log.debug("caching DOM for XMLObject (document is %sbound)", bindDocument ? "" : "not ");
     setDOM(domElement, bindDocument);
     janitor.release();  // safely transferred
     releaseParentDOM(true);
@@ -111,7 +127,8 @@ DOMElement* AbstractXMLObjectMarshaller::marshall(
 DOMElement* AbstractXMLObjectMarshaller::marshall(
     DOMElement* parentElement
 #ifndef XMLTOOLING_NO_XMLSEC
-    ,const std::vector<xmlsignature::Signature*>* sigs
+    ,const vector<Signature*>* sigs
+    ,const Credential* credential
 #endif
     ) const
 {
@@ -119,14 +136,14 @@ DOMElement* AbstractXMLObjectMarshaller::marshall(
     xmltooling::NDC ndc("marshall");
 #endif
 
-    if (XT_log.isDebugEnabled()) {
-        XT_log.debug("starting to marshalling %s", getElementQName().toString().c_str());
+    if (m_log.isDebugEnabled()) {
+        m_log.debug("starting to marshalling %s", getElementQName().toString().c_str());
     }
 
     DOMElement* cachedDOM=getDOM();
     if (cachedDOM) {
         if (parentElement->getOwnerDocument()==cachedDOM->getOwnerDocument()) {
-            XT_log.debug("XMLObject has a usable cached DOM, reusing it");
+            m_log.debug("XMLObject has a usable cached DOM, reusing it");
             if (parentElement!=cachedDOM->getParentNode()) {
                 parentElement->appendChild(cachedDOM);
                 releaseParentDOM(true);
@@ -144,19 +161,19 @@ DOMElement* AbstractXMLObjectMarshaller::marshall(
     }
     
     // If we get here, we didn't have a usable DOM (and/or we released the one we had).
-    XT_log.debug("creating root element to marshall");
+    m_log.debug("creating root element to marshall");
     DOMElement* domElement = parentElement->getOwnerDocument()->createElementNS(
         getElementQName().getNamespaceURI(), getElementQName().getLocalPart()
         );
     parentElement->appendChild(domElement);
 #ifndef XMLTOOLING_NO_XMLSEC
-    marshallInto(domElement, sigs);
+    marshallInto(domElement, sigs, credential);
 #else
     marshallInto(domElement);
 #endif
 
     //Recache the DOM.
-    XT_log.debug("caching DOM for XMLObject");
+    m_log.debug("caching DOM for XMLObject");
     setDOM(domElement, false);
     releaseParentDOM(true);
 
@@ -166,28 +183,66 @@ DOMElement* AbstractXMLObjectMarshaller::marshall(
 void AbstractXMLObjectMarshaller::marshallInto(
     DOMElement* targetElement
 #ifndef XMLTOOLING_NO_XMLSEC
-    ,const std::vector<xmlsignature::Signature*>* sigs
+    ,const vector<Signature*>* sigs
+    ,const Credential* credential
 #endif
     ) const
 {
     if (getElementQName().hasPrefix())
         targetElement->setPrefix(getElementQName().getPrefix());
 
-    if (m_schemaLocation) {
-        static const XMLCh schemaLocation[]= UNICODE_LITERAL_14(s,c,h,e,m,a,L,o,c,a,t,i,o,n);
-        if (targetElement->getParentNode()==NULL || targetElement->getParentNode()->getNodeType()==DOMNode::DOCUMENT_NODE)
-            targetElement->setAttributeNS(XSI_NS,schemaLocation,m_schemaLocation); 
+    if (m_schemaLocation || m_noNamespaceSchemaLocation) {
+        static const XMLCh schemaLocation[] = {
+            chLatin_x, chLatin_s, chLatin_i, chColon,
+            chLatin_s, chLatin_c, chLatin_h, chLatin_e, chLatin_m, chLatin_a,
+            chLatin_L, chLatin_o, chLatin_c, chLatin_a, chLatin_t, chLatin_i, chLatin_o, chLatin_n, chNull
+            };
+        static const XMLCh noNamespaceSchemaLocation[] = {
+            chLatin_x, chLatin_s, chLatin_i, chColon,
+            chLatin_n, chLatin_o, chLatin_N, chLatin_a, chLatin_m, chLatin_e, chLatin_s, chLatin_p, chLatin_a, chLatin_c, chLatin_e,
+            chLatin_S, chLatin_c, chLatin_h, chLatin_e, chLatin_m, chLatin_a,
+            chLatin_L, chLatin_o, chLatin_c, chLatin_a, chLatin_t, chLatin_i, chLatin_o, chLatin_n, chNull
+            };
+        if (targetElement->getParentNode()==nullptr || targetElement->getParentNode()->getNodeType()==DOMNode::DOCUMENT_NODE) {
+            if (m_schemaLocation)
+                targetElement->setAttributeNS(XSI_NS,schemaLocation,m_schemaLocation); 
+            if (m_noNamespaceSchemaLocation)
+                targetElement->setAttributeNS(XSI_NS,noNamespaceSchemaLocation,m_noNamespaceSchemaLocation); 
+        }
+    }
+    
+    static const XMLCh _nil[] = { chLatin_x, chLatin_s, chLatin_i, chColon, chLatin_n, chLatin_i, chLatin_l, chNull };
+    
+    if (m_nil != xmlconstants::XML_BOOL_NULL) {
+        switch (m_nil) {
+            case xmlconstants::XML_BOOL_TRUE:
+               targetElement->setAttributeNS(XSI_NS, _nil, xmlconstants::XML_TRUE);
+                break;
+            case xmlconstants::XML_BOOL_ONE:
+               targetElement->setAttributeNS(XSI_NS, _nil, xmlconstants::XML_ONE);
+                break;
+            case xmlconstants::XML_BOOL_FALSE:
+               targetElement->setAttributeNS(XSI_NS, _nil, xmlconstants::XML_FALSE);
+                break;
+            case xmlconstants::XML_BOOL_ZERO:
+               targetElement->setAttributeNS(XSI_NS, _nil, xmlconstants::XML_ZERO);
+                break;
+        }
+        m_log.debug("adding XSI namespace to list of namespaces visibly used by XMLObject");
+        addNamespace(Namespace(XSI_NS, XSI_PREFIX, false, Namespace::VisiblyUsed));
     }
 
     marshallElementType(targetElement);
     marshallNamespaces(targetElement);
     marshallAttributes(targetElement);
-    marshallContent(targetElement);
     
 #ifndef XMLTOOLING_NO_XMLSEC
+    marshallContent(targetElement,credential);
     if (sigs) {
-        for_each(sigs->begin(),sigs->end(),mem_fun<void,Signature>(&Signature::sign));
+        for_each(sigs->begin(),sigs->end(),bind2nd(mem_fun1_t<void,Signature,const Credential*>(&Signature::sign),credential));
     }
+#else
+    marshallContent(targetElement);
 #endif
 }
 
@@ -195,7 +250,7 @@ void AbstractXMLObjectMarshaller::marshallElementType(DOMElement* domElement) co
 {
     const QName* type = getSchemaType();
     if (type) {
-        XT_log.debug("setting xsi:type attribute for XMLObject");
+        m_log.debug("setting xsi:type attribute for XMLObject");
         
         const XMLCh* typeLocalName = type->getLocalPart();
         if (!typeLocalName || !*typeLocalName) {
@@ -220,8 +275,8 @@ void AbstractXMLObjectMarshaller::marshallElementType(DOMElement* domElement) co
         if (xsivalue != typeLocalName)
             XMLString::release(&xsivalue);
 
-        XT_log.debug("Adding XSI namespace to list of namespaces used by XMLObject");
-        addNamespace(Namespace(XSI_NS, XSI_PREFIX));
+        m_log.debug("adding XSI namespace to list of namespaces visibly used by XMLObject");
+        addNamespace(Namespace(XSI_NS, XSI_PREFIX, false, Namespace::VisiblyUsed));
     }
 }
 
@@ -231,6 +286,10 @@ public:
         const XMLCh* prefix=ns.getNamespacePrefix();
         const XMLCh* uri=ns.getNamespaceURI();
         
+        // Check for xmlns:xml.
+        if (XMLString::equals(prefix, XML_PREFIX) && XMLString::equals(uri, XML_NS))
+            return;
+
         // Check to see if the prefix is already declared properly above this node.
         if (!ns.alwaysDeclare()) {
             const XMLCh* declared=lookupNamespaceURI(domElement->getParentNode(),prefix);
@@ -246,6 +305,7 @@ public:
             XMLString::catString(xmlns,colon);
             XMLString::catString(xmlns,prefix);
             domElement->setAttributeNS(XMLNS_NS, xmlns, uri);
+            delete[] xmlns;
         }
         else {
             domElement->setAttributeNS(XMLNS_NS, XMLNS_PREFIX, uri);
@@ -253,12 +313,12 @@ public:
     }
 
     const XMLCh* lookupNamespaceURI(const DOMNode* n, const XMLCh* prefix) const {
-        // Return NULL if no declaration in effect. The empty string signifies the null namespace.
+        // Return nullptr if no declaration in effect. The empty string signifies the null namespace.
         if (!n || n->getNodeType()!=DOMNode::ELEMENT_NODE) {
             // At the root, the default namespace is set to the null namespace.
             if (!prefix || !*prefix)
                 return &chNull;
-            return NULL;    // we're done
+            return nullptr;    // we're done
         }
         DOMNamedNodeMap* attributes = static_cast<const DOMElement*>(n)->getAttributes();
         if (!attributes)
@@ -285,26 +345,40 @@ public:
 
 void AbstractXMLObjectMarshaller::marshallNamespaces(DOMElement* domElement) const
 {
-    XT_log.debug("marshalling namespace attributes for XMLObject");
+    m_log.debug("marshalling namespace attributes for XMLObject");
     const set<Namespace>& namespaces = getNamespaces();
     for_each(namespaces.begin(),namespaces.end(),bind1st(_addns(),domElement));
 }
 
-void AbstractXMLObjectMarshaller::marshallContent(DOMElement* domElement) const
+void AbstractXMLObjectMarshaller::marshallContent(
+    DOMElement* domElement
+#ifndef XMLTOOLING_NO_XMLSEC
+    ,const Credential* credential
+#endif
+    ) const
 {
-    XT_log.debug("marshalling text and child elements for XMLObject");
+    m_log.debug("marshalling text and child elements for XMLObject");
     
-    const XMLCh* val;
     unsigned int pos=0;
+    const XMLCh* val = getTextContent(pos);
+    if (val && *val)
+        domElement->appendChild(domElement->getOwnerDocument()->createTextNode(val));
+    
     const list<XMLObject*>& children=getOrderedChildren();
-    for (list<XMLObject*>::const_iterator i=children.begin(); i!=children.end(); ++i, ++pos) {
-        val = getTextContent(pos);
-        if (val && *val)
-            domElement->appendChild(domElement->getOwnerDocument()->createTextNode(val));
-        if (*i)
+    for (list<XMLObject*>::const_iterator i=children.begin(); i!=children.end(); ++i) {
+        if (*i) {
+#ifndef XMLTOOLING_NO_XMLSEC
+            (*i)->marshall(domElement,nullptr,credential);
+#else
             (*i)->marshall(domElement);
+#endif
+            val = getTextContent(++pos);
+            if (val && *val)
+                domElement->appendChild(domElement->getOwnerDocument()->createTextNode(val));
+        }
     }
-    val = getTextContent(pos);
-    if (val && *val)
-        domElement->appendChild(domElement->getOwnerDocument()->createTextNode(val));
+}
+
+void AbstractXMLObjectMarshaller::marshallAttributes(DOMElement* domElement) const
+{
 }