static void StartOuterRDFDescription ( const XMP_Node & xmpTree, XMP_VarString & outputStr, XMP_StringPtr newline, XMP_StringPtr indentStr, XMP_Index baseIndent ) { // Begin the outer rdf:Description start tag. for ( XMP_Index level = baseIndent+2; level > 0; --level ) outputStr += indentStr; outputStr += kRDF_SchemaStart; outputStr += '"'; outputStr += xmpTree.name; outputStr += '"'; // Write all necessary xmlns attributes. XMP_VarString usedNS; usedNS.reserve ( 400 ); // The predefined prefixes add up to about 320 bytes. usedNS = ":xml:rdf:"; for ( size_t schema = 0, schemaLim = xmpTree.children.size(); schema != schemaLim; ++schema ) { const XMP_Node * currSchema = xmpTree.children[schema]; DeclareUsedNamespaces ( currSchema, usedNS, outputStr, newline, indentStr, baseIndent+4 ); } } // StartOuterRDFDescription
static void SerializePrettyRDFSchema ( const XMP_VarString & treeName, const XMP_Node * schemaNode, XMP_VarString & outputStr, XMP_OptionBits options, XMP_StringPtr newline, XMP_StringPtr indentStr, XMP_Index baseIndent ) { XMP_Assert ( schemaNode->options & kXMP_SchemaNode ); XMP_Assert ( schemaNode->qualifiers.empty() ); // Write the rdf:Description start tag with the namespace declarations. XMP_Index level; for ( level = baseIndent+2; level > 0; --level ) outputStr += indentStr; outputStr += kRDF_SchemaStart; outputStr += '"'; outputStr += treeName; outputStr += '"'; size_t totalLen = 8; // Start at 8 for "xml:rdf:". XMP_cStringMapPos currPos = sNamespacePrefixToURIMap->begin(); XMP_cStringMapPos endPos = sNamespacePrefixToURIMap->end(); for ( ; currPos != endPos; ++currPos ) totalLen += currPos->first.size(); XMP_VarString usedNS; usedNS.reserve ( totalLen ); usedNS = "xml:rdf:"; DeclareUsedNamespaces ( schemaNode, usedNS, outputStr, newline, indentStr, baseIndent+4 ); outputStr += ">"; outputStr += newline; // Write alias comments, if wanted. if ( options & kXMP_WriteAliasComments ) { // *** Hoist into a routine, used for Plain XMP also. #if 0 // *** Buggy, disable for now. XMP_cAliasMapPos aliasPos = sRegisteredAliasMap->begin(); XMP_cAliasMapPos aliasEnd = sRegisteredAliasMap->end(); for ( ; aliasPos != aliasEnd; ++aliasPos ) { size_t nsPos = aliasPos->first.find ( schemaNode->value ); if ( nsPos == XMP_VarString::npos ) continue; XMP_Assert ( nsPos == 0 ); for ( level = baseIndent+3; level > 0; --level ) outputStr += indentStr; outputStr += "<!-- "; outputStr += aliasPos->first; outputStr += " is aliased to "; for ( size_t step = 1, stepLim = aliasPos->second.size(); step != stepLim; ++step ) { outputStr += aliasPos->second[step].step; } outputStr += " -->"; outputStr += newline; } #endif } // Write each of the schema's actual properties. for ( size_t propNum = 0, propLim = schemaNode->children.size(); propNum < propLim; ++propNum ) { const XMP_Node * currProp = schemaNode->children[propNum]; SerializePrettyRDFProperty ( currProp, outputStr, newline, indentStr, baseIndent+3 ); } // Write the rdf:Description end tag. for ( level = baseIndent+2; level > 0; --level ) outputStr += indentStr; outputStr += kRDF_SchemaEnd; outputStr += newline; } // SerializePrettyRDFSchema
static void SerializeCompactRDFSchemas ( const XMP_Node & xmpTree, XMP_VarString & outputStr, XMP_StringPtr newline, XMP_StringPtr indentStr, XMP_Index baseIndent ) { XMP_Index level; size_t schema, schemaLim; // Begin the rdf:Description start tag. for ( level = baseIndent+2; level > 0; --level ) outputStr += indentStr; outputStr += kRDF_SchemaStart; outputStr += '"'; outputStr += xmpTree.name; outputStr += '"'; // Write all necessary xmlns attributes. size_t totalLen = 8; // Start at 8 for "xml:rdf:". XMP_cStringMapPos currPos = sNamespacePrefixToURIMap->begin(); XMP_cStringMapPos endPos = sNamespacePrefixToURIMap->end(); for ( ; currPos != endPos; ++currPos ) totalLen += currPos->first.size(); XMP_VarString usedNS; usedNS.reserve ( totalLen ); usedNS = "xml:rdf:"; for ( schema = 0, schemaLim = xmpTree.children.size(); schema != schemaLim; ++schema ) { const XMP_Node * currSchema = xmpTree.children[schema]; DeclareUsedNamespaces ( currSchema, usedNS, outputStr, newline, indentStr, baseIndent+4 ); } // Write the top level "attrProps" and close the rdf:Description start tag. bool allAreAttrs = true; for ( schema = 0, schemaLim = xmpTree.children.size(); schema != schemaLim; ++schema ) { const XMP_Node * currSchema = xmpTree.children[schema]; allAreAttrs &= SerializeCompactRDFAttrProps ( currSchema, outputStr, newline, indentStr, baseIndent+3 ); } if ( ! allAreAttrs ) { outputStr += ">"; outputStr += newline; } else { outputStr += "/>"; outputStr += newline; return; // ! Done if all properties in all schema are written as attributes. } // Write the remaining properties for each schema. for ( schema = 0, schemaLim = xmpTree.children.size(); schema != schemaLim; ++schema ) { const XMP_Node * currSchema = xmpTree.children[schema]; SerializeCompactRDFElemProps ( currSchema, outputStr, newline, indentStr, baseIndent+3 ); } // Write the rdf:Description end tag. // *** Elide the end tag if everything (all props in all schema) is an attr. for ( level = baseIndent+2; level > 0; --level ) outputStr += indentStr; outputStr += kRDF_SchemaEnd; outputStr += newline; } // SerializeCompactRDFSchemas
static void SerializeAsRDF ( const XMPMeta & xmpObj, XMP_VarString & headStr, // Everything up to the padding. XMP_VarString & tailStr, // Everything after the padding. XMP_OptionBits options, XMP_StringPtr newline, XMP_StringPtr indentStr, XMP_Index baseIndent ) { const size_t treeNameLen = xmpObj.tree.name.size(); const size_t indentLen = strlen ( indentStr ); // First estimate the worst case space and reserve room in the output string. This optimization // avoids reallocating and copying the output as it grows. The initial count does not look at // the values of properties, so it does not account for character entities, e.g. 
 for newline. // Since there can be a lot of these in things like the base 64 encoding of a large thumbnail, // inflate the count by 1/4 (easy to do) to accommodate. // *** Need to include estimate for alias comments. size_t outputLen = 2 * (strlen(kPacketHeader) + strlen(kRDF_XMPMetaStart) + strlen(kRDF_RDFStart) + 3*baseIndent*indentLen); for ( size_t schemaNum = 0, schemaLim = xmpObj.tree.children.size(); schemaNum < schemaLim; ++schemaNum ) { const XMP_Node * currSchema = xmpObj.tree.children[schemaNum]; outputLen += 2*(baseIndent+2)*indentLen + strlen(kRDF_SchemaStart) + treeNameLen + strlen(kRDF_SchemaEnd) + 2; outputLen += EstimateRDFSize ( currSchema, baseIndent+2, indentLen ); } outputLen += (outputLen >> 2); // Inflate by 1/4, an empirical fudge factor. // Now generate the RDF into the head string as UTF-8. XMP_Index level; headStr.erase(); headStr.reserve ( outputLen ); // Write the packet header PI. if ( ! (options & kXMP_OmitPacketWrapper) ) { for ( level = baseIndent; level > 0; --level ) headStr += indentStr; headStr += kPacketHeader; headStr += newline; } // Write the xmpmeta element's start tag. if ( ! (options & kXMP_OmitXMPMetaElement) ) { for ( level = baseIndent; level > 0; --level ) headStr += indentStr; headStr += kRDF_XMPMetaStart; headStr += kXMPCore_VersionMessage "\">"; headStr += newline; } // Write the rdf:RDF start tag. for ( level = baseIndent+1; level > 0; --level ) headStr += indentStr; headStr += kRDF_RDFStart; headStr += newline; // Write all of the properties. if ( options & kXMP_UseCompactFormat ) { SerializeCompactRDFSchemas ( xmpObj.tree, headStr, newline, indentStr, baseIndent ); } else { if ( xmpObj.tree.children.size() > 0 ) { for ( size_t schemaNum = 0, schemaLim = xmpObj.tree.children.size(); schemaNum < schemaLim; ++schemaNum ) { const XMP_Node * currSchema = xmpObj.tree.children[schemaNum]; SerializePrettyRDFSchema ( xmpObj.tree.name, currSchema, headStr, options, newline, indentStr, baseIndent ); } } else { for ( XMP_Index level = baseIndent+2; level > 0; --level ) headStr += indentStr; headStr += kRDF_SchemaStart; // Special case an empty XMP object. headStr += '"'; headStr += xmpObj.tree.name; headStr += "\"/>"; headStr += newline; } } // Write the rdf:RDF end tag. for ( level = baseIndent+1; level > 0; --level ) headStr += indentStr; headStr += kRDF_RDFEnd; headStr += newline; // Write the xmpmeta end tag. if ( ! (options & kXMP_OmitXMPMetaElement) ) { for ( level = baseIndent; level > 0; --level ) headStr += indentStr; headStr += kRDF_XMPMetaEnd; headStr += newline; } // Write the packet trailer PI into the tail string as UTF-8. tailStr.erase(); if ( ! (options & kXMP_OmitPacketWrapper) ) { tailStr.reserve ( strlen(kPacketTrailer) + (strlen(indentStr) * baseIndent) ); for ( level = baseIndent; level > 0; --level ) tailStr += indentStr; tailStr += kPacketTrailer; if ( options & kXMP_ReadOnlyPacket ) tailStr[tailStr.size()-4] = 'r'; } // ! This assert is just a performance check, to see if the reserve was enough. // *** XMP_Assert ( headStr.size() <= outputLen ); // *** Don't use an assert. Think of some way to track this without risk of aborting the client. } // SerializeAsRDF