// ================================================================================================= // 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 #include #include // ! 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 += "'; } 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 += "\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 += "'; } } } } } // 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 // =================================================================================================