1
// =================================================================================================
2
// Copyright 2002-2007 Adobe Systems Incorporated
3
// All Rights Reserved.
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.
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
// =================================================================================================
12
#include "XMP_Environment.h" // ! This must be the first include!
13
#include "XMPCore_Impl.hpp"
15
#include "XMPMeta.hpp"
16
#include "XMPIterator.hpp"
17
#include "XMPUtils.hpp"
19
#include "XMP_Version.h"
20
#include "UnicodeInlines.incl_cpp"
21
#include "UnicodeConversions.hpp"
30
#pragma warning ( disable : 4533 ) // initialization of '...' is skipped by 'goto ...'
31
#pragma warning ( disable : 4702 ) // unreachable code
32
#pragma warning ( disable : 4800 ) // forcing value to bool 'true' or 'false' (performance warning)
33
#pragma warning ( disable : 4996 ) // '...' was declared deprecated
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
42
// =================================================================================================
43
// Local Types and Constants
44
// =========================
47
// =================================================================================================
51
XMP_VarString * xdefaultName = 0;
53
// These are embedded version strings.
55
const char * kXMPCore_EmbeddedVersion = kXMPCore_VersionMessage;
56
const char * kXMPCore_EmbeddedCopyright = kXMPCoreName " " kXMP_CopyrightStr;
58
// =================================================================================================
62
#define IsHexDigit(ch) ( (('0' <= (ch)) && ((ch) <= '9')) || (('A' <= (ch)) && ((ch) <= 'F')) )
63
#define HexDigitValue(ch) ( (((ch) - '0') < 10) ? ((ch) - '0') : ((ch) - 'A' + 10) )
65
static const char * kTenSpaces = " ";
66
#define OutProcPadding(pad) { size_t padLen = (pad); \
67
for ( ; padLen >= 10; padLen -= 10 ) OutProcNChars ( kTenSpaces, 10 ); \
68
for ( ; padLen > 0; padLen -= 1 ) OutProcNChars ( " ", 1 ); }
71
#define OutProcNewline() { status = (*outProc) ( refCon, "\n", 1 ); if ( status != 0 ) goto EXIT; }
73
#define OutProcNChars(p,n) { status = (*outProc) ( refCon, (p), (n) ); if ( status != 0 ) goto EXIT; }
75
#define OutProcLiteral(lit) { status = (*outProc) ( refCon, (lit), strlen(lit) ); if ( status != 0 ) goto EXIT; }
77
#define OutProcString(str) { status = (*outProc) ( refCon, (str).c_str(), (str).size() ); if ( status != 0 ) goto EXIT; }
79
#define OutProcULong(num) { snprintf ( buffer, sizeof(buffer), "%lu", (num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \
80
status = (*outProc) ( refCon, buffer, strlen(buffer) ); if ( status != 0 ) goto EXIT; }
82
#define OutProcHexInt(num) { snprintf ( buffer, sizeof(buffer), "%lX", (num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \
83
status = (*outProc) ( refCon, buffer, strlen(buffer) ); if ( status != 0 ) goto EXIT; }
85
static const char * kIndent = " ";
86
#define OutProcIndent(lev) { for ( size_t i = 0; i < (lev); ++i ) OutProcNChars ( kIndent, 3 ); }
89
// -------------------------------------------------------------------------------------------------
94
DumpStringMap ( const XMP_StringMap & map, XMP_StringPtr label, XMP_TextOutputProc outProc, void * refCon )
97
XMP_cStringMapPos currPos;
98
XMP_cStringMapPos endPos = map.end();
101
for ( currPos = map.begin(); currPos != endPos; ++currPos ) {
102
size_t currLen = currPos->first.size();
103
if ( currLen > maxLen ) maxLen = currLen;
107
OutProcLiteral ( label );
110
for ( currPos = map.begin(); currPos != endPos; ++currPos ) {
111
OutProcNChars ( " ", 2 );
112
OutProcString ( currPos->first );
113
OutProcPadding ( maxLen - currPos->first.size() );
114
OutProcNChars ( " => ", 4 );
115
OutProcString ( currPos->second );
125
// -------------------------------------------------------------------------------------------------
130
DumpNodeOptions ( XMP_OptionBits options,
131
XMP_TextOutputProc outProc,
135
char buffer [32]; // Decimal of a 64 bit int is at most about 20 digits.
137
static const char * optNames[] = { " schema", // 0x8000_0000
141
" ?27", // 0x0800_0000
145
" ?23", // 0x0080_0000
149
" ?19", // 0x0008_0000
153
" -AFTER-", // 0x0000_8000
157
" isAlt", // 0x0000_0800
161
" hasType", // 0x0000_0080
165
" ?3", // 0x0000_0008
170
if ( options == 0 ) {
172
OutProcNChars ( "(0x0)", 5 );
176
OutProcNChars ( "(0x", 3 );
177
OutProcHexInt ( options );
178
OutProcNChars ( " :", 2 );
180
XMP_OptionBits mask = 0x80000000;
181
for ( int b = 0; b < 32; ++b ) {
182
if ( options & mask ) OutProcLiteral ( optNames[b] );
185
OutProcNChars ( ")", 1 );
195
// -------------------------------------------------------------------------------------------------
199
// *** Extract the validation code into a separate routine to call on exit in debug builds.
202
DumpPropertyTree ( const XMP_Node * currNode,
205
XMP_TextOutputProc outProc,
209
char buffer [32]; // Decimal of a 64 bit int is at most about 20 digits.
211
OutProcIndent ( (size_t)indent );
212
if ( itemIndex == 0 ) {
213
if ( currNode->options & kXMP_PropIsQualifier ) OutProcNChars ( "? ", 2 );
214
OutProcString ( currNode->name );
216
OutProcNChars ( "[", 1 );
217
OutProcULong ( static_cast<unsigned long>(itemIndex) );
218
OutProcNChars ( "]", 1 );
221
if ( ! (currNode->options & kXMP_PropCompositeMask) ) {
222
OutProcNChars ( " = \"", 4 );
223
OutProcString ( currNode->value );
224
OutProcNChars ( "\"", 1 );
227
if ( currNode->options != 0 ) {
228
OutProcNChars ( " ", 2 );
229
status = DumpNodeOptions ( currNode->options, outProc, refCon );
230
if ( status != 0 ) goto EXIT;
233
if ( currNode->options & kXMP_PropHasLang ) {
234
if ( currNode->qualifiers.empty() || (currNode->qualifiers[0]->name != "xml:lang") ) {
235
OutProcLiteral ( " ** bad lang flag **" );
238
// *** Check rdf:type also.
240
if ( ! (currNode->options & kXMP_PropCompositeMask) ) {
241
if ( ! currNode->children.empty() ) OutProcLiteral ( " ** bad children **" );
242
} else if ( currNode->options & kXMP_PropValueIsArray ) {
243
if ( currNode->options & kXMP_PropValueIsStruct ) OutProcLiteral ( " ** bad comp flags **" );
244
} else if ( (currNode->options & kXMP_PropCompositeMask) != kXMP_PropValueIsStruct ) {
245
OutProcLiteral ( " ** bad comp flags **" );
248
#if 0 // *** XMP_DebugBuild
249
if ( (currNode->_namePtr != currNode->name.c_str()) ||
250
(currNode->_valuePtr != currNode->value.c_str()) ) OutProcLiteral ( " ** bad debug string **" );
255
for ( size_t qualNum = 0, qualLim = currNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
257
const XMP_Node * currQual = currNode->qualifiers[qualNum];
259
if ( currQual->parent != currNode ) OutProcLiteral ( "** bad parent link => " );
260
if ( currQual->name == kXMP_ArrayItemName ) OutProcLiteral ( "** bad qual name => " );
261
if ( ! (currQual->options & kXMP_PropIsQualifier) ) OutProcLiteral ( "** bad qual flag => " );
262
if ( currQual->name == "xml:lang" ) {
263
if ( (qualNum != 0) || (! (currNode->options & kXMP_PropHasLang)) ) OutProcLiteral ( "** bad lang qual => " );
266
status = DumpPropertyTree ( currQual, indent+2, 0, outProc, refCon );
267
if ( status != 0 ) goto EXIT;
271
for ( size_t childNum = 0, childLim = currNode->children.size(); childNum < childLim; ++childNum ) {
273
const XMP_Node * currChild = currNode->children[childNum];
275
if ( currChild->parent != currNode ) OutProcLiteral ( "** bad parent link => " );
276
if ( currChild->options & kXMP_PropIsQualifier ) OutProcLiteral ( "** bad qual flag => " );
278
if ( currNode->options & kXMP_PropValueIsArray ) {
279
itemIndex = childNum+1;
280
if ( currChild->name != kXMP_ArrayItemName ) OutProcLiteral ( "** bad item name => " );
283
if ( currChild->name == kXMP_ArrayItemName ) OutProcLiteral ( "** bad field name => " );
286
status = DumpPropertyTree ( currChild, indent+1, itemIndex, outProc, refCon );
287
if ( status != 0 ) goto EXIT;
294
} // DumpPropertyTree
297
// -------------------------------------------------------------------------------------------------
303
static inline void PutHexByte ( FILE * log, unsigned char ch )
306
fprintf ( log, "\\x" );
308
fprintf ( log, "%c", kHexDigits[ch] );
310
fprintf ( log, "%c%c", kHexDigits[ch>>4], kHexDigits[ch&0xF] );
315
// -------------------------------------------------------------------------------------------------
317
static void PutClearString ( FILE * log, const std::string & str )
320
for ( size_t i = 0; i != str.size(); ++i ) {
321
unsigned char ch = str[i];
322
if ( (0x20 <= ch) && (ch <= 0x7F) ) {
323
fprintf ( log, "%c", ch );
325
PutHexByte ( log, ch );
331
// -------------------------------------------------------------------------------------------------
333
static void DumpXMLTree ( FILE * log, const XML_Node & node, int indent )
337
#if 0 // *** XMP_DebugBuild
338
if ( (node._namePtr != node.name.c_str()) ||
339
(node._valuePtr != node.value.c_str()) ) fprintf ( log, "*** bad debug string ***\n" );
342
for ( i = 0; i != (size_t)indent; ++i ) fprintf ( log, " " );
344
switch ( node.kind ) {
347
fprintf ( log, "\nStart of XML tree dump\n\n" );
348
if ( (indent != 0) || (! node.attrs.empty()) ||
349
(! node.ns.empty()) || (! node.name.empty()) || (!node.value.empty()) ) fprintf ( log, " ** invalid root ** \n" );
350
for ( i = 0; i < node.children.size(); ++i ) {
351
XMP_Uns8 kind = node.children[i]->kind;
352
if ( (kind == kRootNode) || (kind == kAttrNode) ) fprintf ( log, " ** invalid child ** \n" );
353
DumpXMLTree ( log, *node.children[i], indent+1 );
355
fprintf ( log, "\nEnd of XML tree dump\n" );
359
fprintf ( log, "Elem %s", node.name.c_str() );
360
if ( indent == 0 ) fprintf ( log, " ** invalid elem ** " );
361
if ( ! node.ns.empty() ) fprintf ( log, " @ %s", node.ns.c_str() );
362
fprintf ( log, "\n" );
363
for ( i = 0; i < node.attrs.size(); ++i ) {
364
XMP_Uns8 kind = node.attrs[i]->kind;
365
if ( kind != kAttrNode ) fprintf ( log, " ** invalid attr ** \n" );
366
DumpXMLTree ( log, *node.attrs[i], indent+2 );
368
for ( i = 0; i < node.children.size(); ++i ) {
369
XMP_Uns8 kind = node.children[i]->kind;
370
if ( (kind == kRootNode) || (kind == kAttrNode) ) fprintf ( log, " ** invalid child ** \n" );
371
DumpXMLTree ( log, *node.children[i], indent+1 );
376
fprintf ( log, "Attr %s", node.name.c_str() );
377
if ( (indent == 0) || node.name.empty() || (! node.attrs.empty()) || (! node.children.empty()) ) fprintf ( log, " ** invalid attr ** " );
378
fprintf ( log, " = \"" );
379
PutClearString ( log, node.value );
380
fprintf ( log, "\"" );
381
if ( ! node.ns.empty() ) fprintf ( log, " @ %s", node.ns.c_str() );
382
fprintf ( log, "\n" );
386
if ( (indent == 0) || (! node.ns.empty()) || (! node.name.empty()) ||
387
(! node.attrs.empty()) || (! node.children.empty()) ) fprintf ( log, " ** invalid cdata ** \n" );
388
fprintf ( log, "\"" );
389
PutClearString ( log, node.value );
390
fprintf ( log, "\"\n" );
394
fprintf ( log, "PI %s", node.name.c_str() );
395
if ( (indent == 0) || node.name.empty() || (! node.children.empty()) ) fprintf ( log, " ** invalid pi ** \n" );
396
if ( ! node.value.empty() ) {
397
fprintf ( log, " <? " );
398
PutClearString ( log, node.value );
399
fprintf ( log, " ?>" );
401
fprintf ( log, "\n" );
408
#endif // DumpXMLParseTree
411
// =================================================================================================
416
XMPMeta::XMPMeta() : clientRefs(0), prevTkVer(0), tree(XMP_Node(0,"",0)), xmlParser(0)
418
// Nothing more to do, clientRefs is incremented in wrapper.
419
#if XMP_TraceCTorDTor
420
printf ( "Default construct XMPMeta @ %.8X\n", this );
424
// -------------------------------------------------------------------------------------------------
426
XMPMeta::~XMPMeta() RELEASE_NO_THROW
428
#if XMP_TraceCTorDTor
429
printf ( "Destruct XMPMeta @ %.8X\n", this );
432
XMP_Assert ( this->clientRefs <= 0 );
433
if ( xmlParser != 0 ) delete ( xmlParser );
439
// =================================================================================================
440
// Class Static Functions
441
// ======================
444
// =================================================================================================
446
// -------------------------------------------------------------------------------------------------
450
/* class-static */ void
451
XMPMeta::GetVersionInfo ( XMP_VersionInfo * info )
454
memset ( info, 0, sizeof(XMP_VersionInfo) );
456
info->major = XMP_API_VERSION_MAJOR;
457
info->minor = XMP_API_VERSION_MINOR;
458
info->micro = XMP_API_VERSION_MICRO;
459
info->isDebug = kXMPCore_DebugFlag;
460
info->flags = 0; // ! None defined yet.
461
info->message = kXMPCore_VersionMessage;
465
// -------------------------------------------------------------------------------------------------
469
/* class-static */ bool
470
XMPMeta::Initialize()
472
// Allocate and initialize static objects.
475
if ( sXMP_InitCount > 1 ) return true;
478
// xmpOut = fopen ( "xmp.out", "w" ); // Coordinate with client glue in WXMP_Common.hpp
479
fprintf ( xmpOut, "XMP initializing\n" ); fflush ( xmpOut );
482
sExceptionMessage = new XMP_VarString();
483
XMP_InitMutex ( &sXMPCoreLock );
484
sOutputNS = new XMP_VarString;
485
sOutputStr = new XMP_VarString;
487
xdefaultName = new XMP_VarString ( "x-default" );
489
sNamespaceURIToPrefixMap = new XMP_StringMap;
490
sNamespacePrefixToURIMap = new XMP_StringMap;
491
sRegisteredAliasMap = new XMP_AliasMap;
493
InitializeUnicodeConversions();
495
// Register standard namespaces and aliases.
497
XMP_StringPtr voidPtr;
498
XMP_StringLen voidLen;
500
(void) RegisterNamespace ( kXMP_NS_XML, "xml", &voidPtr, &voidLen );
501
(void) RegisterNamespace ( kXMP_NS_RDF, "rdf", &voidPtr, &voidLen );
502
(void) RegisterNamespace ( kXMP_NS_DC, "dc", &voidPtr, &voidLen );
504
(void) RegisterNamespace ( kXMP_NS_XMP, "xap", &voidPtr, &voidLen );
505
(void) RegisterNamespace ( kXMP_NS_PDF, "pdf", &voidPtr, &voidLen );
506
(void) RegisterNamespace ( kXMP_NS_Photoshop, "photoshop", &voidPtr, &voidLen );
507
(void) RegisterNamespace ( kXMP_NS_PSAlbum, "album", &voidPtr, &voidLen );
508
(void) RegisterNamespace ( kXMP_NS_EXIF, "exif", &voidPtr, &voidLen );
509
(void) RegisterNamespace ( kXMP_NS_EXIF_Aux, "aux", &voidPtr, &voidLen );
510
(void) RegisterNamespace ( kXMP_NS_TIFF, "tiff", &voidPtr, &voidLen );
511
(void) RegisterNamespace ( kXMP_NS_PNG, "png", &voidPtr, &voidLen );
512
(void) RegisterNamespace ( kXMP_NS_JPEG, "jpeg", &voidPtr, &voidLen );
513
(void) RegisterNamespace ( kXMP_NS_JP2K, "jp2k", &voidPtr, &voidLen );
514
(void) RegisterNamespace ( kXMP_NS_CameraRaw, "crs", &voidPtr, &voidLen );
515
(void) RegisterNamespace ( kXMP_NS_ASF, "asf", &voidPtr, &voidLen );
516
(void) RegisterNamespace ( kXMP_NS_WAV, "wav", &voidPtr, &voidLen );
518
(void) RegisterNamespace ( kXMP_NS_AdobeStockPhoto, "bmsp", &voidPtr, &voidLen );
520
(void) RegisterNamespace ( kXMP_NS_XMP_Rights, "xapRights", &voidPtr, &voidLen );
521
(void) RegisterNamespace ( kXMP_NS_XMP_MM, "xapMM", &voidPtr, &voidLen );
522
(void) RegisterNamespace ( kXMP_NS_XMP_BJ, "xapBJ", &voidPtr, &voidLen );
523
(void) RegisterNamespace ( kXMP_NS_XMP_Note, "xmpNote", &voidPtr, &voidLen );
525
(void) RegisterNamespace ( kXMP_NS_DM, "xmpDM", &voidPtr, &voidLen );
526
(void) RegisterNamespace ( kXMP_NS_XMP_Text, "xapT", &voidPtr, &voidLen );
527
(void) RegisterNamespace ( kXMP_NS_XMP_PagedFile, "xapTPg", &voidPtr, &voidLen );
528
(void) RegisterNamespace ( kXMP_NS_XMP_Graphics, "xapG", &voidPtr, &voidLen );
529
(void) RegisterNamespace ( kXMP_NS_XMP_Image, "xapGImg", &voidPtr, &voidLen );
531
(void) RegisterNamespace ( kXMP_NS_XMP_Font, "stFnt", &voidPtr, &voidLen );
532
(void) RegisterNamespace ( kXMP_NS_XMP_Dimensions, "stDim", &voidPtr, &voidLen );
533
(void) RegisterNamespace ( kXMP_NS_XMP_ResourceEvent, "stEvt", &voidPtr, &voidLen );
534
(void) RegisterNamespace ( kXMP_NS_XMP_ResourceRef, "stRef", &voidPtr, &voidLen );
535
(void) RegisterNamespace ( kXMP_NS_XMP_ST_Version, "stVer", &voidPtr, &voidLen );
536
(void) RegisterNamespace ( kXMP_NS_XMP_ST_Job, "stJob", &voidPtr, &voidLen );
537
(void) RegisterNamespace ( kXMP_NS_XMP_ManifestItem, "stMfs", &voidPtr, &voidLen );
539
(void) RegisterNamespace ( kXMP_NS_XMP_IdentifierQual, "xmpidq", &voidPtr, &voidLen );
541
(void) RegisterNamespace ( kXMP_NS_IPTCCore, "Iptc4xmpCore", &voidPtr, &voidLen );
543
(void) RegisterNamespace ( kXMP_NS_PDFA_Schema, "pdfaSchema", &voidPtr, &voidLen );
544
(void) RegisterNamespace ( kXMP_NS_PDFA_Property, "pdfaProperty", &voidPtr, &voidLen );
545
(void) RegisterNamespace ( kXMP_NS_PDFA_Type, "pdfaType", &voidPtr, &voidLen );
546
(void) RegisterNamespace ( kXMP_NS_PDFA_Field, "pdfaField", &voidPtr, &voidLen );
547
(void) RegisterNamespace ( kXMP_NS_PDFA_ID, "pdfaid", &voidPtr, &voidLen );
548
(void) RegisterNamespace ( kXMP_NS_PDFA_Extension, "pdfaExtension", &voidPtr, &voidLen );
550
(void) RegisterNamespace ( kXMP_NS_PDFX, "pdfx", &voidPtr, &voidLen );
551
(void) RegisterNamespace ( kXMP_NS_PDFX_ID, "pdfxid", &voidPtr, &voidLen );
553
(void) RegisterNamespace ( "adobe:ns:meta/", "x", &voidPtr, &voidLen );
554
(void) RegisterNamespace ( "http://ns.adobe.com/iX/1.0/", "iX", &voidPtr, &voidLen );
556
// 06-Oct-07, ahu: Do not use aliases. They result in unexpected behaviour.
557
// XMPMeta::RegisterStandardAliases ( "" );
559
// Initialize the other core classes.
561
if ( ! XMPIterator::Initialize() ) XMP_Throw ( "Failure from XMPIterator::Initialize", kXMPErr_InternalFailure );
562
if ( ! XMPUtils::Initialize() ) XMP_Throw ( "Failure from XMPUtils::Initialize", kXMPErr_InternalFailure );
564
// Do miscelaneous semantic checks of types and arithmetic.
566
XMP_Assert ( sizeof(XMP_Int8) == 1 );
567
XMP_Assert ( sizeof(XMP_Int16) == 2 );
568
XMP_Assert ( sizeof(XMP_Int32) == 4 );
569
XMP_Assert ( sizeof(XMP_Int64) == 8 );
570
XMP_Assert ( sizeof(XMP_Uns8) == 1 );
571
XMP_Assert ( sizeof(XMP_Uns16) == 2 );
572
XMP_Assert ( sizeof(XMP_Uns32) == 4 );
573
XMP_Assert ( sizeof(XMP_Uns64) == 8 );
575
XMP_Assert ( sizeof(XMP_OptionBits) == 4 ); // Check that option masking work on all 32 bits.
576
XMP_OptionBits flag = ~0UL;
577
XMP_Assert ( flag == (XMP_OptionBits)(-1L) );
578
XMP_Assert ( (flag ^ kXMP_PropHasLang) == 0xFFFFFFBFUL );
579
XMP_Assert ( (flag & ~kXMP_PropHasLang) == 0xFFFFFFBFUL );
581
XMP_OptionBits opt1 = 0; // Check the general option bit macros.
582
XMP_OptionBits opt2 = ~0UL;
583
XMP_SetOption ( opt1, kXMP_PropValueIsArray );
584
XMP_ClearOption ( opt2, kXMP_PropValueIsArray );
585
XMP_Assert ( opt1 == ~opt2 );
586
XMP_Assert ( XMP_TestOption ( opt1, kXMP_PropValueIsArray ) );
587
XMP_Assert ( ! XMP_TestOption ( opt2, kXMP_PropValueIsArray ) );
589
XMP_Assert ( XMP_PropIsSimple ( ~kXMP_PropCompositeMask ) ); // Check the special option bit macros.
590
XMP_Assert ( ! XMP_PropIsSimple ( kXMP_PropValueIsStruct ) );
591
XMP_Assert ( ! XMP_PropIsSimple ( kXMP_PropValueIsArray ) );
593
XMP_Assert ( XMP_PropIsStruct ( kXMP_PropValueIsStruct ) );
594
XMP_Assert ( XMP_PropIsArray ( kXMP_PropValueIsArray ) );
595
XMP_Assert ( ! XMP_PropIsStruct ( ~kXMP_PropValueIsStruct ) );
596
XMP_Assert ( ! XMP_PropIsArray ( ~kXMP_PropValueIsArray ) );
598
XMP_Assert ( XMP_ArrayIsUnordered ( ~kXMP_PropArrayIsOrdered ) );
599
XMP_Assert ( XMP_ArrayIsOrdered ( kXMP_PropArrayIsOrdered ) );
600
XMP_Assert ( XMP_ArrayIsAlternate ( kXMP_PropArrayIsAlternate ) );
601
XMP_Assert ( XMP_ArrayIsAltText ( kXMP_PropArrayIsAltText ) );
602
XMP_Assert ( ! XMP_ArrayIsUnordered ( kXMP_PropArrayIsOrdered ) );
603
XMP_Assert ( ! XMP_ArrayIsOrdered ( ~kXMP_PropArrayIsOrdered ) );
604
XMP_Assert ( ! XMP_ArrayIsAlternate ( ~kXMP_PropArrayIsAlternate ) );
605
XMP_Assert ( ! XMP_ArrayIsAltText ( ~kXMP_PropArrayIsAltText ) );
607
XMP_Assert ( XMP_PropHasQualifiers ( kXMP_PropHasQualifiers ) );
608
XMP_Assert ( XMP_PropIsQualifier ( kXMP_PropIsQualifier ) );
609
XMP_Assert ( XMP_PropHasLang ( kXMP_PropHasLang ) );
610
XMP_Assert ( ! XMP_PropHasQualifiers ( ~kXMP_PropHasQualifiers ) );
611
XMP_Assert ( ! XMP_PropIsQualifier ( ~kXMP_PropIsQualifier ) );
612
XMP_Assert ( ! XMP_PropHasLang ( ~kXMP_PropHasLang ) );
614
XMP_Assert ( XMP_NodeIsSchema ( kXMP_SchemaNode ) );
615
XMP_Assert ( XMP_PropIsAlias ( kXMP_PropIsAlias ) );
616
XMP_Assert ( ! XMP_NodeIsSchema ( ~kXMP_SchemaNode ) );
617
XMP_Assert ( ! XMP_PropIsAlias ( ~kXMP_PropIsAlias ) );
619
#if 0 // Generally off, enable to hand check generated code.
620
extern XMP_OptionBits opt3, opt4;
621
if ( XMP_TestOption ( opt3, kXMP_PropValueIsArray ) ) opt4 = opt3;
622
if ( ! XMP_TestOption ( opt3, kXMP_PropValueIsStruct ) ) opt4 = opt3;
623
static bool ok1 = XMP_TestOption ( opt4, kXMP_PropValueIsArray );
624
static bool ok2 = ! XMP_TestOption ( opt4, kXMP_PropValueIsStruct );
627
// Make sure the embedded info strings are referenced and kept.
628
if ( (kXMPCore_EmbeddedVersion[0] == 0) || (kXMPCore_EmbeddedCopyright[0] == 0) ) return false;
634
// -------------------------------------------------------------------------------------------------
638
#define EliminateGlobal(g) delete ( g ); g = 0
640
/* class-static */ void
641
XMPMeta::Terminate() RELEASE_NO_THROW
644
if ( sXMP_InitCount > 0 ) return;
647
fprintf ( xmpOut, "XMP terminating\n" ); fflush ( xmpOut );
648
// fclose ( xmpOut ); // Coordinate with fopen in XMPMeta::Initialize.
651
XMPIterator::Terminate();
652
XMPUtils::Terminate();
654
EliminateGlobal ( sNamespaceURIToPrefixMap );
655
EliminateGlobal ( sNamespacePrefixToURIMap );
656
EliminateGlobal ( sRegisteredAliasMap );
658
EliminateGlobal ( xdefaultName );
659
EliminateGlobal ( sOutputNS );
660
EliminateGlobal ( sOutputStr );
661
EliminateGlobal ( sExceptionMessage );
663
XMP_TermMutex ( sXMPCoreLock );
668
// -------------------------------------------------------------------------------------------------
672
/* class-static */ void
673
XMPMeta::Unlock ( XMP_OptionBits options )
675
options = options; // Avoid unused parameter warning. // *** Need IgnoreParam macro.
678
fprintf ( xmpOut, " Unlocking XMP toolkit, count = %d\n", sLockCount ); fflush ( xmpOut );
681
XMP_Assert ( sLockCount == 0 );
682
XMP_ExitCriticalRegion ( sXMPCoreLock );
687
// -------------------------------------------------------------------------------------------------
692
XMPMeta::UnlockObject ( XMP_OptionBits options ) const
694
options = options; // Avoid unused parameter warning.
696
XMPMeta::Unlock ( 0 );
701
// -------------------------------------------------------------------------------------------------
705
// Dump the prefix to URI map (easier to read) and verify that both are consistent and legit.
707
// *** Should put checks in a separate routine for regular calling in debug builds.
709
/* class-static */ XMP_Status
710
XMPMeta::DumpNamespaces ( XMP_TextOutputProc outProc,
713
XMP_Assert ( outProc != 0 ); // ! Enforced by wrapper.
716
XMP_StringMapPos p2uEnd = sNamespacePrefixToURIMap->end(); // ! Move up to avoid gcc complaints.
717
XMP_StringMapPos u2pEnd = sNamespaceURIToPrefixMap->end();
719
status = DumpStringMap ( *sNamespacePrefixToURIMap, "Dumping namespace prefix to URI map", outProc, refCon );
720
if ( status != 0 ) goto EXIT;
722
if ( sNamespacePrefixToURIMap->size() != sNamespaceURIToPrefixMap->size() ) {
723
OutProcLiteral ( "** bad namespace map sizes **" );
724
XMP_Throw ( "Fatal namespace map problem", kXMPErr_InternalFailure );
727
for ( XMP_StringMapPos nsLeft = sNamespacePrefixToURIMap->begin(); nsLeft != p2uEnd; ++nsLeft ) {
729
XMP_StringMapPos nsOther = sNamespaceURIToPrefixMap->find ( nsLeft->second );
730
if ( (nsOther == u2pEnd) || (nsLeft != sNamespacePrefixToURIMap->find ( nsOther->second )) ) {
731
OutProcLiteral ( " ** bad namespace URI ** " );
732
OutProcString ( nsLeft->second );
736
for ( XMP_StringMapPos nsRight = nsLeft; nsRight != p2uEnd; ++nsRight ) {
737
if ( nsRight == nsLeft ) continue; // ! Can't start at nsLeft+1, no operator+!
738
if ( nsLeft->second == nsRight->second ) {
739
OutProcLiteral ( " ** duplicate namespace URI ** " );
740
OutProcString ( nsLeft->second );
747
for ( XMP_StringMapPos nsLeft = sNamespaceURIToPrefixMap->begin(); nsLeft != u2pEnd; ++nsLeft ) {
749
XMP_StringMapPos nsOther = sNamespacePrefixToURIMap->find ( nsLeft->second );
750
if ( (nsOther == p2uEnd) || (nsLeft != sNamespaceURIToPrefixMap->find ( nsOther->second )) ) {
751
OutProcLiteral ( " ** bad namespace prefix ** " );
752
OutProcString ( nsLeft->second );
756
for ( XMP_StringMapPos nsRight = nsLeft; nsRight != u2pEnd; ++nsRight ) {
757
if ( nsRight == nsLeft ) continue; // ! Can't start at nsLeft+1, no operator+!
758
if ( nsLeft->second == nsRight->second ) {
759
OutProcLiteral ( " ** duplicate namespace prefix ** " );
760
OutProcString ( nsLeft->second );
772
(void) DumpStringMap ( *sNamespaceURIToPrefixMap, "Dumping namespace URI to prefix map", outProc, refCon );
773
XMP_Throw ( "Fatal namespace map problem", kXMPErr_InternalFailure );
779
// -------------------------------------------------------------------------------------------------
783
/* class-static */ XMP_Status
784
XMPMeta::DumpAliases ( XMP_TextOutputProc outProc,
787
XMP_Assert ( outProc != 0 ); // ! Enforced by wrapper.
790
XMP_Assert ( sRegisteredAliasMap != 0 );
792
XMP_cAliasMapPos aliasPos;
793
XMP_cAliasMapPos aliasEnd = sRegisteredAliasMap->end();
796
for ( aliasPos = sRegisteredAliasMap->begin(); aliasPos != aliasEnd; ++aliasPos ) {
797
size_t currLen = aliasPos->first.size();
798
if ( currLen > maxLen ) maxLen = currLen;
801
OutProcLiteral ( "Dumping alias name to actual path map" );
804
for ( aliasPos = sRegisteredAliasMap->begin(); aliasPos != aliasEnd; ++aliasPos ) {
806
OutProcNChars ( " ", 3 );
807
OutProcString ( aliasPos->first );
808
OutProcPadding ( maxLen - aliasPos->first.size() );
809
OutProcNChars ( " => ", 4 );
811
size_t actualPathSize = aliasPos->second.size();
812
for ( size_t stepNum = 1; stepNum < actualPathSize; ++stepNum ) OutProcString ( aliasPos->second[stepNum].step );
814
XMP_OptionBits arrayForm = aliasPos->second[1].options & kXMP_PropArrayFormMask;
816
if ( arrayForm == 0 ) {
817
if ( actualPathSize != 2 ) OutProcLiteral ( " ** bad actual path **" );
819
OutProcNChars ( " ", 2 );
820
DumpNodeOptions ( arrayForm, outProc, refCon );
821
if ( ! (arrayForm & kXMP_PropValueIsArray) ) OutProcLiteral ( " ** bad array form **" );
822
if ( actualPathSize != 3 ) OutProcLiteral ( " ** bad actual path **" );
825
if ( aliasPos->second[0].options != kXMP_SchemaNode ) OutProcLiteral ( " ** bad schema form **" );
837
// -------------------------------------------------------------------------------------------------
841
/* class-static */ XMP_OptionBits
842
XMPMeta::GetGlobalOptions()
844
XMP_OptionBits options = 0;
848
} // GetGlobalOptions
851
// -------------------------------------------------------------------------------------------------
855
/* class-static */ void
856
XMPMeta::SetGlobalOptions ( XMP_OptionBits options )
859
XMP_Throw ( "Unimplemented method XMPMeta::SetGlobalOptions", kXMPErr_Unimplemented );
860
void * p; p = &options; // Avoid unused param warnings.
862
} // SetGlobalOptions
865
// -------------------------------------------------------------------------------------------------
869
/* class-static */ bool
870
XMPMeta::RegisterNamespace ( XMP_StringPtr namespaceURI,
871
XMP_StringPtr suggestedPrefix,
872
XMP_StringPtr * registeredPrefix,
873
XMP_StringLen * prefixSize )
875
bool prefixMatches = false;
877
XMP_Assert ( (registeredPrefix != 0) && (prefixSize != 0) ); // ! Enforced by wrapper.
878
if ( (*namespaceURI == 0) || (*suggestedPrefix == 0) ) {
879
XMP_Throw ( "Empty namespace URI or prefix", kXMPErr_BadParam );
882
XMP_VarString nsURI ( namespaceURI );
883
XMP_VarString suggPrefix ( suggestedPrefix );
884
if ( suggPrefix[suggPrefix.size()-1] != ':' ) suggPrefix += ':';
885
VerifySimpleXMLName ( suggestedPrefix, suggestedPrefix+suggPrefix.size()-1 ); // Exclude the colon.
887
XMP_StringMapPos uriPos = sNamespaceURIToPrefixMap->find ( nsURI );
889
if ( uriPos == sNamespaceURIToPrefixMap->end() ) {
891
// The URI is not yet registered, make sure we use a unique prefix.
893
XMP_VarString uniqPrefix ( suggPrefix );
898
if ( sNamespacePrefixToURIMap->find ( uniqPrefix ) == sNamespacePrefixToURIMap->end() ) break;
900
snprintf ( buffer, sizeof(buffer), "_%d_:", suffix ); // AUDIT: Using sizeof for snprintf length is safe.
901
uniqPrefix = suggPrefix;
902
uniqPrefix.erase ( uniqPrefix.size()-1 ); // ! Remove the trailing ':'.
903
uniqPrefix += buffer;
906
// Add the new namespace to both maps.
908
XMP_StringPair newNS ( nsURI, uniqPrefix );
909
uriPos = sNamespaceURIToPrefixMap->insert ( sNamespaceURIToPrefixMap->end(), newNS );
911
newNS.first.swap ( newNS.second );
912
(void) sNamespacePrefixToURIMap->insert ( sNamespacePrefixToURIMap->end(), newNS );
916
// Return the actual prefix and see if it matches the suggested prefix.
918
*registeredPrefix = uriPos->second.c_str();
919
*prefixSize = uriPos->second.size();
921
prefixMatches = ( uriPos->second == suggPrefix );
922
return prefixMatches;
924
} // RegisterNamespace
927
// -------------------------------------------------------------------------------------------------
928
// GetNamespacePrefix
929
// ------------------
931
/* class-static */ bool
932
XMPMeta::GetNamespacePrefix ( XMP_StringPtr namespaceURI,
933
XMP_StringPtr * namespacePrefix,
934
XMP_StringLen * prefixSize )
938
XMP_Assert ( *namespaceURI != 0 ); // ! Enforced by wrapper.
939
XMP_Assert ( (namespacePrefix != 0) && (prefixSize != 0) ); // ! Enforced by wrapper.
941
XMP_VarString nsURI ( namespaceURI );
942
XMP_StringMapPos uriPos = sNamespaceURIToPrefixMap->find ( nsURI );
944
if ( uriPos != sNamespaceURIToPrefixMap->end() ) {
945
*namespacePrefix = uriPos->second.c_str();
946
*prefixSize = uriPos->second.size();
952
} // GetNamespacePrefix
955
// -------------------------------------------------------------------------------------------------
959
/* class-static */ bool
960
XMPMeta::GetNamespaceURI ( XMP_StringPtr namespacePrefix,
961
XMP_StringPtr * namespaceURI,
962
XMP_StringLen * uriSize )
966
XMP_Assert ( *namespacePrefix != 0 ); // ! Enforced by wrapper.
967
XMP_Assert ( (namespacePrefix != 0) && (namespaceURI != 0) ); // ! Enforced by wrapper.
969
XMP_VarString nsPrefix ( namespacePrefix );
970
if ( nsPrefix[nsPrefix.size()-1] != ':' ) nsPrefix += ':';
972
XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( nsPrefix );
974
if ( prefixPos != sNamespacePrefixToURIMap->end() ) {
975
*namespaceURI = prefixPos->second.c_str();
976
*uriSize = prefixPos->second.size();
985
// -------------------------------------------------------------------------------------------------
989
// *** Don't allow standard namespaces to be deleted.
991
/* class-static */ void
992
XMPMeta::DeleteNamespace ( XMP_StringPtr namespaceURI )
994
namespaceURI = namespaceURI; // Avoid unused parameter warning.
995
XMP_Assert ( *namespaceURI != 0 ); // ! Enforced by wrapper.
996
XMP_Throw ( "Unimplemented method XMPMeta::DeleteNamespace", kXMPErr_Unimplemented ); // *** #error "write me"
1001
// -------------------------------------------------------------------------------------------------
1005
// Allow 3 kinds of alias:
1006
// TopProp => TopProp
1007
// TopProp => TopArray[1]
1008
// TopProp => TopArray[@xml:lang='x-default']
1010
// A new alias can be made to something that is already aliased, as long as the net result is one of
1011
// the legitimate forms. The new alias can already have aliases to it, also as long as result of
1012
// adjusting all of the exiting aliases leaves them legal.
1014
// ! The caller assumes all risk that new aliases do not invalidate existing XMPMeta objects. Any
1015
// ! conflicts will result in later references throwing bad XPath exceptions.
1017
/* class-static */ void
1018
XMPMeta::RegisterAlias ( XMP_StringPtr aliasNS,
1019
XMP_StringPtr aliasProp,
1020
XMP_StringPtr actualNS,
1021
XMP_StringPtr actualProp,
1022
XMP_OptionBits arrayForm )
1024
XMP_ExpandedXPath expAlias, expActual;
1025
XMP_AliasMapPos mapPos;
1026
XMP_ExpandedXPath * regActual = 0;
1028
XMP_Assert ( (aliasNS != 0) && (aliasProp != 0) && (actualNS != 0) && (actualProp != 0) ); // Enforced by wrapper.
1030
// Expand the alias and actual names, make sure they are one of the basic 3 forms. When counting
1031
// the expanded XPath size remember that the schema URI is the first component. We don't have to
1032
// compare the schema URIs though, the (unique) prefix is part of the top property name.
1034
ExpandXPath ( aliasNS, aliasProp, &expAlias );
1035
ExpandXPath ( actualNS, actualProp, &expActual );
1036
if ( (expAlias.size() != 2) || (expActual.size() != 2) ) {
1037
XMP_Throw ( "Alias and actual property names must be simple", kXMPErr_BadXPath );
1040
arrayForm = VerifySetOptions ( arrayForm, 0 );
1041
if ( arrayForm != 0 ) {
1042
if ( (arrayForm & ~kXMP_PropArrayFormMask) != 0 ) XMP_Throw ( "Only array form flags are allowed", kXMPErr_BadOptions );
1043
expActual[1].options |= arrayForm; // Set the array form for the top level step.
1044
if ( ! (arrayForm & kXMP_PropArrayIsAltText) ) {
1045
expActual.push_back ( XPathStepInfo ( "[1]", kXMP_ArrayIndexStep ) );
1047
expActual.push_back ( XPathStepInfo ( "[?xml:lang=\"x-default\"]", kXMP_QualSelectorStep ) );
1051
// See if there are any conflicts with existing aliases. A couple of the checks are easy. If the
1052
// alias is already aliased it is only OK to reregister an identical alias. If the actual is
1053
// already aliased to something else and the new chain is legal, just swap in the old base.
1055
mapPos = sRegisteredAliasMap->find ( expAlias[kRootPropStep].step );
1056
if ( mapPos != sRegisteredAliasMap->end() ) {
1058
// This alias is already registered to something, make sure it is the same something.
1060
regActual = &mapPos->second;
1061
if ( arrayForm != (mapPos->second[1].options & kXMP_PropArrayFormMask) ) {
1062
XMP_Throw ( "Mismatch with existing alias array form", kXMPErr_BadParam );
1064
if ( expActual.size() != regActual->size() ) {
1065
XMP_Throw ( "Mismatch with existing actual path", kXMPErr_BadParam );
1067
if ( expActual[kRootPropStep].step != (*regActual)[kRootPropStep].step ) {
1068
XMP_Throw ( "Mismatch with existing actual name", kXMPErr_BadParam );
1070
if ( (expActual.size() == 3) && (expActual[kAliasIndexStep].step != (*regActual)[kAliasIndexStep].step) ) {
1071
XMP_Throw ( "Mismatch with existing actual array item", kXMPErr_BadParam );
1077
mapPos = sRegisteredAliasMap->find ( expActual[kRootPropStep].step );
1078
if ( mapPos != sRegisteredAliasMap->end() ) {
1080
// The actual is already aliased to something else.
1082
regActual = &mapPos->second;
1083
if ( expActual.size() == 2 ) {
1084
expActual = *regActual; // TopProp => TopProp => anything : substitute the entire old base.
1085
} else if ( regActual->size() != 2 ) {
1086
XMP_Throw ( "Can't alias an array item to an array item", kXMPErr_BadParam ); // TopProp => TopArray[] => TopArray[] : nope.
1088
expActual[kSchemaStep].step = (*regActual)[kSchemaStep].step; // TopProp => TopArray[] => TopProp :
1089
expActual[kRootPropStep].step = (*regActual)[kRootPropStep].step; // substitute the old base name.
1094
// Checking for existing aliases to this one is touchier. This involves updating the alias map,
1095
// which must not be done unless all of the changes are legal. So we need 2 loops, one to verify
1096
// that everything is OK, and one to make the changes. The bad case is:
1097
// TopProp => TopArray[] => TopArray[]
1098
// In the valid cases we back substitute the new base.
1100
for ( mapPos = sRegisteredAliasMap->begin(); mapPos != sRegisteredAliasMap->end(); ++mapPos ) {
1101
regActual = &mapPos->second;
1102
if ( expAlias[kRootPropStep].step == (*regActual)[kRootPropStep].step ) {
1103
if ( (regActual->size() == 2) && (expAlias.size() == 2) ) {
1104
XMP_Throw ( "Can't alias an array item to an array item", kXMPErr_BadParam );
1109
for ( mapPos = sRegisteredAliasMap->begin(); mapPos != sRegisteredAliasMap->end(); ++mapPos ) {
1110
regActual = &mapPos->second;
1111
if ( expAlias[kRootPropStep].step == (*regActual)[kRootPropStep].step ) {
1113
if ( regActual->size() == 1 ) {
1114
*regActual = expActual; // TopProp => TopProp => anything : substitute the entire new base.
1116
(*regActual)[kSchemaStep].step = expActual[kSchemaStep].step; // TopProp => TopArray[] => TopProp :
1117
(*regActual)[kRootPropStep].step = expActual[kRootPropStep].step; // substitute the new base name.
1123
// Finally, all is OK to register the new alias.
1125
(void) sRegisteredAliasMap->insert ( XMP_AliasMap::value_type ( expAlias[kRootPropStep].step, expActual ) );
1130
// -------------------------------------------------------------------------------------------------
1134
/* class-static */ bool
1135
XMPMeta::ResolveAlias ( XMP_StringPtr aliasNS,
1136
XMP_StringPtr aliasProp,
1137
XMP_StringPtr * actualNS,
1138
XMP_StringLen * nsSize,
1139
XMP_StringPtr * actualProp,
1140
XMP_StringLen * propSize,
1141
XMP_OptionBits * arrayForm )
1143
XMP_Assert ( (aliasNS != 0) && (aliasProp != 0) ); // Enforced by wrapper.
1144
XMP_Assert ( (actualNS != 0) && (nsSize != 0) && (actualProp != 0) && (propSize != 0) && (arrayForm != 0) ); // Enforced by wrapper.
1146
// Expand the input path and look up the first component in the alias table. Return if not an alias.
1148
XMP_ExpandedXPath fullPath, minPath;
1149
ExpandXPath ( aliasNS, aliasProp, &fullPath );
1150
XMP_Assert ( fullPath.size() >= 2 );
1152
minPath.push_back ( fullPath[kSchemaStep] );
1153
minPath.push_back ( fullPath[kRootPropStep] );
1154
XMP_AliasMapPos mapPos = sRegisteredAliasMap->find ( minPath[kRootPropStep].step );
1155
if ( mapPos == sRegisteredAliasMap->end() ) return false;
1157
// Replace the alias portion of the full expanded path. Compose the output path string.
1159
const XMP_ExpandedXPath & actualPath = mapPos->second;
1161
fullPath[kSchemaStep] = actualPath[kSchemaStep];
1162
fullPath[kRootPropStep] = actualPath[kRootPropStep];
1163
if ( actualPath.size() > 2 ) { // This is an alias to an array item.
1164
XMP_ExpandedXPathPos insertPos = fullPath.begin() + kAliasIndexStep;
1165
fullPath.insert ( insertPos, actualPath[kAliasIndexStep] );
1168
*sOutputNS = fullPath[kSchemaStep].step;
1169
*actualNS = sOutputNS->c_str();
1170
*nsSize = sOutputNS->size();
1172
ComposeXPath ( fullPath, sOutputStr );
1173
*actualProp = sOutputStr->c_str();
1174
*propSize = sOutputStr->size();
1176
*arrayForm = actualPath[kRootPropStep].options & kXMP_PropArrayFormMask;
1178
#if XMP_DebugBuild // Test that the output string is valid and unchanged by round trip expand/compose.
1179
XMP_ExpandedXPath rtPath;
1180
ExpandXPath ( *actualNS, *actualProp, &rtPath );
1181
std::string rtString;
1182
ComposeXPath ( rtPath, &rtString );
1183
XMP_Assert ( rtString == *sOutputStr );
1191
// -------------------------------------------------------------------------------------------------
1195
/* class-static */ void
1196
XMPMeta::DeleteAlias ( XMP_StringPtr aliasNS,
1197
XMP_StringPtr aliasProp )
1200
XMP_Assert ( (aliasNS != 0) && (aliasProp != 0) ); // Enforced by wrapper.
1201
XMP_Throw ( "Unimplemented method XMPMeta::DeleteAlias", kXMPErr_Unimplemented ); // *** #error "write me"
1202
void * p; p = &aliasNS; p = &aliasProp; // Avoid unused param warnings.
1207
// -------------------------------------------------------------------------------------------------
1208
// RegisterStandardAliases
1209
// -----------------------
1211
/* class-static */ void
1212
XMPMeta::RegisterStandardAliases ( XMP_StringPtr schemaNS )
1214
XMP_Assert ( schemaNS != 0 ); // Enforced by wrapper.
1216
const bool doAll = (*schemaNS == 0);
1218
if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_XMP ) ) {
1219
// Aliases from XMP to DC.
1220
XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered );
1221
XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Authors", kXMP_NS_DC, "creator", 0 );
1222
XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Description", kXMP_NS_DC, "description", 0 );
1223
XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Format", kXMP_NS_DC, "format", 0 );
1224
XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Keywords", kXMP_NS_DC, "subject", 0 );
1225
XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Locale", kXMP_NS_DC, "language", 0 );
1226
XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Title", kXMP_NS_DC, "title", 0 );
1227
XMPMeta::RegisterAlias ( kXMP_NS_XMP_Rights, "Copyright", kXMP_NS_DC, "rights", 0 );
1230
if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_PDF ) ) {
1231
// Aliases from PDF to DC and XMP.
1232
XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered );
1233
XMPMeta::RegisterAlias ( kXMP_NS_PDF, "BaseURL", kXMP_NS_XMP, "BaseURL", 0 );
1234
XMPMeta::RegisterAlias ( kXMP_NS_PDF, "CreationDate", kXMP_NS_XMP, "CreateDate", 0 );
1235
XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Creator", kXMP_NS_XMP, "CreatorTool", 0 );
1236
XMPMeta::RegisterAlias ( kXMP_NS_PDF, "ModDate", kXMP_NS_XMP, "ModifyDate", 0 );
1237
XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Subject", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText );
1238
XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText );
1241
if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_Photoshop ) ) {
1242
// Aliases from PHOTOSHOP to DC and XMP.
1243
XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered );
1244
XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Caption", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText );
1245
XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Copyright", kXMP_NS_DC, "rights", kXMP_PropArrayIsAltText );
1246
XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Keywords", kXMP_NS_DC, "subject", 0 );
1247
XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Marked", kXMP_NS_XMP_Rights, "Marked", 0 );
1248
XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText );
1249
XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "WebStatement", kXMP_NS_XMP_Rights, "WebStatement", 0 );
1252
if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_TIFF ) || XMP_LitMatch ( schemaNS, kXMP_NS_EXIF ) ) {
1253
// Aliases from TIFF and EXIF to DC and XMP.
1254
XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "Artist", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered);
1255
XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "Copyright", kXMP_NS_DC, "rights", 0 );
1256
XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "DateTime", kXMP_NS_XMP, "ModifyDate", 0 );
1257
XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "ImageDescription", kXMP_NS_DC, "description", 0 );
1258
XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "Software", kXMP_NS_XMP, "CreatorTool", 0 );
1261
if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_PNG ) ) { // ! From Acrobat ImageCapture:
1262
XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered);
1263
XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Copyright", kXMP_NS_DC, "rights", kXMP_PropArrayIsAltText);
1264
XMPMeta::RegisterAlias ( kXMP_NS_PNG, "CreationTime", kXMP_NS_XMP, "CreateDate", 0 );
1265
XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Description", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText);
1266
XMPMeta::RegisterAlias ( kXMP_NS_PNG, "ModificationTime", kXMP_NS_XMP, "ModifyDate", 0 );
1267
XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Software", kXMP_NS_XMP, "CreatorTool", 0 );
1268
XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText);
1271
} // RegisterStandardAliases
1274
// =================================================================================================
1279
// =================================================================================================
1282
// -------------------------------------------------------------------------------------------------
1287
XMPMeta::DumpObject ( XMP_TextOutputProc outProc,
1288
void * refCon ) const
1290
XMP_Assert ( outProc != 0 ); // ! Enforced by wrapper.
1293
OutProcLiteral ( "Dumping XMPMeta object \"" );
1294
OutProcString ( tree.name );
1295
OutProcNChars ( "\" ", 3 );
1296
status = DumpNodeOptions ( tree.options, outProc, refCon );
1297
if ( status != 0 ) goto EXIT;
1298
#if 0 // *** XMP_DebugBuild
1299
if ( (tree._namePtr != tree.name.c_str()) ||
1300
(tree._valuePtr != tree.value.c_str()) ) OutProcLiteral ( " ** bad debug string **" );
1304
if ( ! tree.value.empty() ) {
1305
OutProcLiteral ( "** bad root value ** \"" );
1306
OutProcString ( tree.value );
1307
OutProcNChars ( "\"", 1 );
1311
if ( ! tree.qualifiers.empty() ) {
1312
OutProcLiteral ( "** bad root qualifiers **" );
1314
for ( size_t qualNum = 0, qualLim = tree.qualifiers.size(); qualNum < qualLim; ++qualNum ) {
1315
status = DumpPropertyTree ( tree.qualifiers[qualNum], 3, 0, outProc, refCon );
1319
if ( ! tree.children.empty() ) {
1321
for ( size_t childNum = 0, childLim = tree.children.size(); childNum < childLim; ++childNum ) {
1323
const XMP_Node * currSchema = tree.children[childNum];
1326
OutProcIndent ( 1 );
1327
OutProcString ( currSchema->name );
1328
OutProcNChars ( " ", 2 );
1329
OutProcString ( currSchema->value );
1330
OutProcNChars ( " ", 2 );
1331
status = DumpNodeOptions ( currSchema->options, outProc, refCon );
1332
if ( status != 0 ) goto EXIT;
1333
#if 0 // *** XMP_DebugBuild
1334
if ( (currSchema->_namePtr != currSchema->name.c_str()) ||
1335
(currSchema->_valuePtr != currSchema->value.c_str()) ) OutProcLiteral ( " ** bad debug string **" );
1339
if ( ! (currSchema->options & kXMP_SchemaNode) ) {
1340
OutProcLiteral ( "** bad schema options **" );
1344
if ( ! currSchema->qualifiers.empty() ) {
1345
OutProcLiteral ( "** bad schema qualifiers **" );
1347
for ( size_t qualNum = 0, qualLim = currSchema->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
1348
DumpPropertyTree ( currSchema->qualifiers[qualNum], 3, 0, outProc, refCon );
1352
for ( size_t childNum = 0, childLim = currSchema->children.size(); childNum < childLim; ++childNum ) {
1353
DumpPropertyTree ( currSchema->children[childNum], 2, 0, outProc, refCon );
1366
// -------------------------------------------------------------------------------------------------
1371
XMPMeta::CountArrayItems ( XMP_StringPtr schemaNS,
1372
XMP_StringPtr arrayName ) const
1374
XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper.
1376
XMP_ExpandedXPath expPath;
1377
ExpandXPath ( schemaNS, arrayName, &expPath );
1379
const XMP_Node * arrayNode = FindConstNode ( &tree, expPath );
1381
if ( arrayNode == 0 ) return 0;
1382
if ( ! (arrayNode->options & kXMP_PropValueIsArray) ) XMP_Throw ( "The named property is not an array", kXMPErr_BadXPath );
1383
return arrayNode->children.size();
1385
} // CountArrayItems
1388
// -------------------------------------------------------------------------------------------------
1393
XMPMeta::GetObjectName ( XMP_StringPtr * namePtr,
1394
XMP_StringLen * nameLen ) const
1397
*namePtr = tree.name.c_str();
1398
*nameLen = tree.name.size();
1403
// -------------------------------------------------------------------------------------------------
1408
XMPMeta::SetObjectName ( XMP_StringPtr name )
1410
VerifyUTF8 ( name ); // Throws if the string is not legit UTF-8.
1416
// -------------------------------------------------------------------------------------------------
1421
XMPMeta::GetObjectOptions() const
1423
XMP_OptionBits options = 0;
1427
} // GetObjectOptions
1430
// -------------------------------------------------------------------------------------------------
1435
XMPMeta::SetObjectOptions ( XMP_OptionBits options )
1438
XMP_Throw ( "Unimplemented method XMPMeta::SetObjectOptions", kXMPErr_Unimplemented );
1439
void * p; p = &options; // Avoid unused param warnings.
1441
} // SetObjectOptions
1444
// -------------------------------------------------------------------------------------------------
1449
XMPMeta::Clone ( XMP_OptionBits options ) const
1451
if ( options != 0 ) XMP_Throw ( "No options are defined yet", kXMPErr_BadOptions );
1453
XMPMeta * clone = new XMPMeta;
1455
clone->tree.options = this->tree.options;
1456
clone->tree.name = this->tree.name;
1457
clone->tree.value = this->tree.value;
1458
XMP_Assert ( this->tree.parent == 0 );
1460
#if 0 // *** XMP_DebugBuild
1461
clone->tree._namePtr = clone->tree.name.c_str();
1462
clone->tree._valuePtr = clone->tree.value.c_str();
1465
CloneOffspring ( &this->tree, &clone->tree );
1467
XMP_Assert ( clone->clientRefs == 0 ); // Gets incremneted later.
1472
// =================================================================================================