~ubuntu-branches/debian/lenny/exiv2/lenny

« back to all changes in this revision

Viewing changes to xmpsdk/src/XMPMeta-GetSet.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Mark Purcell
  • Date: 2008-06-21 08:23:53 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20080621082353-b1n4w08trwfwbfl4
Tags: 0.17.1-1
* New upstream release
  - Library transition cleared on debian-release/ d-d-a
* Version 0.17 also fixes:
  - CVE-2008-2696: DoS via metadata in images (Closes: #486328)
  - crashes when fed with wrong file (Closes: #485670)
* Urgency medium for CVE fix
* debian/patches/gcc4.3.diff unecessary for gcc-4.3
* Add /usr/share/bug/exiv2/presubj message for reportbug(1)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// =================================================================================================
 
2
// Copyright 2002-2007 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
 
73
SetNodeValue ( XMP_Node * node, XMP_StringPtr value )
 
74
{
 
75
 
 
76
        #if XMP_DebugBuild      // ! Hack to force an assert.
 
77
                if ( (node->name == "xap:TestAssertNotify") && XMP_LitMatch ( value, "DoIt!" ) ) {
 
78
                        XMP_Assert ( node->name != "xap: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
 
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
 
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
 
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
 
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
 
343
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
 
372
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
 
396
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
 
421
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
703
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
 
722
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
 
742
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
 
763
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
 
784
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
 
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
 
980
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
 
1006
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
 
1032
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
 
1058
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
 
1084
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
 
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
 
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
 
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
 
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
 
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
// =================================================================================================