1 // =================================================================================================
2 // Copyright 2004 Adobe Systems Incorporated
3 // All Rights Reserved.
4 //
5 // NOTICE:  Adobe permits you to use, modify, and distribute this file in accordance with the terms
6 // of the Adobe license agreement accompanying it.
7 // =================================================================================================
8 
9 #include "public/include/XMP_Environment.h"	// ! This must be the first include!
10 #include "XMPCore/source/XMPCore_Impl.hpp"
11 #include "XMPCore/source/XMPMeta.hpp"
12 #include "source/ExpatAdapter.hpp"
13 
14 #include <cstring>
15 
16 #if DEBUG
17 	#include <iostream>
18 #endif
19 
20 using namespace std;
21 
22 #if XMP_WinBuild
23 	#pragma warning ( disable : 4189 )	// local variable is initialized but not referenced
24 	#pragma warning ( disable : 4505 )	// unreferenced local function has been removed
25 #endif
26 
27 // =================================================================================================
28 
29 // *** This might be faster and use less memory as a state machine. A big advantage of building an
30 // *** XML tree though is easy lookahead during the recursive descent processing.
31 
32 // *** It would be nice to give a line number or byte offset in the exception messages.
33 
34 
35 // 7 RDF/XML Grammar (from http://www.w3.org/TR/rdf-syntax-grammar/#section-Infoset-Grammar)
36 //
37 // 7.1 Grammar summary
38 //
39 // 7.2.2 coreSyntaxTerms
40 //		rdf:RDF | rdf:ID | rdf:about | rdf:parseType | rdf:resource | rdf:nodeID | rdf:datatype
41 //
42 // 7.2.3 syntaxTerms
43 //		coreSyntaxTerms | rdf:Description | rdf:li
44 //
45 // 7.2.4 oldTerms
46 //		rdf:aboutEach | rdf:aboutEachPrefix | rdf:bagID
47 //
48 // 7.2.5 nodeElementURIs
49 //		anyURI - ( coreSyntaxTerms | rdf:li | oldTerms )
50 //
51 // 7.2.6 propertyElementURIs
52 //		anyURI - ( coreSyntaxTerms | rdf:Description | oldTerms )
53 //
54 // 7.2.7 propertyAttributeURIs
55 //		anyURI - ( coreSyntaxTerms | rdf:Description | rdf:li | oldTerms )
56 //
57 // 7.2.8 doc
58 //		root ( document-element == RDF, children == list ( RDF ) )
59 //
60 // 7.2.9 RDF
61 //		start-element ( URI == rdf:RDF, attributes == set() )
62 //		nodeElementList
63 //		end-element()
64 //
65 // 7.2.10 nodeElementList
66 //		ws* ( nodeElement ws* )*
67 //
68 // 7.2.11 nodeElement
69 //		start-element ( URI == nodeElementURIs,
70 //						attributes == set ( ( idAttr | nodeIdAttr | aboutAttr )?, propertyAttr* ) )
71 //		propertyEltList
72 //		end-element()
73 //
74 // 7.2.12 ws
75 //		A text event matching white space defined by [XML] definition White Space Rule [3] S in section Common Syntactic Constructs.
76 //
77 // 7.2.13 propertyEltList
78 //		ws* ( propertyElt ws* )*
79 //
80 // 7.2.14 propertyElt
81 //		resourcePropertyElt | literalPropertyElt | parseTypeLiteralPropertyElt |
82 //		parseTypeResourcePropertyElt | parseTypeCollectionPropertyElt | parseTypeOtherPropertyElt | emptyPropertyElt
83 //
84 // 7.2.15 resourcePropertyElt
85 //		start-element ( URI == propertyElementURIs, attributes == set ( idAttr? ) )
86 //		ws* nodeElement ws*
87 //		end-element()
88 //
89 // 7.2.16 literalPropertyElt
90 //		start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, datatypeAttr?) )
91 //		text()
92 //		end-element()
93 //
94 // 7.2.17 parseTypeLiteralPropertyElt
95 //		start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseLiteral ) )
96 //		literal
97 //		end-element()
98 //
99 // 7.2.18 parseTypeResourcePropertyElt
100 //		start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseResource ) )
101 //		propertyEltList
102 //		end-element()
103 //
104 // 7.2.19 parseTypeCollectionPropertyElt
105 //		start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseCollection ) )
106 //		nodeElementList
107 //		end-element()
108 //
109 // 7.2.20 parseTypeOtherPropertyElt
110 //		start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseOther ) )
111 //		propertyEltList
112 //		end-element()
113 //
114 // 7.2.21 emptyPropertyElt
115 //		start-element ( URI == propertyElementURIs,
116 //						attributes == set ( idAttr?, ( resourceAttr | nodeIdAttr )?, propertyAttr* ) )
117 //		end-element()
118 //
119 // 7.2.22 idAttr
120 //		attribute ( URI == rdf:ID, string-value == rdf-id )
121 //
122 // 7.2.23 nodeIdAttr
123 //		attribute ( URI == rdf:nodeID, string-value == rdf-id )
124 //
125 // 7.2.24 aboutAttr
126 //		attribute ( URI == rdf:about, string-value == URI-reference )
127 //
128 // 7.2.25 propertyAttr
129 //		attribute ( URI == propertyAttributeURIs, string-value == anyString )
130 //
131 // 7.2.26 resourceAttr
132 //		attribute ( URI == rdf:resource, string-value == URI-reference )
133 //
134 // 7.2.27 datatypeAttr
135 //		attribute ( URI == rdf:datatype, string-value == URI-reference )
136 //
137 // 7.2.28 parseLiteral
138 //		attribute ( URI == rdf:parseType, string-value == "Literal")
139 //
140 // 7.2.29 parseResource
141 //		attribute ( URI == rdf:parseType, string-value == "Resource")
142 //
143 // 7.2.30 parseCollection
144 //		attribute ( URI == rdf:parseType, string-value == "Collection")
145 //
146 // 7.2.31 parseOther
147 //		attribute ( URI == rdf:parseType, string-value == anyString - ("Resource" | "Literal" | "Collection") )
148 //
149 // 7.2.32 URI-reference
150 //		An RDF URI Reference.
151 //
152 // 7.2.33 literal
153 //		Any XML element content that is allowed according to [XML] definition Content of Elements Rule [43] content
154 //		in section 3.1 Start-Tags, End-Tags, and Empty-Element Tags.
155 //
156 // 7.2.34 rdf-id
157 //		An attribute string-value matching any legal [XML-NS] token NCName.
158 
159 
160 // =================================================================================================
161 // Primary Parsing Functions
162 // =========================
163 //
164 // Each of these is responsible for recognizing an RDF syntax production and adding the appropriate
165 // structure to the XMP tree. They simply return for success, failures will throw an exception. The
166 // class exists only to provide access to the error notification object.
167 
168 class RDF_Parser {
169 public:
170 
171 	void RDF ( XMP_Node * xmpTree, const XML_Node & xmlNode );
172 
173 	void NodeElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel );
174 
175 	void NodeElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
176 
177 	void NodeElementAttrs ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
178 
179 	void PropertyElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel );
180 
181 	void PropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
182 
183 	void ResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
184 
185 	void LiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
186 
187 	void ParseTypeLiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
188 
189 	void ParseTypeResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
190 
191 	void ParseTypeCollectionPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
192 
193 	void ParseTypeOtherPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
194 
195 	void EmptyPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel );
196 
RDF_Parser(XMPMeta::ErrorCallbackInfo * ec)197 	RDF_Parser ( XMPMeta::ErrorCallbackInfo * ec ) : errorCallback(ec) {};
198 
199 private:
200 
RDF_Parser()201 	RDF_Parser() {
202 
203 		errorCallback = NULL;
204 
205 	};	// Hidden on purpose.
206 
207 	XMPMeta::ErrorCallbackInfo * errorCallback;
208 
209 	XMP_Node * AddChildNode ( XMP_Node * xmpParent, const XML_Node & xmlNode, const XMP_StringPtr value, bool isTopLevel );
210 
211 	XMP_Node * AddQualifierNode ( XMP_Node * xmpParent, const XMP_VarString & name, const XMP_VarString & value );
212 
213 	XMP_Node * AddQualifierNode ( XMP_Node * xmpParent, const XML_Node & attr );
214 
215 	void FixupQualifiedNode ( XMP_Node * xmpParent );
216 
217 };
218 
219 enum { kIsTopLevel = true, kNotTopLevel = false };
220 
221 // =================================================================================================
222 
223 typedef XMP_Uns8 RDFTermKind;
224 
225 // *** Logic might be safer with just masks.
226 
227 enum {
228 	kRDFTerm_Other				=  0,
229 	kRDFTerm_RDF				=  1,	// Start of coreSyntaxTerms.
230 	kRDFTerm_ID					=  2,
231 	kRDFTerm_about				=  3,
232 	kRDFTerm_parseType			=  4,
233 	kRDFTerm_resource			=  5,
234 	kRDFTerm_nodeID				=  6,
235 	kRDFTerm_datatype			=  7,	// End of coreSyntaxTerms.
236 	kRDFTerm_Description		=  8,	// Start of additions for syntaxTerms.
237 	kRDFTerm_li					=  9,	// End of of additions for syntaxTerms.
238 	kRDFTerm_aboutEach			= 10,	// Start of oldTerms.
239 	kRDFTerm_aboutEachPrefix	= 11,
240 	kRDFTerm_bagID				= 12,	// End of oldTerms.
241 
242 	kRDFTerm_FirstCore          = kRDFTerm_RDF,
243 	kRDFTerm_LastCore           = kRDFTerm_datatype,
244 	kRDFTerm_FirstSyntax        = kRDFTerm_FirstCore,	// ! Yes, the syntax terms include the core terms.
245 	kRDFTerm_LastSyntax         = kRDFTerm_li,
246 	kRDFTerm_FirstOld           = kRDFTerm_aboutEach,
247 	kRDFTerm_LastOld            = kRDFTerm_bagID
248 };
249 
250 enum {
251 	kRDFMask_Other				= 1 << kRDFTerm_Other,
252 	kRDFMask_RDF				= 1 << kRDFTerm_RDF,
253 	kRDFMask_ID					= 1 << kRDFTerm_ID,
254 	kRDFMask_about				= 1 << kRDFTerm_about,
255 	kRDFMask_parseType			= 1 << kRDFTerm_parseType,
256 	kRDFMask_resource			= 1 << kRDFTerm_resource,
257 	kRDFMask_nodeID				= 1 << kRDFTerm_nodeID,
258 	kRDFMask_datatype			= 1 << kRDFTerm_datatype,
259 	kRDFMask_Description		= 1 << kRDFTerm_Description,
260 	kRDFMask_li					= 1 << kRDFTerm_li,
261 	kRDFMask_aboutEach			= 1 << kRDFTerm_aboutEach,
262 	kRDFMask_aboutEachPrefix	= 1 << kRDFTerm_aboutEachPrefix,
263 	kRDFMask_bagID				= 1 << kRDFTerm_bagID
264 };
265 
266 enum {
267 	kRDF_HasValueElem = 0x10000000UL	// ! Contains rdf:value child. Must fit within kXMP_ImplReservedMask!
268 };
269 
270 // -------------------------------------------------------------------------------------------------
271 // GetRDFTermKind
272 // --------------
273 
274 static RDFTermKind
GetRDFTermKind(const XMP_VarString & name)275 GetRDFTermKind ( const XMP_VarString & name )
276 {
277 	RDFTermKind term = kRDFTerm_Other;
278 
279 	// Arranged to hopefully minimize the parse time for large XMP.
280 
281 	if ( (name.size() > 4) && (strncmp ( name.c_str(), "rdf:", 4 ) == 0) ) {
282 
283 		if ( name == "rdf:li" ) {
284 			term = kRDFTerm_li;
285 		} else if ( name == "rdf:parseType" ) {
286 			term = kRDFTerm_parseType;
287 		} else if ( name == "rdf:Description" ) {
288 			term = kRDFTerm_Description;
289 		} else if ( name == "rdf:about" ) {
290 			term = kRDFTerm_about;
291 		} else if ( name == "rdf:resource" ) {
292 			term = kRDFTerm_resource;
293 		} else if ( name == "rdf:RDF" ) {
294 			term = kRDFTerm_RDF;
295 		} else if ( name == "rdf:ID" ) {
296 			term = kRDFTerm_ID;
297 		} else if ( name == "rdf:nodeID" ) {
298 			term = kRDFTerm_nodeID;
299 		} else if ( name == "rdf:datatype" ) {
300 			term = kRDFTerm_datatype;
301 		} else if ( name == "rdf:aboutEach" ) {
302 			term = kRDFTerm_aboutEach;
303 		} else if ( name == "rdf:aboutEachPrefix" ) {
304 			term = kRDFTerm_aboutEachPrefix;
305 		} else if ( name == "rdf:bagID" ) {
306 			term = kRDFTerm_bagID;
307 		}
308 
309 	}
310 
311 	return term;
312 
313 }	// GetRDFTermKind
314 
315 // =================================================================================================
316 
317 static void
RemoveChild(XMP_Node * xmpParent,size_t index)318 RemoveChild ( XMP_Node * xmpParent, size_t index )
319 {
320 	XMP_Node * child = xmpParent->children[index];
321 	xmpParent->children.erase ( xmpParent->children.begin() + index );
322 	delete child;
323 }
324 
325 // -------------------------------------------------------------------------------------------------
326 
327 static void
RemoveQualifier(XMP_Node * xmpParent,size_t index)328 RemoveQualifier ( XMP_Node * xmpParent, size_t index )
329 {
330 	XMP_Node * qualifier = xmpParent->qualifiers[index];
331 	xmpParent->qualifiers.erase ( xmpParent->qualifiers.begin() + index );
332 	delete qualifier;
333 }
334 
335 // -------------------------------------------------------------------------------------------------
336 
337 static void
RemoveQualifier(XMP_Node * xmpParent,XMP_NodePtrPos pos)338 RemoveQualifier ( XMP_Node * xmpParent, XMP_NodePtrPos pos )
339 {
340 	XMP_Node * qualifier = *pos;
341 	xmpParent->qualifiers.erase ( pos );
342 	delete qualifier;
343 }
344 
345 // =================================================================================================
346 
347 // -------------------------------------------------------------------------------------------------
348 // IsCoreSyntaxTerm
349 // ----------------
350 //
351 // 7.2.2 coreSyntaxTerms
352 //		rdf:RDF | rdf:ID | rdf:about | rdf:parseType | rdf:resource | rdf:nodeID | rdf:datatype
353 
354 static bool
IsCoreSyntaxTerm(RDFTermKind term)355 IsCoreSyntaxTerm ( RDFTermKind term )
356 {
357 	if 	( (kRDFTerm_FirstCore <= term) && (term <= kRDFTerm_LastCore) ) return true;
358 	return false;
359 }
360 
361 // -------------------------------------------------------------------------------------------------
362 // IsSyntaxTerm
363 // ------------
364 //
365 // 7.2.3 syntaxTerms
366 //		coreSyntaxTerms | rdf:Description | rdf:li
367 
368 static bool
IsSyntaxTerm(RDFTermKind term)369 IsSyntaxTerm ( RDFTermKind term )
370 {
371 	if 	( (kRDFTerm_FirstSyntax <= term) && (term <= kRDFTerm_LastSyntax) ) return true;
372 	return false;
373 }
374 
375 // -------------------------------------------------------------------------------------------------
376 // IsOldTerm
377 // ---------
378 //
379 // 7.2.4 oldTerms
380 //		rdf:aboutEach | rdf:aboutEachPrefix | rdf:bagID
381 
382 static bool
IsOldTerm(RDFTermKind term)383 IsOldTerm ( RDFTermKind term )
384 {
385 	if 	( (kRDFTerm_FirstOld <= term) && (term <= kRDFTerm_LastOld) ) return true;
386 	return false;
387 }
388 
389 // -------------------------------------------------------------------------------------------------
390 // IsNodeElementName
391 // -----------------
392 //
393 // 7.2.5 nodeElementURIs
394 //		anyURI - ( coreSyntaxTerms | rdf:li | oldTerms )
395 
396 static bool
IsNodeElementName(RDFTermKind term)397 IsNodeElementName ( RDFTermKind term )
398 {
399 	if 	( (term == kRDFTerm_li) || IsOldTerm ( term ) ) return false;
400 	return (! IsCoreSyntaxTerm ( term ));
401 }
402 
403 // -------------------------------------------------------------------------------------------------
404 // IsPropertyElementName
405 // ---------------------
406 //
407 // 7.2.6 propertyElementURIs
408 //		anyURI - ( coreSyntaxTerms | rdf:Description | oldTerms )
409 
410 static bool
IsPropertyElementName(RDFTermKind term)411 IsPropertyElementName ( RDFTermKind term )
412 {
413 	if 	( (term == kRDFTerm_Description) || IsOldTerm ( term ) ) return false;
414 	return (! IsCoreSyntaxTerm ( term ));
415 }
416 
417 // -------------------------------------------------------------------------------------------------
418 // IsPropertyAttributeName
419 // -----------------------
420 //
421 // 7.2.7 propertyAttributeURIs
422 //		anyURI - ( coreSyntaxTerms | rdf:Description | rdf:li | oldTerms )
423 
424 static bool
IsPropertyAttributeName(RDFTermKind term)425 IsPropertyAttributeName ( RDFTermKind term )
426 {
427 	if 	( (term == kRDFTerm_Description) || (term == kRDFTerm_li) || IsOldTerm ( term ) ) return false;
428 	return (! IsCoreSyntaxTerm ( term ));
429 }
430 
431 // -------------------------------------------------------------------------------------------------
432 // IsNumberedArrayItemName
433 // -----------------------
434 //
435 // Return true for a name of the form "rdf:_n", where n is a decimal integer. We're not strict about
436 // the integer part, it just has to be characters in the range '0'..'9'.
437 
438 static bool
IsNumberedArrayItemName(const std::string & name)439 IsNumberedArrayItemName ( const std::string & name )
440 {
441 	if ( name.size() <= 5 ) return false;
442 	if ( strncmp ( name.c_str(), "rdf:_", 5 ) != 0 ) return false;
443 	for ( size_t i = 5; i < name.size(); ++i ) {
444 		if ( (name[i] < '0') | (name[i] > '9') ) return false;
445 	}
446 	return true;
447 }
448 
449 // =================================================================================================
450 // RDF_Parser::AddChildNode
451 // ========================
452 
AddChildNode(XMP_Node * xmpParent,const XML_Node & xmlNode,const XMP_StringPtr value,bool isTopLevel)453 XMP_Node * RDF_Parser::AddChildNode ( XMP_Node * xmpParent, const XML_Node & xmlNode, const XMP_StringPtr value, bool isTopLevel )
454 {
455 
456 	if ( xmlNode.ns.empty() ) {
457 		XMP_Error error ( kXMPErr_BadRDF, "XML namespace required for all elements and attributes" );
458 		this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
459 		return 0;
460 	}
461 
462 	bool isArrayParent = (xmpParent->options & kXMP_PropValueIsArray) !=0;
463 	bool isArrayItem   = (xmlNode.name == "rdf:li");
464 	bool isValueNode   = (xmlNode.name == "rdf:value");
465 	XMP_OptionBits childOptions = 0;
466 	XMP_StringPtr  childName = xmlNode.name.c_str();
467 
468 	if ( isTopLevel ) {
469 
470 		// Lookup the schema node, adjust the XMP parent pointer.
471 		XMP_Assert ( xmpParent->parent == 0 );	// Incoming parent must be the tree root.
472 		XMP_Node * schemaNode = FindSchemaNode ( xmpParent, xmlNode.ns.c_str(), kXMP_CreateNodes );
473 		if ( schemaNode->options & kXMP_NewImplicitNode ) schemaNode->options ^= kXMP_NewImplicitNode;	// Clear the implicit node bit.
474 			// *** Should use "opt &= ~flag" (no conditional), need runtime check for proper 32 bit code.
475 		xmpParent = schemaNode;
476 
477 		// If this is an alias set the isAlias flag in the node and the hasAliases flag in the tree.
478 		if ( sRegisteredAliasMap->find ( xmlNode.name ) != sRegisteredAliasMap->end() ) {
479 			childOptions |= kXMP_PropIsAlias;
480 			schemaNode->parent->options |= kXMP_PropHasAliases;
481 		}
482 
483 	}
484 
485 	// Check use of rdf:li and rdf:_n names. Must be done before calling FindChildNode!
486 	if ( isArrayItem ) {
487 
488 		// rdf:li can only be used for array children.
489 		if ( ! isArrayParent ) {
490 			XMP_Error error ( kXMPErr_BadRDF, "Misplaced rdf:li element" );
491 			this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
492 			return 0;
493 		}
494 		childName = kXMP_ArrayItemName;
495 
496 	} else if ( isArrayParent ) {
497 
498 		// Tolerate use of rdf:_n, don't verify order.
499 		if ( IsNumberedArrayItemName ( xmlNode.name ) ) {
500 			childName = kXMP_ArrayItemName;
501 			isArrayItem = true;
502 		} else {
503 			XMP_Error error ( kXMPErr_BadRDF, "Array items cannot have arbitrary child names" );
504 			this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
505 			return 0;
506 		}
507 
508 	}
509 
510 	// Make sure that this is not a duplicate of a named node.
511 	if ( ! (isArrayItem | isValueNode) ) {
512 		if ( FindChildNode ( xmpParent, childName, kXMP_ExistingOnly ) != 0 ) {
513 			XMP_Error error ( kXMPErr_BadXMP, "Duplicate property or field node" );
514 			this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
515 			return 0;
516 		}
517 	}
518 
519 	// Make sure an rdf:value node is used properly.
520 	if ( isValueNode ) {
521 		if ( isTopLevel || (! (xmpParent->options & kXMP_PropValueIsStruct)) ) {
522 			XMP_Error error ( kXMPErr_BadRDF, "Misplaced rdf:value element" );
523 			this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
524 			return 0;
525 		}
526 		xmpParent->options |= kRDF_HasValueElem;
527 	}
528 
529 	// Add the new child to the XMP parent node.
530 	XMP_Node * newChild = new XMP_Node ( xmpParent, childName, value, childOptions );
531 	if ( (! isValueNode) || xmpParent->children.empty() ) {
532 		 xmpParent->children.push_back ( newChild );
533 	} else {
534 		 xmpParent->children.insert ( xmpParent->children.begin(), newChild );
535 	}
536 
537 	return newChild;
538 
539 }	// RDF_Parser::AddChildNode
540 
541 // =================================================================================================
542 // RDF_Parser::AddQualifierNode
543 // ============================
544 
AddQualifierNode(XMP_Node * xmpParent,const XMP_VarString & name,const XMP_VarString & value)545 XMP_Node * RDF_Parser::AddQualifierNode ( XMP_Node * xmpParent, const XMP_VarString & name, const XMP_VarString & value )
546 {
547 
548 	const bool isLang = (name == "xml:lang");
549 	const bool isType = (name == "rdf:type");
550 
551 	XMP_Node * newQual = 0;
552 
553 	newQual = new XMP_Node ( xmpParent, name, value, kXMP_PropIsQualifier );
554 
555 	if ( ! (isLang | isType) ) {
556 		xmpParent->qualifiers.push_back ( newQual );
557 	} else if ( isLang ) {
558 		if ( xmpParent->qualifiers.empty() ) {
559 			xmpParent->qualifiers.push_back ( newQual );
560 		} else {
561 			xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin(), newQual );
562 		}
563 		xmpParent->options |= kXMP_PropHasLang;
564 	} else {
565 		XMP_Assert ( isType );
566 		if ( xmpParent->qualifiers.empty() ) {
567 			xmpParent->qualifiers.push_back ( newQual );
568 		} else {
569 			size_t offset = 0;
570 			if ( XMP_PropHasLang ( xmpParent->options ) ) offset = 1;
571 			xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin()+offset, newQual );
572 		}
573 		xmpParent->options |= kXMP_PropHasType;
574 	}
575 
576 	xmpParent->options |= kXMP_PropHasQualifiers;
577 
578 	return newQual;
579 
580 }	// RDF_Parser::AddQualifierNode
581 
582 // =================================================================================================
583 // RDF_Parser::AddQualifierNode
584 // ============================
585 
AddQualifierNode(XMP_Node * xmpParent,const XML_Node & attr)586 XMP_Node * RDF_Parser::AddQualifierNode ( XMP_Node * xmpParent, const XML_Node & attr )
587 {
588 	if ( attr.ns.empty() ) {
589 		XMP_Error error ( kXMPErr_BadRDF, "XML namespace required for all elements and attributes" );
590 		this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
591 		return 0;
592 	}
593 
594 	return this->AddQualifierNode ( xmpParent, attr.name, attr.value );
595 
596 }	// RDF_Parser::AddQualifierNode
597 
598 // =================================================================================================
599 // RDF_Parser::FixupQualifiedNode
600 // ==============================
601 //
602 // The parent is an RDF pseudo-struct containing an rdf:value field. Fix the XMP data model. The
603 // rdf:value node must be the first child, the other children are qualifiers. The form, value, and
604 // children of the rdf:value node are the real ones. The rdf:value node's qualifiers must be added
605 // to the others.
606 
FixupQualifiedNode(XMP_Node * xmpParent)607 void RDF_Parser::FixupQualifiedNode ( XMP_Node * xmpParent )
608 {
609 	size_t qualNum, qualLim;
610 	size_t childNum, childLim;
611 
612 	XMP_Enforce ( (xmpParent->options & kXMP_PropValueIsStruct) && (! xmpParent->children.empty()) );
613 
614 	XMP_Node * valueNode = xmpParent->children[0];
615 	XMP_Enforce ( valueNode->name == "rdf:value" );
616 
617 	xmpParent->qualifiers.reserve ( xmpParent->qualifiers.size() + xmpParent->children.size() + valueNode->qualifiers.size() );
618 
619 	// Move the qualifiers on the value node to the parent. Make sure an xml:lang qualifier stays at
620 	// the front.
621 
622 	qualNum = 0;
623 	qualLim = valueNode->qualifiers.size();
624 
625 	if ( valueNode->options & kXMP_PropHasLang ) {
626 
627 		if ( xmpParent->options & kXMP_PropHasLang ) {
628 			XMP_Error error ( kXMPErr_BadXMP, "Duplicate xml:lang for rdf:value element" );
629 			this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
630 			XMP_Assert ( xmpParent->qualifiers[0]->name == "xml:lang" );
631 			RemoveQualifier ( xmpParent, 0 );	// Use the rdf:value node's language.
632 		}
633 
634 		XMP_Node * langQual = valueNode->qualifiers[0];
635 
636 		XMP_Assert ( langQual->name == "xml:lang" );
637 		langQual->parent = xmpParent;
638 		xmpParent->options |= kXMP_PropHasLang;
639 		XMP_ClearOption ( valueNode->options, kXMP_PropHasLang );
640 
641 		if ( xmpParent->qualifiers.empty() ) {
642 			xmpParent->qualifiers.push_back ( langQual );	// *** Should use utilities to add qual & set parent.
643 		} else {
644 			xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin(), langQual );
645 		}
646 		valueNode->qualifiers[0] = 0;	// We just moved it to the parent.
647 
648 		qualNum = 1;	// Start the remaining copy after the xml:lang qualifier.
649 
650 	}
651 
652 	for ( ; qualNum != qualLim; ++qualNum ) {
653 
654 		XMP_Node * currQual = valueNode->qualifiers[qualNum];
655 		XMP_NodePtrPos existingPos;
656 		XMP_Node * existingQual = FindQualifierNode ( xmpParent, currQual->name.c_str(), kXMP_ExistingOnly, &existingPos );
657 
658 		if ( existingQual != 0 ) {
659 			XMP_Error error ( kXMPErr_BadXMP, "Duplicate qualifier node" );
660 			this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
661 			RemoveQualifier ( xmpParent, existingPos );	// Use the rdf:value node's qualifier.
662 		}
663 
664 		currQual->parent = xmpParent;
665 		xmpParent->qualifiers.push_back ( currQual );
666 		valueNode->qualifiers[qualNum] = 0;	// We just moved it to the parent.
667 
668 	}
669 
670 	valueNode->qualifiers.clear();	// ! There should be nothing but null pointers.
671 
672 	// Change the parent's other children into qualifiers. This loop starts at 1, child 0 is the
673 	// rdf:value node. Put xml:lang at the front, append all others.
674 
675 	for ( childNum = 1, childLim = xmpParent->children.size(); childNum != childLim; ++childNum ) {
676 
677 		XMP_Node * currQual = xmpParent->children[childNum];
678 		bool isLang = (currQual->name == "xml:lang");
679 
680 		if ( FindQualifierNode ( xmpParent, currQual->name.c_str(), kXMP_ExistingOnly ) != 0 ) {
681 			XMP_Error error ( kXMPErr_BadXMP, "Duplicate qualifier" );
682 			this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
683 			delete currQual;
684 
685 		} else {
686 
687 			currQual->options |= kXMP_PropIsQualifier;
688 			currQual->parent = xmpParent;
689 
690 			if ( isLang ) {
691 				xmpParent->options |= kXMP_PropHasLang;
692 			} else if ( currQual->name == "rdf:type" ) {
693 				xmpParent->options |= kXMP_PropHasType;
694 			}
695 
696 			if ( (! isLang) || xmpParent->qualifiers.empty() ) {
697 				xmpParent->qualifiers.push_back ( currQual );
698 			} else {
699 				xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin(), currQual );
700 			}
701 
702 		}
703 
704 		xmpParent->children[childNum] = 0;	// We just moved it to the qualifers, or ignored it.
705 
706 	}
707 
708 	if ( ! xmpParent->qualifiers.empty() ) xmpParent->options |= kXMP_PropHasQualifiers;
709 
710 	// Move the options and value last, other checks need the parent's original options. Move the
711 	// value node's children to be the parent's children. Delete the now useless value node.
712 
713 	XMP_Assert ( xmpParent->options & (kXMP_PropValueIsStruct | kRDF_HasValueElem) );
714 	xmpParent->options &= ~ (kXMP_PropValueIsStruct | kRDF_HasValueElem);
715 	xmpParent->options |= valueNode->options;
716 
717 	xmpParent->value.swap ( valueNode->value );
718 
719 	xmpParent->children[0] = 0;	// ! Remove the value node itself before the swap.
720 	xmpParent->children.swap ( valueNode->children );
721 
722 	for ( childNum = 0, childLim = xmpParent->children.size(); childNum != childLim; ++childNum ) {
723 		XMP_Node * currChild = xmpParent->children[childNum];
724 		currChild->parent = xmpParent;
725 	}
726 
727 	delete valueNode;
728 
729 }	// RDF_Parser::FixupQualifiedNode
730 
731 // =================================================================================================
732 // RDF_Parser::RDF
733 // ===============
734 //
735 // 7.2.9 RDF
736 //		start-element ( URI == rdf:RDF, attributes == set() )
737 //		nodeElementList
738 //		end-element()
739 //
740 // The top level rdf:RDF node. It can only have xmlns attributes, which have already been removed
741 // during construction of the XML tree.
742 
RDF(XMP_Node * xmpTree,const XML_Node & xmlNode)743 void RDF_Parser::RDF ( XMP_Node * xmpTree, const XML_Node & xmlNode )
744 {
745 
746 	if ( ! xmlNode.attrs.empty() ) {
747 		XMP_Error error ( kXMPErr_BadRDF, "Invalid attributes of rdf:RDF element" );
748 		this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
749 	}
750 	this->NodeElementList ( xmpTree, xmlNode, kIsTopLevel );	// ! Attributes are ignored.
751 
752 }	// RDF_Parser::RDF
753 
754 // =================================================================================================
755 // RDF_Parser::NodeElementList
756 // ===========================
757 //
758 // 7.2.10 nodeElementList
759 //		ws* ( nodeElement ws* )*
760 
NodeElementList(XMP_Node * xmpParent,const XML_Node & xmlParent,bool isTopLevel)761 void RDF_Parser::NodeElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel )
762 {
763 	XMP_Assert ( isTopLevel );
764 
765 	XML_cNodePos currChild = xmlParent.content.begin();	// *** Change these loops to the indexed pattern.
766 	XML_cNodePos endChild  = xmlParent.content.end();
767 
768 	for ( ; currChild != endChild; ++currChild ) {
769 		if ( (*currChild)->IsWhitespaceNode() ) continue;
770 		this->NodeElement ( xmpParent, **currChild, isTopLevel );
771 	}
772 
773 }	// RDF_Parser::NodeElementList
774 
775 // =================================================================================================
776 // RDF_Parser::NodeElement
777 // =======================
778 //
779 // 7.2.5 nodeElementURIs
780 //		anyURI - ( coreSyntaxTerms | rdf:li | oldTerms )
781 //
782 // 7.2.11 nodeElement
783 //		start-element ( URI == nodeElementURIs,
784 //						attributes == set ( ( idAttr | nodeIdAttr | aboutAttr )?, propertyAttr* ) )
785 //		propertyEltList
786 //		end-element()
787 //
788 // A node element URI is rdf:Description or anything else that is not an RDF term.
789 
NodeElement(XMP_Node * xmpParent,const XML_Node & xmlNode,bool isTopLevel)790 void RDF_Parser::NodeElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
791 {
792 	RDFTermKind nodeTerm = GetRDFTermKind ( xmlNode.name );
793 	if ( (nodeTerm != kRDFTerm_Description) && (nodeTerm != kRDFTerm_Other) ) {
794 		XMP_Error error ( kXMPErr_BadRDF, "Node element must be rdf:Description or typedNode" );
795 		this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
796 	} else if ( isTopLevel && (nodeTerm == kRDFTerm_Other) ) {
797 		XMP_Error error ( kXMPErr_BadXMP, "Top level typedNode not allowed" );
798 		this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
799 	} else {
800 		this->NodeElementAttrs ( xmpParent, xmlNode, isTopLevel );
801 		this->PropertyElementList ( xmpParent, xmlNode, isTopLevel );
802 	}
803 
804 }	// RDF_Parser::NodeElement
805 
806 // =================================================================================================
807 // RDF_Parser::NodeElementAttrs
808 // ============================
809 //
810 // 7.2.7 propertyAttributeURIs
811 //		anyURI - ( coreSyntaxTerms | rdf:Description | rdf:li | oldTerms )
812 //
813 // 7.2.11 nodeElement
814 //		start-element ( URI == nodeElementURIs,
815 //						attributes == set ( ( idAttr | nodeIdAttr | aboutAttr )?, propertyAttr* ) )
816 //		propertyEltList
817 //		end-element()
818 //
819 // Process the attribute list for an RDF node element. A property attribute URI is anything other
820 // than an RDF term. The rdf:ID and rdf:nodeID attributes are simply ignored, as are rdf:about
821 // attributes on inner nodes.
822 
823 static const XMP_OptionBits kExclusiveAttrMask = (kRDFMask_ID | kRDFMask_nodeID | kRDFMask_about);
824 
NodeElementAttrs(XMP_Node * xmpParent,const XML_Node & xmlNode,bool isTopLevel)825 void RDF_Parser::NodeElementAttrs ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
826 {
827 	XMP_OptionBits exclusiveAttrs = 0;	// Used to detect attributes that are mutually exclusive.
828 
829 	XML_cNodePos currAttr = xmlNode.attrs.begin();
830 	XML_cNodePos endAttr  = xmlNode.attrs.end();
831 
832 	for ( ; currAttr != endAttr; ++currAttr ) {
833 
834 		RDFTermKind attrTerm = GetRDFTermKind ( (*currAttr)->name );
835 
836 		switch ( attrTerm ) {
837 
838 			case kRDFTerm_ID     :
839 			case kRDFTerm_nodeID :
840 			case kRDFTerm_about  :
841 
842 				if ( exclusiveAttrs & kExclusiveAttrMask ) {
843 					XMP_Error error ( kXMPErr_BadRDF, "Mutally exclusive about, ID, nodeID attributes" );
844 					this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
845 					continue;	// Skip the later mutually exclusive attributes.
846 				}
847 				exclusiveAttrs |= (1 << attrTerm);
848 
849 				if ( isTopLevel && (attrTerm == kRDFTerm_about) ) {
850 					// This is the rdf:about attribute on a top level node. Set the XMP tree name if
851 					// it doesn't have a name yet. Make sure this name matches the XMP tree name.
852 					XMP_Assert ( xmpParent->parent == 0 );	// Must be the tree root node.
853 					if ( xmpParent->name.empty() ) {
854 						xmpParent->name = (*currAttr)->value;
855 					} else if ( ! (*currAttr)->value.empty() ) {
856 						if ( xmpParent->name != (*currAttr)->value ) {
857 							XMP_Error error ( kXMPErr_BadXMP, "Mismatched top level rdf:about values" );
858 							this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
859 						}
860 					}
861 				}
862 
863 				break;
864 
865 			case kRDFTerm_Other :
866 				this->AddChildNode ( xmpParent, **currAttr, (*currAttr)->value.c_str(), isTopLevel );
867 				break;
868 
869 			default :
870 				{
871 					XMP_Error error ( kXMPErr_BadRDF, "Invalid nodeElement attribute" );
872 					this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
873 				}
874 				continue;
875 
876 		}
877 
878 	}
879 
880 }	// RDF_Parser::NodeElementAttrs
881 
882 // =================================================================================================
883 // RDF_Parser::PropertyElementList
884 // ===============================
885 //
886 // 7.2.13 propertyEltList
887 //		ws* ( propertyElt ws* )*
888 
PropertyElementList(XMP_Node * xmpParent,const XML_Node & xmlParent,bool isTopLevel)889 void RDF_Parser::PropertyElementList ( XMP_Node * xmpParent, const XML_Node & xmlParent, bool isTopLevel )
890 {
891 	XML_cNodePos currChild = xmlParent.content.begin();
892 	XML_cNodePos endChild  = xmlParent.content.end();
893 
894 	for ( ; currChild != endChild; ++currChild ) {
895 		if ( (*currChild)->IsWhitespaceNode() ) continue;
896 		if ( (*currChild)->kind != kElemNode ) {
897 			XMP_Error error ( kXMPErr_BadRDF, "Expected property element node not found" );
898 			this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
899 			continue;
900 		}
901 		this->PropertyElement ( xmpParent, **currChild, isTopLevel );
902 	}
903 
904 }	// RDF_Parser::PropertyElementList
905 
906 // =================================================================================================
907 // RDF_Parser::PropertyElement
908 // ===========================
909 //
910 // 7.2.14 propertyElt
911 //		resourcePropertyElt | literalPropertyElt | parseTypeLiteralPropertyElt |
912 //		parseTypeResourcePropertyElt | parseTypeCollectionPropertyElt | parseTypeOtherPropertyElt | emptyPropertyElt
913 //
914 // 7.2.15 resourcePropertyElt
915 //		start-element ( URI == propertyElementURIs, attributes == set ( idAttr? ) )
916 //		ws* nodeElement ws*
917 //		end-element()
918 //
919 // 7.2.16 literalPropertyElt
920 //		start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, datatypeAttr?) )
921 //		text()
922 //		end-element()
923 //
924 // 7.2.17 parseTypeLiteralPropertyElt
925 //		start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseLiteral ) )
926 //		literal
927 //		end-element()
928 //
929 // 7.2.18 parseTypeResourcePropertyElt
930 //		start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseResource ) )
931 //		propertyEltList
932 //		end-element()
933 //
934 // 7.2.19 parseTypeCollectionPropertyElt
935 //		start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseCollection ) )
936 //		nodeElementList
937 //		end-element()
938 //
939 // 7.2.20 parseTypeOtherPropertyElt
940 //		start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseOther ) )
941 //		propertyEltList
942 //		end-element()
943 //
944 // 7.2.21 emptyPropertyElt
945 //		start-element ( URI == propertyElementURIs,
946 //						attributes == set ( idAttr?, ( resourceAttr | nodeIdAttr )?, propertyAttr* ) )
947 //		end-element()
948 //
949 // The various property element forms are not distinguished by the XML element name, but by their
950 // attributes for the most part. The exceptions are resourcePropertyElt and literalPropertyElt. They
951 // are distinguished by their XML element content.
952 //
953 // NOTE: The RDF syntax does not explicitly include the xml:lang attribute although it can appear in
954 // many of these. We have to allow for it in the attibute counts below.
955 
PropertyElement(XMP_Node * xmpParent,const XML_Node & xmlNode,bool isTopLevel)956 void RDF_Parser::PropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
957 {
958 	RDFTermKind nodeTerm = GetRDFTermKind ( xmlNode.name );
959 	if ( ! IsPropertyElementName ( nodeTerm ) ) {
960 		XMP_Error error ( kXMPErr_BadRDF, "Invalid property element name" );
961 		this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
962 		return;
963 	}
964 
965 	if ( xmlNode.attrs.size() > 3 ) {
966 
967 		// Only an emptyPropertyElt can have more than 3 attributes.
968 		this->EmptyPropertyElement ( xmpParent, xmlNode, isTopLevel );
969 
970 	} else {
971 
972 		// Look through the attributes for one that isn't rdf:ID or xml:lang, it will usually tell
973 		// what we should be dealing with. The called routines must verify their specific syntax!
974 
975 		XML_cNodePos currAttr = xmlNode.attrs.begin();
976 		XML_cNodePos endAttr  = xmlNode.attrs.end();
977 		XMP_VarString * attrName = 0;
978 
979 		for ( ; currAttr != endAttr; ++currAttr ) {
980 			attrName = &((*currAttr)->name);
981 			if ( (*attrName != "xml:lang") && (*attrName != "rdf:ID") ) break;
982 		}
983 
984 		if ( currAttr != endAttr ) {
985 
986 			XMP_Assert ( attrName != 0 );
987 			XMP_VarString& attrValue = (*currAttr)->value;
988 
989 			if ( *attrName == "rdf:datatype" ) {
990 				this->LiteralPropertyElement ( xmpParent, xmlNode, isTopLevel );
991 			} else if ( *attrName != "rdf:parseType" ) {
992 				this->EmptyPropertyElement ( xmpParent, xmlNode, isTopLevel );
993 			} else if ( attrValue == "Literal" ) {
994 				this->ParseTypeLiteralPropertyElement ( xmpParent, xmlNode, isTopLevel );
995 			} else if ( attrValue == "Resource" ) {
996 				this->ParseTypeResourcePropertyElement ( xmpParent, xmlNode, isTopLevel );
997 			} else if ( attrValue == "Collection" ) {
998 				this->ParseTypeCollectionPropertyElement ( xmpParent, xmlNode, isTopLevel );
999 			} else {
1000 				this->ParseTypeOtherPropertyElement ( xmpParent, xmlNode, isTopLevel );
1001 			}
1002 
1003 		} else {
1004 
1005 			// Only rdf:ID and xml:lang, could be a resourcePropertyElt, a literalPropertyElt, or an.
1006 			// emptyPropertyElt. Look at the child XML nodes to decide which.
1007 
1008 			if ( xmlNode.content.empty() ) {
1009 
1010 				this->EmptyPropertyElement ( xmpParent, xmlNode, isTopLevel );
1011 
1012 			} else {
1013 
1014 				XML_cNodePos currChild = xmlNode.content.begin();
1015 				XML_cNodePos endChild  = xmlNode.content.end();
1016 
1017 				for ( ; currChild != endChild; ++currChild ) {
1018 					if ( (*currChild)->kind != kCDataNode ) break;
1019 				}
1020 
1021 				if ( currChild == endChild ) {
1022 					this->LiteralPropertyElement ( xmpParent, xmlNode, isTopLevel );
1023 				} else {
1024 					this->ResourcePropertyElement ( xmpParent, xmlNode, isTopLevel );
1025 				}
1026 
1027 			}
1028 
1029 		}
1030 
1031 	}
1032 
1033 }	// RDF_Parser::PropertyElement
1034 
1035 // =================================================================================================
1036 // RDF_Parser::ResourcePropertyElement
1037 // ===================================
1038 //
1039 // 7.2.15 resourcePropertyElt
1040 //		start-element ( URI == propertyElementURIs, attributes == set ( idAttr? ) )
1041 //		ws* nodeElement ws*
1042 //		end-element()
1043 //
1044 // This handles structs using an rdf:Description node, arrays using rdf:Bag/Seq/Alt, and Typed Nodes.
1045 // It also catches and cleans up qualified properties written with rdf:Description and rdf:value.
1046 
ResourcePropertyElement(XMP_Node * xmpParent,const XML_Node & xmlNode,bool isTopLevel)1047 void RDF_Parser::ResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
1048 {
1049 	if ( isTopLevel && (xmlNode.name == "iX:changes") ) return;	// Strip old "punchcard" chaff.
1050 
1051 	XMP_Node * newCompound = this->AddChildNode ( xmpParent, xmlNode, "", isTopLevel );
1052 	if ( newCompound == 0 ) return;	// Ignore lower level errors.
1053 
1054 	XML_cNodePos currAttr = xmlNode.attrs.begin();
1055 	XML_cNodePos endAttr  = xmlNode.attrs.end();
1056 
1057 	for ( ; currAttr != endAttr; ++currAttr ) {
1058 		XMP_VarString & attrName = (*currAttr)->name;
1059 		if ( attrName == "xml:lang" ) {
1060 			this->AddQualifierNode ( newCompound, **currAttr );
1061 		} else if ( attrName == "rdf:ID" ) {
1062 			continue;	// Ignore all rdf:ID attributes.
1063 		} else {
1064 			XMP_Error error ( kXMPErr_BadRDF, "Invalid attribute for resource property element" );
1065 			this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
1066 			continue;
1067 		}
1068 	}
1069 
1070 	XML_cNodePos currChild = xmlNode.content.begin();
1071 	XML_cNodePos endChild  = xmlNode.content.end();
1072 
1073 	for ( ; currChild != endChild; ++currChild ) {
1074 		if ( ! (*currChild)->IsWhitespaceNode() ) break;
1075 	}
1076 	if ( currChild == endChild ) {
1077 		XMP_Error error ( kXMPErr_BadRDF, "Missing child of resource property element" );
1078 		this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
1079 		return;
1080 	}
1081 	if ( (*currChild)->kind != kElemNode ) {
1082 		XMP_Error error ( kXMPErr_BadRDF, "Children of resource property element must be XML elements" );
1083 		this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
1084 		return;
1085 	}
1086 
1087 	if ( (*currChild)->name == "rdf:Bag" ) {
1088 		newCompound->options |= kXMP_PropValueIsArray;
1089 	} else if ( (*currChild)->name == "rdf:Seq" ) {
1090 		newCompound->options |= kXMP_PropValueIsArray | kXMP_PropArrayIsOrdered;
1091 	} else if ( (*currChild)->name == "rdf:Alt" ) {
1092 		newCompound->options |= kXMP_PropValueIsArray | kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate;
1093 	} else {
1094 		// This is the Typed Node case. Add an rdf:type qualifier with a URI value.
1095 		if ( (*currChild)->name != "rdf:Description" ) {
1096 			XMP_VarString typeName ( (*currChild)->ns );
1097 			size_t colonPos = (*currChild)->name.find_first_of(':');
1098 			if ( colonPos == XMP_VarString::npos ) {
1099 				XMP_Error error ( kXMPErr_BadXMP, "All XML elements must be in a namespace" );
1100 				this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
1101 				return;
1102 			}
1103 			typeName.append ( (*currChild)->name, colonPos+1, XMP_VarString::npos );	// Append just the local name.
1104 			XMP_Node * typeQual = this->AddQualifierNode ( newCompound, XMP_VarString("rdf:type"), typeName );
1105 			if ( typeQual != 0 ) typeQual->options |= kXMP_PropValueIsURI;
1106 		}
1107 		newCompound->options |= kXMP_PropValueIsStruct;
1108 	}
1109 
1110 	this->NodeElement ( newCompound, **currChild, kNotTopLevel );
1111 	if ( newCompound->options & kRDF_HasValueElem ) {
1112 		this->FixupQualifiedNode ( newCompound );
1113 	} else if ( newCompound->options & kXMP_PropArrayIsAlternate ) {
1114 		DetectAltText ( newCompound );
1115 	}
1116 
1117 	for ( ++currChild; currChild != endChild; ++currChild ) {
1118 		if ( ! (*currChild)->IsWhitespaceNode() ) {
1119 			XMP_Error error ( kXMPErr_BadRDF, "Invalid child of resource property element" );
1120 			this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
1121 			break;	// Don't bother looking for more trailing errors.
1122 		}
1123 	}
1124 
1125 }	// RDF_Parser::ResourcePropertyElement
1126 
1127 // =================================================================================================
1128 // RDF_Parser::LiteralPropertyElement
1129 // ==================================
1130 //
1131 // 7.2.16 literalPropertyElt
1132 //		start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, datatypeAttr?) )
1133 //		text()
1134 //		end-element()
1135 //
1136 // Add a leaf node with the text value and qualifiers for the attributes.
1137 
LiteralPropertyElement(XMP_Node * xmpParent,const XML_Node & xmlNode,bool isTopLevel)1138 void RDF_Parser::LiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
1139 {
1140 	XMP_Node * newChild = this->AddChildNode ( xmpParent, xmlNode, "", isTopLevel );
1141 	if ( newChild == 0 ) return;	// Ignore lower level errors.
1142 
1143 	XML_cNodePos currAttr = xmlNode.attrs.begin();
1144 	XML_cNodePos endAttr  = xmlNode.attrs.end();
1145 
1146 	for ( ; currAttr != endAttr; ++currAttr ) {
1147 		XMP_VarString & attrName = (*currAttr)->name;
1148 		if ( attrName == "xml:lang" ) {
1149 			this->AddQualifierNode ( newChild, **currAttr );
1150 		} else if ( (attrName == "rdf:ID") || (attrName == "rdf:datatype") ) {
1151 			continue; 	// Ignore all rdf:ID and rdf:datatype attributes.
1152 		} else {
1153 			XMP_Error error ( kXMPErr_BadRDF, "Invalid attribute for literal property element" );
1154 			this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
1155 			continue;
1156 		}
1157 	}
1158 
1159 	XML_cNodePos currChild = xmlNode.content.begin();
1160 	XML_cNodePos endChild  = xmlNode.content.end();
1161 	size_t textSize = 0;
1162 
1163 	for ( ; currChild != endChild; ++currChild ) {
1164 		if ( (*currChild)->kind == kCDataNode ) {
1165 			textSize += (*currChild)->value.size();
1166 		} else {
1167 			XMP_Error error ( kXMPErr_BadRDF, "Invalid child of literal property element" );
1168 			this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
1169 		}
1170 	}
1171 
1172 	newChild->value.reserve ( textSize );
1173 
1174 	for ( currChild = xmlNode.content.begin(); currChild != endChild; ++currChild ) {
1175 		newChild->value += (*currChild)->value;
1176 	}
1177 
1178 }	// RDF_Parser::LiteralPropertyElement
1179 
1180 // =================================================================================================
1181 // RDF_Parser::ParseTypeLiteralPropertyElement
1182 // ===========================================
1183 //
1184 // 7.2.17 parseTypeLiteralPropertyElt
1185 //		start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseLiteral ) )
1186 //		literal
1187 //		end-element()
1188 
ParseTypeLiteralPropertyElement(XMP_Node * xmpParent,const XML_Node & xmlNode,bool isTopLevel)1189 void RDF_Parser::ParseTypeLiteralPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
1190 {
1191 	IgnoreParam(xmpParent); IgnoreParam(xmlNode); IgnoreParam(isTopLevel);
1192 	XMP_Error error ( kXMPErr_BadXMP, "ParseTypeLiteral property element not allowed" );
1193 	this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
1194 
1195 }	// RDF_Parser::ParseTypeLiteralPropertyElement
1196 
1197 // =================================================================================================
1198 // RDF_Parser::ParseTypeResourcePropertyElement
1199 // ============================================
1200 //
1201 // 7.2.18 parseTypeResourcePropertyElt
1202 //		start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseResource ) )
1203 //		propertyEltList
1204 //		end-element()
1205 //
1206 // Add a new struct node with a qualifier for the possible rdf:ID attribute. Then process the XML
1207 // child nodes to get the struct fields.
1208 
ParseTypeResourcePropertyElement(XMP_Node * xmpParent,const XML_Node & xmlNode,bool isTopLevel)1209 void RDF_Parser::ParseTypeResourcePropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
1210 {
1211 	XMP_Node * newStruct = this->AddChildNode ( xmpParent, xmlNode, "", isTopLevel );
1212 	if ( newStruct == 0 ) return;	// Ignore lower level errors.
1213 	newStruct->options  |= kXMP_PropValueIsStruct;
1214 
1215 	XML_cNodePos currAttr = xmlNode.attrs.begin();
1216 	XML_cNodePos endAttr  = xmlNode.attrs.end();
1217 
1218 	for ( ; currAttr != endAttr; ++currAttr ) {
1219 		XMP_VarString & attrName = (*currAttr)->name;
1220 		if ( attrName == "rdf:parseType" ) {
1221 			continue;	// ! The caller ensured the value is "Resource".
1222 		} else if ( attrName == "xml:lang" ) {
1223 			this->AddQualifierNode ( newStruct, **currAttr );
1224 		} else if ( attrName == "rdf:ID" ) {
1225 			continue;	// Ignore all rdf:ID attributes.
1226 		} else {
1227 			XMP_Error error ( kXMPErr_BadRDF, "Invalid attribute for ParseTypeResource property element" );
1228 			this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
1229 			continue;
1230 		}
1231 	}
1232 
1233 	this->PropertyElementList ( newStruct, xmlNode, kNotTopLevel );
1234 
1235 	if ( newStruct->options & kRDF_HasValueElem ) this->FixupQualifiedNode ( newStruct );
1236 
1237 	// *** Need to look for arrays using rdf:Description and rdf:type.
1238 
1239 }	// RDF_Parser::ParseTypeResourcePropertyElement
1240 
1241 // =================================================================================================
1242 // RDF_Parser::ParseTypeCollectionPropertyElement
1243 // ==============================================
1244 //
1245 // 7.2.19 parseTypeCollectionPropertyElt
1246 //		start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseCollection ) )
1247 //		nodeElementList
1248 //		end-element()
1249 
ParseTypeCollectionPropertyElement(XMP_Node * xmpParent,const XML_Node & xmlNode,bool isTopLevel)1250 void RDF_Parser::ParseTypeCollectionPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
1251 {
1252 	IgnoreParam(xmpParent); IgnoreParam(xmlNode); IgnoreParam(isTopLevel);
1253 	XMP_Error error ( kXMPErr_BadXMP, "ParseTypeCollection property element not allowed" );
1254 	this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
1255 
1256 }	// RDF_Parser::ParseTypeCollectionPropertyElement
1257 
1258 // =================================================================================================
1259 // RDF_Parser::ParseTypeOtherPropertyElement
1260 // =========================================
1261 //
1262 // 7.2.20 parseTypeOtherPropertyElt
1263 //		start-element ( URI == propertyElementURIs, attributes == set ( idAttr?, parseOther ) )
1264 //		propertyEltList
1265 //		end-element()
1266 
ParseTypeOtherPropertyElement(XMP_Node * xmpParent,const XML_Node & xmlNode,bool isTopLevel)1267 void RDF_Parser::ParseTypeOtherPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
1268 {
1269 	IgnoreParam(xmpParent); IgnoreParam(xmlNode); IgnoreParam(isTopLevel);
1270 	XMP_Error error ( kXMPErr_BadXMP, "ParseTypeOther property element not allowed" );
1271 	this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
1272 
1273 }	// RDF_Parser::ParseTypeOtherPropertyElement
1274 
1275 // =================================================================================================
1276 // RDF_Parser::EmptyPropertyElement
1277 // ================================
1278 //
1279 // 7.2.21 emptyPropertyElt
1280 //		start-element ( URI == propertyElementURIs,
1281 //						attributes == set ( idAttr?, ( resourceAttr | nodeIdAttr )?, propertyAttr* ) )
1282 //		end-element()
1283 //
1284 //	<ns:Prop1/>  <!-- a simple property with an empty value -->
1285 //	<ns:Prop2 rdf:resource="http://www.adobe.com/"/> <!-- a URI value -->
1286 //	<ns:Prop3 rdf:value="..." ns:Qual="..."/> <!-- a simple qualified property -->
1287 //	<ns:Prop4 ns:Field1="..." ns:Field2="..."/> <!-- a struct with simple fields -->
1288 //
1289 // An emptyPropertyElt is an element with no contained content, just a possibly empty set of
1290 // attributes. An emptyPropertyElt can represent three special cases of simple XMP properties: a
1291 // simple property with an empty value (ns:Prop1), a simple property whose value is a URI
1292 // (ns:Prop2), or a simple property with simple qualifiers (ns:Prop3). An emptyPropertyElt can also
1293 // represent an XMP struct whose fields are all simple and unqualified (ns:Prop4).
1294 //
1295 // It is an error to use both rdf:value and rdf:resource - that can lead to invalid  RDF in the
1296 // verbose form written using a literalPropertyElt.
1297 //
1298 // The XMP mapping for an emptyPropertyElt is a bit different from generic RDF, partly for
1299 // design reasons and partly for historical reasons. The XMP mapping rules are:
1300 //	1. If there is an rdf:value attribute then this is a simple property with a text value.
1301 //		All other attributes are qualifiers.
1302 //	2. If there is an rdf:resource attribute then this is a simple property with a URI value.
1303 //		All other attributes are qualifiers.
1304 //	3. If there are no attributes other than xml:lang, rdf:ID, or rdf:nodeID then this is a simple
1305 //		property with an empty value.
1306 //	4. Otherwise this is a struct, the attributes other than xml:lang, rdf:ID, or rdf:nodeID are fields.
1307 
EmptyPropertyElement(XMP_Node * xmpParent,const XML_Node & xmlNode,bool isTopLevel)1308 void RDF_Parser::EmptyPropertyElement ( XMP_Node * xmpParent, const XML_Node & xmlNode, bool isTopLevel )
1309 {
1310 	bool hasPropertyAttrs = false;
1311 	bool hasResourceAttr  = false;
1312 	bool hasNodeIDAttr    = false;
1313 	bool hasValueAttr     = false;
1314 
1315 	const XML_Node * valueNode = 0;	// ! Can come from rdf:value or rdf:resource.
1316 
1317 	if ( ! xmlNode.content.empty() ) {
1318 		XMP_Error error ( kXMPErr_BadRDF, "Nested content not allowed with rdf:resource or property attributes" );
1319 		this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
1320 		return;
1321 	}
1322 
1323 	// First figure out what XMP this maps to and remember the XML node for a simple value.
1324 
1325 	XML_cNodePos currAttr = xmlNode.attrs.begin();
1326 	XML_cNodePos endAttr  = xmlNode.attrs.end();
1327 
1328 	for ( ; currAttr != endAttr; ++currAttr ) {
1329 
1330 		RDFTermKind attrTerm = GetRDFTermKind ( (*currAttr)->name );
1331 
1332 		switch ( attrTerm ) {
1333 
1334 			case kRDFTerm_ID :
1335 				// Nothing to do.
1336 				break;
1337 
1338 			case kRDFTerm_resource :
1339 				if ( hasNodeIDAttr ) {
1340 					XMP_Error error ( kXMPErr_BadRDF, "Empty property element can't have both rdf:resource and rdf:nodeID" );
1341 					this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
1342 					return;
1343 				}
1344 				if ( hasValueAttr ) {
1345 					XMP_Error error ( kXMPErr_BadXMP, "Empty property element can't have both rdf:value and rdf:resource" );
1346 					this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
1347 					return;
1348 				}
1349 				hasResourceAttr = true;
1350 				if ( ! hasValueAttr ) valueNode = *currAttr;
1351 				break;
1352 
1353 			case kRDFTerm_nodeID :
1354 				if ( hasResourceAttr ) {
1355 					XMP_Error error ( kXMPErr_BadRDF, "Empty property element can't have both rdf:resource and rdf:nodeID" );
1356 					this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
1357 					return;
1358 				}
1359 				hasNodeIDAttr = true;
1360 				break;
1361 
1362 			case kRDFTerm_Other :
1363 				if ( (*currAttr)->name == "rdf:value" ) {
1364 					if ( hasResourceAttr ) {
1365 						XMP_Error error ( kXMPErr_BadXMP, "Empty property element can't have both rdf:value and rdf:resource" );
1366 						this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
1367 						return;
1368 					}
1369 					hasValueAttr = true;
1370 					valueNode = *currAttr;
1371 				} else if ( (*currAttr)->name != "xml:lang" ) {
1372 					hasPropertyAttrs = true;
1373 				}
1374 				break;
1375 
1376 			default :
1377 				{
1378 					XMP_Error error ( kXMPErr_BadRDF, "Unrecognized attribute of empty property element" );
1379 					this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
1380 				}
1381 
1382 				return;
1383 
1384 		}
1385 
1386 	}
1387 
1388 	// Create the right kind of child node and visit the attributes again to add the fields or qualifiers.
1389 	// ! Because of implementation vagaries, the xmpParent is the tree root for top level properties.
1390 	// ! The schema is found, created if necessary, by AddChildNode.
1391 
1392 	XMP_Node * childNode = this->AddChildNode ( xmpParent, xmlNode, "", isTopLevel );
1393 	if ( childNode == 0 ) return;	// Ignore lower level errors.
1394 	bool childIsStruct = false;
1395 
1396 	if ( hasValueAttr | hasResourceAttr ) {
1397 		childNode->value = valueNode->value;
1398 		if ( ! hasValueAttr ) childNode->options |= kXMP_PropValueIsURI;	// ! Might have both rdf:value and rdf:resource.
1399 	} else if ( hasPropertyAttrs ) {
1400 		childNode->options |= kXMP_PropValueIsStruct;
1401 		childIsStruct = true;
1402 	}
1403 
1404 	currAttr = xmlNode.attrs.begin();
1405 	endAttr  = xmlNode.attrs.end();
1406 
1407 	for ( ; currAttr != endAttr; ++currAttr ) {
1408 
1409 		if ( *currAttr == valueNode ) continue;	// Skip the rdf:value or rdf:resource attribute holding the value.
1410 		RDFTermKind attrTerm = GetRDFTermKind ( (*currAttr)->name );
1411 
1412 		switch ( attrTerm ) {
1413 
1414 			case kRDFTerm_ID       :
1415 			case kRDFTerm_nodeID   :
1416 				break;	// Ignore all rdf:ID and rdf:nodeID attributes.
1417 
1418 			case kRDFTerm_resource :
1419 				this->AddQualifierNode ( childNode, **currAttr );
1420 				break;
1421 
1422 			case kRDFTerm_Other :
1423 				if ( (! childIsStruct) || (*currAttr)->name == "xml:lang" ) {
1424 					this->AddQualifierNode ( childNode, **currAttr );
1425 				} else {
1426 					this->AddChildNode ( childNode, **currAttr, (*currAttr)->value.c_str(), false );
1427 				}
1428 				break;
1429 
1430 			default :
1431 				{
1432 					XMP_Error error ( kXMPErr_BadRDF, "Unrecognized attribute of empty property element" );
1433 					this->errorCallback->NotifyClient ( kXMPErrSev_Recoverable, error );
1434 				}
1435 				continue;
1436 
1437 		}
1438 
1439 	}
1440 
1441 }	// RDF_Parser::EmptyPropertyElement
1442 
1443 // =================================================================================================
1444 // XMPMeta::ProcessRDF
1445 // ===================
1446 //
1447 // Parse the XML tree of the RDF and build the corresponding XMP tree.
1448 
ProcessRDF(const XML_Node & rdfNode,XMP_OptionBits options)1449 void XMPMeta::ProcessRDF ( const XML_Node & rdfNode, XMP_OptionBits options )
1450 {
1451 	IgnoreParam(options);
1452 
1453 	RDF_Parser parser ( &this->errorCallback );
1454 
1455 	parser.RDF ( &this->tree, rdfNode );
1456 
1457 }	// XMPMeta::ProcessRDF
1458 
1459 // =================================================================================================
1460