Coverage Report

Created: 2026-04-29 07:00

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