static void
RemoveSchemaChildren ( XMP_NodePtrPos schemaPos, bool doAll )
{
	XMP_Node * schemaNode = *schemaPos;
	XMP_Assert ( XMP_NodeIsSchema ( schemaNode->options ) );
		
	// ! Iterate backwards to reduce shuffling as children are erased and to simplify the logic for
	// ! denoting the current child. (Erasing child n makes the old n+1 now be n.)

	size_t		   propCount = schemaNode->children.size();
	XMP_NodePtrPos beginPos	 = schemaNode->children.begin();
	
	for ( size_t propNum = propCount-1, propLim = (size_t)(-1); propNum != propLim; --propNum ) {
		XMP_NodePtrPos currProp = beginPos + propNum;
		if ( doAll || IsExternalProperty ( schemaNode->name, (*currProp)->name ) ) {
			delete *currProp;	// ! Both delete the node and erase the pointer from the parent.
			schemaNode->children.erase ( currProp );
		}
	}
	
	if ( schemaNode->children.empty() ) {
		XMP_Node * tree = schemaNode->parent;
		tree->children.erase ( schemaPos );
		delete schemaNode;
	}

}	// RemoveSchemaChildren
示例#2
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
示例#3
0
bool
XMPIterator::Next ( XMP_StringPtr *	 schemaNS,
					XMP_StringLen *	 nsSize,
					XMP_StringPtr *	 propPath,
					XMP_StringLen *	 pathSize,
					XMP_StringPtr *	 propValue,
					XMP_StringLen *	 valueSize,
					XMP_OptionBits * propOptions )
{
	// *** Lock the XMPMeta object if we ever stop using a full DLL lock.
	
	// ! 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.
	
	if ( info.currPos == info.endPos ) return false;	// Happens at the start of an empty iteration.
	
	#if TraceIterators
		printf ( "Next iteration from %s, stage = %s, iterator @ %.8X\n",
			     info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage], this );
	#endif
	
	const XMP_Node * xmpNode = GetNextXMPNode ( info );
	if ( xmpNode == 0 ) return false;
	bool isSchemaNode = XMP_NodeIsSchema ( info.currPos->options );
	
	if ( info.options & kXMP_IterJustLeafNodes ) {
		while ( isSchemaNode || (! xmpNode->children.empty()) ) {
			info.currPos->visitStage = kIter_VisitQualifiers;	// Skip to this node's children.
			xmpNode = GetNextXMPNode ( info );
			if ( xmpNode == 0 ) return false;
			isSchemaNode = XMP_NodeIsSchema ( info.currPos->options );
		}
	}
	
	*schemaNS = info.currSchema.c_str();
	*nsSize   = info.currSchema.size();

	*propOptions = info.currPos->options;

	*propPath  = "";
	*pathSize  = 0;
	*propValue = "";
	*valueSize = 0;
	
	if ( ! (*propOptions & kXMP_SchemaNode) ) {

		*propPath = info.currPos->fullPath.c_str();
		*pathSize = info.currPos->fullPath.size();
		if ( info.options & kXMP_IterJustLeafName ) {
			*propPath += info.currPos->leafOffset;
			*pathSize -= info.currPos->leafOffset;
		}
		
		if ( ! (*propOptions & kXMP_PropCompositeMask) ) {
			*propValue = xmpNode->value.c_str();
			*valueSize = xmpNode->value.size();
		}

	}
	
	#if TraceIterators
		printf ( "    Next node %s, stage = %s\n",
			     info.currPos->fullPath.c_str(), sStageNames[info.currPos->visitStage] );
	#endif
	
	return true;

}	// Next
示例#4
0
    int XmpParser::decode(      XmpData&     xmpData,
                          const std::string& xmpPacket)
    { try {
        xmpData.clear();
        if (xmpPacket.empty()) return 0;

        if (!initialize()) {
#ifndef SUPPRESS_WARNINGS
            std::cerr << "XMP Toolkit initialization failed.\n";
#endif
            return 2;
        }

        SXMPMeta meta(xmpPacket.data(), static_cast<XMP_StringLen>(xmpPacket.size()));
        SXMPIterator iter(meta);
        std::string schemaNs, propPath, propValue;
        XMP_OptionBits opt;
        while (iter.Next(&schemaNs, &propPath, &propValue, &opt)) {
#ifdef DEBUG
            printNode(schemaNs, propPath, propValue, opt);
#endif
            if (XMP_PropIsAlias(opt)) {
                throw Error(47, schemaNs, propPath, propValue);
                continue;
            }
            if (XMP_NodeIsSchema(opt)) {
                // Register unknown namespaces with Exiv2
                // (Namespaces are automatically registered with the XMP Toolkit)
                if (XmpProperties::prefix(schemaNs).empty()) {
                    std::string prefix;
                    bool ret = meta.GetNamespacePrefix(schemaNs.c_str(), &prefix);
                    if (!ret) throw Error(45, schemaNs);
                    prefix = prefix.substr(0, prefix.size() - 1);
                    XmpProperties::registerNs(schemaNs, prefix);
                }
                continue;
            }
            XmpKey::AutoPtr key = makeXmpKey(schemaNs, propPath);
            if (XMP_ArrayIsAltText(opt)) {
                // Read Lang Alt property
                LangAltValue::AutoPtr val(new LangAltValue);
                XMP_Index count = meta.CountArrayItems(schemaNs.c_str(), propPath.c_str());
                while (count-- > 0) {
                    // Get the text
                    bool haveNext = iter.Next(&schemaNs, &propPath, &propValue, &opt);
#ifdef DEBUG
                    printNode(schemaNs, propPath, propValue, opt);
#endif
                    if (   !haveNext
                        || !XMP_PropIsSimple(opt)
                        || !XMP_PropHasLang(opt)) {
                        throw Error(41, propPath, opt);
                    }
                    const std::string text = propValue;
                    // Get the language qualifier
                    haveNext = iter.Next(&schemaNs, &propPath, &propValue, &opt);
#ifdef DEBUG
                    printNode(schemaNs, propPath, propValue, opt);
#endif
                    if (   !haveNext
                        || !XMP_PropIsSimple(opt)
                        || !XMP_PropIsQualifier(opt)
                        || propPath.substr(propPath.size() - 8, 8) != "xml:lang") {
                        throw Error(42, propPath, opt);
                    }
                    val->value_[propValue] = text;
                }
                xmpData.add(*key.get(), val.get());
                continue;
            }
            if (    XMP_PropIsArray(opt)
                && !XMP_PropHasQualifiers(opt)
                && !XMP_ArrayIsAltText(opt)) {
                // Check if all elements are simple
                bool simpleArray = true;
                SXMPIterator aIter(meta, schemaNs.c_str(), propPath.c_str());
                std::string aSchemaNs, aPropPath, aPropValue;
                XMP_OptionBits aOpt;
                while (aIter.Next(&aSchemaNs, &aPropPath, &aPropValue, &aOpt)) {
                    if (propPath == aPropPath) continue;
                    if (   !XMP_PropIsSimple(aOpt)
                        ||  XMP_PropHasQualifiers(aOpt)
                        ||  XMP_PropIsQualifier(aOpt)
                        ||  XMP_NodeIsSchema(aOpt)
                        ||  XMP_PropIsAlias(aOpt)) {
                        simpleArray = false;
                        break;
                    }
                }
                if (simpleArray) {
                    // Read the array into an XmpArrayValue
                    XmpArrayValue::AutoPtr val(new XmpArrayValue(arrayValueTypeId(opt)));
                    XMP_Index count = meta.CountArrayItems(schemaNs.c_str(), propPath.c_str());
                    while (count-- > 0) {
                        iter.Next(&schemaNs, &propPath, &propValue, &opt);
#ifdef DEBUG
                        printNode(schemaNs, propPath, propValue, opt);
#endif
                        val->read(propValue);
                    }
                    xmpData.add(*key.get(), val.get());
                    continue;
                }
            }
            XmpTextValue::AutoPtr val(new XmpTextValue);
            if (   XMP_PropIsStruct(opt)
                || XMP_PropIsArray(opt)) {
                // Create a metadatum with only XMP options
                val->setXmpArrayType(xmpArrayType(opt));
                val->setXmpStruct(xmpStruct(opt));
                xmpData.add(*key.get(), val.get());
                continue;
            }
            if (   XMP_PropIsSimple(opt)
                || XMP_PropIsQualifier(opt)) {
                val->read(propValue);
                xmpData.add(*key.get(), val.get());
                continue;
            }
            // Don't let any node go by unnoticed
            throw Error(39, key->key(), opt);
        } // iterate through all XMP nodes

        return 0;
    }
    catch (const XMP_Error& e) {
#ifndef SUPPRESS_WARNINGS
        std::cerr << Error(40, e.GetID(), e.GetErrMsg()) << "\n";
#endif
        xmpData.clear();
        return 3;
    }} // XmpParser::decode
/* class static */ void
XMPUtils::RemoveProperties ( XMPMeta *		xmpObj,
							 XMP_StringPtr	schemaNS,
							 XMP_StringPtr	propName,
							 XMP_OptionBits options )
{
	XMP_Assert ( (schemaNS != 0) && (propName != 0) );	// ! Enforced by wrapper.
	
	const bool doAll = XMP_TestOption (options, kXMPUtil_DoAllProperties );
	const bool includeAliases = XMP_TestOption ( options, kXMPUtil_IncludeAliases );
	
	if ( *propName != 0 ) {
	
		// Remove just the one indicated property. This might be an alias, the named schema might
		// not actually exist. So don't lookup the schema node.
		
		if ( *schemaNS == 0 ) XMP_Throw ( "Property name requires schema namespace", kXMPErr_BadParam );
		
		XMP_ExpandedXPath expPath;
		ExpandXPath ( schemaNS, propName, &expPath );
		
		XMP_NodePtrPos propPos;
		XMP_Node * propNode = FindNode ( &(xmpObj->tree), expPath, kXMP_ExistingOnly, kXMP_NoOptions, &propPos );
		if ( propNode != 0 ) {
			if ( doAll || IsExternalProperty ( expPath[kSchemaStep].step, expPath[kRootPropStep].step ) ) {
				XMP_Node * parent = propNode->parent;	// *** Should have XMP_Node::RemoveChild(pos).
				delete propNode;	// ! Both delete the node and erase the pointer from the parent.
				parent->children.erase ( propPos );
				DeleteEmptySchema ( parent );
			}
		}
	
	} else if ( *schemaNS != 0 ) {
	
		// Remove all properties from the named schema. Optionally include aliases, in which case
		// there might not be an actual schema node. 

		XMP_NodePtrPos schemaPos;
		XMP_Node * schemaNode = FindSchemaNode ( &xmpObj->tree, schemaNS, kXMP_ExistingOnly, &schemaPos );
		if ( schemaNode != 0 ) RemoveSchemaChildren ( schemaPos, doAll );
		
		if ( includeAliases ) {
		
			// We're removing the aliases also. Look them up by their namespace prefix. Yes, the
			// alias map is sorted so we could process just that portion. But that takes more code
			// and the extra speed isn't worth it. (Plus this way we avoid a dependence on the map
			// implementation.) Lookup the XMP node from the alias, to make sure the actual exists.

			XMP_StringPtr nsPrefix;
			XMP_StringLen nsLen;
			(void) XMPMeta::GetNamespacePrefix ( schemaNS, &nsPrefix, &nsLen );
			
			XMP_AliasMapPos currAlias = sRegisteredAliasMap->begin();
			XMP_AliasMapPos endAlias  = sRegisteredAliasMap->end();
			
			for ( ; currAlias != endAlias; ++currAlias ) {
				if ( strncmp ( currAlias->first.c_str(), nsPrefix, nsLen ) == 0 ) {
					XMP_NodePtrPos actualPos;
					XMP_Node * actualProp = FindNode ( &xmpObj->tree, currAlias->second, kXMP_ExistingOnly, kXMP_NoOptions, &actualPos );
					if ( actualProp != 0 ) {
						XMP_Node * rootProp = actualProp;
						while ( ! XMP_NodeIsSchema ( rootProp->parent->options ) ) rootProp = rootProp->parent;
						if ( doAll || IsExternalProperty ( rootProp->parent->name, rootProp->name ) ) {
							XMP_Node * parent = actualProp->parent;
							delete actualProp;	// ! Both delete the node and erase the pointer from the parent.
							parent->children.erase ( actualPos );
							DeleteEmptySchema ( parent );
						}
					}
				}
			}

		}

	} else {
		
		// Remove all appropriate properties from all schema. In this case we don't have to be
		// concerned with aliases, they are handled implicitly from the actual properties.

		// ! Iterate backwards to reduce shuffling if schema are erased and to simplify the logic
		// ! for denoting the current schema. (Erasing schema n makes the old n+1 now be n.)

		size_t		   schemaCount = xmpObj->tree.children.size();
		XMP_NodePtrPos beginPos	   = xmpObj->tree.children.begin();
		
		for ( size_t schemaNum = schemaCount-1, schemaLim = (size_t)(-1); schemaNum != schemaLim; --schemaNum ) {
			XMP_NodePtrPos currSchema = beginPos + schemaNum;
			RemoveSchemaChildren ( currSchema, doAll );
		}
	
	}

}	// RemoveProperties