diff options
Diffstat (limited to 'gpr/source/lib/xmp_core/XML_Node.cpp')
-rw-r--r-- | gpr/source/lib/xmp_core/XML_Node.cpp | 473 |
1 files changed, 473 insertions, 0 deletions
diff --git a/gpr/source/lib/xmp_core/XML_Node.cpp b/gpr/source/lib/xmp_core/XML_Node.cpp new file mode 100644 index 0000000..c7ac1ce --- /dev/null +++ b/gpr/source/lib/xmp_core/XML_Node.cpp @@ -0,0 +1,473 @@ +// ================================================================================================= +// Copyright 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 "public/include/XMP_Environment.h" // ! Must be the first #include! +#include "XMLParserAdapter.hpp" + +#include <map> +#include <cstring> +#include <cstdio> + +// ! 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::GetLeafContentValue +//============================== + +std::string* XML_Node::GetLeafContentPtr() const +{ + if ( (! this->IsLeafContentNode()) || this->content.empty() ) return 0; + + return &this->content[0]->value; + +} // 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", (int)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 + +// ================================================================================================= |