blob: 48fcac61d61b46a543e4fa8337bd12bebc618329 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* XSEC
*
* XSECXMLNSStack := NS Stack for simple canonicalisation
*
* $Id$
*
*/
// XSEC
#include <xsec/framework/XSECDefs.hpp>
#include <xsec/framework/XSECError.hpp>
#include <xsec/utils/XSECDOMUtils.hpp>
#include <xsec/canon/XSECXMLNSStack.hpp>
// Xerces
XERCES_CPP_NAMESPACE_USE
// --------------------------------------------------------------------------------
// Holder structures
// --------------------------------------------------------------------------------
typedef struct XSECNSHolderStruct {
XERCES_CPP_NAMESPACE_QUALIFIER DOMNode * mp_ns; // Actual NS attribute
XERCES_CPP_NAMESPACE_QUALIFIER DOMNode * mp_owner; // Owner Element
struct XSECNSHolderStruct * mp_hides; // WHat does this NS hide?
struct XSECNSHolderStruct * mp_next; // Next in list
XERCES_CPP_NAMESPACE_QUALIFIER DOMNode * mp_printed; // Node at which it was printed
bool m_isDefault; // Is this a default NS?
} XSECNSHolder;
typedef struct XSECNSElementStruct {
XERCES_CPP_NAMESPACE_QUALIFIER DOMNode * mp_elt; // Element
struct XSECNSHolderStruct * mp_firstNS; // WHat does this NS hide?
} XSECNSElement;
// --------------------------------------------------------------------------------
// Construct/Destruct
// --------------------------------------------------------------------------------
XSECXMLNSStack::XSECXMLNSStack() {
}
XSECXMLNSStack::~XSECXMLNSStack() {
// Need to iterate through the Stack to
XSECNSElement * t;
XSECNSHolder * u, *v;
while (m_elements.size() > 0) {
t = m_elements.top();
u = t->mp_firstNS;
while (u != NULL) {
v = u->mp_next;
delete u;
u = v;
}
delete t;
m_elements.pop();
}
}
// --------------------------------------------------------------------------------
// Stack Functions
// --------------------------------------------------------------------------------
void XSECXMLNSStack::pushElement(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode * elt) {
XSECNSElement * t;
XSECnew(t, XSECNSElement);
t->mp_elt = elt;
t->mp_firstNS = NULL;
m_elements.push(t);
}
void XSECXMLNSStack::popElement() {
// First - are there any namespaces to remove from the currently visible list?
XSECNSHolder * t, *u;
XSECNSElement * e = m_elements.top();
// Iterate through the current namespaces vector
XSECNSHolderVectorType::iterator it = m_currentNS.begin();
while (it != m_currentNS.end()) {
t = *it;
if (t->mp_owner == e->mp_elt) {
// Need to delete this
m_currentNS.erase(it);
if (t->mp_hides != NULL) {
m_currentNS.push_back(t->mp_hides);
}
// TODO - Fix this, it is naieve and slow
it = m_currentNS.begin();
}
else {
if (t->mp_printed == e->mp_elt)
t->mp_printed = NULL;
it++;
}
}
// OK - Now we delete the NS nodes
t = e->mp_firstNS;
while (t != NULL) {
u = t->mp_next;
delete t;
t = u;
}
// Now delete the element holder itself
m_elements.pop();
delete e;
}
// --------------------------------------------------------------------------------
// NS Addition
// --------------------------------------------------------------------------------
void XSECXMLNSStack::addNamespace(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode * ns) {
// Create the new entry for this node
XSECNSHolder * t, *u;
XSECnew(t, XSECNSHolder);
t->mp_hides = NULL;
t->mp_next = NULL;
t->mp_ns = ns;
t->mp_owner = (m_elements.top())->mp_elt;
t->mp_printed = NULL;
t->m_isDefault = strEquals(ns->getNodeName(), DSIGConstants::s_unicodeStrXmlns);
// Does this hide something in the current namespace list?
XSECNSHolderVectorType::iterator it = m_currentNS.begin();
while (it != m_currentNS.end()) {
u = (*it);
if (strEquals(u->mp_ns->getNodeName(), ns->getNodeName())) {
// This hides a current NS entry
t->mp_hides = u;
m_currentNS.erase(it);
it = m_currentNS.end();
}
else
it++;
}
// Now push it onto the namespace vector
m_currentNS.push_back(t);
// Add me to the current element's namespaces
XSECNSElement * e = m_elements.top();
t->mp_next = e->mp_firstNS;
e->mp_firstNS = t;
}
void XSECXMLNSStack::printNamespace(DOMNode * ns, DOMNode * elt) {
XSECNSHolder * t;
XSECNSHolderVectorType::iterator it = m_currentNS.begin();
while (it != m_currentNS.end()) {
t = (*it);
// Fix for bug#47353, go ahead and track printing of default namespaces.
if (t->mp_ns == ns) { // && t->m_isDefault == false) {
t->mp_printed = elt;
break;
}
it++;
}
}
// --------------------------------------------------------------------------------
// NS Searching
// --------------------------------------------------------------------------------
DOMNode * XSECXMLNSStack::getFirstNamespace(void) {
m_currentNSIterator = m_currentNS.begin();
while (m_currentNSIterator != m_currentNS.end() &&
(*m_currentNSIterator)->mp_printed != NULL)
m_currentNSIterator++;
if (m_currentNSIterator != m_currentNS.end())
return (*m_currentNSIterator)->mp_ns;
return NULL;
}
DOMNode * XSECXMLNSStack::getNextNamespace(void) {
if (m_currentNSIterator == m_currentNS.end())
return NULL;
m_currentNSIterator++;
while (m_currentNSIterator != m_currentNS.end() &&
(*m_currentNSIterator)->mp_printed != NULL)
m_currentNSIterator++;
if (m_currentNSIterator == m_currentNS.end())
return NULL;
return (*m_currentNSIterator)->mp_ns;
}
// Fix for bug#47353, explicit check for non-empty default NS decl.
bool XSECXMLNSStack::isNonEmptyDefaultNS(void) {
for (XSECNSHolderVectorType::iterator it = m_currentNS.begin(); it != m_currentNS.end(); ++it) {
if ((*it)->m_isDefault) {
const XMLCh* val = (*it)->mp_ns->getNodeValue();
if (val && *val)
return true;
}
}
return false;
}