summaryrefslogtreecommitdiff
path: root/source/common/XML_Node.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/common/XML_Node.cpp')
-rw-r--r--source/common/XML_Node.cpp459
1 files changed, 459 insertions, 0 deletions
diff --git a/source/common/XML_Node.cpp b/source/common/XML_Node.cpp
new file mode 100644
index 0000000..9163fff
--- /dev/null
+++ b/source/common/XML_Node.cpp
@@ -0,0 +1,459 @@
+// =================================================================================================
+// Copyright 2005-2007 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
+// of the Adobe license agreement accompanying it.
+// =================================================================================================
+
+#include "XMP_Environment.h" // ! Must be the first #include!
+#include "XMLParserAdapter.hpp"
+
+#include <map>
+
+// ! Can't include XMP..._Impl.hpp - used by both Core and Files.
+#define XMP_LitNMatch(s,l,n) (std::strncmp((s),(l),(n)) == 0)
+
+#if XMP_WinBuild
+ #define snprintf _snprintf
+ #pragma warning ( disable : 4996 ) // snprintf is safe
+#endif
+
+// =================================================================================================
+
+#if 0 // Pattern for iterating over the children or attributes:
+ for ( size_t xxNum = 0, xxLim = _node_->_offspring_->size(); xxNum < xxLim; ++xxNum ) {
+ const XML_NodePtr _curr_ = _node_->_offspring_[xxNum];
+ }
+#endif
+
+// =================================================================================================
+// XML_Node::IsWhitespaceNode
+//===========================
+
+bool XML_Node::IsWhitespaceNode() const
+{
+ if ( this->kind != kCDataNode ) return false;
+
+ for ( size_t i = 0; i < this->value.size(); ++i ) {
+ unsigned char ch = this->value[i];
+ if ( IsWhitespaceChar ( ch ) ) continue;
+ // *** Add checks for other whitespace characters.
+ return false; // All the checks failed, this isn't whitespace.
+ }
+
+ return true;
+
+} // XML_Node::IsWhitespaceNode
+
+// =================================================================================================
+// XML_Node::IsLeafContentNode
+//============================
+
+bool XML_Node::IsLeafContentNode() const
+{
+ if ( this->kind != kElemNode ) return false;
+ if ( this->content.size() == 0 ) return true;
+ if ( this->content.size() > 1 ) return false;
+ if ( this->content[0]->kind != kCDataNode ) return false;
+
+ return true;
+
+} // XML_Node::IsLeafContentNode
+
+// =================================================================================================
+// XML_Node::IsEmptyLeafNode
+//==========================
+
+bool XML_Node::IsEmptyLeafNode() const
+{
+
+ if ( (this->kind != kElemNode) || (this->content.size() != 0) ) return false;
+ return true;
+
+} // XML_Node::IsEmptyLeafNode
+
+// =================================================================================================
+// XML_Node::GetAttrValue
+//=======================
+
+XMP_StringPtr XML_Node::GetAttrValue ( XMP_StringPtr attrName ) const
+{
+
+ for ( size_t i = 0, aLim = this->attrs.size(); i < aLim; ++i ) {
+ XML_Node * attrPtr = this->attrs[i];
+ if ( ! attrPtr->ns.empty() ) continue; // This form of GetAttrValue is for attrs in no namespace.
+ if ( attrPtr->name == attrName ) return attrPtr->value.c_str();
+ }
+
+ return 0; // Not found.
+
+} // XML_Node::GetAttrValue
+
+// =================================================================================================
+// XML_Node::SetAttrValue
+//=======================
+
+void XML_Node::SetAttrValue ( XMP_StringPtr attrName, XMP_StringPtr attrValue )
+{
+
+ for ( size_t i = 0, aLim = this->attrs.size(); i < aLim; ++i ) {
+ XML_Node * attrPtr = this->attrs[i];
+ if ( ! attrPtr->ns.empty() ) continue; // This form of SetAttrValue is for attrs in no namespace.
+ if ( attrPtr->name == attrName ) {
+ attrPtr->value = attrValue;
+ return;
+ }
+ }
+
+} // XML_Node::SetAttrValue
+
+// =================================================================================================
+// XML_Node::GetLeafContentValue
+//==============================
+
+XMP_StringPtr XML_Node::GetLeafContentValue() const
+{
+ if ( (! this->IsLeafContentNode()) || this->content.empty() ) return "";
+
+ return this->content[0]->value.c_str();
+
+} // XML_Node::GetLeafContentValue
+
+// =================================================================================================
+// XML_Node::SetLeafContentValue
+//==============================
+
+void XML_Node::SetLeafContentValue ( XMP_StringPtr newValue )
+{
+ XML_Node * valueNode;
+
+ if ( ! this->content.empty() ) {
+ valueNode = this->content[0];
+ } else {
+ valueNode = new XML_Node ( this, "", kCDataNode );
+ this->content.push_back ( valueNode );
+ }
+
+ valueNode->value = newValue;
+
+} // XML_Node::SetLeafContentValue
+
+// =================================================================================================
+// XML_Node::CountNamedElements
+//=============================
+
+size_t XML_Node::CountNamedElements ( XMP_StringPtr nsURI, XMP_StringPtr localName ) const
+{
+ size_t count = 0;
+
+ for ( size_t i = 0, vLim = this->content.size(); i < vLim; ++i ) {
+ const XML_Node & child = *this->content[i];
+ if ( child.ns != nsURI ) continue;
+ if ( strcmp ( localName, child.name.c_str()+child.nsPrefixLen ) != 0 ) continue;
+ ++count;
+ }
+
+ return count;
+
+} // XML_Node::CountNamedElements
+
+// =================================================================================================
+// XML_Node::GetNamedElement
+//==========================
+
+XML_NodePtr XML_Node::GetNamedElement ( XMP_StringPtr nsURI, XMP_StringPtr localName, size_t which /* = 0 */ )
+{
+
+ for ( size_t i = 0, vLim = this->content.size(); i < vLim; ++i ) {
+ XML_Node * childPtr = this->content[i];
+ if ( childPtr->ns != nsURI ) continue;
+ if ( strcmp ( localName, childPtr->name.c_str()+childPtr->nsPrefixLen ) != 0 ) continue;
+ if ( which == 0 ) return childPtr;
+ --which;
+ }
+
+ return 0; /// Not found.
+
+} // XML_Node::GetNamedElement
+
+// =================================================================================================
+// DumpNodeList
+// ============
+
+static const char * kNodeKinds[] = { "root", "elem", "attr", "cdata", "pi" };
+
+static void DumpNodeList ( std::string * buffer, const XML_NodeVector & list, int indent )
+{
+
+ for ( size_t i = 0, limit = list.size(); i < limit; ++i ) {
+
+ const XML_Node * node = list[i];
+
+ for ( int t = indent; t > 0; --t ) *buffer += " ";
+ if ( node->IsWhitespaceNode() ) {
+ *buffer += "-- whitespace --\n";
+ continue;
+ }
+
+ *buffer += node->name;
+ *buffer += " - ";
+ *buffer += kNodeKinds[node->kind];
+ if ( ! node->value.empty() ) {
+ *buffer += ", value=\"";
+ *buffer += node->value;
+ *buffer += "\"";
+ }
+ if ( ! node->ns.empty() ) {
+ *buffer += ", ns=\"";
+ *buffer += node->ns;
+ *buffer += "\"";
+ }
+ if ( node->nsPrefixLen != 0 ) {
+ *buffer += ", prefixLen=";
+ char numBuf [20];
+ snprintf ( numBuf, sizeof(numBuf), "%d", node->nsPrefixLen );
+ *buffer += numBuf;
+ }
+ *buffer += "\n";
+
+ if ( ! node->attrs.empty() ) {
+ for ( int t = indent+1; t > 0; --t ) *buffer += " ";
+ *buffer += "attrs:\n";
+ DumpNodeList ( buffer, node->attrs, indent+2 );
+ }
+
+ if ( ! node->content.empty() ) {
+ DumpNodeList ( buffer, node->content, indent+1 );
+ }
+
+ }
+
+} // DumpNodeList
+
+// =================================================================================================
+// XML_Node::Dump
+//===============
+
+void XML_Node::Dump ( std::string * buffer )
+{
+
+ *buffer = "Dump of XML_Node tree\n";
+
+ *buffer += "Root info: name=\"";
+ *buffer += this->name;
+ *buffer += "\", value=\"";
+ *buffer += this->value;
+ *buffer += "\", ns=\"";
+ *buffer += this->ns;
+ *buffer += "\", kind=";
+ *buffer += kNodeKinds[this->kind];
+ *buffer += "\n";
+
+ if ( ! this->attrs.empty() ) {
+ *buffer += " attrs:\n";
+ DumpNodeList ( buffer, this->attrs, 2 );
+ }
+ *buffer += "\n";
+
+ DumpNodeList ( buffer, this->content, 0 );
+
+} // XML_Node::Dump
+
+// =================================================================================================
+// SerializeOneNode
+// ================
+
+static void SerializeOneNode ( std::string * buffer, const XML_Node & node )
+{
+ size_t i, limit;
+ XMP_StringPtr namePtr = node.name.c_str();
+ if ( XMP_LitNMatch ( namePtr, "_dflt_:", 7 ) ) namePtr += 7; // Hack for default namespaces.
+
+ switch ( node.kind ) {
+
+ case kElemNode:
+ *buffer += '<';
+ *buffer += namePtr;
+ for ( i = 0, limit = node.attrs.size(); i < limit; ++i ) {
+ SerializeOneNode ( buffer, *node.attrs[i] );
+ }
+ if ( node.content.empty() ) {
+ *buffer += "/>";
+ } else {
+ *buffer += '>';
+ for ( i = 0, limit = node.content.size(); i < limit; ++i ) {
+ SerializeOneNode ( buffer, *node.content[i] );
+ }
+ *buffer += "</";
+ *buffer += namePtr;
+ *buffer += '>';
+ }
+ break;
+
+ case kAttrNode:
+ *buffer += ' ';
+ *buffer += namePtr;
+ *buffer += "=\"";
+ *buffer += node.value;
+ *buffer += '"';
+ break;
+
+ case kCDataNode:
+ *buffer += node.value;
+ break;
+
+ case kPINode:
+ *buffer += node.value; // *** Note that we're dropping PIs during the Expat parse.
+ break;
+
+ }
+
+} // SerializeOneNode
+
+// =================================================================================================
+// CollectNamespaceDecls
+// =====================
+
+typedef std::map < std::string, std::string > NamespaceMap;
+
+static void CollectNamespaceDecls ( NamespaceMap * nsMap, const XML_Node & node )
+{
+ size_t i, limit;
+
+ if ( ! node.ns.empty() ) {
+ size_t nameMid = 0;
+ while ( node.name[nameMid] != ':' ) ++nameMid;
+ std::string prefix = node.name.substr ( 0, nameMid );
+ (*nsMap)[prefix] = node.ns;
+ }
+
+ if ( node.kind == kElemNode ) {
+
+ for ( i = 0, limit = node.attrs.size(); i < limit; ++i ) {
+ CollectNamespaceDecls ( nsMap, *node.attrs[i] );
+ }
+
+ for ( i = 0, limit = node.content.size(); i < limit; ++i ) {
+ const XML_Node & content = *node.content[i];
+ if ( content.kind == kElemNode ) CollectNamespaceDecls ( nsMap, content );
+ }
+
+ }
+
+} // CollectNamespaceDecls
+
+// =================================================================================================
+// XML_Node::Serialize
+//====================
+
+void XML_Node::Serialize ( std::string * buffer )
+{
+ buffer->erase();
+
+ if ( this->kind != kRootNode ) {
+
+ SerializeOneNode ( buffer, *this );
+
+ } else {
+
+ // Do the outermost level here, in order to add the XML version and namespace declarations.
+
+ *buffer += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+
+ for ( size_t outer = 0, oLimit = this->content.size(); outer < oLimit; ++outer ) {
+
+ const XML_Node & node = *this->content[outer];
+
+ if ( node.kind != kElemNode ) {
+
+ SerializeOneNode ( buffer, node );
+
+ } else {
+
+ XMP_StringPtr namePtr = node.name.c_str();
+ if ( XMP_LitNMatch ( namePtr, "_dflt_:", 7 ) ) namePtr += 7; // Hack for default namespaces.
+
+ *buffer += '<';
+ *buffer += namePtr;
+
+ NamespaceMap nsMap;
+ CollectNamespaceDecls ( &nsMap, node );
+ NamespaceMap::iterator nsDecl = nsMap.begin();
+ NamespaceMap::iterator nsEnd = nsMap.end();
+ for ( ; nsDecl != nsEnd; ++nsDecl ) {
+ const std::string & prefix = nsDecl->first;
+ *buffer += " xmlns";
+ if ( prefix != "_dflt_" ) { *buffer += ':'; *buffer += prefix; }
+ *buffer += "=\"";
+ *buffer += nsDecl->second;
+ *buffer += '"';
+ }
+
+ for ( size_t attr = 0, aLimit = node.attrs.size(); attr < aLimit; ++attr ) {
+ SerializeOneNode ( buffer, *node.attrs[attr] );
+ }
+
+ if ( node.content.empty() ) {
+ *buffer += "/>";
+ } else {
+ *buffer += '>';
+ for ( size_t child = 0, cLimit = node.content.size(); child < cLimit; ++child ) {
+ SerializeOneNode ( buffer, *node.content[child] );
+ }
+ *buffer += "</";
+ *buffer += namePtr;
+ *buffer += '>';
+ }
+
+ }
+
+ }
+
+ }
+
+
+} // XML_Node::Serialize
+
+// =================================================================================================
+// XML_Node::RemoveAttrs
+//======================
+
+void XML_Node::RemoveAttrs()
+{
+
+ for ( size_t i = 0, vLim = this->attrs.size(); i < vLim; ++i ) delete this->attrs[i];
+ this->attrs.clear();
+
+} // XML_Node::RemoveAttrs
+
+// =================================================================================================
+// XML_Node::RemoveContent
+//========================
+
+void XML_Node::RemoveContent()
+{
+
+ for ( size_t i = 0, vLim = this->content.size(); i < vLim; ++i ) delete this->content[i];
+ this->content.clear();
+
+} // XML_Node::RemoveContent
+
+// =================================================================================================
+// XML_Node::ClearNode
+//====================
+
+void XML_Node::ClearNode()
+{
+
+ this->kind = 0;
+ this->ns.erase();
+ this->name.erase();
+ this->value.erase();
+
+ this->RemoveAttrs();
+ this->RemoveContent();
+
+} // XML_Node::ClearNode
+
+// =================================================================================================