1 // =================================================================================================
2 // Copyright 2003 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 "public/include/XMP_Environment.h"	// ! This must be the first include!
13 #include "XMPCore/source/XMPCore_Impl.hpp"
14 
15 #include "XMPCore/source/XMPMeta.hpp"
16 #include "XMPCore/source/XMPIterator.hpp"
17 #include "XMPCore/source/XMPUtils.hpp"
18 #include "public/include/XMP_Version.h"
19 #include "source/UnicodeInlines.incl_cpp"
20 #include "source/UnicodeConversions.hpp"
21 
22 
23 #include "XMPCore/XMPCoreDefines.h"
24 #if ENABLE_CPP_DOM_MODEL
25 	#include "XMPCommon/XMPCommon_I.h"
26 	#include "XMPCore/Interfaces/ICoreConfigurationManager_I.h"
27 	#include "XMPCommon/Interfaces/IMemoryAllocator.h"
28 	#include "XMPCore/Interfaces/INameSpacePrefixMap_I.h"
29 	#include "XMPCommon/ImplHeaders/SharedObjectImpl.h"
30 	#include "XMPCore/Interfaces/ICoreObjectFactory_I.h"
31 	#include "XMPCore/Interfaces/IDOMImplementationRegistry_I.h"
32 #endif
33 
34 
35 #include <algorithm>	// For sort and stable_sort.
36 #include <cstdio>		// For snprintf.
37 
38 #if XMP_DebugBuild
39 	#include <iostream>
40 #endif
41 
42 using namespace std;
43 
44 #if XMP_WinBuild
45 	#pragma warning ( disable : 4533 )	// initialization of '...' is skipped by 'goto ...'
46 	#pragma warning ( disable : 4702 )	// unreachable code
47 	#pragma warning ( disable : 4800 )	// forcing value to bool 'true' or 'false' (performance warning)
48 	#pragma warning ( disable : 4996 )	// '...' was declared deprecated
49 #endif
50 
51 
52 	#if ENABLE_CPP_DOM_MODEL
53 		#if !XMP_StaticBuild
54 
55 		#if XMP_WinBuild
56 			#pragma warning( push )
57 			#pragma warning( disable : 4250 )
58 		#endif
59 		class InternalClientAllocator
60 			: public AdobeXMPCommon::IMemoryAllocator
61 		{
62 		public:
allocate(AdobeXMPCommon::sizet size)63 			virtual void * APICALL allocate( AdobeXMPCommon::sizet size ) __NOTHROW__ {
64 				return sXMP_MemAlloc( size );
65 			}
66 
deallocate(void * ptr)67 			virtual void APICALL deallocate( void * ptr ) __NOTHROW__ {
68 				sXMP_MemFree( ptr );
69 			}
70 
reallocate(void * ptr,AdobeXMPCommon::sizet size)71 			virtual void * APICALL reallocate( void * ptr, AdobeXMPCommon::sizet size ) __NOTHROW__ {
72 				return NULL;
73 			}
74 
~InternalClientAllocator()75 			virtual ~InternalClientAllocator(){}
76 
77 		};
78 		static InternalClientAllocator * sInternalClientAllocator( NULL );
79 		#if XMP_WinBuild
80 			#pragma warning( pop )
81 		#endif
82 
83 		#endif  // !XMP_StaticBuild
84 	#endif  // ENABLE_CPP_DOM_MODEL
85 
86 
87 // *** Use the XMP_PropIsXyz (Schema, Simple, Struct, Array, ...) macros
88 // *** Add debug codegen checks, e.g. that typical masking operations really work
89 // *** Change all uses of strcmp and strncmp to XMP_LitMatch and XMP_LitNMatch
90 
91 
92 // =================================================================================================
93 // Local Types and Constants
94 // =========================
95 
96 
97 // =================================================================================================
98 // Static Variables
99 // ================
100 
101 XMP_VarString * xdefaultName = 0;	// Needed in XMPMeta-Parse.cpp, MoveExplicitAliases.
102 
103 static XMPMeta::ErrorCallbackInfo sDefaultErrorCallback;
104 
105 // These are embedded version strings.
106 
107 const char * kXMPCore_EmbeddedVersion   = kXMPCore_VersionMessage;
108 const char * kXMPCore_EmbeddedCopyright = kXMPCoreName " " kXMP_CopyrightStr;
109 
110 // =================================================================================================
111 // Local Utilities
112 // ===============
113 
114 
115 // -------------------------------------------------------------------------------------------------
116 // DumpNodeOptions
117 // ---------------
118 
119 void
DumpNodeOptions(XMP_OptionBits options,XMP_TextOutputProc outProc,void * refCon)120 DumpNodeOptions	( XMP_OptionBits	 options,
121 				  XMP_TextOutputProc outProc,
122 				  void *			 refCon )
123 {
124 	char		buffer [32];	// Decimal of a 64 bit int is at most about 20 digits.
125 	memset(buffer, 0, 32);
126 
127 	static const char * optNames[] = { " schema",		// 0x8000_0000
128 									   " ?30",
129 									   " ?29",
130 									   " -COMMAS-",
131 									   " ?27",			// 0x0800_0000
132 									   " ?26",
133 									   " ?25",
134 									   " ?24",
135 									   " ?23",			// 0x0080_0000
136 									   " isStale",
137 									   " isDerived",
138 									   " isStable",
139 									   " ?19",			// 0x0008_0000
140 									   " isInternal",
141 									   " hasAliases",
142 									   " isAlias",
143 									   " -AFTER-",		// 0x0000_8000
144 									   " -BEFORE-",
145 									   " isCompact",
146 									   " isLangAlt",
147 									   " isAlt",		// 0x0000_0800
148 									   " isOrdered",
149 									   " isArray",
150 									   " isStruct",
151 									   " hasType",		// 0x0000_0080
152 									   " hasLang",
153 									   " isQual",
154 									   " hasQual",
155 									   " ?3",			// 0x0000_0008
156 									   " ?2",
157 									   " URI",
158 									   " ?0" };
159 
160 	if ( options == 0 ) {
161 
162 		OutProcNChars ( "(0x0)", 5 );
163 
164 	} else {
165 
166 		OutProcNChars ( "(0x", 3 );
167 		OutProcHexInt ( options );
168 		OutProcNChars ( " :", 2 );
169 
170 		XMP_OptionBits mask = 0x80000000;
171 		for ( int b = 0; b < 32; ++b ) {
172 			if ( options & mask ) OutProcLiteral ( optNames[b] );
173 			mask = mask >> 1;
174 		}
175 		OutProcNChars ( ")", 1 );
176 
177 	}
178 
179 }	// DumpNodeOptions
180 
181 
182 // -------------------------------------------------------------------------------------------------
183 // DumpPropertyTree
184 // ----------------
185 
186 // *** Extract the validation code into a separate routine to call on exit in debug builds.
187 
188 static void
DumpPropertyTree(const XMP_Node * currNode,int indent,size_t itemIndex,XMP_TextOutputProc outProc,void * refCon)189 DumpPropertyTree ( const XMP_Node *	  currNode,
190 				   int				  indent,
191 				   size_t			  itemIndex,
192 				   XMP_TextOutputProc outProc,
193 				   void *			  refCon )
194 {
195 	char buffer [32];	// Decimal of a 64 bit int is at most about 20 digits.
196 
197 	OutProcIndent ( (size_t)indent );
198 	if ( itemIndex == 0 ) {
199 		if ( currNode->options & kXMP_PropIsQualifier ) OutProcNChars ( "? ", 2 );
200 		DumpClearString ( currNode->name, outProc, refCon );
201 	} else {
202 		OutProcNChars ( "[", 1 );
203 		OutProcDecInt ( itemIndex );
204 		OutProcNChars ( "]", 1 );
205 	}
206 
207 	if ( ! (currNode->options & kXMP_PropCompositeMask) ) {
208 		OutProcNChars ( " = \"", 4 );
209 		DumpClearString ( currNode->value, outProc, refCon );
210 		OutProcNChars ( "\"", 1 );
211 	}
212 
213 	if ( currNode->options != 0 ) {
214 		OutProcNChars ( "  ", 2 );
215 		DumpNodeOptions ( currNode->options, outProc, refCon );
216 	}
217 
218 	if ( currNode->options & kXMP_PropHasLang ) {
219 		if ( currNode->qualifiers.empty() || (currNode->qualifiers[0]->name != "xml:lang") ) {
220 			OutProcLiteral ( "  ** bad lang flag **" );
221 		}
222 	}
223 	// *** Check rdf:type also.
224 
225 	if ( ! (currNode->options & kXMP_PropCompositeMask) ) {
226 		if ( ! currNode->children.empty() ) OutProcLiteral ( "  ** bad children **" );
227 	} else if ( currNode->options & kXMP_PropValueIsArray ) {
228 		if ( currNode->options & kXMP_PropValueIsStruct ) OutProcLiteral ( "  ** bad comp flags **" );
229 	} else if ( (currNode->options & kXMP_PropCompositeMask) != kXMP_PropValueIsStruct ) {
230 		OutProcLiteral ( "  ** bad comp flags **" );
231 	}
232 
233 	#if 0	// *** XMP_DebugBuild
234 		if ( (currNode->_namePtr != currNode->name.c_str()) ||
235 			 (currNode->_valuePtr != currNode->value.c_str()) ) OutProcLiteral ( "  ** bad debug string **" );
236 	#endif
237 
238 	OutProcNewline();
239 
240 	for ( size_t qualNum = 0, qualLim = currNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
241 
242 		const XMP_Node * currQual = currNode->qualifiers[qualNum];
243 
244 		if ( currQual->parent != currNode ) OutProcLiteral ( "** bad parent link => " );
245 		if ( currQual->name == kXMP_ArrayItemName ) OutProcLiteral ( "** bad qual name => " );
246 		if ( ! (currQual->options & kXMP_PropIsQualifier) ) OutProcLiteral ( "** bad qual flag => " );
247 		if ( currQual->name == "xml:lang" ) {
248 			if ( (qualNum != 0) || (! (currNode->options & kXMP_PropHasLang)) ) OutProcLiteral ( "** bad lang qual => " );
249 		}
250 
251 		DumpPropertyTree ( currQual, indent+2, 0, outProc, refCon );
252 
253 	}
254 
255 	for ( size_t childNum = 0, childLim = currNode->children.size(); childNum < childLim; ++childNum ) {
256 
257 		const XMP_Node * currChild = currNode->children[childNum];
258 
259 		if ( currChild->parent != currNode ) OutProcLiteral ( "** bad parent link => " );
260 		if ( currChild->options & kXMP_PropIsQualifier ) OutProcLiteral ( "** bad qual flag => " );
261 
262 		if ( currNode->options & kXMP_PropValueIsArray ) {
263 			itemIndex = childNum+1;
264 			if ( currChild->name != kXMP_ArrayItemName ) OutProcLiteral ( "** bad item name => " );
265 		} else {
266 			itemIndex = 0;
267 			if ( currChild->name == kXMP_ArrayItemName ) OutProcLiteral ( "** bad field name => " );
268 		}
269 
270 		DumpPropertyTree ( currChild, indent+1, itemIndex, outProc, refCon );
271 
272 	}
273 
274 }	// DumpPropertyTree
275 
276 
277 // -------------------------------------------------------------------------------------------------
278 // DumpXMLTree
279 // -----------
280 
281 #if DumpXMLParseTree
282 
PutHexByte(FILE * log,unsigned char ch)283 static inline void PutHexByte ( FILE * log, unsigned char ch )
284 {
285 
286 	fprintf ( log, "\\x" );
287 	if ( ch < 0x10 ) {
288 		fprintf ( log, "%c", kHexDigits[ch] );
289 	} else {
290 		fprintf ( log, "%c%c", kHexDigits[ch>>4], kHexDigits[ch&0xF] );
291 	}
292 
293 }	// PutHexByte
294 
295 // -------------------------------------------------------------------------------------------------
296 
PutClearString(FILE * log,const std::string & str)297 static void PutClearString ( FILE * log, const std::string & str )
298 {
299 
300 	for ( size_t i = 0; i != str.size(); ++i ) {
301 		unsigned char ch = str[i];
302 		if ( (0x20 <= ch) && (ch <= 0x7F) ) {
303 			fprintf ( log, "%c", ch );
304 		} else {
305 			PutHexByte ( log, ch );
306 		}
307 	}
308 
309 }	// PutClearString
310 
311 // -------------------------------------------------------------------------------------------------
312 
DumpXMLTree(FILE * log,const XML_Node & node,int indent)313 static void DumpXMLTree ( FILE * log, const XML_Node & node, int indent )
314 {
315 	size_t i;
316 
317 	#if 0	// *** XMP_DebugBuild
318 		if ( (node._namePtr != node.name.c_str()) ||
319 			 (node._valuePtr != node.value.c_str()) ) fprintf ( log, "*** bad debug string ***\n" );
320 	#endif
321 
322 	for ( i = 0; i != (size_t)indent; ++i ) fprintf ( log, "  " );
323 
324 	switch ( node.kind ) {
325 
326 		case kRootNode :
327 			fprintf ( log, "\nStart of XML tree dump\n\n" );
328 			if ( (indent != 0) || (! node.attrs.empty()) ||
329 				 (! node.ns.empty()) || (! node.name.empty()) || (!node.value.empty()) ) fprintf ( log, " ** invalid root ** \n" );
330 			for ( i = 0; i < node.children.size(); ++i ) {
331 				XMP_Uns8 kind = node.children[i]->kind;
332 				if ( (kind == kRootNode) || (kind == kAttrNode) ) fprintf ( log, " ** invalid child ** \n" );
333 				DumpXMLTree ( log, *node.children[i], indent+1 );
334 			}
335 			fprintf ( log, "\nEnd of XML tree dump\n" );
336 			break;
337 
338 		case kElemNode :
339 			fprintf ( log, "Elem %s", node.name.c_str() );
340 			if ( indent == 0 ) fprintf ( log, " ** invalid elem ** " );
341 			if ( ! node.ns.empty() ) fprintf ( log, " @ %s", node.ns.c_str() );
342 			fprintf ( log, "\n" );
343 			for ( i = 0; i < node.attrs.size(); ++i ) {
344 				XMP_Uns8 kind = node.attrs[i]->kind;
345 				if ( kind != kAttrNode ) fprintf ( log, " ** invalid attr ** \n" );
346 				DumpXMLTree ( log, *node.attrs[i], indent+2 );
347 			}
348 			for ( i = 0; i < node.children.size(); ++i ) {
349 				XMP_Uns8 kind = node.children[i]->kind;
350 				if ( (kind == kRootNode) || (kind == kAttrNode) ) fprintf ( log, " ** invalid child ** \n" );
351 				DumpXMLTree ( log, *node.children[i], indent+1 );
352 			}
353 			break;
354 
355 		case kAttrNode :
356 			fprintf ( log, "Attr %s", node.name.c_str() );
357 			if ( (indent == 0) || node.name.empty() || (! node.attrs.empty()) || (! node.children.empty()) ) fprintf ( log, " ** invalid attr ** " );
358 			fprintf ( log, " = \"" );
359 			PutClearString ( log, node.value );
360 			fprintf ( log, "\"" );
361 			if ( ! node.ns.empty() ) fprintf ( log, " @ %s", node.ns.c_str() );
362 			fprintf ( log, "\n" );
363 			break;
364 
365 		case kCDataNode :
366 			if ( (indent == 0) || (! node.ns.empty()) || (! node.name.empty()) ||
367 				 (! node.attrs.empty()) || (! node.children.empty()) ) fprintf ( log, " ** invalid cdata ** \n" );
368 			fprintf ( log, "\"" );
369 			PutClearString ( log, node.value );
370 			fprintf ( log, "\"\n" );
371 			break;
372 
373 		case kPINode :
374 			fprintf ( log, "PI %s", node.name.c_str() );
375 			if ( (indent == 0) || node.name.empty() || (! node.children.empty()) ) fprintf ( log, " ** invalid pi ** \n" );
376 			if ( ! node.value.empty() ) {
377 				fprintf ( log, " <? " );
378 				PutClearString ( log, node.value );
379 				fprintf ( log, " ?>" );
380 			}
381 			fprintf ( log, "\n" );
382 			break;
383 
384 	}
385 
386 }	// DumpXMLTree
387 
388 #endif	// DumpXMLParseTree
389 
390 
391 // -------------------------------------------------------------------------------------------------
392 // CompareNodeNames
393 // ----------------
394 //
395 // Comparison routine for sorting XMP nodes by name. The name "xml:lang" is less than anything else,
396 // and "rdf:type" is less than anything except "xml:lang". This preserves special rules for qualifiers.
397 
398 static bool
CompareNodeNames(XMP_Node * left,XMP_Node * right)399 CompareNodeNames ( XMP_Node * left, XMP_Node * right )
400 {
401 
402 	if ( left->name  == "xml:lang" ) return true;
403 	if ( right->name == "xml:lang" ) return false;
404 
405 	if ( left->name  == "rdf:type" ) return true;
406 	if ( right->name == "rdf:type" ) return false;
407 
408 	return ( left->name < right->name );
409 
410 }	// CompareNodeNames
411 
412 
413 // -------------------------------------------------------------------------------------------------
414 // CompareNodeValues
415 // -----------------
416 //
417 // Comparison routine for sorting XMP nodes by value.
418 
419 static bool
CompareNodeValues(XMP_Node * left,XMP_Node * right)420 CompareNodeValues ( XMP_Node * left, XMP_Node * right )
421 {
422 
423 	if ( XMP_PropIsSimple ( left->options ) && XMP_PropIsSimple ( right->options ) ) {
424 		return ( left->value < right->value );
425 	}
426 
427 	XMP_OptionBits leftForm  = left->options & kXMP_PropCompositeMask;
428 	XMP_OptionBits rightForm = right->options & kXMP_PropCompositeMask;
429 
430 	return ( leftForm < rightForm );
431 
432 }	// CompareNodeValues
433 
434 
435 // -------------------------------------------------------------------------------------------------
436 // CompareNodeLangs
437 // ----------------
438 //
439 // Comparison routine for sorting XMP nodes by xml:lang qualifier. An "x-default" value is less than
440 // any other language.
441 
442 static bool
CompareNodeLangs(XMP_Node * left,XMP_Node * right)443 CompareNodeLangs ( XMP_Node * left, XMP_Node * right )
444 {
445 
446 	if ( left->qualifiers.empty()  || (left->qualifiers[0]->name  != "xml:lang") ) return false;
447 	if ( right->qualifiers.empty() || (right->qualifiers[0]->name != "xml:lang") ) return false;
448 
449 	if ( left->qualifiers[0]->value  == "x-default" ) return true;
450 	if ( right->qualifiers[0]->value == "x-default" ) return false;
451 
452 	return ( left->qualifiers[0]->value < right->qualifiers[0]->value );
453 
454 }	// CompareNodeLangs
455 
456 
457 // -------------------------------------------------------------------------------------------------
458 // SortWithinOffspring
459 // -------------------
460 //
461 // Sort one level down, within the elements of a node vector. This sorts the qualifiers of each
462 // node. If the node is a struct it sorts the fields by names. If the node is an unordered array it
463 // sorts the elements by value. If the node is an AltText array it sorts the elements by language.
464 
465 static void
SortWithinOffspring(XMP_NodeOffspring & nodeVec)466 SortWithinOffspring ( XMP_NodeOffspring & nodeVec )
467 {
468 
469 	for ( size_t i = 0, limit = nodeVec.size(); i < limit; ++i ) {
470 
471 		XMP_Node * currPos = nodeVec[i];
472 
473 		if ( ! currPos->qualifiers.empty() ) {
474 			sort ( currPos->qualifiers.begin(), currPos->qualifiers.end(), CompareNodeNames );
475 			SortWithinOffspring ( currPos->qualifiers );
476 		}
477 
478 		if ( ! currPos->children.empty() ) {
479 
480 			if ( XMP_PropIsStruct ( currPos->options ) || XMP_NodeIsSchema ( currPos->options ) ) {
481 				sort ( currPos->children.begin(), currPos->children.end(), CompareNodeNames );
482 			} else if ( XMP_PropIsArray ( currPos->options ) ) {
483 				if ( XMP_ArrayIsUnordered ( currPos->options ) ) {
484 					stable_sort ( currPos->children.begin(), currPos->children.end(), CompareNodeValues );
485 				} else if ( XMP_ArrayIsAltText ( currPos->options ) ) {
486 					sort ( currPos->children.begin(), currPos->children.end(), CompareNodeLangs );
487 				}
488 			}
489 
490 			SortWithinOffspring ( currPos->children );
491 
492 		}
493 
494 	}
495 
496 }	// SortWithinOffspring
497 
498 
499 // -------------------------------------------------------------------------------------------------
500 // RegisterAlias
501 // -------------
502 //
503 // Allow 3 kinds of alias:
504 //	TopProp => TopProp
505 //	TopProp => TopArray[1]
506 //	TopProp => TopArray[@xml:lang='x-default']
507 //
508 // A new alias can be made to something that is already aliased, as long as the net result is one of
509 // the legitimate forms. The new alias can already have aliases to it, also as long as result of
510 // adjusting all of the exiting aliases leaves them legal.
511 //
512 // ! The caller assumes all risk that new aliases do not invalidate existing XMPMeta objects. Any
513 // ! conflicts will result in later references throwing bad XPath exceptions.
514 
515 static void
RegisterAlias(XMP_StringPtr aliasNS,XMP_StringPtr aliasProp,XMP_StringPtr actualNS,XMP_StringPtr actualProp,XMP_OptionBits arrayForm)516 RegisterAlias ( XMP_StringPtr  aliasNS,
517 				XMP_StringPtr  aliasProp,
518 				XMP_StringPtr  actualNS,
519 				XMP_StringPtr  actualProp,
520 				XMP_OptionBits arrayForm )
521 {
522 	XMP_ExpandedXPath	expAlias, expActual;
523 	XMP_AliasMapPos		mapPos;
524 	XMP_ExpandedXPath *	regActual = 0;
525 
526 	XMP_Assert ( (aliasNS != 0) && (aliasProp != 0) && (actualNS != 0) && (actualProp != 0) );	// Enforced by wrapper.
527 
528 	// Expand the alias and actual names, make sure they are one of the basic 3 forms. When counting
529 	// the expanded XPath size remember that the schema URI is the first component. We don't have to
530 	// compare the schema URIs though, the (unique) prefix is part of the top property name.
531 
532 	ExpandXPath ( aliasNS, aliasProp, &expAlias );
533 	ExpandXPath ( actualNS, actualProp, &expActual );
534 	if ( (expAlias.size() != 2) || (expActual.size() != 2) ) {
535 		XMP_Throw ( "Alias and actual property names must be simple", kXMPErr_BadXPath );
536 	}
537 
538 	arrayForm = VerifySetOptions ( arrayForm, 0 );
539 	if ( arrayForm != 0 ) {
540 		if ( (arrayForm & ~kXMP_PropArrayFormMask) != 0 ) XMP_Throw ( "Only array form flags are allowed", kXMPErr_BadOptions );
541 		expActual[1].options |= arrayForm;	// Set the array form for the top level step.
542 		if ( ! (arrayForm & kXMP_PropArrayIsAltText) ) {
543 			expActual.push_back ( XPathStepInfo ( "[1]", kXMP_ArrayIndexStep ) );
544 		} else {
545 			expActual.push_back ( XPathStepInfo ( "[?xml:lang=\"x-default\"]", kXMP_QualSelectorStep ) );
546 		}
547 	}
548 
549 	// See if there are any conflicts with existing aliases. A couple of the checks are easy. If the
550 	// alias is already aliased it is only OK to reregister an identical alias. If the actual is
551 	// already aliased to something else and the new chain is legal, just swap in the old base.
552 
553 	mapPos = sRegisteredAliasMap->find ( expAlias[kRootPropStep].step );
554 	if ( mapPos != sRegisteredAliasMap->end() ) {
555 
556 		// This alias is already registered to something, make sure it is the same something.
557 
558 		regActual = &mapPos->second;
559 		if ( arrayForm != (mapPos->second[1].options & kXMP_PropArrayFormMask) ) {
560 			XMP_Throw ( "Mismatch with existing alias array form", kXMPErr_BadParam );
561 		}
562 		if ( expActual.size() != regActual->size() ) {
563 			XMP_Throw ( "Mismatch with existing actual path", kXMPErr_BadParam );
564 		}
565 		if ( expActual[kRootPropStep].step != (*regActual)[kRootPropStep].step ) {
566 			XMP_Throw ( "Mismatch with existing actual name", kXMPErr_BadParam );
567 		}
568 		if ( (expActual.size() == 3) && (expActual[kAliasIndexStep].step != (*regActual)[kAliasIndexStep].step) ) {
569 			XMP_Throw ( "Mismatch with existing actual array item", kXMPErr_BadParam );
570 		}
571 		return;
572 
573 	}
574 
575 	mapPos = sRegisteredAliasMap->find ( expActual[kRootPropStep].step );
576 	if ( mapPos != sRegisteredAliasMap->end() ) {
577 
578 		// The actual is already aliased to something else.
579 
580 		regActual = &mapPos->second;
581 		if ( expActual.size() == 2 ) {
582 			expActual = *regActual;	// TopProp => TopProp => anything : substitute the entire old base.
583 		} else if ( regActual->size() != 2 ) {
584 			XMP_Throw ( "Can't alias an array item to an array item", kXMPErr_BadParam );	// TopProp => TopArray[] => TopArray[] : nope.
585 		} else {
586 			expActual[kSchemaStep].step = (*regActual)[kSchemaStep].step;		// TopProp => TopArray[] => TopProp :
587 			expActual[kRootPropStep].step   = (*regActual)[kRootPropStep].step;	//	substitute the old base name.
588 		}
589 
590 	}
591 
592 	// Checking for existing aliases to this one is touchier. This involves updating the alias map,
593 	// which must not be done unless all of the changes are legal. So we need 2 loops, one to verify
594 	// that everything is OK, and one to make the changes. The bad case is:
595 	//	TopProp => TopArray[] => TopArray[]
596 	// In the valid cases we back substitute the new base.
597 
598 	for ( mapPos = sRegisteredAliasMap->begin(); mapPos != sRegisteredAliasMap->end(); ++mapPos ) {
599 		regActual = &mapPos->second;
600 		if ( expAlias[kRootPropStep].step == (*regActual)[kRootPropStep].step ) {
601 			if ( (regActual->size() == 2) && (expAlias.size() == 2) ) {
602 				XMP_Throw ( "Can't alias an array item to an array item", kXMPErr_BadParam );
603 			}
604 		}
605 	}
606 
607 	for ( mapPos = sRegisteredAliasMap->begin(); mapPos != sRegisteredAliasMap->end(); ++mapPos ) {
608 		regActual = &mapPos->second;
609 		if ( expAlias[kRootPropStep].step == (*regActual)[kRootPropStep].step ) {
610 
611 			if ( regActual->size() == 1 ) {
612 				*regActual = expActual;	// TopProp => TopProp => anything : substitute the entire new base.
613 			} else {
614 				(*regActual)[kSchemaStep].step = expActual[kSchemaStep].step;	// TopProp => TopArray[] => TopProp :
615 				(*regActual)[kRootPropStep].step   = expActual[kRootPropStep].step;		//	substitute the new base name.
616 			}
617 
618 		}
619 	}
620 
621 	// Finally, all is OK to register the new alias.
622 
623 	(void) sRegisteredAliasMap->insert ( XMP_AliasMap::value_type ( expAlias[kRootPropStep].step, expActual ) );
624 
625 }	// RegisterAlias
626 
627 
628 // -------------------------------------------------------------------------------------------------
629 // RegisterStandardAliases
630 // -----------------------
631 
632 static void
RegisterStandardAliases()633 RegisterStandardAliases()
634 {
635 
636 	// Aliases from XMP to DC.
637 	RegisterAlias ( kXMP_NS_XMP, "Author",       kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered );
638 	RegisterAlias ( kXMP_NS_XMP, "Authors",      kXMP_NS_DC, "creator", 0 );
639 	RegisterAlias ( kXMP_NS_XMP, "Description",  kXMP_NS_DC, "description", 0 );
640 	RegisterAlias ( kXMP_NS_XMP, "Format",       kXMP_NS_DC, "format", 0 );
641 	RegisterAlias ( kXMP_NS_XMP, "Keywords",     kXMP_NS_DC, "subject", 0 );
642 	RegisterAlias ( kXMP_NS_XMP, "Locale",       kXMP_NS_DC, "language", 0 );
643 	RegisterAlias ( kXMP_NS_XMP, "Title",        kXMP_NS_DC, "title", 0 );
644 	RegisterAlias ( kXMP_NS_XMP_Rights, "Copyright", kXMP_NS_DC, "rights", 0 );
645 
646 	// Aliases from PDF to DC and XMP.
647 	RegisterAlias ( kXMP_NS_PDF, "Author",       kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered );
648 	RegisterAlias ( kXMP_NS_PDF, "BaseURL",      kXMP_NS_XMP, "BaseURL", 0 );
649 	RegisterAlias ( kXMP_NS_PDF, "CreationDate", kXMP_NS_XMP, "CreateDate", 0 );
650 	RegisterAlias ( kXMP_NS_PDF, "Creator",      kXMP_NS_XMP, "CreatorTool", 0 );
651 	RegisterAlias ( kXMP_NS_PDF, "ModDate",      kXMP_NS_XMP, "ModifyDate", 0 );
652 	RegisterAlias ( kXMP_NS_PDF, "Subject",      kXMP_NS_DC,  "description", kXMP_PropArrayIsAltText );
653 	RegisterAlias ( kXMP_NS_PDF, "Title",        kXMP_NS_DC,  "title", kXMP_PropArrayIsAltText );
654 
655 	// Aliases from Photoshop to DC and XMP.
656 	RegisterAlias ( kXMP_NS_Photoshop, "Author",       kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered );
657 	RegisterAlias ( kXMP_NS_Photoshop, "Caption",      kXMP_NS_DC, "description", kXMP_PropArrayIsAltText );
658 	RegisterAlias ( kXMP_NS_Photoshop, "Copyright",    kXMP_NS_DC, "rights", kXMP_PropArrayIsAltText );
659 	RegisterAlias ( kXMP_NS_Photoshop, "Keywords",     kXMP_NS_DC, "subject", 0 );
660 	RegisterAlias ( kXMP_NS_Photoshop, "Marked",       kXMP_NS_XMP_Rights, "Marked", 0 );
661 	RegisterAlias ( kXMP_NS_Photoshop, "Title",        kXMP_NS_DC, "title", kXMP_PropArrayIsAltText );
662 	RegisterAlias ( kXMP_NS_Photoshop, "WebStatement", kXMP_NS_XMP_Rights, "WebStatement", 0 );
663 
664 	// Aliases from TIFF and EXIF to DC and XMP.
665 	RegisterAlias ( kXMP_NS_TIFF, "Artist",            kXMP_NS_DC,  "creator", kXMP_PropArrayIsOrdered);
666 	RegisterAlias ( kXMP_NS_TIFF, "Copyright",         kXMP_NS_DC,  "rights", 0 );
667 	RegisterAlias ( kXMP_NS_TIFF, "DateTime",          kXMP_NS_XMP, "ModifyDate", 0 );
668 	RegisterAlias ( kXMP_NS_EXIF, "DateTimeDigitized", kXMP_NS_XMP, "CreateDate", 0 );
669 	RegisterAlias ( kXMP_NS_TIFF, "ImageDescription",  kXMP_NS_DC,  "description", kXMP_PropArrayIsAltText );
670 	RegisterAlias ( kXMP_NS_TIFF, "Software",          kXMP_NS_XMP, "CreatorTool", 0 );
671 
672 	// Aliases from PNG to DC and XMP.
673 	RegisterAlias ( kXMP_NS_PNG, "Author",           kXMP_NS_DC,  "creator", kXMP_PropArrayIsOrdered);
674 	RegisterAlias ( kXMP_NS_PNG, "Copyright",        kXMP_NS_DC,  "rights", kXMP_PropArrayIsAltText);
675 	RegisterAlias ( kXMP_NS_PNG, "CreationTime",     kXMP_NS_XMP, "CreateDate", 0 );
676 	RegisterAlias ( kXMP_NS_PNG, "Description",      kXMP_NS_DC,  "description", kXMP_PropArrayIsAltText);
677 	RegisterAlias ( kXMP_NS_PNG, "ModificationTime", kXMP_NS_XMP, "ModifyDate", 0 );
678 	RegisterAlias ( kXMP_NS_PNG, "Software",         kXMP_NS_XMP, "CreatorTool", 0 );
679 	RegisterAlias ( kXMP_NS_PNG, "Title",            kXMP_NS_DC,  "title", kXMP_PropArrayIsAltText);
680 
681 }	// RegisterStandardAliases
682 
683 
684 // =================================================================================================
685 // Constructors
686 // ============
687 
688 
XMPMeta()689 XMPMeta::XMPMeta() : tree(XMP_Node(0,"",0)), clientRefs(0), xmlParser(0)
690 {
691 	#if XMP_TraceCTorDTor
692 		printf ( "Default construct XMPMeta @ %.8X\n", this );
693 	#endif
694 
695 	if ( sDefaultErrorCallback.clientProc != 0 ) {
696 		this->errorCallback.wrapperProc = sDefaultErrorCallback.wrapperProc;
697 		this->errorCallback.clientProc = sDefaultErrorCallback.clientProc;
698 		this->errorCallback.context = sDefaultErrorCallback.context;
699 		this->errorCallback.limit = sDefaultErrorCallback.limit;
700 	}
701 
702 }	// XMPMeta
703 
704 // -------------------------------------------------------------------------------------------------
705 
~XMPMeta()706 XMPMeta::~XMPMeta() RELEASE_NO_THROW
707 {
708 	#if XMP_TraceCTorDTor
709 		printf ( "Destruct XMPMeta @ %.8X\n", this );
710 	#endif
711 
712 	XMP_Assert ( this->clientRefs <= 0 );
713 	if ( xmlParser != 0 ) delete ( xmlParser );
714 	xmlParser = 0;
715 
716 }	// ~XMPMeta
717 
718 
719 // =================================================================================================
720 // Class Static Functions
721 // ======================
722 //
723 //
724 // =================================================================================================
725 
726 // -------------------------------------------------------------------------------------------------
727 // GetVersionInfo
728 // --------------
729 
730 /* class-static */ void
GetVersionInfo(XMP_VersionInfo * info)731 XMPMeta::GetVersionInfo ( XMP_VersionInfo * info )
732 {
733 
734 	memset ( info, 0, sizeof(*info) );	// AUDIT: Safe, using sizeof the destination.
735 	XMP_Assert ( sizeof(*info) == sizeof(XMP_VersionInfo) );
736 
737 	info->major   = XMPCORE_API_VERSION_MAJOR;
738 	info->minor   = XMPCORE_API_VERSION_MINOR;
739 	info->micro   = 0; //no longer used
740 	info->isDebug = kXMPCore_DebugFlag;
741 	info->flags   = 0;	// ! None defined yet.
742 	info->message = kXMPCore_VersionMessage;
743 
744 }	// GetVersionInfo
745 
746 // -------------------------------------------------------------------------------------------------
747 // Initialize
748 // ----------
749 
750 #if XMP_TraceCoreCalls
751 	FILE * xmpCoreLog = stderr;
752 #endif
753 
754 #if UseGlobalLibraryLock
755 	XMP_BasicMutex sLibraryLock;
756 #endif
757 
758 /* class-static */ bool
Initialize()759 XMPMeta::Initialize()
760 {
761 	// Allocate and initialize static objects.
762 
763 	++sXMP_InitCount;
764 	if ( sXMP_InitCount > 1 ) return true;
765 
766 	#if XMP_TraceCoreCallsToFile
767 		xmpCoreLog = fopen ( "XMPCoreLog.txt", "w" );
768 		if ( xmpCoreLog == 0 ) xmpCoreLog = stderr;
769 	#endif
770 
771 	#if UseGlobalLibraryLock
772 		InitializeBasicMutex ( sLibraryLock );
773 	#endif
774 
775 	if ( ! Initialize_LibUtils() ) return false;
776 
777 	#if ENABLE_CPP_DOM_MODEL
778 		try {
779 			AdobeXMPCore_Int::InitializeXMPCommonFramework();
780 
781 		} catch ( ... ) {
782 			return false;
783 		}
784 		AdobeXMPCore_Int::INameSpacePrefixMap_I::CreateDefaultNameSpacePrefixMap();
785 		sDefaultNamespacePrefixMapLock = new XMP_ReadWriteLock;
786 
787 		// Explicitly setting sUseNewCoreAPIs as false (default value)
788 		sUseNewCoreAPIs = false;
789 	#endif
790 
791 	xdefaultName = new XMP_VarString ( "x-default" );
792 
793 	sRegisteredNamespaces = new XMP_NamespaceTable;
794 	sRegisteredAliasMap   = new XMP_AliasMap;
795 	InitializeUnicodeConversions();
796 
797 
798 	// Register standard namespaces and aliases.
799 
800 	XMP_StringPtr	voidPtr;
801 	XMP_StringLen	voidLen;
802 
803 	(void) RegisterNamespace ( kXMP_NS_XML, "xml", &voidPtr, &voidLen );
804 	(void) RegisterNamespace ( kXMP_NS_RDF, "rdf", &voidPtr, &voidLen );
805 	(void) RegisterNamespace ( kXMP_NS_DC, "dc", &voidPtr, &voidLen );
806 
807 	(void) RegisterNamespace ( kXMP_NS_XMP, "xmp", &voidPtr, &voidLen );
808 	(void) RegisterNamespace ( kXMP_NS_PDF, "pdf", &voidPtr, &voidLen );
809 	(void) RegisterNamespace ( kXMP_NS_Photoshop, "photoshop", &voidPtr, &voidLen );
810 	(void) RegisterNamespace ( kXMP_NS_PSAlbum, "album", &voidPtr, &voidLen );
811 	(void) RegisterNamespace ( kXMP_NS_EXIF, "exif", &voidPtr, &voidLen );
812 	(void) RegisterNamespace ( kXMP_NS_EXIF_Aux, "aux", &voidPtr, &voidLen );
813 	(void) RegisterNamespace ( kXMP_NS_ExifEX, "exifEX", &voidPtr, &voidLen );
814 	(void) RegisterNamespace ( kXMP_NS_TIFF, "tiff", &voidPtr, &voidLen );
815 	(void) RegisterNamespace ( kXMP_NS_PNG, "png", &voidPtr, &voidLen );
816 	(void) RegisterNamespace ( kXMP_NS_JPEG, "jpeg", &voidPtr, &voidLen );
817 	(void) RegisterNamespace ( kXMP_NS_JP2K, "jp2k", &voidPtr, &voidLen );
818 	(void) RegisterNamespace ( kXMP_NS_CameraRaw, "crs", &voidPtr, &voidLen );
819 	(void) RegisterNamespace ( kXMP_NS_ASF, "asf", &voidPtr, &voidLen );
820 	(void) RegisterNamespace ( kXMP_NS_WAV, "wav", &voidPtr, &voidLen );
821 
822 	(void) RegisterNamespace ( kXMP_NS_AdobeStockPhoto, "bmsp", &voidPtr, &voidLen );
823 	(void) RegisterNamespace ( kXMP_NS_CreatorAtom, "creatorAtom", &voidPtr, &voidLen );
824 
825 	(void) RegisterNamespace ( kXMP_NS_XMP_Rights, "xmpRights", &voidPtr, &voidLen );
826 	(void) RegisterNamespace ( kXMP_NS_XMP_MM, "xmpMM", &voidPtr, &voidLen );
827 	(void) RegisterNamespace ( kXMP_NS_XMP_BJ, "xmpBJ", &voidPtr, &voidLen );
828 	(void) RegisterNamespace ( kXMP_NS_XMP_Note, "xmpNote", &voidPtr, &voidLen );
829 
830 	(void) RegisterNamespace ( kXMP_NS_DM, "xmpDM", &voidPtr, &voidLen );
831 	(void) RegisterNamespace ( kXMP_NS_Script, "xmpScript", &voidPtr, &voidLen );
832 	(void) RegisterNamespace ( kXMP_NS_BWF, "bext", &voidPtr, &voidLen );
833 	(void) RegisterNamespace ( kXMP_NS_AEScart, "AEScart", &voidPtr, &voidLen );
834 	(void) RegisterNamespace ( kXMP_NS_RIFFINFO, "riffinfo", &voidPtr, &voidLen );
835 	(void) RegisterNamespace ( kXMP_NS_XMP_Text, "xmpT", &voidPtr, &voidLen );
836 	(void) RegisterNamespace ( kXMP_NS_XMP_PagedFile, "xmpTPg", &voidPtr, &voidLen );
837 	(void) RegisterNamespace ( kXMP_NS_XMP_Graphics, "xmpG", &voidPtr, &voidLen );
838 	(void) RegisterNamespace ( kXMP_NS_XMP_Image, "xmpGImg", &voidPtr, &voidLen );
839 
840 	(void) RegisterNamespace ( kXMP_NS_XMP_Font, "stFnt", &voidPtr, &voidLen );
841 	(void) RegisterNamespace ( kXMP_NS_XMP_Dimensions, "stDim", &voidPtr, &voidLen );
842 	(void) RegisterNamespace ( kXMP_NS_XMP_ResourceEvent, "stEvt", &voidPtr, &voidLen );
843 	(void) RegisterNamespace ( kXMP_NS_XMP_ResourceRef, "stRef", &voidPtr, &voidLen );
844 	(void) RegisterNamespace ( kXMP_NS_XMP_ST_Version, "stVer", &voidPtr, &voidLen );
845 	(void) RegisterNamespace ( kXMP_NS_XMP_ST_Job, "stJob", &voidPtr, &voidLen );
846 	(void) RegisterNamespace ( kXMP_NS_XMP_ManifestItem, "stMfs", &voidPtr, &voidLen );
847 
848 	(void) RegisterNamespace ( kXMP_NS_XMP_IdentifierQual, "xmpidq", &voidPtr, &voidLen );
849 
850 	(void) RegisterNamespace ( kXMP_NS_IPTCCore, "Iptc4xmpCore", &voidPtr, &voidLen );
851 	(void) RegisterNamespace ( kXMP_NS_IPTCExt, "Iptc4xmpExt", &voidPtr, &voidLen );
852 	(void) RegisterNamespace ( kXMP_NS_DICOM, "DICOM", &voidPtr, &voidLen );
853 	(void) RegisterNamespace ( kXMP_NS_PLUS, "plus", &voidPtr, &voidLen );
854 
855 	(void) RegisterNamespace ( kXMP_NS_PDFA_Schema, "pdfaSchema", &voidPtr, &voidLen );
856 	(void) RegisterNamespace ( kXMP_NS_PDFA_Property, "pdfaProperty", &voidPtr, &voidLen );
857 	(void) RegisterNamespace ( kXMP_NS_PDFA_Type, "pdfaType", &voidPtr, &voidLen );
858 	(void) RegisterNamespace ( kXMP_NS_PDFA_Field, "pdfaField", &voidPtr, &voidLen );
859 	(void) RegisterNamespace ( kXMP_NS_PDFA_ID, "pdfaid", &voidPtr, &voidLen );
860 	(void) RegisterNamespace ( kXMP_NS_PDFA_Extension, "pdfaExtension", &voidPtr, &voidLen );
861 
862 	(void) RegisterNamespace ( kXMP_NS_PDFX, "pdfx", &voidPtr, &voidLen );
863 	(void) RegisterNamespace ( kXMP_NS_PDFX_ID, "pdfxid", &voidPtr, &voidLen );
864 
865 	(void) RegisterNamespace ( "adobe:ns:meta/", "x", &voidPtr, &voidLen );
866 	(void) RegisterNamespace ( "http://ns.adobe.com/iX/1.0/", "iX", &voidPtr, &voidLen );
867 
868 	(void) RegisterNamespace( kXMP_NS_iXML, "iXML", &voidPtr, &voidLen );
869 
870 	RegisterStandardAliases();
871 
872 	// Initialize the other core classes.
873 
874 	if ( ! XMPIterator::Initialize() ) XMP_Throw ( "Failure from XMPIterator::Initialize", kXMPErr_InternalFailure );
875 	if ( ! XMPUtils::Initialize() ) XMP_Throw ( "Failure from XMPUtils::Initialize", kXMPErr_InternalFailure );
876 	// Do miscelaneous semantic checks of types and arithmetic.
877 
878 	XMP_Assert ( sizeof(XMP_Int8) == 1 );
879 	XMP_Assert ( sizeof(XMP_Int16) == 2 );
880 	XMP_Assert ( sizeof(XMP_Int32) == 4 );
881 	XMP_Assert ( sizeof(XMP_Int64) == 8 );
882 	XMP_Assert ( sizeof(XMP_Uns8) == 1 );
883 	XMP_Assert ( sizeof(XMP_Uns16) == 2 );
884 	XMP_Assert ( sizeof(XMP_Uns32) == 4 );
885 	XMP_Assert ( sizeof(XMP_Uns64) == 8 );
886 	XMP_Assert ( sizeof(XMP_Bool) == 1 );
887 
888 	XMP_Assert ( sizeof(XMP_OptionBits) == 4 );	// Check that option masking work on all 32 bits.
889 	XMP_OptionBits flag = (XMP_OptionBits) (~0UL);
890 	XMP_Assert ( flag == (XMP_OptionBits)(-1L) );
891 	XMP_Assert ( (flag ^ kXMP_PropHasLang) == 0xFFFFFFBFUL );
892 	XMP_Assert ( (flag & ~kXMP_PropHasLang) == 0xFFFFFFBFUL );
893 
894 	XMP_OptionBits opt1 = 0;	// Check the general option bit macros.
895 	XMP_OptionBits opt2 = (XMP_OptionBits)~0UL;
896 	XMP_SetOption ( opt1, kXMP_PropValueIsArray );
897 	XMP_ClearOption ( opt2, kXMP_PropValueIsArray );
898 	XMP_Assert ( opt1 == ~opt2 );
899 	XMP_Assert ( XMP_TestOption ( opt1, kXMP_PropValueIsArray ) );
900 	XMP_Assert ( ! XMP_TestOption ( opt2, kXMP_PropValueIsArray ) );
901 
902 	XMP_Assert ( XMP_PropIsSimple ( ~kXMP_PropCompositeMask ) );	// Check the special option bit macros.
903 	XMP_Assert ( ! XMP_PropIsSimple ( kXMP_PropValueIsStruct ) );
904 	XMP_Assert ( ! XMP_PropIsSimple ( kXMP_PropValueIsArray ) );
905 
906 	XMP_Assert ( XMP_PropIsStruct ( kXMP_PropValueIsStruct ) );
907 	XMP_Assert ( XMP_PropIsArray  ( kXMP_PropValueIsArray ) );
908 	XMP_Assert ( ! XMP_PropIsStruct ( ~kXMP_PropValueIsStruct ) );
909 	XMP_Assert ( ! XMP_PropIsArray  ( ~kXMP_PropValueIsArray ) );
910 
911 	XMP_Assert ( XMP_ArrayIsUnordered ( ~kXMP_PropArrayIsOrdered ) );
912 	XMP_Assert ( XMP_ArrayIsOrdered   ( kXMP_PropArrayIsOrdered ) );
913 	XMP_Assert ( XMP_ArrayIsAlternate ( kXMP_PropArrayIsAlternate ) );
914 	XMP_Assert ( XMP_ArrayIsAltText   ( kXMP_PropArrayIsAltText ) );
915 	XMP_Assert ( ! XMP_ArrayIsUnordered ( kXMP_PropArrayIsOrdered ) );
916 	XMP_Assert ( ! XMP_ArrayIsOrdered   ( ~kXMP_PropArrayIsOrdered ) );
917 	XMP_Assert ( ! XMP_ArrayIsAlternate ( ~kXMP_PropArrayIsAlternate ) );
918 	XMP_Assert ( ! XMP_ArrayIsAltText   ( ~kXMP_PropArrayIsAltText ) );
919 
920 	XMP_Assert ( XMP_PropHasQualifiers ( kXMP_PropHasQualifiers ) );
921 	XMP_Assert ( XMP_PropIsQualifier   ( kXMP_PropIsQualifier ) );
922 	XMP_Assert ( XMP_PropHasLang       ( kXMP_PropHasLang ) );
923 	XMP_Assert ( ! XMP_PropHasQualifiers ( ~kXMP_PropHasQualifiers ) );
924 	XMP_Assert ( ! XMP_PropIsQualifier   ( ~kXMP_PropIsQualifier ) );
925 	XMP_Assert ( ! XMP_PropHasLang       ( ~kXMP_PropHasLang ) );
926 
927 	XMP_Assert ( XMP_NodeIsSchema ( kXMP_SchemaNode ) );
928 	XMP_Assert ( XMP_PropIsAlias  ( kXMP_PropIsAlias ) );
929 	XMP_Assert ( ! XMP_NodeIsSchema ( ~kXMP_SchemaNode ) );
930 	XMP_Assert ( ! XMP_PropIsAlias  ( ~kXMP_PropIsAlias ) );
931 
932 	#if 0	// Generally off, enable to hand check generated code.
933 		extern XMP_OptionBits opt3, opt4;
934 		if ( XMP_TestOption ( opt3, kXMP_PropValueIsArray ) ) opt4 = opt3;
935 		if ( ! XMP_TestOption ( opt3, kXMP_PropValueIsStruct ) ) opt4 = opt3;
936 		static bool ok1 = XMP_TestOption ( opt4, kXMP_PropValueIsArray );
937 		static bool ok2 = ! XMP_TestOption ( opt4, kXMP_PropValueIsStruct );
938 	#endif
939 
940 	// Make sure the embedded info strings are referenced and kept.
941 	if ( (kXMPCore_EmbeddedVersion[0] == 0) || (kXMPCore_EmbeddedCopyright[0] == 0) ) return false;
942 	return true;
943 
944 }	// Initialize
945 
946 
947 // -------------------------------------------------------------------------------------------------
948 // Terminate
949 // ---------
950 
951 /* class-static */ void
Terminate()952 XMPMeta::Terminate() RELEASE_NO_THROW
953 {
954 	--sXMP_InitCount;
955 	if ( sXMP_InitCount != 0 ) return;	// Not ready to terminate, or already terminated.
956 
957 	XMPIterator::Terminate();
958 	XMPUtils::Terminate();
959 #if ENABLE_CPP_DOM_MODEL
960 		AdobeXMPCore_Int::INameSpacePrefixMap_I::DestroyDefaultNameSapcePrefixMap();
961 		AdobeXMPCore_Int::IDOMImplementationRegistry_I::DestoryDOMImplementationRegistry();
962 		AdobeXMPCore_Int::ICoreObjectFactory_I::DestroyCoreObjectFactory();
963 		AdobeXMPCore_Int::ICoreConfigurationManager_I::DestroyCoreConfigurationManager();
964 		AdobeXMPCore_Int::TerminateXMPCommonFramework();
965 		EliminateGlobal( sDefaultNamespacePrefixMapLock );
966 		// Explicitly setting sUseNewCoreAPIs as false (default value)
967 		sUseNewCoreAPIs = false;
968 		#if !XMP_StaticBuild
969 			EliminateGlobal( sInternalClientAllocator );
970 		#endif
971 #endif
972 
973 
974 	EliminateGlobal ( sRegisteredNamespaces );
975 	EliminateGlobal ( sRegisteredAliasMap );
976 
977 	EliminateGlobal ( xdefaultName );
978 
979 	Terminate_LibUtils();
980 
981 	#if UseGlobalLibraryLock
982 		TerminateBasicMutex ( sLibraryLock );
983 	#endif
984 
985 	#if XMP_TraceCoreCallsToFile
986 		if ( xmpCoreLog != stderr ) fclose ( xmpCoreLog );
987 		xmpCoreLog = stderr;
988 	#endif
989 
990 	// reset static variables
991 	sDefaultErrorCallback.Clear();
992 }	// Terminate
993 
994 
995 // -------------------------------------------------------------------------------------------------
996 // DumpNamespaces
997 // --------------
998 //
999 // Dump the prefix to URI map (easier to read) and verify that both are consistent and legit.
1000 
1001 // *** Should put checks in a separate routine for regular calling in debug builds.
1002 
1003 /* class-static */ XMP_Status
DumpNamespaces(XMP_TextOutputProc outProc,void * refCon)1004 XMPMeta::DumpNamespaces ( XMP_TextOutputProc outProc,
1005                           void *             refCon )
1006 {
1007 
1008 	sRegisteredNamespaces->Dump ( outProc, refCon );
1009 	return 0;
1010 
1011 }	// DumpNamespaces
1012 
1013 
1014 // -------------------------------------------------------------------------------------------------
1015 // GetGlobalOptions
1016 // ----------------
1017 
1018 /* class-static */ XMP_OptionBits
GetGlobalOptions()1019 XMPMeta::GetGlobalOptions()
1020 {
1021 	XMP_OptionBits	options = 0;
1022 
1023 	return options;
1024 
1025 }	// GetGlobalOptions
1026 
1027 
1028 // -------------------------------------------------------------------------------------------------
1029 // SetGlobalOptions
1030 // ----------------
1031 
1032 /* class-static */ void
SetGlobalOptions(XMP_OptionBits options)1033 XMPMeta::SetGlobalOptions ( XMP_OptionBits options )
1034 {
1035 
1036 	void * p; p = &options;	// Avoid unused param warnings.
1037 	XMP_Throw("Unimplemented method XMPMeta::SetGlobalOptions", kXMPErr_Unimplemented);
1038 
1039 }	// SetGlobalOptions
1040 
1041 
1042 // -------------------------------------------------------------------------------------------------
1043 // RegisterNamespace
1044 // -----------------
1045 
1046 /* class-static */ bool
RegisterNamespace(XMP_StringPtr namespaceURI,XMP_StringPtr suggestedPrefix,XMP_StringPtr * registeredPrefix,XMP_StringLen * prefixSize)1047 XMPMeta::RegisterNamespace ( XMP_StringPtr	 namespaceURI,
1048 							 XMP_StringPtr	 suggestedPrefix,
1049 							 XMP_StringPtr * registeredPrefix,
1050 							 XMP_StringLen * prefixSize )
1051 {
1052 
1053 	bool returnValue = sRegisteredNamespaces->Define ( namespaceURI, suggestedPrefix, registeredPrefix, prefixSize );
1054 #if ENABLE_CPP_DOM_MODEL
1055 	const char * prefix = NULL;
1056 	XMP_StringLen len = 0;
1057 	sRegisteredNamespaces->GetPrefix( namespaceURI, &prefix, &len );
1058 	XMP_VarString prefixWithoutColon( prefix, len - 1 );
1059 	{
1060 		XMP_AutoLock aLock( sDefaultNamespacePrefixMapLock, true );
1061 		AdobeXMPCore_Int::INameSpacePrefixMap_I::InsertInDefaultNameSpacePrefixMap( prefixWithoutColon.c_str(), prefixWithoutColon.size(), namespaceURI, AdobeXMPCommon::npos );
1062 	}
1063 #endif
1064 	return returnValue;
1065 }	// RegisterNamespace
1066 
1067 
1068 // -------------------------------------------------------------------------------------------------
1069 // GetNamespacePrefix
1070 // ------------------
1071 
1072 /* class-static */ bool
GetNamespacePrefix(XMP_StringPtr namespaceURI,XMP_StringPtr * namespacePrefix,XMP_StringLen * prefixSize)1073 XMPMeta::GetNamespacePrefix	( XMP_StringPtr   namespaceURI,
1074 							  XMP_StringPtr * namespacePrefix,
1075 							  XMP_StringLen * prefixSize )
1076 {
1077 
1078 	return sRegisteredNamespaces->GetPrefix ( namespaceURI, namespacePrefix, prefixSize );
1079 
1080 }	// GetNamespacePrefix
1081 
1082 
1083 // -------------------------------------------------------------------------------------------------
1084 // GetNamespaceURI
1085 // ---------------
1086 
1087 /* class-static */ bool
GetNamespaceURI(XMP_StringPtr namespacePrefix,XMP_StringPtr * namespaceURI,XMP_StringLen * uriSize)1088 XMPMeta::GetNamespaceURI ( XMP_StringPtr   namespacePrefix,
1089 						   XMP_StringPtr * namespaceURI,
1090 						   XMP_StringLen * uriSize )
1091 {
1092 
1093 	return sRegisteredNamespaces->GetURI ( namespacePrefix, namespaceURI, uriSize );
1094 
1095 }	// GetNamespaceURI
1096 
1097 
1098 // -------------------------------------------------------------------------------------------------
1099 // DeleteNamespace
1100 // ---------------
1101 
1102 // *** Don't allow standard namespaces to be deleted.
1103 // *** We would be better off not having this. Instead, have local namespaces from parsing be
1104 // *** restricted to the object that introduced them.
1105 
1106 /* class-static */ void
DeleteNamespace(XMP_StringPtr namespaceURI)1107 XMPMeta::DeleteNamespace ( XMP_StringPtr namespaceURI )
1108 {
1109 
1110 	XMP_Throw ( "Unimplemented method XMPMeta::DeleteNamespace", kXMPErr_Unimplemented );
1111 
1112 }	// DeleteNamespace
1113 
1114 
1115 // =================================================================================================
1116 // Class Methods
1117 // =============
1118 //
1119 //
1120 // =================================================================================================
1121 
1122 
1123 // -------------------------------------------------------------------------------------------------
1124 // DumpObject
1125 // ----------
1126 
1127 void
DumpObject(XMP_TextOutputProc outProc,void * refCon) const1128 XMPMeta::DumpObject ( XMP_TextOutputProc outProc,
1129                       void *             refCon ) const
1130 {
1131 	XMP_Assert ( outProc != 0 );	// ! Enforced by wrapper.
1132 
1133 	OutProcLiteral ( "Dumping XMPMeta object \"" );
1134 	DumpClearString ( tree.name, outProc, refCon );
1135 	OutProcNChars ( "\"  ", 3 );
1136 	DumpNodeOptions ( tree.options, outProc, refCon );
1137 	#if 0	// *** XMP_DebugBuild
1138 		if ( (tree._namePtr != tree.name.c_str()) ||
1139 			 (tree._valuePtr != tree.value.c_str()) ) OutProcLiteral ( "  ** bad debug string **" );
1140 	#endif
1141 	OutProcNewline();
1142 
1143 	if ( ! tree.value.empty() ) {
1144 		OutProcLiteral ( "** bad root value **  \"" );
1145 		DumpClearString ( tree.value, outProc, refCon );
1146 		OutProcNChars ( "\"", 1 );
1147 		OutProcNewline();
1148 	}
1149 
1150 	if ( ! tree.qualifiers.empty() ) {
1151 		OutProcLiteral ( "** bad root qualifiers **" );
1152 		OutProcNewline();
1153 		for ( size_t qualNum = 0, qualLim = tree.qualifiers.size(); qualNum < qualLim; ++qualNum ) {
1154 			DumpPropertyTree ( tree.qualifiers[qualNum], 3, 0, outProc, refCon );
1155 		}
1156 	}
1157 
1158 	if ( ! tree.children.empty() ) {
1159 
1160 		for ( size_t childNum = 0, childLim = tree.children.size(); childNum < childLim; ++childNum ) {
1161 
1162 			const XMP_Node * currSchema = tree.children[childNum];
1163 
1164 			OutProcNewline();
1165 			OutProcIndent ( 1 );
1166 			DumpClearString ( currSchema->value, outProc, refCon );
1167 			OutProcNChars ( "  ", 2 );
1168 			DumpClearString ( currSchema->name, outProc, refCon );
1169 			OutProcNChars ( "  ", 2 );
1170 			DumpNodeOptions ( currSchema->options, outProc, refCon );
1171 			#if 0	// *** XMP_DebugBuild
1172 				if ( (currSchema->_namePtr != currSchema->name.c_str()) ||
1173 					 (currSchema->_valuePtr != currSchema->value.c_str()) ) OutProcLiteral ( "  ** bad debug string **" );
1174 			#endif
1175 			OutProcNewline();
1176 
1177 			if ( ! (currSchema->options & kXMP_SchemaNode) ) {
1178 				OutProcLiteral ( "** bad schema options **" );
1179 				OutProcNewline();
1180 			}
1181 
1182 			if ( ! currSchema->qualifiers.empty() ) {
1183 				OutProcLiteral ( "** bad schema qualifiers **" );
1184 				OutProcNewline();
1185 				for ( size_t qualNum = 0, qualLim = currSchema->qualifiers.size(); qualNum < qualLim; ++qualNum ) {
1186 					DumpPropertyTree ( currSchema->qualifiers[qualNum], 3, 0, outProc, refCon );
1187 				}
1188 			}
1189 
1190 			for ( size_t numChild = 0, childLimit = currSchema->children.size(); numChild < childLimit; ++numChild ) {
1191 				DumpPropertyTree ( currSchema->children[numChild], 2, 0, outProc, refCon );
1192 			}
1193 
1194 		}
1195 
1196 	}
1197 
1198 }	// DumpObject
1199 
1200 
1201 // -------------------------------------------------------------------------------------------------
1202 // CountArrayItems
1203 // ---------------
1204 
1205 XMP_Index
CountArrayItems(XMP_StringPtr schemaNS,XMP_StringPtr arrayName) const1206 XMPMeta::CountArrayItems ( XMP_StringPtr schemaNS,
1207 						   XMP_StringPtr arrayName ) const
1208 {
1209 	XMP_Assert ( (schemaNS != 0) && (arrayName != 0) );	// Enforced by wrapper.
1210 
1211 	XMP_ExpandedXPath	expPath;
1212 	ExpandXPath ( schemaNS, arrayName, &expPath );
1213 
1214 	const XMP_Node * arrayNode = FindConstNode ( &tree, expPath );
1215 
1216 	if ( arrayNode == 0 ) return 0;
1217 	if ( ! (arrayNode->options & kXMP_PropValueIsArray) ) XMP_Throw ( "The named property is not an array", kXMPErr_BadXPath );
1218 	return static_cast<XMP_Index>( arrayNode->children.size() );
1219 
1220 }	// CountArrayItems
1221 
1222 
1223 // -------------------------------------------------------------------------------------------------
1224 // GetObjectName
1225 // -------------
1226 
1227 void
GetObjectName(XMP_StringPtr * namePtr,XMP_StringLen * nameLen) const1228 XMPMeta::GetObjectName ( XMP_StringPtr * namePtr,
1229 						 XMP_StringLen * nameLen ) const
1230 {
1231 
1232 	*namePtr = tree.name.c_str();
1233 	*nameLen = static_cast<XMP_Index>( tree.name.size() );
1234 
1235 }	// GetObjectName
1236 
1237 
1238 // -------------------------------------------------------------------------------------------------
1239 // SetObjectName
1240 // -------------
1241 
1242 void
SetObjectName(XMP_StringPtr name)1243 XMPMeta::SetObjectName ( XMP_StringPtr name )
1244 {
1245 	VerifyUTF8 ( name );	// Throws if the string is not legit UTF-8.
1246 	tree.name = name;
1247 
1248 }	// SetObjectName
1249 
1250 
1251 // -------------------------------------------------------------------------------------------------
1252 // GetObjectOptions
1253 // ----------------
1254 
1255 XMP_OptionBits
GetObjectOptions() const1256 XMPMeta::GetObjectOptions() const
1257 {
1258 	XMP_OptionBits	options	= 0;
1259 
1260 	return options;
1261 
1262 }	// GetObjectOptions
1263 
1264 
1265 // -------------------------------------------------------------------------------------------------
1266 // SetObjectOptions
1267 // ----------------
1268 
1269 void
SetObjectOptions(XMP_OptionBits options)1270 XMPMeta::SetObjectOptions ( XMP_OptionBits options )
1271 {
1272 	void * p; p = &options;	// Avoid unused param warnings.
1273 	XMP_Throw ( "Unimplemented method XMPMeta::SetObjectOptions", kXMPErr_Unimplemented );
1274 
1275 
1276 }	// SetObjectOptions
1277 
1278 
1279 // -------------------------------------------------------------------------------------------------
1280 // Sort
1281 // ----
1282 //
1283 // At the top level the namespaces are sorted by their prefixes. Within a namespace, the top level
1284 // properties are sorted by name. Within a struct, the fields are sorted by their qualified name,
1285 // i.e. their XML prefix:local form. Unordered arrays of simple items are sorted by value. Language
1286 // Alternative arrays are sorted by the xml:lang qualifiers, with the "x-default" item placed first.
1287 
1288 void
Sort()1289 XMPMeta::Sort()
1290 {
1291 
1292 	if ( ! this->tree.qualifiers.empty() ) {
1293 		sort ( this->tree.qualifiers.begin(), this->tree.qualifiers.end(), CompareNodeNames );
1294 		SortWithinOffspring ( this->tree.qualifiers );
1295 	}
1296 
1297 	if ( ! this->tree.children.empty() ) {
1298 		// The schema prefixes are the node's value, the name is the URI, so we sort schemas by value.
1299 		sort ( this->tree.children.begin(), this->tree.children.end(), CompareNodeValues );
1300 		SortWithinOffspring ( this->tree.children );
1301 	}
1302 
1303 }	// Sort
1304 
1305 
1306 // -------------------------------------------------------------------------------------------------
1307 // Erase
1308 // -----
1309 //
1310 // Clear everything except for clientRefs.
1311 
1312 void
Erase()1313 XMPMeta::Erase()
1314 {
1315 
1316 	if ( this->xmlParser != 0 ) {
1317 		delete ( this->xmlParser );
1318 		this->xmlParser = 0;
1319 	}
1320 	this->tree.ClearNode();
1321 
1322 }	// Erase
1323 
1324 
1325 // -------------------------------------------------------------------------------------------------
1326 // Clone
1327 // -----
1328 
1329 void
Clone(XMPMeta * clone,XMP_OptionBits options) const1330 XMPMeta::Clone ( XMPMeta * clone, XMP_OptionBits options ) const
1331 {
1332 	if ( clone == 0 ) XMP_Throw ( "Null clone pointer", kXMPErr_BadParam );
1333 	if ( options != 0 ) XMP_Throw ( "No options are defined yet", kXMPErr_BadOptions );
1334 	XMP_Assert ( this->tree.parent == 0 );
1335 
1336 	clone->tree.ClearNode();
1337 
1338 	clone->tree.options = this->tree.options;
1339 	clone->tree.name    = this->tree.name;
1340 	clone->tree.value   = this->tree.value;
1341 	clone->errorCallback = this->errorCallback;
1342 
1343 	#if 0	// *** XMP_DebugBuild
1344 		clone->tree._namePtr = clone->tree.name.c_str();
1345 		clone->tree._valuePtr = clone->tree.value.c_str();
1346 	#endif
1347 
1348 	CloneOffspring ( &this->tree, &clone->tree );
1349 
1350 }	// Clone
1351 
1352 // =================================================================================================
1353 // XMP_Node::GetLocalURI
1354 // =====================
1355 //
1356 // This has to be someplace where XMPMeta::GetNamespaceURI is visible.
1357 
GetLocalURI(XMP_StringPtr * uriStr,XMP_StringLen * uriSize) const1358 void XMP_Node::GetLocalURI ( XMP_StringPtr * uriStr, XMP_StringLen * uriSize ) const
1359 {
1360 
1361 	if ( uriStr != 0 ) *uriStr = "";	// Set up empty defaults.
1362 	if ( uriSize != 0 ) *uriSize = 0;
1363 
1364 	if ( this->name.empty() ) return;
1365 
1366 	if ( XMP_NodeIsSchema ( this->options ) ) {
1367 
1368 		if ( uriStr != 0 ) *uriStr = this->name.c_str();
1369 		if ( uriSize != 0 ) *uriSize = static_cast<XMP_StringLen>( this->name.size() );
1370 
1371 	} else {
1372 
1373 		size_t colonPos = this->name.find_first_of(':');
1374 		if ( colonPos == XMP_VarString::npos ) return;	// ! Name of array items is "[]".
1375 
1376 		XMP_VarString prefix ( this->name, 0, colonPos );
1377 		XMPMeta::GetNamespaceURI ( prefix.c_str(), uriStr, uriSize );
1378 
1379 	}
1380 
1381 }
1382 
GetFullQualifiedName(XMP_StringPtr * uriStr,XMP_StringLen * uriSize,XMP_StringPtr * nameStr,XMP_StringLen * nameSize) const1383 void XMP_Node::GetFullQualifiedName( XMP_StringPtr * uriStr, XMP_StringLen * uriSize, XMP_StringPtr * nameStr, XMP_StringLen * nameSize ) const
1384 {
1385 	if ( uriStr != 0 ) *uriStr = "";	// Set up empty defaults.
1386 	if ( uriSize != 0 ) *uriSize = 0;
1387 	if ( nameStr != 0 ) *nameStr = "";
1388 	if ( nameSize != 0 ) *nameSize = 0;
1389 
1390 	if ( this->name.empty() ) return;
1391 
1392 	if ( XMP_NodeIsSchema ( this->options ) ) {
1393 
1394 		if ( uriStr != 0 ) *uriStr = this->name.c_str();
1395 		if ( uriSize != 0 ) *uriSize = static_cast<XMP_StringLen>( this->name.size() );
1396 		if ( nameStr != 0 ) *nameStr = this->value.c_str();
1397 		if ( nameSize != 0 ) *nameSize = static_cast<XMP_StringLen>( this->value.size() );
1398 
1399 	} else {
1400 
1401 		size_t colonPos = this->name.find_first_of(':');
1402 		if ( colonPos == XMP_VarString::npos ) return;	// ! Name of array items is "[]".
1403 
1404 		XMP_VarString prefix ( this->name, 0, colonPos );
1405 		XMPMeta::GetNamespaceURI ( prefix.c_str(), uriStr, uriSize );
1406 		*nameStr = this->name.c_str() + colonPos + 1;
1407 		*nameSize = static_cast<XMP_StringLen>( this->name.size() - colonPos - 1 );
1408 	}
1409 }
1410 
1411 // =================================================================================================
1412 // Error notifications
1413 // ===================
1414 
1415 // -------------------------------------------------------------------------------------------------
1416 // SetDefaultErrorCallback
1417 // -----------------------
1418 
1419 /* class-static */ void
SetDefaultErrorCallback(XMPMeta_ErrorCallbackWrapper wrapperProc,XMPMeta_ErrorCallbackProc clientProc,void * context,XMP_Uns32 limit)1420 XMPMeta::SetDefaultErrorCallback ( XMPMeta_ErrorCallbackWrapper wrapperProc,
1421 								   XMPMeta_ErrorCallbackProc    clientProc,
1422 								   void *    context,
1423 								   XMP_Uns32 limit )
1424 {
1425 	XMP_Assert ( wrapperProc != 0 );	// Must always be set by the glue;
1426 
1427 	sDefaultErrorCallback.wrapperProc = wrapperProc;
1428 	sDefaultErrorCallback.clientProc = clientProc;
1429 	sDefaultErrorCallback.context = context;
1430 	sDefaultErrorCallback.limit = limit;
1431 
1432 }	// SetDefaultErrorCallback
1433 
1434 // -------------------------------------------------------------------------------------------------
1435 // SetErrorCallback
1436 // ----------------
1437 
1438 void
SetErrorCallback(XMPMeta_ErrorCallbackWrapper wrapperProc,XMPMeta_ErrorCallbackProc clientProc,void * context,XMP_Uns32 limit)1439 XMPMeta::SetErrorCallback ( XMPMeta_ErrorCallbackWrapper wrapperProc,
1440 							XMPMeta_ErrorCallbackProc    clientProc,
1441 							void *    context,
1442 							XMP_Uns32 limit )
1443 {
1444 	XMP_Assert ( wrapperProc != 0 );	// Must always be set by the glue;
1445 
1446 	this->errorCallback.Clear();
1447 	this->errorCallback.wrapperProc = wrapperProc;
1448 	this->errorCallback.clientProc = clientProc;
1449 	this->errorCallback.context = context;
1450 	this->errorCallback.limit = limit;
1451 
1452 }	// SetErrorCallback
1453 
1454 // -------------------------------------------------------------------------------------------------
1455 // ResetErrorCallbackLimit
1456 // -----------------------
1457 
1458 void
ResetErrorCallbackLimit(XMP_Uns32 limit)1459 XMPMeta::ResetErrorCallbackLimit ( XMP_Uns32 limit )
1460 {
1461 
1462 	this->errorCallback.limit = limit;
1463 	this->errorCallback.notifications = 0;
1464 	this->errorCallback.topSeverity = kXMPErrSev_Recoverable;
1465 
1466 }	// ResetErrorCallbackLimit
1467 
1468 // -------------------------------------------------------------------------------------------------
1469 // ErrorCallbackInfo::CanNotify
1470 // -------------------------------
1471 //
1472 // This is const just to be usable from const XMPMeta functions.
1473 
CanNotify() const1474 bool XMPMeta::ErrorCallbackInfo::CanNotify() const
1475 {
1476 	XMP_Assert ( (this->clientProc == 0) || (this->wrapperProc != 0) );
1477 	return ( this->clientProc != 0);
1478 }
1479 
1480 // -------------------------------------------------------------------------------------------------
1481 // ErrorCallbackInfo::ClientCallbackWrapper
1482 // -------------------------------
1483 //
1484 // This is const just to be usable from const XMPMeta functions.
1485 
ClientCallbackWrapper(XMP_StringPtr filePath,XMP_ErrorSeverity severity,XMP_Int32 cause,XMP_StringPtr messsage) const1486 bool XMPMeta::ErrorCallbackInfo::ClientCallbackWrapper ( XMP_StringPtr filePath, XMP_ErrorSeverity severity, XMP_Int32 cause, XMP_StringPtr messsage ) const
1487 {
1488 	XMP_Bool retValue = (*this->wrapperProc) ( this->clientProc, this->context, severity, cause, messsage );
1489 	return ConvertXMP_BoolToBool(retValue);
1490 }
1491 
1492 // =================================================================================================
1493