XMLSize_t XSECC14n20010315::processNextNode()

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;

}