示例#1
0
static const XMP_Node *
GetNextXMPNode ( IterInfo & info )
{
	const XMP_Node * xmpNode = 0;

	// ----------------------------------------------------------------------------------------------
	// On entry currPos points to an iteration node whose state is either before-visit or visit-self.
	// If it is before-visit then we will return that node's value part now. If it is visit-self it
	// means the previous iteration returned the value portion of that node, so we can advance to the
	// next node in the iteration tree. Then we find the corresponding XMP node, allowing for the XMP
	// tree to have been modified since that part of the iteration tree was constructed.
	
	// ! NOTE: Supporting aliases throws in some nastiness with schemas. There might not be any XMP
	// ! node for the schema, but we still have to visit it because of possible aliases. The static
	// ! sDummySchema is returned if there is no real schema node.

	if ( info.currPos->visitStage != kIter_BeforeVisit ) AdvanceIterPos ( info );
	
	bool isSchemaNode = false;
	XMP_ExpandedXPath expPath;	// Keep outside the loop to avoid constant construct/destruct.
	
	while ( info.currPos != info.endPos ) {

		isSchemaNode = XMP_NodeIsSchema ( info.currPos->options );
		if ( isSchemaNode ) {
			SetCurrSchema ( info, info.currPos->fullPath );
			xmpNode = FindConstSchema ( &info.xmpObj->tree, info.currPos->fullPath.c_str() );
			if ( xmpNode == 0 ) xmpNode = sDummySchema;
		} else {
			ExpandXPath ( info.currSchema.c_str(), info.currPos->fullPath.c_str(), &expPath );
			xmpNode = FindConstNode ( &info.xmpObj->tree, expPath );
		}
		if ( xmpNode != 0 ) break;	// Exit the loop, we found a live XMP node.

		info.currPos->visitStage = kIter_VisitChildren;	// Make AdvanceIterPos move to the next sibling.
		info.currPos->children.clear();
		info.currPos->qualifiers.clear();
		AdvanceIterPos ( info );

	}

	if ( info.currPos == info.endPos ) return 0;
	
	// -------------------------------------------------------------------------------------------
	// Now we've got the iteration node and corresponding XMP node. Add the iteration children for
	// structs and arrays. The children of schema were added when the iterator was constructed.

	XMP_Assert ( info.currPos->visitStage == kIter_BeforeVisit );

	if ( info.currPos->visitStage == kIter_BeforeVisit ) {
		if ( (! isSchemaNode) && (! (info.options & kXMP_IterJustChildren)) ) {
			AddNodeOffspring ( info, *info.currPos, xmpNode );
		}
		info.currPos->visitStage = kIter_VisitSelf;
	}
	
	return xmpNode;

}	// GetNextXMPNode
示例#2
0
XMPIterator::XMPIterator ( const XMPMeta & xmpObj,
						   XMP_StringPtr   schemaNS,
						   XMP_StringPtr   propName,
						   XMP_OptionBits  options ) : clientRefs(0), info(IterInfo(options,&xmpObj))
{
	if ( (options & kXMP_IterClassMask) != kXMP_IterProperties ) {
		XMP_Throw ( "Unsupported iteration kind", kXMPErr_BadOptions );
	}
	
	// *** Lock the XMPMeta object if we ever stop using a full DLL lock.

	if ( *propName != 0 ) {

		// An iterator rooted at a specific node.

		#if TraceIterators
			printf ( "\nNew XMP property iterator for \"%s\", options = %X\n    Schema = %s, root = %s\n",
			         xmpObj.tree.name.c_str(), options, schemaNS, propName );
		#endif
		
		XMP_ExpandedXPath propPath;
		ExpandXPath ( schemaNS, propName, &propPath );
		XMP_Node * propNode = FindConstNode ( &xmpObj.tree, propPath );	// If not found get empty iteration.
		
		if ( propNode != 0 ) {

			XMP_VarString rootName ( propPath[1].step );	// The schema is [0].
			for ( size_t i = 2; i < propPath.size(); ++i ) {
				XMP_OptionBits stepKind = GetStepKind ( propPath[i].options );
				if ( stepKind <= kXMP_QualifierStep ) rootName += '/';
				rootName += propPath[i].step;
			}

			propName = rootName.c_str();
			size_t leafOffset = rootName.size();
			while ( (leafOffset > 0) && (propName[leafOffset] != '/') && (propName[leafOffset] != '[') ) --leafOffset;
			if ( propName[leafOffset] == '/' ) ++leafOffset;

			info.tree.children.push_back ( IterNode ( propNode->options, propName, leafOffset ) );
			SetCurrSchema ( info, propPath[kSchemaStep].step.c_str() );
			if ( info.options & kXMP_IterJustChildren ) {
				AddNodeOffspring ( info, info.tree.children.back(), propNode );
			}

		}
	
	} else if ( *schemaNS != 0 ) {

		// An iterator for all properties in one schema.
		
		#if TraceIterators
			printf ( "\nNew XMP schema iterator for \"%s\", options = %X\n    Schema = %s\n",
			         xmpObj.tree.name.c_str(), options, schemaNS );
		#endif
		
		info.tree.children.push_back ( IterNode ( kXMP_SchemaNode, schemaNS, 0 ) );
		IterNode & iterSchema = info.tree.children.back();
		
		XMP_Node * xmpSchema = FindConstSchema ( &xmpObj.tree, schemaNS );
		if ( xmpSchema != 0 ) AddSchemaProps ( info, iterSchema, xmpSchema );
		
		if ( info.options & kXMP_IterIncludeAliases ) AddSchemaAliases ( info, iterSchema, schemaNS );
		
		if ( iterSchema.children.empty() ) {
			info.tree.children.pop_back();	// No properties, remove the schema node.
		} else {
			SetCurrSchema ( info, schemaNS );
		}
	
	} else {

		// An iterator for all properties in all schema. First add schema that exist (have children),
		// adding aliases from them if appropriate. Then add schema that have no actual properties
		// but do have aliases to existing properties, if we're including aliases in the iteration.
		
		#if TraceIterators
			printf ( "\nNew XMP tree iterator for \"%s\", options = %X\n",
			         xmpObj.tree.name.c_str(), options );
		#endif
		
		// First pick up the schema that exist.
		
		for ( size_t schemaNum = 0, schemaLim = xmpObj.tree.children.size(); schemaNum != schemaLim; ++schemaNum ) {

			const XMP_Node * xmpSchema = xmpObj.tree.children[schemaNum];
			info.tree.children.push_back ( IterNode ( kXMP_SchemaNode, xmpSchema->name, 0 ) );
			IterNode & iterSchema = info.tree.children.back();

			if ( ! (info.options & kXMP_IterJustChildren) ) {
				AddSchemaProps ( info, iterSchema, xmpSchema );
				if ( info.options & kXMP_IterIncludeAliases ) AddSchemaAliases ( info, iterSchema, xmpSchema->name.c_str() );
				if ( iterSchema.children.empty() ) info.tree.children.pop_back();	// No properties, remove the schema node.
			}

		}
		
		if ( info.options & kXMP_IterIncludeAliases ) {

			// Add the schema that only have aliases. The most convenient, and safest way, is to go
			// through the registered namespaces, see if it exists, and let AddSchemaAliases do its
			// thing if not. Don't combine with the above loop, it is nicer to have the "real" stuff
			// be in storage order (not subject to the namespace map order).
			
			// ! We don't do the kXMP_IterJustChildren handing in the same way here as above. The
			// ! existing schema (presumably) have actual children. We need to call AddSchemaAliases
			// ! here to determine if the namespace has any aliases to existing properties. We then
			// ! strip the children if necessary.

			XMP_cStringMapPos currNS = sNamespaceURIToPrefixMap->begin();
			XMP_cStringMapPos endNS  = sNamespaceURIToPrefixMap->end();
			for ( ; currNS != endNS; ++currNS ) {
				XMP_StringPtr schemaName = currNS->first.c_str();
				if ( FindConstSchema ( &xmpObj.tree, schemaName ) != 0 ) continue;
				info.tree.children.push_back ( IterNode ( kXMP_SchemaNode, schemaName, 0 ) );
				IterNode & iterSchema = info.tree.children.back();
				AddSchemaAliases ( info, iterSchema, schemaName );
				if ( iterSchema.children.empty() ) {
					info.tree.children.pop_back();	// No aliases, remove the schema node.
				} else if ( info.options & kXMP_IterJustChildren ) {
					iterSchema.children.clear();	// Get rid of the children.
				}
			}

		}

	}
	
	// Set the current iteration position to the first node to be visited.
	
	info.currPos = info.tree.children.begin();
	info.endPos  = info.tree.children.end();
	
	if ( (info.options & kXMP_IterJustChildren) && (info.currPos != info.endPos) && (*schemaNS != 0) ) {
		info.currPos->visitStage = kIter_VisitSelf;
	}

	#if TraceIterators
		if ( info.currPos == info.endPos ) {
			printf ( "    ** Empty iteration **\n" );
		} else {
			printf ( "    Initial node %s, stage = %s, iterator @ %.8X\n",
			         info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage], this );
		}
	#endif
	
}	// XMPIterator for XMPMeta objects
示例#3
0
static void
AdvanceIterPos ( IterInfo & info )
{
	// -------------------------------------------------------------------------------------------
	// Keep looking until we find a node to visit or the end of everything. The first time through
	// the current node will exist, we just visited it. But we have to keep looking if the current
	// node was the last of its siblings or is an empty schema.
	
	// ! It is possible that info.currPos == info.endPos on entry. Don't dereference info.currPos yet!

	while ( true ) {
	
		if ( info.currPos == info.endPos ) {
		
			// ------------------------------------------------------------------------------------
			// At the end of a set of siblings, move up to an ancestor. We've either just finished
			// the qualifiers and will move to the children, or have just finished the children and
			// will move on to the next sibling.
			
			if ( info.ancestors.empty() ) break;	// We're at the end of the schema list.

			IterPosPair & parent = info.ancestors.back();
			info.currPos = parent.first;
			info.endPos  = parent.second;
			info.ancestors.pop_back();
			
			#if TraceIterators
				printf ( "    Moved up to %s, stage = %s\n",
				         info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] );
			#endif
		
		} else {
			
			// -------------------------------------------------------------------------------------------
			// Decide what to do with this iteration node based on its state. Don't use a switch statment,
			// some of the cases want to break from the loop. A break in a switch just exits the case.
			
			#if TraceIterators
				printf ( "    Moving from %s, stage = %s\n",
				         info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] );
			#endif
			
			if ( info.currPos->visitStage == kIter_BeforeVisit ) {		// Visit this node now.
				if ( info.currPos->options & kXMP_SchemaNode ) SetCurrSchema ( info, info.currPos->fullPath );
				break;
			}

			if ( info.currPos->visitStage == kIter_VisitSelf ) {		// Just finished visiting the value portion.
				info.currPos->visitStage = kIter_VisitQualifiers;		// Start visiting the qualifiers.
				if ( ! info.currPos->qualifiers.empty() ) {
					info.ancestors.push_back ( IterPosPair ( info.currPos, info.endPos ) );
					info.endPos  = info.currPos->qualifiers.end();		// ! Set the parent's endPos before changing currPos!
					info.currPos = info.currPos->qualifiers.begin();
					break;
				}
			}

			if ( info.currPos->visitStage == kIter_VisitQualifiers ) {	// Just finished visiting the qualifiers.
				info.currPos->qualifiers.clear();
				info.currPos->visitStage = kIter_VisitChildren;			// Start visiting the children.
				if ( ! info.currPos->children.empty() ) {
					info.ancestors.push_back ( IterPosPair ( info.currPos, info.endPos ) );
					info.endPos  = info.currPos->children.end();		// ! Set the parent's endPos before changing currPos!
					info.currPos = info.currPos->children.begin();
					break;
				}
			}

			if ( info.currPos->visitStage == kIter_VisitChildren ) {	// Just finished visiting the children.
				info.currPos->children.clear();
				++info.currPos;											// Move to the next sibling.
				continue;
			}
			
			#if TraceIterators
				if ( info.currPos != info.endPos ) {
					printf ( "    Moved to %s, stage = %s\n",
					         info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] );
				}
			#endif
			
		}

	}	// Loop to find the next node.
	
	XMP_Assert ( (info.currPos == info.endPos) || (info.currPos->visitStage == kIter_BeforeVisit) );

}	// AdvanceIterPos
示例#4
0
XMPIterator::XMPIterator ( const XMPMeta & xmpObj,
						   XMP_StringPtr   schemaNS,
						   XMP_StringPtr   propName,
						   XMP_OptionBits  options ) : clientRefs(0), info(IterInfo(options,&xmpObj))
{
	if ( (options & kXMP_IterClassMask) != kXMP_IterProperties ) {
		XMP_Throw ( "Unsupported iteration kind", kXMPErr_BadOptions );
	}
	
	// *** Lock the XMPMeta object if we ever stop using a full DLL lock.

	if ( *propName != 0 ) {

		// An iterator rooted at a specific node.

		#if TraceIterators
			printf ( "\nNew XMP property iterator for \"%s\", options = %X\n    Schema = %s, root = %s\n",
			         xmpObj.tree.name.c_str(), options, schemaNS, propName );
		#endif
		
		XMP_ExpandedXPath propPath;
		ExpandXPath ( schemaNS, propName, &propPath );
		XMP_Node * propNode = FindConstNode ( &xmpObj.tree, propPath );	// If not found get empty iteration.
		
		if ( propNode != 0 ) {

			XMP_VarString rootName ( propPath[1].step );	// The schema is [0].
			for ( size_t i = 2; i < propPath.size(); ++i ) {
				XMP_OptionBits stepKind = GetStepKind ( propPath[i].options );
				if ( stepKind <= kXMP_QualifierStep ) rootName += '/';
				rootName += propPath[i].step;
			}

			propName = rootName.c_str();
			size_t leafOffset = rootName.size();
			while ( (leafOffset > 0) && (propName[leafOffset] != '/') && (propName[leafOffset] != '[') ) --leafOffset;
			if ( propName[leafOffset] == '/' ) ++leafOffset;

			info.tree.children.push_back ( IterNode ( propNode->options, propName, leafOffset ) );
			SetCurrSchema ( info, propPath[kSchemaStep].step.c_str() );
			if ( info.options & kXMP_IterJustChildren ) {
				AddNodeOffspring ( info, info.tree.children.back(), propNode );
			}

		}
	
	} else if ( *schemaNS != 0 ) {

		// An iterator for all properties in one schema.
		
		#if TraceIterators
			printf ( "\nNew XMP schema iterator for \"%s\", options = %X\n    Schema = %s\n",
			         xmpObj.tree.name.c_str(), options, schemaNS );
		#endif
		
		info.tree.children.push_back ( IterNode ( kXMP_SchemaNode, schemaNS, 0 ) );
		IterNode & iterSchema = info.tree.children.back();
		
		XMP_Node * xmpSchema = FindConstSchema ( &xmpObj.tree, schemaNS );
		if ( xmpSchema != 0 ) AddSchemaProps ( info, iterSchema, xmpSchema );
		
		if ( iterSchema.children.empty() ) {
			info.tree.children.pop_back();	// No properties, remove the schema node.
		} else {
			SetCurrSchema ( info, schemaNS );
		}
	
	} else {

		// An iterator for all properties in all schema. First add schema that exist (have children),
		// adding aliases from them if appropriate. Then add schema that have no actual properties
		// but do have aliases to existing properties, if we're including aliases in the iteration.
		
		#if TraceIterators
			printf ( "\nNew XMP tree iterator for \"%s\", options = %X\n",
			         xmpObj.tree.name.c_str(), options );
		#endif
		
		// First pick up the schema that exist.
		
		for ( size_t schemaNum = 0, schemaLim = xmpObj.tree.children.size(); schemaNum != schemaLim; ++schemaNum ) {

			const XMP_Node * xmpSchema = xmpObj.tree.children[schemaNum];
			info.tree.children.push_back ( IterNode ( kXMP_SchemaNode, xmpSchema->name, 0 ) );
			IterNode & iterSchema = info.tree.children.back();

			if ( ! (info.options & kXMP_IterJustChildren) ) {
				AddSchemaProps ( info, iterSchema, xmpSchema );
				if ( iterSchema.children.empty() ) info.tree.children.pop_back();	// No properties, remove the schema node.
			}

		}

	}
	
	// Set the current iteration position to the first node to be visited.
	
	info.currPos = info.tree.children.begin();
	info.endPos  = info.tree.children.end();
	
	if ( (info.options & kXMP_IterJustChildren) && (info.currPos != info.endPos) && (*schemaNS != 0) ) {
		info.currPos->visitStage = kIter_VisitSelf;
	}

	#if TraceIterators
		if ( info.currPos == info.endPos ) {
			printf ( "    ** Empty iteration **\n" );
		} else {
			printf ( "    Initial node %s, stage = %s, iterator @ %.8X\n",
			         info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage], this );
		}
	#endif
	
}	// XMPIterator for XMPMeta objects