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