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 // Adobe patent application tracking #P435, entitled 'Unique markers to simplify embedding data of
9 // one format in a file with a different format', inventors: Sean Parent, Greg Gilley.
10 // =================================================================================================
11
12 #include "XMP_Environment.h" // ! This must be the first include!
13 #include "XMPCore_Impl.hpp"
14
15 #include "XMPMeta.hpp"
16 #include "XMPIterator.hpp"
17 #include "XMPUtils.hpp"
18
19 #include "XMP_Version.h"
20 #include "UnicodeInlines.incl_cpp"
21 #include "UnicodeConversions.hpp"
22 #include "ExpatAdapter.hpp"
23
24 #if XMP_DebugBuild
25 #include <iostream>
26 #endif
27
28 using namespace std;
29
30 #if XMP_WinBuild
31 #pragma warning ( disable : 4533 ) // initialization of '...' is skipped by 'goto ...'
32 #pragma warning ( disable : 4702 ) // unreachable code
33 #pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
34 #endif
35
36
37 // *** Use the XMP_PropIsXyz (Schema, Simple, Struct, Array, ...) macros
38 // *** Add debug codegen checks, e.g. that typical masking operations really work
39 // *** Change all uses of strcmp and strncmp to XMP_LitMatch and XMP_LitNMatch
40
41
42 // =================================================================================================
43 // Local Types and Constants
44 // =========================
45
46 typedef unsigned char XMP_CLTMatch;
47
48 enum { // Values for XMP_CLTMatch.
49 kXMP_CLT_NoValues,
50 kXMP_CLT_SpecificMatch,
51 kXMP_CLT_SingleGeneric,
52 kXMP_CLT_MultipleGeneric,
53 kXMP_CLT_XDefault,
54 kXMP_CLT_FirstItem
55 };
56
57
58 // =================================================================================================
59 // Static Variables
60 // ================
61
62
63 // =================================================================================================
64 // Local Utilities
65 // ===============
66
67
68 // -------------------------------------------------------------------------------------------------
69 // SetNodeValue
70 // ------------
71
72 static inline void
SetNodeValue(XMP_Node * node,XMP_StringPtr value)73 SetNodeValue ( XMP_Node * node, XMP_StringPtr value )
74 {
75
76 #if XMP_DebugBuild // ! Hack to force an assert.
77 if ( (node->name == "xmp:TestAssertNotify") && XMP_LitMatch ( value, "DoIt!" ) ) {
78 XMP_Assert ( node->name != "xmp:TestAssertNotify" );
79 }
80 #endif
81
82 node->value = value;
83
84 XMP_Uns8* chPtr = (XMP_Uns8*) node->value.c_str(); // Check for valid UTF-8, replace ASCII controls with a space.
85 while ( *chPtr != 0 ) {
86 while ( (*chPtr != 0) && (*chPtr < 0x80) ) {
87 if ( *chPtr < 0x20 ) {
88 if ( (*chPtr != kTab) && (*chPtr != kLF) && (*chPtr != kCR) ) *chPtr = 0x20;
89 } else if (*chPtr == 0x7F ) {
90 *chPtr = 0x20;
91 }
92 ++chPtr;
93 }
94 XMP_Assert ( (*chPtr == 0) || (*chPtr >= 0x80) );
95 if ( *chPtr != 0 ) (void) GetCodePoint ( (const XMP_Uns8 **) &chPtr ); // Throws for bad UTF-8.
96 }
97
98 if ( XMP_PropIsQualifier(node->options) && (node->name == "xml:lang") ) NormalizeLangValue ( &node->value );
99
100 #if 0 // *** XMP_DebugBuild
101 node->_valuePtr = node->value.c_str();
102 #endif
103
104 } // SetNodeValue
105
106
107 // -------------------------------------------------------------------------------------------------
108 // SetNode
109 // -------
110 //
111 // The internals for SetProperty and related calls, used after the node is found or created.
112
113 static void
SetNode(XMP_Node * node,XMP_StringPtr value,XMP_OptionBits options)114 SetNode ( XMP_Node * node, XMP_StringPtr value, XMP_OptionBits options )
115 {
116 if ( options & kXMP_DeleteExisting ) {
117 XMP_ClearOption ( options, kXMP_DeleteExisting );
118 node->options = options;
119 node->value.erase();
120 node->RemoveChildren();
121 node->RemoveQualifiers();
122 }
123
124 node->options |= options; // Keep options set by FindNode when creating a new node.
125
126 if ( value != 0 ) {
127
128 // This is setting the value of a leaf node.
129 if ( node->options & kXMP_PropCompositeMask ) XMP_Throw ( "Composite nodes can't have values", kXMPErr_BadXPath );
130 XMP_Assert ( node->children.empty() );
131 SetNodeValue ( node, value );
132
133 } else {
134
135 // This is setting up an array or struct.
136 if ( ! node->value.empty() ) XMP_Throw ( "Composite nodes can't have values", kXMPErr_BadXPath );
137 if ( node->options & kXMP_PropCompositeMask ) { // Can't change an array to a struct, or vice versa.
138 if ( (options & kXMP_PropCompositeMask) != (node->options & kXMP_PropCompositeMask) ) {
139 XMP_Throw ( "Requested and existing composite form mismatch", kXMPErr_BadXPath );
140 }
141 }
142 node->RemoveChildren();
143
144 }
145
146 } // SetNode
147
148
149 // -------------------------------------------------------------------------------------------------
150 // DoSetArrayItem
151 // --------------
152
153 static void
DoSetArrayItem(XMP_Node * arrayNode,XMP_Index itemIndex,XMP_StringPtr itemValue,XMP_OptionBits options)154 DoSetArrayItem ( XMP_Node * arrayNode,
155 XMP_Index itemIndex,
156 XMP_StringPtr itemValue,
157 XMP_OptionBits options )
158 {
159 XMP_OptionBits itemLoc = options & kXMP_PropArrayLocationMask;
160 XMP_Index arraySize = arrayNode->children.size();
161
162 options &= ~kXMP_PropArrayLocationMask;
163 options = VerifySetOptions ( options, itemValue );
164
165 // Now locate or create the item node and set the value. Note the index parameter is one-based!
166 // The index can be in the range [0..size+1] or "last", normalize it and check the insert flags.
167 // The order of the normalization checks is important. If the array is empty we end up with an
168 // index and location to set item size+1.
169
170 XMP_Node * itemNode = 0;
171
172 if ( itemIndex == kXMP_ArrayLastItem ) itemIndex = arraySize;
173 if ( (itemIndex == 0) && (itemLoc == kXMP_InsertAfterItem) ) {
174 itemIndex = 1;
175 itemLoc = kXMP_InsertBeforeItem;
176 }
177 if ( (itemIndex == arraySize) && (itemLoc == kXMP_InsertAfterItem) ) {
178 itemIndex += 1;
179 itemLoc = 0;
180 }
181 if ( (itemIndex == arraySize+1) && (itemLoc == kXMP_InsertBeforeItem) ) itemLoc = 0;
182
183 if ( itemIndex == arraySize+1 ) {
184
185 if ( itemLoc != 0 ) XMP_Throw ( "Can't insert before or after implicit new item", kXMPErr_BadIndex );
186 itemNode = new XMP_Node ( arrayNode, kXMP_ArrayItemName, 0 );
187 arrayNode->children.push_back ( itemNode );
188
189 } else {
190
191 if ( (itemIndex < 1) || (itemIndex > arraySize) ) XMP_Throw ( "Array index out of bounds", kXMPErr_BadIndex );
192 --itemIndex; // ! Convert the index to a C zero-based value!
193 if ( itemLoc == 0 ) {
194 itemNode = arrayNode->children[itemIndex];
195 } else {
196 XMP_NodePtrPos itemPos = arrayNode->children.begin() + itemIndex;
197 if ( itemLoc == kXMP_InsertAfterItem ) ++itemPos;
198 itemNode = new XMP_Node ( arrayNode, kXMP_ArrayItemName, 0 );
199 itemPos = arrayNode->children.insert ( itemPos, itemNode );
200 }
201
202 }
203
204 SetNode ( itemNode, itemValue, options );
205
206 } // DoSetArrayItem
207
208
209 // -------------------------------------------------------------------------------------------------
210 // ChooseLocalizedText
211 // -------------------
212 //
213 // 1. Look for an exact match with the specific language.
214 // 2. If a generic language is given, look for partial matches.
215 // 3. Look for an "x-default" item.
216 // 4. Choose the first item.
217
218 static XMP_CLTMatch
ChooseLocalizedText(const XMP_Node * arrayNode,XMP_StringPtr genericLang,XMP_StringPtr specificLang,const XMP_Node ** itemNode)219 ChooseLocalizedText ( const XMP_Node * arrayNode,
220 XMP_StringPtr genericLang,
221 XMP_StringPtr specificLang,
222 const XMP_Node * * itemNode )
223 {
224 const XMP_Node * currItem = 0;
225 const size_t itemLim = arrayNode->children.size();
226 size_t itemNum;
227
228 // See if the array has the right form. Allow empty alt arrays, that is what parsing returns.
229 // *** Should check alt-text bit when that is reliably maintained.
230
231 if ( ! ( XMP_ArrayIsAltText(arrayNode->options) ||
232 (arrayNode->children.empty() && XMP_ArrayIsAlternate(arrayNode->options)) ) ) {
233 XMP_Throw ( "Localized text array is not alt-text", kXMPErr_BadXPath );
234 }
235 if ( arrayNode->children.empty() ) {
236 *itemNode = 0;
237 return kXMP_CLT_NoValues;
238 }
239
240 for ( itemNum = 0; itemNum < itemLim; ++itemNum ) {
241 currItem = arrayNode->children[itemNum];
242 if ( currItem->options & kXMP_PropCompositeMask ) {
243 XMP_Throw ( "Alt-text array item is not simple", kXMPErr_BadXPath );
244 }
245 if ( currItem->qualifiers.empty() || (currItem->qualifiers[0]->name != "xml:lang") ) {
246 XMP_Throw ( "Alt-text array item has no language qualifier", kXMPErr_BadXPath );
247 }
248 }
249
250 // Look for an exact match with the specific language.
251 for ( itemNum = 0; itemNum < itemLim; ++itemNum ) {
252 currItem = arrayNode->children[itemNum];
253 if ( currItem->qualifiers[0]->value == specificLang ) {
254 *itemNode = currItem;
255 return kXMP_CLT_SpecificMatch;
256 }
257 }
258
259 if ( *genericLang != 0 ) {
260
261 // Look for the first partial match with the generic language.
262 const size_t genericLen = strlen ( genericLang );
263 for ( itemNum = 0; itemNum < itemLim; ++itemNum ) {
264 currItem = arrayNode->children[itemNum];
265 XMP_StringPtr currLang = currItem->qualifiers[0]->value.c_str();
266 const size_t currLangSize = currItem->qualifiers[0]->value.size();
267 if ( (currLangSize >= genericLen) &&
268 XMP_LitNMatch ( currLang, genericLang, genericLen ) &&
269 ((currLangSize == genericLen) || (currLang[genericLen] == '-')) ) {
270 *itemNode = currItem;
271 break; // ! Don't return, need to look for other matches.
272 }
273 }
274
275 if ( itemNum < itemLim ) {
276
277 // Look for a second partial match with the generic language.
278 for ( ++itemNum; itemNum < itemLim; ++itemNum ) {
279 currItem = arrayNode->children[itemNum];
280 XMP_StringPtr currLang = currItem->qualifiers[0]->value.c_str();
281 const size_t currLangSize = currItem->qualifiers[0]->value.size();
282 if ( (currLangSize >= genericLen) &&
283 XMP_LitNMatch ( currLang, genericLang, genericLen ) &&
284 ((currLangSize == genericLen) || (currLang[genericLen] == '-')) ) {
285 return kXMP_CLT_MultipleGeneric; // ! Leave itemNode with the first partial match.
286 }
287 }
288 return kXMP_CLT_SingleGeneric; // No second partial match was found.
289
290 }
291
292 }
293
294 // Look for an 'x-default' item.
295 for ( itemNum = 0; itemNum < itemLim; ++itemNum ) {
296 currItem = arrayNode->children[itemNum];
297 if ( currItem->qualifiers[0]->value == "x-default" ) {
298 *itemNode = currItem;
299 return kXMP_CLT_XDefault;
300 }
301 }
302
303 // Everything failed, choose the first item.
304 *itemNode = arrayNode->children[0];
305 return kXMP_CLT_FirstItem;
306
307 } // ChooseLocalizedText
308
309
310 // -------------------------------------------------------------------------------------------------
311 // AppendLangItem
312 // --------------
313
314 static void
AppendLangItem(XMP_Node * arrayNode,XMP_StringPtr itemLang,XMP_StringPtr itemValue)315 AppendLangItem ( XMP_Node * arrayNode, XMP_StringPtr itemLang, XMP_StringPtr itemValue )
316 {
317 XMP_Node * newItem = new XMP_Node ( arrayNode, kXMP_ArrayItemName, itemValue, (kXMP_PropHasQualifiers | kXMP_PropHasLang) );
318 XMP_Node * langQual = new XMP_Node ( newItem, "xml:lang", itemLang, kXMP_PropIsQualifier );
319 newItem->qualifiers.push_back ( langQual );
320
321 if ( (arrayNode->children.empty()) || (langQual->value != "x-default") ) {
322 arrayNode->children.push_back ( newItem );
323 } else {
324 arrayNode->children.insert ( arrayNode->children.begin(), newItem );
325 }
326
327 } // AppendLangItem
328
329
330 // =================================================================================================
331 // Class Methods
332 // =============
333 //
334 //
335 // =================================================================================================
336
337
338 // -------------------------------------------------------------------------------------------------
339 // GetProperty
340 // -----------
341
342 bool
GetProperty(XMP_StringPtr schemaNS,XMP_StringPtr propName,XMP_StringPtr * propValue,XMP_StringLen * valueSize,XMP_OptionBits * options) const343 XMPMeta::GetProperty ( XMP_StringPtr schemaNS,
344 XMP_StringPtr propName,
345 XMP_StringPtr * propValue,
346 XMP_StringLen * valueSize,
347 XMP_OptionBits * options ) const
348 {
349 XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
350 XMP_Assert ( (propValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper.
351
352 XMP_ExpandedXPath expPath;
353 ExpandXPath ( schemaNS, propName, &expPath );
354
355 XMP_Node * propNode = FindConstNode ( &tree, expPath );
356 if ( propNode == 0 ) return false;
357
358 *propValue = propNode->value.c_str();
359 *valueSize = propNode->value.size();
360 *options = propNode->options;
361
362 return true;
363
364 } // GetProperty
365
366
367 // -------------------------------------------------------------------------------------------------
368 // GetArrayItem
369 // ------------
370
371 bool
GetArrayItem(XMP_StringPtr schemaNS,XMP_StringPtr arrayName,XMP_Index itemIndex,XMP_StringPtr * itemValue,XMP_StringLen * valueSize,XMP_OptionBits * options) const372 XMPMeta::GetArrayItem ( XMP_StringPtr schemaNS,
373 XMP_StringPtr arrayName,
374 XMP_Index itemIndex,
375 XMP_StringPtr * itemValue,
376 XMP_StringLen * valueSize,
377 XMP_OptionBits * options ) const
378 {
379 XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
380 XMP_Assert ( (itemValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper.
381
382 XMP_StringPtr itemPath;
383 XMP_StringLen pathLen;
384
385 XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath, &pathLen );
386 return GetProperty ( schemaNS, itemPath, itemValue, valueSize, options );
387
388 } // GetArrayItem
389
390
391 // -------------------------------------------------------------------------------------------------
392 // GetStructField
393 // --------------
394
395 bool
GetStructField(XMP_StringPtr schemaNS,XMP_StringPtr structName,XMP_StringPtr fieldNS,XMP_StringPtr fieldName,XMP_StringPtr * fieldValue,XMP_StringLen * valueSize,XMP_OptionBits * options) const396 XMPMeta::GetStructField ( XMP_StringPtr schemaNS,
397 XMP_StringPtr structName,
398 XMP_StringPtr fieldNS,
399 XMP_StringPtr fieldName,
400 XMP_StringPtr * fieldValue,
401 XMP_StringLen * valueSize,
402 XMP_OptionBits * options ) const
403 {
404 XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper.
405 XMP_Assert ( (fieldValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper.
406
407 XMP_StringPtr fieldPath;
408 XMP_StringLen pathLen;
409
410 XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen );
411 return GetProperty ( schemaNS, fieldPath, fieldValue, valueSize, options );
412
413 } // GetStructField
414
415
416 // -------------------------------------------------------------------------------------------------
417 // GetQualifier
418 // ------------
419
420 bool
GetQualifier(XMP_StringPtr schemaNS,XMP_StringPtr propName,XMP_StringPtr qualNS,XMP_StringPtr qualName,XMP_StringPtr * qualValue,XMP_StringLen * valueSize,XMP_OptionBits * options) const421 XMPMeta::GetQualifier ( XMP_StringPtr schemaNS,
422 XMP_StringPtr propName,
423 XMP_StringPtr qualNS,
424 XMP_StringPtr qualName,
425 XMP_StringPtr * qualValue,
426 XMP_StringLen * valueSize,
427 XMP_OptionBits * options ) const
428 {
429 XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper.
430 XMP_Assert ( (qualValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper.
431
432 XMP_StringPtr qualPath;
433 XMP_StringLen pathLen;
434
435 XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen );
436 return GetProperty ( schemaNS, qualPath, qualValue, valueSize, options );
437
438 } // GetQualifier
439
440
441 // -------------------------------------------------------------------------------------------------
442 // SetProperty
443 // -----------
444
445 // *** Should handle array items specially, calling SetArrayItem.
446
447 void
SetProperty(XMP_StringPtr schemaNS,XMP_StringPtr propName,XMP_StringPtr propValue,XMP_OptionBits options)448 XMPMeta::SetProperty ( XMP_StringPtr schemaNS,
449 XMP_StringPtr propName,
450 XMP_StringPtr propValue,
451 XMP_OptionBits options )
452 {
453 XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
454
455 options = VerifySetOptions ( options, propValue );
456
457 XMP_ExpandedXPath expPath;
458 ExpandXPath ( schemaNS, propName, &expPath );
459
460 XMP_Node * propNode = FindNode ( &tree, expPath, kXMP_CreateNodes, options );
461 if ( propNode == 0 ) XMP_Throw ( "Specified property does not exist", kXMPErr_BadXPath );
462
463 SetNode ( propNode, propValue, options );
464
465 } // SetProperty
466
467
468 // -------------------------------------------------------------------------------------------------
469 // SetArrayItem
470 // ------------
471
472 void
SetArrayItem(XMP_StringPtr schemaNS,XMP_StringPtr arrayName,XMP_Index itemIndex,XMP_StringPtr itemValue,XMP_OptionBits options)473 XMPMeta::SetArrayItem ( XMP_StringPtr schemaNS,
474 XMP_StringPtr arrayName,
475 XMP_Index itemIndex,
476 XMP_StringPtr itemValue,
477 XMP_OptionBits options )
478 {
479 XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
480
481 XMP_ExpandedXPath arrayPath;
482 ExpandXPath ( schemaNS, arrayName, &arrayPath );
483 XMP_Node * arrayNode = FindNode ( &tree, arrayPath, kXMP_ExistingOnly ); // Just lookup, don't try to create.
484 if ( arrayNode == 0 ) XMP_Throw ( "Specified array does not exist", kXMPErr_BadXPath );
485
486 DoSetArrayItem ( arrayNode, itemIndex, itemValue, options );
487
488 } // SetArrayItem
489
490
491 // -------------------------------------------------------------------------------------------------
492 // AppendArrayItem
493 // ---------------
494
495 void
AppendArrayItem(XMP_StringPtr schemaNS,XMP_StringPtr arrayName,XMP_OptionBits arrayOptions,XMP_StringPtr itemValue,XMP_OptionBits options)496 XMPMeta::AppendArrayItem ( XMP_StringPtr schemaNS,
497 XMP_StringPtr arrayName,
498 XMP_OptionBits arrayOptions,
499 XMP_StringPtr itemValue,
500 XMP_OptionBits options )
501 {
502 XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
503
504 arrayOptions = VerifySetOptions ( arrayOptions, 0 );
505 if ( (arrayOptions & ~kXMP_PropArrayFormMask) != 0 ) {
506 XMP_Throw ( "Only array form flags allowed for arrayOptions", kXMPErr_BadOptions );
507 }
508
509 // Locate or create the array. If it already exists, make sure the array form from the options
510 // parameter is compatible with the current state.
511
512 XMP_ExpandedXPath arrayPath;
513 ExpandXPath ( schemaNS, arrayName, &arrayPath );
514 XMP_Node * arrayNode = FindNode ( &tree, arrayPath, kXMP_ExistingOnly ); // Just lookup, don't try to create.
515
516 if ( arrayNode != 0 ) {
517 // The array exists, make sure the form is compatible. Zero arrayForm means take what exists.
518 if ( ! (arrayNode->options & kXMP_PropValueIsArray) ) {
519 XMP_Throw ( "The named property is not an array", kXMPErr_BadXPath );
520 }
521 #if 0
522 // *** Disable for now. Need to do some general rethinking of semantic checks.
523 if ( (arrayOptions != 0) && (arrayOptions != (arrayNode->options & kXMP_PropArrayFormMask)) ) {
524 XMP_Throw ( "Mismatch of existing and specified array form", kXMPErr_BadOptions );
525 }
526 #endif
527 } else {
528 // The array does not exist, try to create it.
529 if ( arrayOptions == 0 ) XMP_Throw ( "Explicit arrayOptions required to create new array", kXMPErr_BadOptions );
530 arrayNode = FindNode ( &tree, arrayPath, kXMP_CreateNodes, arrayOptions );
531 if ( arrayNode == 0 ) XMP_Throw ( "Failure creating array node", kXMPErr_BadXPath );
532 }
533
534 DoSetArrayItem ( arrayNode, kXMP_ArrayLastItem, itemValue, (options | kXMP_InsertAfterItem) );
535
536 } // AppendArrayItem
537
538
539 // -------------------------------------------------------------------------------------------------
540 // SetStructField
541 // --------------
542
543 void
SetStructField(XMP_StringPtr schemaNS,XMP_StringPtr structName,XMP_StringPtr fieldNS,XMP_StringPtr fieldName,XMP_StringPtr fieldValue,XMP_OptionBits options)544 XMPMeta::SetStructField ( XMP_StringPtr schemaNS,
545 XMP_StringPtr structName,
546 XMP_StringPtr fieldNS,
547 XMP_StringPtr fieldName,
548 XMP_StringPtr fieldValue,
549 XMP_OptionBits options )
550 {
551 XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper.
552
553 XMP_StringPtr fieldPath;
554 XMP_StringLen pathLen;
555
556 XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen );
557 SetProperty ( schemaNS, fieldPath, fieldValue, options );
558
559 } // SetStructField
560
561
562 // -------------------------------------------------------------------------------------------------
563 // SetQualifier
564 // ------------
565
566 void
SetQualifier(XMP_StringPtr schemaNS,XMP_StringPtr propName,XMP_StringPtr qualNS,XMP_StringPtr qualName,XMP_StringPtr qualValue,XMP_OptionBits options)567 XMPMeta::SetQualifier ( XMP_StringPtr schemaNS,
568 XMP_StringPtr propName,
569 XMP_StringPtr qualNS,
570 XMP_StringPtr qualName,
571 XMP_StringPtr qualValue,
572 XMP_OptionBits options )
573 {
574 XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper.
575
576 XMP_StringPtr qualPath;
577 XMP_StringLen pathLen;
578
579 XMP_ExpandedXPath expPath;
580 ExpandXPath ( schemaNS, propName, &expPath );
581 XMP_Node * propNode = FindNode ( &tree, expPath, kXMP_ExistingOnly );
582 if ( propNode == 0 ) XMP_Throw ( "Specified property does not exist", kXMPErr_BadXPath );
583
584 XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen );
585 SetProperty ( schemaNS, qualPath, qualValue, options );
586
587 } // SetQualifier
588
589
590 // -------------------------------------------------------------------------------------------------
591 // DeleteProperty
592 // --------------
593
594 void
DeleteProperty(XMP_StringPtr schemaNS,XMP_StringPtr propName)595 XMPMeta::DeleteProperty ( XMP_StringPtr schemaNS,
596 XMP_StringPtr propName )
597 {
598 XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
599
600 XMP_ExpandedXPath expPath;
601 ExpandXPath ( schemaNS, propName, &expPath );
602
603 XMP_NodePtrPos ptrPos;
604 XMP_Node * propNode = FindNode ( &tree, expPath, kXMP_ExistingOnly, kXMP_NoOptions, &ptrPos );
605 if ( propNode == 0 ) return;
606 XMP_Node * parentNode = propNode->parent;
607
608 // Erase the pointer from the parent's vector, then delete the node and all below it.
609
610 if ( ! (propNode->options & kXMP_PropIsQualifier) ) {
611
612 parentNode->children.erase ( ptrPos );
613 DeleteEmptySchema ( parentNode );
614
615 } else {
616
617 if ( propNode->name == "xml:lang" ) {
618 XMP_Assert ( parentNode->options & kXMP_PropHasLang ); // *** &= ~flag would be safer
619 parentNode->options ^= kXMP_PropHasLang;
620 } else if ( propNode->name == "rdf:type" ) {
621 XMP_Assert ( parentNode->options & kXMP_PropHasType );
622 parentNode->options ^= kXMP_PropHasType;
623 }
624
625 parentNode->qualifiers.erase ( ptrPos );
626 XMP_Assert ( parentNode->options & kXMP_PropHasQualifiers );
627 if ( parentNode->qualifiers.empty() ) parentNode->options ^= kXMP_PropHasQualifiers;
628
629 }
630
631 delete propNode; // ! The destructor takes care of the whole subtree.
632
633 } // DeleteProperty
634
635
636 // -------------------------------------------------------------------------------------------------
637 // DeleteArrayItem
638 // ---------------
639
640 void
DeleteArrayItem(XMP_StringPtr schemaNS,XMP_StringPtr arrayName,XMP_Index itemIndex)641 XMPMeta::DeleteArrayItem ( XMP_StringPtr schemaNS,
642 XMP_StringPtr arrayName,
643 XMP_Index itemIndex )
644 {
645 XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
646
647 XMP_StringPtr itemPath;
648 XMP_StringLen pathLen;
649
650 XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath, &pathLen );
651 DeleteProperty ( schemaNS, itemPath );
652
653 } // DeleteArrayItem
654
655
656 // -------------------------------------------------------------------------------------------------
657 // DeleteStructField
658 // -----------------
659
660 void
DeleteStructField(XMP_StringPtr schemaNS,XMP_StringPtr structName,XMP_StringPtr fieldNS,XMP_StringPtr fieldName)661 XMPMeta::DeleteStructField ( XMP_StringPtr schemaNS,
662 XMP_StringPtr structName,
663 XMP_StringPtr fieldNS,
664 XMP_StringPtr fieldName )
665 {
666 XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper.
667
668 XMP_StringPtr fieldPath;
669 XMP_StringLen pathLen;
670
671 XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen );
672 DeleteProperty ( schemaNS, fieldPath );
673
674 } // DeleteStructField
675
676
677 // -------------------------------------------------------------------------------------------------
678 // DeleteQualifier
679 // ---------------
680
681 void
DeleteQualifier(XMP_StringPtr schemaNS,XMP_StringPtr propName,XMP_StringPtr qualNS,XMP_StringPtr qualName)682 XMPMeta::DeleteQualifier ( XMP_StringPtr schemaNS,
683 XMP_StringPtr propName,
684 XMP_StringPtr qualNS,
685 XMP_StringPtr qualName )
686 {
687 XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper.
688
689 XMP_StringPtr qualPath;
690 XMP_StringLen pathLen;
691
692 XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen );
693 DeleteProperty ( schemaNS, qualPath );
694
695 } // DeleteQualifier
696
697
698 // -------------------------------------------------------------------------------------------------
699 // DoesPropertyExist
700 // -----------------
701
702 bool
DoesPropertyExist(XMP_StringPtr schemaNS,XMP_StringPtr propName) const703 XMPMeta::DoesPropertyExist ( XMP_StringPtr schemaNS,
704 XMP_StringPtr propName ) const
705 {
706 XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
707
708 XMP_ExpandedXPath expPath;
709 ExpandXPath ( schemaNS, propName, &expPath );
710
711 XMP_Node * propNode = FindConstNode ( &tree, expPath );
712 return (propNode != 0);
713
714 } // DoesPropertyExist
715
716
717 // -------------------------------------------------------------------------------------------------
718 // DoesArrayItemExist
719 // ------------------
720
721 bool
DoesArrayItemExist(XMP_StringPtr schemaNS,XMP_StringPtr arrayName,XMP_Index itemIndex) const722 XMPMeta::DoesArrayItemExist ( XMP_StringPtr schemaNS,
723 XMP_StringPtr arrayName,
724 XMP_Index itemIndex ) const
725 {
726 XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
727
728 XMP_StringPtr itemPath;
729 XMP_StringLen pathLen;
730
731 XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath, &pathLen );
732 return DoesPropertyExist ( schemaNS, itemPath );
733
734 } // DoesArrayItemExist
735
736
737 // -------------------------------------------------------------------------------------------------
738 // DoesStructFieldExist
739 // --------------------
740
741 bool
DoesStructFieldExist(XMP_StringPtr schemaNS,XMP_StringPtr structName,XMP_StringPtr fieldNS,XMP_StringPtr fieldName) const742 XMPMeta::DoesStructFieldExist ( XMP_StringPtr schemaNS,
743 XMP_StringPtr structName,
744 XMP_StringPtr fieldNS,
745 XMP_StringPtr fieldName ) const
746 {
747 XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper.
748
749 XMP_StringPtr fieldPath;
750 XMP_StringLen pathLen;
751
752 XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen );
753 return DoesPropertyExist ( schemaNS, fieldPath );
754
755 } // DoesStructFieldExist
756
757
758 // -------------------------------------------------------------------------------------------------
759 // DoesQualifierExist
760 // ------------------
761
762 bool
DoesQualifierExist(XMP_StringPtr schemaNS,XMP_StringPtr propName,XMP_StringPtr qualNS,XMP_StringPtr qualName) const763 XMPMeta::DoesQualifierExist ( XMP_StringPtr schemaNS,
764 XMP_StringPtr propName,
765 XMP_StringPtr qualNS,
766 XMP_StringPtr qualName ) const
767 {
768 XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper.
769
770 XMP_StringPtr qualPath;
771 XMP_StringLen pathLen;
772
773 XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen );
774 return DoesPropertyExist ( schemaNS, qualPath );
775
776 } // DoesQualifierExist
777
778
779 // -------------------------------------------------------------------------------------------------
780 // GetLocalizedText
781 // ----------------
782
783 bool
GetLocalizedText(XMP_StringPtr schemaNS,XMP_StringPtr arrayName,XMP_StringPtr _genericLang,XMP_StringPtr _specificLang,XMP_StringPtr * actualLang,XMP_StringLen * langSize,XMP_StringPtr * itemValue,XMP_StringLen * valueSize,XMP_OptionBits * options) const784 XMPMeta::GetLocalizedText ( XMP_StringPtr schemaNS,
785 XMP_StringPtr arrayName,
786 XMP_StringPtr _genericLang,
787 XMP_StringPtr _specificLang,
788 XMP_StringPtr * actualLang,
789 XMP_StringLen * langSize,
790 XMP_StringPtr * itemValue,
791 XMP_StringLen * valueSize,
792 XMP_OptionBits * options ) const
793 {
794 XMP_Assert ( (schemaNS != 0) && (arrayName != 0) && (_genericLang != 0) && (_specificLang != 0) ); // Enforced by wrapper.
795 XMP_Assert ( (actualLang != 0) && (langSize != 0) ); // Enforced by wrapper.
796 XMP_Assert ( (itemValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper.
797
798 XMP_VarString zGenericLang ( _genericLang );
799 XMP_VarString zSpecificLang ( _specificLang );
800 NormalizeLangValue ( &zGenericLang );
801 NormalizeLangValue ( &zSpecificLang );
802
803 XMP_StringPtr genericLang = zGenericLang.c_str();
804 XMP_StringPtr specificLang = zSpecificLang.c_str();
805
806 XMP_ExpandedXPath arrayPath;
807 ExpandXPath ( schemaNS, arrayName, &arrayPath );
808
809 const XMP_Node * arrayNode = FindConstNode ( &tree, arrayPath ); // *** This expand/find idiom is used in 3 Getters.
810 if ( arrayNode == 0 ) return false; // *** Should extract it into a local utility.
811
812 XMP_CLTMatch match;
813 const XMP_Node * itemNode;
814
815 match = ChooseLocalizedText ( arrayNode, genericLang, specificLang, &itemNode );
816 if ( match == kXMP_CLT_NoValues ) return false;
817
818 *actualLang = itemNode->qualifiers[0]->value.c_str();
819 *langSize = itemNode->qualifiers[0]->value.size();
820 *itemValue = itemNode->value.c_str();
821 *valueSize = itemNode->value.size();
822 *options = itemNode->options;
823
824 return true;
825
826 } // GetLocalizedText
827
828
829 // -------------------------------------------------------------------------------------------------
830 // SetLocalizedText
831 // ----------------
832
833 void
SetLocalizedText(XMP_StringPtr schemaNS,XMP_StringPtr arrayName,XMP_StringPtr _genericLang,XMP_StringPtr _specificLang,XMP_StringPtr itemValue,XMP_OptionBits options)834 XMPMeta::SetLocalizedText ( XMP_StringPtr schemaNS,
835 XMP_StringPtr arrayName,
836 XMP_StringPtr _genericLang,
837 XMP_StringPtr _specificLang,
838 XMP_StringPtr itemValue,
839 XMP_OptionBits options )
840 {
841 options = options; // Avoid unused parameter warning.
842
843 XMP_Assert ( (schemaNS != 0) && (arrayName != 0) && (_genericLang != 0) && (_specificLang != 0) ); // Enforced by wrapper.
844
845 XMP_VarString zGenericLang ( _genericLang );
846 XMP_VarString zSpecificLang ( _specificLang );
847 NormalizeLangValue ( &zGenericLang );
848 NormalizeLangValue ( &zSpecificLang );
849
850 XMP_StringPtr genericLang = zGenericLang.c_str();
851 XMP_StringPtr specificLang = zSpecificLang.c_str();
852
853 XMP_ExpandedXPath arrayPath;
854 ExpandXPath ( schemaNS, arrayName, &arrayPath );
855
856 // Find the array node and set the options if it was just created.
857 XMP_Node * arrayNode = FindNode ( &tree, arrayPath, kXMP_CreateNodes,
858 (kXMP_PropValueIsArray | kXMP_PropArrayIsOrdered | kXMP_PropArrayIsAlternate) );
859 if ( arrayNode == 0 ) XMP_Throw ( "Failed to find or create array node", kXMPErr_BadXPath );
860 if ( ! XMP_ArrayIsAltText(arrayNode->options) ) {
861 if ( arrayNode->children.empty() && XMP_ArrayIsAlternate(arrayNode->options) ) {
862 arrayNode->options |= kXMP_PropArrayIsAltText;
863 } else {
864 XMP_Throw ( "Localized text array is not alt-text", kXMPErr_BadXPath );
865 }
866 }
867
868 // Make sure the x-default item, if any, is first.
869
870 size_t itemNum, itemLim;
871 XMP_Node * xdItem = 0;
872 bool haveXDefault = false;
873
874 for ( itemNum = 0, itemLim = arrayNode->children.size(); itemNum < itemLim; ++itemNum ) {
875 XMP_Node * currItem = arrayNode->children[itemNum];
876 XMP_Assert ( XMP_PropHasLang(currItem->options) );
877 if ( currItem->qualifiers.empty() || (currItem->qualifiers[0]->name != "xml:lang") ) {
878 XMP_Throw ( "Language qualifier must be first", kXMPErr_BadXPath );
879 }
880 if ( currItem->qualifiers[0]->value == "x-default" ) {
881 xdItem = currItem;
882 haveXDefault = true;
883 break;
884 }
885 }
886
887 if ( haveXDefault && (itemNum != 0) ) {
888 XMP_Assert ( arrayNode->children[itemNum]->qualifiers[0]->value == "x-default" );
889 XMP_Node * temp = arrayNode->children[0];
890 arrayNode->children[0] = arrayNode->children[itemNum];
891 arrayNode->children[itemNum] = temp;
892 }
893
894 // Find the appropriate item. ChooseLocalizedText will make sure the array is a language alternative.
895
896 const XMP_Node * cItemNode; // ! ChooseLocalizedText returns a pointer to a const node.
897 XMP_CLTMatch match = ChooseLocalizedText ( arrayNode, genericLang, specificLang, &cItemNode );
898 XMP_Node * itemNode = const_cast<XMP_Node*> ( cItemNode );
899
900 const bool specificXDefault = XMP_LitMatch ( specificLang, "x-default" );
901
902 switch ( match ) {
903
904 case kXMP_CLT_NoValues :
905
906 // Create the array items for the specificLang and x-default, with x-default first.
907 AppendLangItem ( arrayNode, "x-default", itemValue );
908 haveXDefault = true;
909 if ( ! specificXDefault ) AppendLangItem ( arrayNode, specificLang, itemValue );
910 break;
911
912 case kXMP_CLT_SpecificMatch :
913
914 if ( ! specificXDefault ) {
915 // Update the specific item, update x-default if it matches the old value.
916 if ( haveXDefault && (xdItem != itemNode) && (xdItem->value == itemNode->value) ) {
917 SetNodeValue ( xdItem, itemValue );
918 }
919 SetNodeValue ( itemNode, itemValue ); // ! Do this after the x-default check!
920 } else {
921 // Update all items whose values match the old x-default value.
922 XMP_Assert ( haveXDefault && (xdItem == itemNode) );
923 for ( itemNum = 0, itemLim = arrayNode->children.size(); itemNum < itemLim; ++itemNum ) {
924 XMP_Node * currItem = arrayNode->children[itemNum];
925 if ( (currItem == xdItem) || (currItem->value != xdItem->value) ) continue;
926 SetNodeValue ( currItem, itemValue );
927 }
928 SetNodeValue ( xdItem, itemValue ); // And finally do the x-default item.
929 }
930 break;
931
932 case kXMP_CLT_SingleGeneric :
933
934 // Update the generic item, update x-default if it matches the old value.
935 if ( haveXDefault && (xdItem != itemNode) && (xdItem->value == itemNode->value) ) {
936 SetNodeValue ( xdItem, itemValue );
937 }
938 SetNodeValue ( itemNode, itemValue ); // ! Do this after the x-default check!
939 break;
940
941 case kXMP_CLT_MultipleGeneric :
942
943 // Create the specific language, ignore x-default.
944 AppendLangItem ( arrayNode, specificLang, itemValue );
945 if ( specificXDefault ) haveXDefault = true;
946 break;
947
948 case kXMP_CLT_XDefault :
949
950 // Create the specific language, update x-default if it was the only item.
951 if ( arrayNode->children.size() == 1 ) SetNodeValue ( xdItem, itemValue );
952 AppendLangItem ( arrayNode, specificLang, itemValue );
953 break;
954
955 case kXMP_CLT_FirstItem :
956
957 // Create the specific language, don't add an x-default item.
958 AppendLangItem ( arrayNode, specificLang, itemValue );
959 if ( specificXDefault ) haveXDefault = true;
960 break;
961
962 default :
963 XMP_Throw ( "Unexpected result from ChooseLocalizedText", kXMPErr_InternalFailure );
964
965 }
966
967 // Add an x-default at the front if needed.
968 if ( (! haveXDefault) && (arrayNode->children.size() == 1) ) {
969 AppendLangItem ( arrayNode, "x-default", itemValue );
970 }
971
972 } // SetLocalizedText
973
974
975 // -------------------------------------------------------------------------------------------------
976 // GetProperty_Bool
977 // ----------------
978
979 bool
GetProperty_Bool(XMP_StringPtr schemaNS,XMP_StringPtr propName,bool * propValue,XMP_OptionBits * options) const980 XMPMeta::GetProperty_Bool ( XMP_StringPtr schemaNS,
981 XMP_StringPtr propName,
982 bool * propValue,
983 XMP_OptionBits * options ) const
984 {
985 XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
986 XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper.
987
988 XMP_StringPtr valueStr;
989 XMP_StringLen valueLen;
990
991 bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options );
992 if ( found ) {
993 if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath );
994 *propValue = XMPUtils::ConvertToBool ( valueStr );
995 }
996 return found;
997
998 } // GetProperty_Bool
999
1000
1001 // -------------------------------------------------------------------------------------------------
1002 // GetProperty_Int
1003 // ---------------
1004
1005 bool
GetProperty_Int(XMP_StringPtr schemaNS,XMP_StringPtr propName,XMP_Int32 * propValue,XMP_OptionBits * options) const1006 XMPMeta::GetProperty_Int ( XMP_StringPtr schemaNS,
1007 XMP_StringPtr propName,
1008 XMP_Int32 * propValue,
1009 XMP_OptionBits * options ) const
1010 {
1011 XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
1012 XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper.
1013
1014 XMP_StringPtr valueStr;
1015 XMP_StringLen valueLen;
1016
1017 bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options );
1018 if ( found ) {
1019 if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath );
1020 *propValue = XMPUtils::ConvertToInt ( valueStr );
1021 }
1022 return found;
1023
1024 } // GetProperty_Int
1025
1026
1027 // -------------------------------------------------------------------------------------------------
1028 // GetProperty_Int64
1029 // -----------------
1030
1031 bool
GetProperty_Int64(XMP_StringPtr schemaNS,XMP_StringPtr propName,XMP_Int64 * propValue,XMP_OptionBits * options) const1032 XMPMeta::GetProperty_Int64 ( XMP_StringPtr schemaNS,
1033 XMP_StringPtr propName,
1034 XMP_Int64 * propValue,
1035 XMP_OptionBits * options ) const
1036 {
1037 XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
1038 XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper.
1039
1040 XMP_StringPtr valueStr;
1041 XMP_StringLen valueLen;
1042
1043 bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options );
1044 if ( found ) {
1045 if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath );
1046 *propValue = XMPUtils::ConvertToInt64 ( valueStr );
1047 }
1048 return found;
1049
1050 } // GetProperty_Int64
1051
1052
1053 // -------------------------------------------------------------------------------------------------
1054 // GetProperty_Float
1055 // -----------------
1056
1057 bool
GetProperty_Float(XMP_StringPtr schemaNS,XMP_StringPtr propName,double * propValue,XMP_OptionBits * options) const1058 XMPMeta::GetProperty_Float ( XMP_StringPtr schemaNS,
1059 XMP_StringPtr propName,
1060 double * propValue,
1061 XMP_OptionBits * options ) const
1062 {
1063 XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
1064 XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper.
1065
1066 XMP_StringPtr valueStr;
1067 XMP_StringLen valueLen;
1068
1069 bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options );
1070 if ( found ) {
1071 if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath );
1072 *propValue = XMPUtils::ConvertToFloat ( valueStr );
1073 }
1074 return found;
1075
1076 } // GetProperty_Float
1077
1078
1079 // -------------------------------------------------------------------------------------------------
1080 // GetProperty_Date
1081 // ----------------
1082
1083 bool
GetProperty_Date(XMP_StringPtr schemaNS,XMP_StringPtr propName,XMP_DateTime * propValue,XMP_OptionBits * options) const1084 XMPMeta::GetProperty_Date ( XMP_StringPtr schemaNS,
1085 XMP_StringPtr propName,
1086 XMP_DateTime * propValue,
1087 XMP_OptionBits * options ) const
1088 {
1089 XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
1090 XMP_Assert ( (propValue != 0) && (options != 0) ); // Enforced by wrapper.
1091
1092 XMP_StringPtr valueStr;
1093 XMP_StringLen valueLen;
1094
1095 bool found = GetProperty ( schemaNS, propName, &valueStr, &valueLen, options );
1096 if ( found ) {
1097 if ( ! XMP_PropIsSimple ( *options ) ) XMP_Throw ( "Property must be simple", kXMPErr_BadXPath );
1098 XMPUtils::ConvertToDate ( valueStr, propValue );
1099 }
1100 return found;
1101
1102 } // GetProperty_Date
1103
1104
1105 // -------------------------------------------------------------------------------------------------
1106 // SetProperty_Bool
1107 // ----------------
1108
1109 void
SetProperty_Bool(XMP_StringPtr schemaNS,XMP_StringPtr propName,bool propValue,XMP_OptionBits options)1110 XMPMeta::SetProperty_Bool ( XMP_StringPtr schemaNS,
1111 XMP_StringPtr propName,
1112 bool propValue,
1113 XMP_OptionBits options )
1114 {
1115 XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
1116
1117 XMP_StringPtr valueStr;
1118 XMP_StringLen valueLen;
1119
1120 XMPUtils::ConvertFromBool ( propValue, &valueStr, &valueLen );
1121 SetProperty ( schemaNS, propName, valueStr, options );
1122
1123 } // SetProperty_Bool
1124
1125
1126 // -------------------------------------------------------------------------------------------------
1127 // SetProperty_Int
1128 // ---------------
1129
1130 void
SetProperty_Int(XMP_StringPtr schemaNS,XMP_StringPtr propName,XMP_Int32 propValue,XMP_OptionBits options)1131 XMPMeta::SetProperty_Int ( XMP_StringPtr schemaNS,
1132 XMP_StringPtr propName,
1133 XMP_Int32 propValue,
1134 XMP_OptionBits options )
1135 {
1136 XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
1137
1138 XMP_StringPtr valueStr;
1139 XMP_StringLen valueLen;
1140
1141 XMPUtils::ConvertFromInt ( propValue, "", &valueStr, &valueLen );
1142 SetProperty ( schemaNS, propName, valueStr, options );
1143
1144 } // SetProperty_Int
1145
1146
1147 // -------------------------------------------------------------------------------------------------
1148 // SetProperty_Int64
1149 // -----------------
1150
1151 void
SetProperty_Int64(XMP_StringPtr schemaNS,XMP_StringPtr propName,XMP_Int64 propValue,XMP_OptionBits options)1152 XMPMeta::SetProperty_Int64 ( XMP_StringPtr schemaNS,
1153 XMP_StringPtr propName,
1154 XMP_Int64 propValue,
1155 XMP_OptionBits options )
1156 {
1157 XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
1158
1159 XMP_StringPtr valueStr;
1160 XMP_StringLen valueLen;
1161
1162 XMPUtils::ConvertFromInt64 ( propValue, "", &valueStr, &valueLen );
1163 SetProperty ( schemaNS, propName, valueStr, options );
1164
1165 } // SetProperty_Int64
1166
1167
1168 // -------------------------------------------------------------------------------------------------
1169 // SetProperty_Float
1170 // -----------------
1171
1172 void
SetProperty_Float(XMP_StringPtr schemaNS,XMP_StringPtr propName,double propValue,XMP_OptionBits options)1173 XMPMeta::SetProperty_Float ( XMP_StringPtr schemaNS,
1174 XMP_StringPtr propName,
1175 double propValue,
1176 XMP_OptionBits options )
1177 {
1178 XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
1179
1180 XMP_StringPtr valueStr;
1181 XMP_StringLen valueLen;
1182
1183 XMPUtils::ConvertFromFloat ( propValue, "", &valueStr, &valueLen );
1184 SetProperty ( schemaNS, propName, valueStr, options );
1185
1186 } // SetProperty_Float
1187
1188
1189 // -------------------------------------------------------------------------------------------------
1190 // SetProperty_Date
1191 // ----------------
1192
1193 void
SetProperty_Date(XMP_StringPtr schemaNS,XMP_StringPtr propName,const XMP_DateTime & propValue,XMP_OptionBits options)1194 XMPMeta::SetProperty_Date ( XMP_StringPtr schemaNS,
1195 XMP_StringPtr propName,
1196 const XMP_DateTime & propValue,
1197 XMP_OptionBits options )
1198 {
1199 XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper.
1200
1201 XMP_StringPtr valueStr;
1202 XMP_StringLen valueLen;
1203
1204 XMPUtils::ConvertFromDate ( propValue, &valueStr, &valueLen );
1205 SetProperty ( schemaNS, propName, valueStr, options );
1206
1207 } // SetProperty_Date
1208
1209 // =================================================================================================
1210
1211