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