in xsec/canon/XSECC14n20010315.cpp [924:1621]
XMLSize_t XSECC14n20010315::processNextNode() {
	// The information currently in the buffer has all been used.  We now process the
	// next node.
	DOMNode *next;				// For working (had *ns)
	DOMNamedNodeMap *tmpAtts;	//  "     "
	safeBuffer currentName(128), currentValue(1024), sbWork;
	bool done, xmlnsFound;
	if (m_allNodesDone) {
		return 0;					// No bytes copied because nothing more to be done
	}
	// Always zeroise buffers to make work simpler
	m_bufferLength = m_bufferPoint = 0;
	m_buffer.sbStrcpyIn("");
	// Find out if this is a node to process
	bool processNode;
	int nodeT;
	if (mp_nextNode == 0) {
		// Dummy element - we need to insert a default namespace
		nodeT = DOMNode::ATTRIBUTE_NODE;
		processNode = true;
	}
	else {
		processNode = ((!m_XPathSelection) || (m_XPathMap.hasNode(mp_nextNode)));
		nodeT = mp_nextNode->getNodeType();
	}
	switch (nodeT) {
	case DOMNode::DOCUMENT_NODE : // Start of a document
		// Check if finished
		if (m_returnedFromChild) {
			// All done!
			m_allNodesDone = true;
			return 0;
		}
		// In c14n we don't actually do anything for a document node except
		// process the childeren
		mp_firstElementNode = ((DOMDocument *) mp_nextNode)->getDocumentElement();
		next = mp_nextNode->getFirstChild();
		if (next == NULL) {
			// Empty document?
			m_allNodesDone = true;
		}
		mp_nextNode = next;
		m_bufferLength = m_bufferPoint = 0;		// To ensure nobody copies "nothing"
		return 0;
	case DOMNode::DOCUMENT_TYPE_NODE : // Ignore me
		m_returnedFromChild = true;
		m_buffer.sbStrcpyIn("");
		break;
	case DOMNode::PROCESSING_INSTRUCTION_NODE : // Just print
		if (processNode) {
			if ((mp_nextNode->getParentNode() == mp_doc) && m_firstElementProcessed) {
				// this is a top level node and first element done
				m_buffer.sbStrcpyIn("\x00A<?");
			}
			else
				m_buffer.sbStrcpyIn("<?");
			m_formatBuffer << (*mp_formatter << mp_nextNode->getNodeName());
			m_buffer.sbStrcatIn(m_formatBuffer);
			m_formatBuffer << (*mp_formatter << ((DOMProcessingInstruction *) mp_nextNode)->getData());
			if (m_formatBuffer.sbStrlen() > 0) {
				m_buffer.sbStrcatIn(" ");
				m_buffer.sbStrcatIn(m_formatBuffer);
			}
			m_buffer.sbStrcatIn("?>");
			if ((mp_nextNode->getParentNode() == mp_doc) && !m_firstElementProcessed) {
				// this is a top level node and first element done
				m_buffer.sbStrcatIn("\x00A");
			}
		}
		// Node fully processed
		m_returnedFromChild = true;
		break;
	case DOMNode::COMMENT_NODE : // Just print out
		if (processNode && m_processComments) {
			if ((mp_nextNode->getParentNode() == mp_doc) && m_firstElementProcessed) {
				// this is a top level node and first element done
				m_buffer.sbStrcpyIn("\x00A<!--");
			}
			else
				m_buffer.sbStrcpyIn("<!--");
			m_formatBuffer << (*mp_formatter << mp_nextNode->getNodeValue());
			if (m_formatBuffer.sbStrlen() > 0) {
				m_buffer.sbStrcatIn(m_formatBuffer);
			}
			m_buffer.sbStrcatIn("-->");
			if ((mp_nextNode->getParentNode() == mp_doc) && !m_firstElementProcessed) {
				// this is a top level node and first element done
				m_buffer.sbStrcatIn("\x00A");
			}
		}
		m_returnedFromChild = true;	// Fool the tree processor
		break;
	case DOMNode::CDATA_SECTION_NODE :
	case DOMNode::TEXT_NODE : // Straight copy for now
		if (processNode) {
			m_formatBuffer << (*mp_formatter << mp_nextNode->getNodeValue());
			// Do c14n cleaning on the text string
			m_buffer = c14nCleanText(m_formatBuffer);
		}
		// Fall through
		m_returnedFromChild = true;		// Fool the tree processor
		break;
	case DOMNode::ELEMENT_NODE : // This is an element that we can easily process
		// If we are going "up" then we simply close off the element
		if (m_returnedFromChild) {
			if (processNode) {
				m_buffer.sbStrcpyIn ("</");
				m_formatBuffer << (*mp_formatter << mp_nextNode->getNodeName());
				m_buffer.sbStrcatIn(m_formatBuffer);
				m_buffer.sbStrcatIn(">");
			}
			if (m_useNamespaceStack)
				m_nsStack.popElement();
			break;
		}
		if (processNode) {
			m_buffer.sbStrcpyIn("<");
			m_formatBuffer << (*mp_formatter << mp_nextNode->getNodeName());
			m_buffer.sbStrcatIn(m_formatBuffer);
		}
		// We now set up for attributes and name spaces
		if (m_useNamespaceStack)
			m_nsStack.pushElement(mp_nextNode);
		mp_attributes = NULL;
		tmpAtts = mp_nextNode->getAttributes();
		next = mp_nextNode;
		done = false;
		xmlnsFound = false;
		while (!done) {
			// Need to sort the attributes
			XMLSize_t size;
			if (tmpAtts != NULL)
				size = tmpAtts->getLength();
			else
				size = 0;
			XSECNodeListElt *toIns;
			XMLSize_t i;
			for (i = 0; i < size; ++i) {
				// Get the name and value of the attribute
				currentName << (*mp_formatter << tmpAtts->item(i)->getNodeName());
				currentValue << (*mp_formatter << tmpAtts->item(i)->getNodeValue());
				// Build the string used to sort this node
				if ((next == mp_nextNode) && currentName.sbStrncmp("xmlns", 5) == 0) {
					// Are we using the namespace stack?  If so - store this for later
					// processing
					if (m_useNamespaceStack) {
						m_nsStack.addNamespace(tmpAtts->item(i));
					}
					else {
						// Is this the default?
						if (currentName.sbStrcmp("xmlns") == 0 &&
							(!m_XPathSelection || m_XPathMap.hasNode(tmpAtts->item(i))) &&
							!currentValue.sbStrcmp("") == 0)
							xmlnsFound = true;
						// A namespace node - See if we need to output
						if (checkRenderNameSpaceNode(mp_nextNode, tmpAtts->item(i))) {
							// Add to the list
							m_formatBuffer << (*mp_formatter << tmpAtts->item(i)->getNodeName());
							if (m_formatBuffer[5] == ':')
								currentName.sbStrcpyIn((char *) &m_formatBuffer[6]);
							else
								currentName.sbStrcpyIn("");
							toIns = new XSECNodeListElt;
							toIns->element = tmpAtts->item(i);
							// Build and insert name space node
							toIns->sortString.sbStrcpyIn(XMLNS_PREFIX);
							toIns->sortString.sbStrcatIn(currentName);
							// Insert node
							mp_attributes = insertNodeIntoList(mp_attributes, toIns);
						}
					}
				}
				else {
					// A "normal" attribute - only process if selected or no XPath or is an
					// XML node from a previously un-printed Element node
					bool XMLElement = (next != mp_nextNode) && (!m_exclusive) && !currentName.sbStrncmp("xml:", 4) &&
                        (!m_incl11 || currentName.sbStrcmp("xml:id"));
					// If we have an XML element, make sure it was not printed between this
					// node and the node currently  being worked on
					if (XMLElement) {
						DOMNode *t = mp_nextNode->getParentNode();
						if (m_XPathSelection && m_XPathMap.hasNode(t))
							XMLElement = false;
						else {
							// This is a real node that we have to check
							t = mp_nextNode;
							while (t != next) {
								DOMNamedNodeMap *ta;
								XMLSize_t sz;
								ta = t->getAttributes();
								if (ta != NULL)
									sz = ta->getLength();
								else
									sz = 0;
								for (XMLSize_t j = 0; j < sz; ++j) {
									if (strEquals(ta->item(j)->getNodeName(),
										tmpAtts->item(i)->getNodeName()) == true) {
										XMLElement = false;
										break;
									}
								}
								t = t->getParentNode();
							}
						}
					}
					if ((!m_XPathSelection && next == mp_nextNode) || XMLElement || ((next == mp_nextNode) && m_XPathMap.hasNode(tmpAtts->item(i)))) {
						toIns = new XSECNodeListElt;
						toIns->element = tmpAtts->item(i);
						// First the correct prefix to ensure will be sorted
						// in correct placing against XMLNS nodes
						toIns->sortString.sbStrcpyIn(ATTRIBUTE_PREFIX);
						// Find the namespace URI
						const XMLCh * nsURI =
							tmpAtts->item(i)->getNamespaceURI();
						if (nsURI == NULL) {
							toIns->sortString.sbStrcatIn(NOURI_PREFIX);
						}
						else {
							m_formatBuffer << (*mp_formatter << nsURI);
							toIns->sortString.sbStrcatIn(HAVEURI_PREFIX);
							toIns->sortString.sbStrcatIn(m_formatBuffer);
						}
						// Append the local name as the secondary key
						const XMLCh * ln = tmpAtts->item(i)->getNodeName();
						int index = XMLString::indexOf(ln, chColon);
						if (index >= 0)
							ln = &ln[index+1];
						m_formatBuffer << (*mp_formatter << ln);
						toIns->sortString.sbStrcatIn(m_formatBuffer);
						// Insert node
						mp_attributes = insertNodeIntoList(mp_attributes, toIns);
					} /* else (sbStrCmp xmlns) */
				}
			} /* for */
#if 1
			// Now go upwards and find parent for xml name spaces
			if (processNode && (m_XPathSelection || mp_nextNode == mp_firstElementNode)) {
				next = next->getParentNode();
				if (next == 0) // || NodeInList(mp_XPathMap, next))
					done = true;
				else
					tmpAtts = next->getAttributes();
			}
			else
#endif
				done = true;
		} /* while tmpAtts != NULL */
		// Now add namespace nodes - but only if we are using the namespace stack
		// (They have already been added otherwise
		if (m_useNamespaceStack) {
			DOMNode * nsnode = m_nsStack.getFirstNamespace();
			while (nsnode != NULL) {
				// Get the name and value of the attribute
				currentName << (*mp_formatter << nsnode->getNodeName());
				currentValue << (*mp_formatter << nsnode->getNodeValue());
				// Is this the default?
				if (currentName.sbStrcmp("xmlns") == 0 &&
					(!m_XPathSelection || m_XPathMap.hasNode(nsnode)) &&
					!currentValue.sbStrcmp("") == 0)
					xmlnsFound = true;
				// A namespace node - See if we need to output
				if (checkRenderNameSpaceNode(mp_nextNode, nsnode)) {
					// Add to the list
					XSECNodeListElt *toIns;
					m_formatBuffer << (*mp_formatter << nsnode->getNodeName());
					if (m_formatBuffer[5] == ':')
						currentName.sbStrcpyIn((char *) &m_formatBuffer[6]);
					else
						currentName.sbStrcpyIn("");
					toIns = new XSECNodeListElt;
					toIns->element = nsnode;
					// Build and insert name space node
					toIns->sortString.sbStrcpyIn(XMLNS_PREFIX);
					toIns->sortString.sbStrcatIn(currentName);
					// Insert node
					mp_attributes = insertNodeIntoList(mp_attributes, toIns);
					// Mark as printed in the NS Stack
					m_nsStack.printNamespace(nsnode, mp_nextNode);
				}
				nsnode = m_nsStack.getNextNamespace();
			}
			// Fix for bug#47353, make sure we set xmlnsFound regardless of what the printing process saw.
	        if (!xmlnsFound)
	            xmlnsFound = m_nsStack.isNonEmptyDefaultNS();
		} /* if (m_useNamespaceStack) */
		// Check to see if we add xmlns=""
		if (processNode && !xmlnsFound && mp_nextNode != mp_firstElementNode) {
			// Is this exclusive?
			safeBuffer sbLocalName("");
			if (m_exclusiveDefault) {
				if (visiblyUtilises(mp_nextNode, sbLocalName)) {
					// May have to output!
					next = mp_nextNode->getParentNode();
					while (next != NULL) {
						if (!m_XPathSelection || m_useNamespaceStack || m_XPathMap.hasNode(next)) {
							DOMNode *tmpAtt;
							// An output ancestor
							if (visiblyUtilises(next, sbLocalName)) {
								DOMNode * nextAttParent = next;
								while (nextAttParent != NULL) {
									// Have a hit!
									tmpAtts = nextAttParent->getAttributes();
									if (tmpAtts != NULL)
										tmpAtt = tmpAtts->getNamedItem(DSIGConstants::s_unicodeStrXmlns);
									if (tmpAtts != NULL && tmpAtt != NULL && (!m_XPathSelection || m_useNamespaceStack || m_XPathMap.hasNode(tmpAtt))) {
										// Check URI is the same
										if (!strEquals(tmpAtt->getNodeValue(), "")) {
											xmlnsFound = true;
											nextAttParent = NULL;
										}
									}
									else {
										// Doesn't have a default namespace in the node-set
										next = nextAttParent = NULL;
										break;
									}
									if (m_useNamespaceStack && nextAttParent)
										nextAttParent = nextAttParent->getParentNode();
									else
										nextAttParent = NULL;
								}
							}
						}
						if (next)
							next = next->getParentNode();
					}
				}
			} /* m_exclusiveDefault */
			else {
				//DOM_Node next;
				next = mp_nextNode->getParentNode();
				while (!xmlnsFound && next != NULL) {
					while (next != NULL && !m_useNamespaceStack && (m_XPathSelection && !m_XPathMap.hasNode(next)))
						next = next->getParentNode();
					XMLSize_t size;
					if (next != NULL)
						tmpAtts = next->getAttributes();
					if (next != NULL && tmpAtts != NULL)
						size = tmpAtts->getLength();
					else
						size = 0;
					for (XMLSize_t i = 0; i < size; ++i) {
						currentName << (*mp_formatter << tmpAtts->item(i)->getNodeName());
						currentValue << (*mp_formatter << tmpAtts->item(i)->getNodeValue());
						if ((currentName.sbStrcmp("xmlns") == 0) &&
							(m_useNamespaceStack || !m_XPathSelection || m_XPathMap.hasNode(tmpAtts->item(i)))) {
							if (currentValue.sbStrcmp("") != 0) {
								xmlnsFound = true;
							}
							else {
								xmlnsFound = false;
								next = NULL;
							}
						}
					}
					if (m_useNamespaceStack && next != NULL)
						next = next->getParentNode();
					else
						next = NULL;
				}
			}
			// Did we find a non empty namespace?
			if (xmlnsFound) {
				currentName.sbStrcpyIn("");		// Don't include xmlns prefix
				XSECNodeListElt * toIns;
				toIns = new XSECNodeListElt;
				toIns->element = NULL;		// To trigger the state engine
				// Build and insert name space node
				toIns->sortString.sbStrcpyIn(XMLNS_PREFIX);
				toIns->sortString.sbStrcatIn(currentName);
				// Insert node
				mp_attributes = insertNodeIntoList(mp_attributes, toIns);
			}
		}
		if (mp_attributes != NULL) {
			// Now we have set up the attribute list, set next node and return!
			mp_attributeParent = mp_nextNode;
			mp_nextNode = mp_attributes->element;
			mp_currentAttribute = mp_attributes;
			m_bufferLength = m_buffer.sbStrlen();
			m_bufferPoint = 0;
			return m_bufferLength;
		} /* attrributes != NULL */
		if (processNode)
			m_buffer.sbStrcatIn(">");
		// Fall through to find next node
		break;
	case DOMNode::ATTRIBUTE_NODE : // Output attr_name="value"
		// Always process an attribute node as we have already checked they should
		// be printed
		m_buffer.sbStrcpyIn(" ");
		if (mp_nextNode != 0) {
			m_formatBuffer << (*mp_formatter << mp_nextNode->getNodeName());
			m_buffer.sbStrcatIn(m_formatBuffer);
			m_buffer.sbStrcatIn("=\"");
			m_formatBuffer << (*mp_formatter << mp_nextNode->getNodeValue());
			sbWork = c14nCleanAttribute(m_formatBuffer);
			m_buffer.sbStrcatIn(sbWork);
			m_buffer.sbStrcatIn("\"");
		}
		else {
			m_buffer.sbStrcatIn("xmlns");
			m_buffer.sbStrcatIn("=\"");
			m_buffer.sbStrcatIn("\"");
		}
		// Now see if next node is an attribute
		mp_currentAttribute = mp_currentAttribute->next;
		if (mp_currentAttribute != NULL) {
			// Easy case
			mp_nextNode = mp_currentAttribute->element;
			m_bufferLength = m_buffer.sbStrlen();
			m_bufferPoint = 0;
			return m_bufferLength;
		} /* if mp_currentAttributes != NULL) */
		// need to clear out the node list
		while (mp_attributes != NULL) {
			mp_currentAttribute = mp_attributes->next;
			delete mp_attributes;
			mp_attributes = mp_currentAttribute;
		}
		mp_attributes = mp_currentAttribute = mp_firstNonNsAttribute = NULL;
		// return us to the element node
		mp_nextNode = mp_attributeParent;
		// End the element definition
		if (!m_XPathSelection || (m_XPathMap.hasNode(mp_nextNode)))
			m_buffer.sbStrcatIn(">");
		m_returnedFromChild = false;
		break;
	default:
		break;
	}
	// A node has fallen through to the default case for finding the next node.
	m_bufferLength = m_buffer.sbStrlen();;
	m_bufferPoint = 0;
	// Firstly, was the last piece of processing because we "came up" from a child node?
	if (m_returnedFromChild) {
		if (mp_nextNode == mp_startNode) {
			// we have closed off the document!
			m_allNodesDone = true;
			return m_bufferLength;
		}
		if (mp_nextNode == mp_firstElementNode) {
			// we have closed off the main mp_doc elt
			m_firstElementProcessed = true;
		}
	}
	else {
		// Going down - so check for children nodes
		next = mp_nextNode->getFirstChild();
		if (next != NULL)
			mp_nextNode = next;
		else
			// No children, so need to close this node off!
			m_returnedFromChild = true;
		return m_bufferLength;
	}
	// If we get here all childeren (if there are any) are done
	next = mp_nextNode->getNextSibling();
	if (next != NULL) {
		m_returnedFromChild = false;
		mp_nextNode = next;
		return m_bufferLength;
	}
	// No more nodes at this level either!
	mp_nextNode = mp_nextNode->getParentNode();
	m_returnedFromChild = true;
	return m_bufferLength;
}