diff options
Diffstat (limited to 'source/XMPCore')
-rw-r--r-- | source/XMPCore/ExpatAdapter.cpp | 33 | ||||
-rw-r--r-- | source/XMPCore/ParseRDF.cpp | 77 | ||||
-rw-r--r-- | source/XMPCore/WXMPIterator.cpp | 120 | ||||
-rw-r--r-- | source/XMPCore/WXMPMeta.cpp | 782 | ||||
-rw-r--r-- | source/XMPCore/WXMPUtils.cpp | 434 | ||||
-rw-r--r-- | source/XMPCore/XMPCore_Impl.cpp | 133 | ||||
-rw-r--r-- | source/XMPCore/XMPCore_Impl.hpp | 204 | ||||
-rw-r--r-- | source/XMPCore/XMPIterator.cpp | 103 | ||||
-rw-r--r-- | source/XMPCore/XMPIterator.hpp | 10 | ||||
-rw-r--r-- | source/XMPCore/XMPMeta-GetSet.cpp | 276 | ||||
-rw-r--r-- | source/XMPCore/XMPMeta-Parse.cpp | 39 | ||||
-rw-r--r-- | source/XMPCore/XMPMeta-Serialize.cpp | 160 | ||||
-rw-r--r-- | source/XMPCore/XMPMeta.cpp | 927 | ||||
-rw-r--r-- | source/XMPCore/XMPMeta.hpp | 56 | ||||
-rw-r--r-- | source/XMPCore/XMPUtils-FileInfo.cpp | 444 | ||||
-rw-r--r-- | source/XMPCore/XMPUtils.cpp | 767 | ||||
-rw-r--r-- | source/XMPCore/XMPUtils.hpp | 79 |
17 files changed, 1853 insertions, 2791 deletions
diff --git a/source/XMPCore/ExpatAdapter.cpp b/source/XMPCore/ExpatAdapter.cpp index 3dff828..48f6763 100644 --- a/source/XMPCore/ExpatAdapter.cpp +++ b/source/XMPCore/ExpatAdapter.cpp @@ -1,5 +1,5 @@ // ================================================================================================= -// Copyright 2005-2008 Adobe Systems Incorporated +// Copyright 2005 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms @@ -62,14 +62,16 @@ static void CommentHandler ( void * userData, XMP_StringPtr commen // ================================================================================================= -extern "C" ExpatAdapter * XMP_NewExpatAdapter() +extern "C" ExpatAdapter * XMP_NewExpatAdapter ( bool useGlobalNamespaces ) { - return new ExpatAdapter; + + return new ExpatAdapter ( useGlobalNamespaces ); + } // XMP_NewExpatAdapter // ================================================================================================= -ExpatAdapter::ExpatAdapter() : parser(0) +ExpatAdapter::ExpatAdapter ( bool useGlobalNamespaces ) : parser(0), registeredNamespaces(0) { #if XMP_DebugBuild @@ -82,6 +84,12 @@ ExpatAdapter::ExpatAdapter() : parser(0) this->parser = XML_ParserCreateNS ( 0, FullNameSeparator ); if ( this->parser == 0 ) XMP_Throw ( "Failure creating Expat parser", kXMPErr_ExternalFailure ); + if ( useGlobalNamespaces ) { + this->registeredNamespaces = sRegisteredNamespaces; + } else { + this->registeredNamespaces = new XMP_NamespaceTable ( *sRegisteredNamespaces ); + } + XML_SetUserData ( this->parser, this ); XML_SetNamespaceDeclHandler ( this->parser, StartNamespaceDeclHandler, EndNamespaceDeclHandler ); @@ -109,6 +117,9 @@ ExpatAdapter::~ExpatAdapter() if ( this->parser != 0 ) XML_ParserFree ( this->parser ); this->parser = 0; + + if ( this->registeredNamespaces != sRegisteredNamespaces ) delete ( this->registeredNamespaces ); + this->registeredNamespaces = 0; } // ExpatAdapter::~ExpatAdapter @@ -181,7 +192,7 @@ void ExpatAdapter::ParseBuffer ( const void * buffer, size_t length, bool last / // ================================================================================================= -static void SetQualName ( XMP_StringPtr fullName, XML_Node * node ) +static void SetQualName ( ExpatAdapter * thiz, XMP_StringPtr fullName, XML_Node * node ) { // Expat delivers the full name as a catenation of namespace URI, separator, and local name. @@ -207,7 +218,7 @@ static void SetQualName ( XMP_StringPtr fullName, XML_Node * node ) node->ns.assign ( fullName, sepPos ); if ( node->ns == "http://purl.org/dc/1.1/" ) node->ns = "http://purl.org/dc/elements/1.1/"; - bool found = XMPMeta::GetNamespacePrefix ( node->ns.c_str(), &prefix, &prefixLen ); + bool found = thiz->registeredNamespaces->GetPrefix ( node->ns.c_str(), &prefix, &prefixLen ); if ( ! found ) XMP_Throw ( "Unknown URI in Expat full name", kXMPErr_ExternalFailure ); node->nsPrefixLen = prefixLen; // ! Includes the ':'. @@ -243,9 +254,7 @@ static void StartNamespaceDeclHandler ( void * userData, XMP_StringPtr prefix, X // As a bug fix hack, change a URI of "http://purl.org/dc/1.1/" to ""http://purl.org/dc/elements/1.1/. // Early versions of Flash that put XMP in SWF used a bad URI for the dc: namespace. - #if XMP_DebugBuild & DumpXMLParseEvents // Avoid unused variable warning. - ExpatAdapter * thiz = (ExpatAdapter*)userData; - #endif + ExpatAdapter * thiz = (ExpatAdapter*)userData; if ( prefix == 0 ) prefix = "_dflt_"; // Have default namespace. if ( uri == 0 ) return; // Ignore, have xmlns:pre="", no URI to register. @@ -258,7 +267,7 @@ static void StartNamespaceDeclHandler ( void * userData, XMP_StringPtr prefix, X #endif if ( XMP_LitMatch ( uri, "http://purl.org/dc/1.1/" ) ) uri = "http://purl.org/dc/elements/1.1/"; - (void) XMPMeta::RegisterNamespace ( uri, prefix, &voidStringPtr, &voidStringLen ); + (void) thiz->registeredNamespaces->Define ( uri, prefix, 0, 0 ); } // StartNamespaceDeclHandler @@ -313,7 +322,7 @@ static void StartElementHandler ( void * userData, XMP_StringPtr name, XMP_Strin XML_Node * parentNode = thiz->parseStack.back(); XML_Node * elemNode = new XML_Node ( parentNode, "", kElemNode ); - SetQualName ( name, elemNode ); + SetQualName ( thiz, name, elemNode ); for ( XMP_StringPtr* attr = attrs; *attr != 0; attr += 2 ) { @@ -321,7 +330,7 @@ static void StartElementHandler ( void * userData, XMP_StringPtr name, XMP_Strin XMP_StringPtr attrValue = *(attr+1); XML_Node * attrNode = new XML_Node ( elemNode, "", kAttrNode ); - SetQualName ( attrName, attrNode ); + SetQualName ( thiz, attrName, attrNode ); attrNode->value = attrValue; if ( attrNode->name == "xml:lang" ) NormalizeLangValue ( &attrNode->value ); elemNode->attrs.push_back ( attrNode ); diff --git a/source/XMPCore/ParseRDF.cpp b/source/XMPCore/ParseRDF.cpp index 31fb2b9..9931194 100644 --- a/source/XMPCore/ParseRDF.cpp +++ b/source/XMPCore/ParseRDF.cpp @@ -1,5 +1,5 @@ // ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated +// Copyright 2004 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms @@ -490,30 +490,30 @@ AddQualifierNode ( XMP_Node * xmpParent, const XMP_VarString & name, const XMP_V XMP_Node * newQual = 0; - newQual = new XMP_Node ( xmpParent, name, value, kXMP_PropIsQualifier ); + newQual = new XMP_Node ( xmpParent, name, value, kXMP_PropIsQualifier ); - if ( ! (isLang | isType) ) { + if ( ! (isLang | isType) ) { + xmpParent->qualifiers.push_back ( newQual ); + } else if ( isLang ) { + if ( xmpParent->qualifiers.empty() ) { xmpParent->qualifiers.push_back ( newQual ); - } else if ( isLang ) { - if ( xmpParent->qualifiers.empty() ) { - xmpParent->qualifiers.push_back ( newQual ); - } else { - xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin(), newQual ); - } - xmpParent->options |= kXMP_PropHasLang; } else { - XMP_Assert ( isType ); - if ( xmpParent->qualifiers.empty() ) { - xmpParent->qualifiers.push_back ( newQual ); - } else { - size_t offset = 0; - if ( XMP_PropHasLang ( xmpParent->options ) ) offset = 1; - xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin()+offset, newQual ); - } - xmpParent->options |= kXMP_PropHasType; + xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin(), newQual ); } + xmpParent->options |= kXMP_PropHasLang; + } else { + XMP_Assert ( isType ); + if ( xmpParent->qualifiers.empty() ) { + xmpParent->qualifiers.push_back ( newQual ); + } else { + size_t offset = 0; + if ( XMP_PropHasLang ( xmpParent->options ) ) offset = 1; + xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin()+offset, newQual ); + } + xmpParent->options |= kXMP_PropHasType; + } - xmpParent->options |= kXMP_PropHasQualifiers; + xmpParent->options |= kXMP_PropHasQualifiers; return newQual; @@ -608,26 +608,25 @@ FixupQualifiedNode ( XMP_Node * xmpParent ) for ( childNum = 1, childLim = xmpParent->children.size(); childNum != childLim; ++childNum ) { XMP_Node * currQual = xmpParent->children[childNum]; - - bool isLang = (currQual->name == "xml:lang"); - - currQual->options |= kXMP_PropIsQualifier; - currQual->parent = xmpParent; - - if ( isLang ) { - if ( xmpParent->options & kXMP_PropHasLang ) XMP_Throw ( "Duplicate xml:lang qualifier", kXMPErr_BadXMP ); - xmpParent->options |= kXMP_PropHasLang; - } else if ( currQual->name == "rdf:type" ) { - xmpParent->options |= kXMP_PropHasType; - } - - if ( (! isLang) || xmpParent->qualifiers.empty() ) { - xmpParent->qualifiers.push_back ( currQual ); - } else { - xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin(), currQual ); - } - xmpParent->children[childNum] = 0; // We just moved it to the qualifers. + bool isLang = (currQual->name == "xml:lang"); + currQual->options |= kXMP_PropIsQualifier; + currQual->parent = xmpParent; + + if ( isLang ) { + if ( xmpParent->options & kXMP_PropHasLang ) XMP_Throw ( "Duplicate xml:lang qualifier", kXMPErr_BadXMP ); + xmpParent->options |= kXMP_PropHasLang; + } else if ( currQual->name == "rdf:type" ) { + xmpParent->options |= kXMP_PropHasType; + } + + if ( (! isLang) || xmpParent->qualifiers.empty() ) { + xmpParent->qualifiers.push_back ( currQual ); + } else { + xmpParent->qualifiers.insert ( xmpParent->qualifiers.begin(), currQual ); + } + xmpParent->children[childNum] = 0; // We just moved it to the qualifers. + } if ( ! xmpParent->qualifiers.empty() ) xmpParent->options |= kXMP_PropHasQualifiers; diff --git a/source/XMPCore/WXMPIterator.cpp b/source/XMPCore/WXMPIterator.cpp index b52fa0d..6b0e69e 100644 --- a/source/XMPCore/WXMPIterator.cpp +++ b/source/XMPCore/WXMPIterator.cpp @@ -1,5 +1,5 @@ // ================================================================================================= -// Copyright 2002-2007 Adobe Systems Incorporated +// Copyright 2004 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms @@ -7,11 +7,13 @@ // ================================================================================================= #include "XMP_Environment.h" // ! This must be the first include! -#include "XMPCore_Impl.hpp" +#include "XMP_Const.h" -#include "XMPIterator.hpp" #include "client-glue/WXMPIterator.hpp" +#include "XMPCore_Impl.hpp" +#include "XMPIterator.hpp" + #if XMP_WinBuild #pragma warning ( disable : 4101 ) // unreferenced local variable #pragma warning ( disable : 4189 ) // local variable is initialized but not referenced @@ -36,18 +38,20 @@ WXMPIterator_PropCTor_1 ( XMPMetaRef xmpRef, XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPIterator_PropCTor_1" ) + XMP_ENTER_Static ( "WXMPIterator_PropCTor_1" ) // No lib object yet, use the static entry. if ( schemaNS == 0 ) schemaNS = ""; if ( propName == 0 ) propName = ""; const XMPMeta & xmpObj = WtoXMPMeta_Ref ( xmpRef ); - XMPIterator * iter = new XMPIterator ( xmpObj, schemaNS, propName, options ); + XMP_AutoLock metaLock ( &xmpObj.lock, kXMP_ReadLock ); + + XMPIterator * iter = new XMPIterator ( xmpObj, schemaNS, propName, options ); ++iter->clientRefs; XMP_Assert ( iter->clientRefs == 1 ); wResult->ptrResult = XMPIteratorRef ( iter ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -58,7 +62,7 @@ WXMPIterator_TableCTor_1 ( XMP_StringPtr schemaNS, XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPIterator_TableCTor_1" ) + XMP_ENTER_Static ( "WXMPIterator_TableCTor_1" ) // No lib object yet, use the static entry. if ( schemaNS == 0 ) schemaNS = ""; if ( propName == 0 ) propName = ""; @@ -68,53 +72,39 @@ WXMPIterator_TableCTor_1 ( XMP_StringPtr schemaNS, XMP_Assert ( iter->clientRefs == 1 ); wResult->ptrResult = XMPIteratorRef ( iter ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPIterator_IncrementRefCount_1 ( XMPIteratorRef iterRef ) +WXMPIterator_IncrementRefCount_1 ( XMPIteratorRef xmpObjRef ) { WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER ( "WXMPIterator_IncrementRefCount_1" ) + XMP_ENTER_ObjWrite ( XMPIterator, "WXMPIterator_IncrementRefCount_1" ) - XMPIterator * thiz = (XMPIterator*)iterRef; - ++thiz->clientRefs; XMP_Assert ( thiz->clientRefs > 1 ); - XMP_EXIT_WRAPPER_NO_THROW + XMP_EXIT_NoThrow } // ------------------------------------------------------------------------------------------------- void -WXMPIterator_DecrementRefCount_1 ( XMPIteratorRef iterRef ) +WXMPIterator_DecrementRefCount_1 ( XMPIteratorRef xmpObjRef ) { WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER ( "WXMPIterator_DecrementRefCount_1" ) + XMP_ENTER_ObjWrite ( XMPIterator, "WXMPIterator_DecrementRefCount_1" ) - XMPIterator * thiz = (XMPIterator*)iterRef; - XMP_Assert ( thiz->clientRefs > 0 ); --thiz->clientRefs; - if ( thiz->clientRefs <= 0 ) delete ( thiz ); - - XMP_EXIT_WRAPPER_NO_THROW -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPIterator_Unlock_1 ( XMP_OptionBits options ) -{ - WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPIterator_Unlock_1" ) + if ( thiz->clientRefs <= 0 ) { + objLock.Release(); + delete ( thiz ); + } - XMPIterator::Unlock ( options ); - - XMP_EXIT_WRAPPER_NO_THROW + XMP_EXIT_NoThrow } // ================================================================================================= @@ -122,61 +112,53 @@ WXMPIterator_Unlock_1 ( XMP_OptionBits options ) // ===================== void -WXMPIterator_Next_1 ( XMPIteratorRef iterRef, - XMP_StringPtr * schemaNS, - XMP_StringLen * nsSize, - XMP_StringPtr * propPath, - XMP_StringLen * pathSize, - XMP_StringPtr * propValue, - XMP_StringLen * valueSize, +WXMPIterator_Next_1 ( XMPIteratorRef xmpObjRef, + void * schemaNS, + void * propPath, + void * propValue, XMP_OptionBits * propOptions, + SetClientStringProc SetClientString, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPIterator_Next_1" ) - - if ( schemaNS == 0 ) schemaNS = &voidStringPtr; - if ( nsSize == 0 ) nsSize = &voidStringLen; - if ( propPath == 0 ) propPath = &voidStringPtr; - if ( pathSize == 0 ) pathSize = &voidStringLen; - if ( propValue == 0 ) propValue = &voidStringPtr; - if ( valueSize == 0 ) valueSize = &voidStringLen; + XMP_ENTER_ObjWrite ( XMPIterator, "WXMPIterator_Next_1" ) + + XMP_StringPtr schemaPtr = 0; + XMP_StringLen schemaLen = 0; + XMP_StringPtr pathPtr = 0; + XMP_StringLen pathLen = 0; + XMP_StringPtr valuePtr = 0; + XMP_StringLen valueLen = 0; + if ( propOptions == 0 ) propOptions = &voidOptionBits; - XMPIterator * iter = WtoXMPIterator_Ptr ( iterRef ); - XMP_Bool found = iter->Next ( schemaNS, nsSize, propPath, pathSize, propValue, valueSize, propOptions ); + XMP_AutoLock metaLock ( &thiz->info.xmpObj->lock, kXMP_ReadLock, (thiz->info.xmpObj != 0) ); + + XMP_Bool found = thiz->Next ( &schemaPtr, &schemaLen, &pathPtr, &pathLen, &valuePtr, &valueLen, propOptions ); wResult->int32Result = found; + + if ( found ) { + if ( schemaNS != 0 ) (*SetClientString) ( schemaNS, schemaPtr, schemaLen ); + if ( propPath != 0 ) (*SetClientString) ( propPath, pathPtr, pathLen ); + if ( propValue != 0 ) (*SetClientString) ( propValue, valuePtr, valueLen ); + } - XMP_EXIT_WRAPPER_KEEP_LOCK ( found ) + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPIterator_Skip_1 ( XMPIteratorRef iterRef, +WXMPIterator_Skip_1 ( XMPIteratorRef xmpObjRef, XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPIterator_Skip_1" ) - - XMPIterator * iter = WtoXMPIterator_Ptr ( iterRef ); - iter->Skip ( options ); + XMP_ENTER_ObjWrite ( XMPIterator, "WXMPIterator_Skip_1" ) - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPUtils_UnlockIter_1 ( XMPIteratorRef iterRef, - XMP_OptionBits options ) -{ - WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_UnlockIter_1" ) + XMP_AutoLock metaLock ( &thiz->info.xmpObj->lock, kXMP_ReadLock, (thiz->info.xmpObj != 0) ); - XMPIterator * iter = WtoXMPIterator_Ptr ( iterRef ); - iter->UnlockIter ( options ); + thiz->Skip ( options ); - XMP_EXIT_WRAPPER_NO_THROW + XMP_EXIT } // ================================================================================================= diff --git a/source/XMPCore/WXMPMeta.cpp b/source/XMPCore/WXMPMeta.cpp index 4c95c5d..e7138e4 100644 --- a/source/XMPCore/WXMPMeta.cpp +++ b/source/XMPCore/WXMPMeta.cpp @@ -1,5 +1,5 @@ // ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated +// Copyright 2004 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms @@ -7,11 +7,13 @@ // ================================================================================================= #include "XMP_Environment.h" // ! This must be the first include! -#include "XMPCore_Impl.hpp" +#include "XMP_Const.h" -#include "XMPMeta.hpp" #include "client-glue/WXMPMeta.hpp" +#include "XMPCore_Impl.hpp" +#include "XMPMeta.hpp" + #if XMP_WinBuild #pragma warning ( disable : 4101 ) // unreferenced local variable #pragma warning ( disable : 4189 ) // local variable is initialized but not referenced @@ -34,11 +36,11 @@ extern "C" { WXMPMeta_GetVersionInfo_1 ( XMP_VersionInfo * info ) { WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_GetVersionInfo_1" ) + XMP_ENTER_NoLock ( "WXMPMeta_GetVersionInfo_1" ) XMPMeta::GetVersionInfo ( info ); - XMP_EXIT_WRAPPER_NO_THROW + XMP_EXIT_NoThrow } // ------------------------------------------------------------------------------------------------- @@ -46,12 +48,11 @@ WXMPMeta_GetVersionInfo_1 ( XMP_VersionInfo * info ) /* class static */ void WXMPMeta_Initialize_1 ( WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_Initialize_1" ) + XMP_ENTER_NoLock ( "WXMPMeta_Initialize_1" ) - bool ok = XMPMeta::Initialize(); - wResult->int32Result = ok; + wResult->int32Result = XMPMeta::Initialize(); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -59,11 +60,11 @@ WXMPMeta_Initialize_1 ( WXMP_Result * wResult ) WXMPMeta_Terminate_1() { WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_Terminate_1" ) + XMP_ENTER_NoLock ( "WXMPMeta_Terminate_1" ) XMPMeta::Terminate(); - XMP_EXIT_WRAPPER_NO_THROW + XMP_EXIT_NoThrow } // ================================================================================================= @@ -73,83 +74,61 @@ WXMPMeta_Terminate_1() void WXMPMeta_CTor_1 ( WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_CTor_1" ) + XMP_ENTER_Static ( "WXMPMeta_CTor_1" ) // No lib object yet, use the static entry. XMPMeta * xmpObj = new XMPMeta(); ++xmpObj->clientRefs; XMP_Assert ( xmpObj->clientRefs == 1 ); wResult->ptrResult = XMPMetaRef ( xmpObj ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_IncrementRefCount_1 ( XMPMetaRef xmpRef ) +WXMPMeta_IncrementRefCount_1 ( XMPMetaRef xmpObjRef ) { WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER ( "WXMPMeta_IncrementRefCount_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_IncrementRefCount_1" ) - XMPMeta * thiz = (XMPMeta*)xmpRef; - ++thiz->clientRefs; XMP_Assert ( thiz->clientRefs > 0 ); - XMP_EXIT_WRAPPER_NO_THROW + XMP_EXIT_NoThrow } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_DecrementRefCount_1 ( XMPMetaRef xmpRef ) +WXMPMeta_DecrementRefCount_1 ( XMPMetaRef xmpObjRef ) { WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER ( "WXMPMeta_DecrementRefCount_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_DecrementRefCount_1" ) - XMPMeta * thiz = (XMPMeta*)xmpRef; - XMP_Assert ( thiz->clientRefs > 0 ); --thiz->clientRefs; - if ( thiz->clientRefs <= 0 ) delete ( thiz ); + if ( thiz->clientRefs <= 0 ) { + objLock.Release(); + delete ( thiz ); + } - XMP_EXIT_WRAPPER_NO_THROW + XMP_EXIT_NoThrow } // ================================================================================================= // Class Static Wrappers // ===================== -// -// These are DLL-entry wrappers for class-static functions. They all follow a simple pattern: -// -// try -// acquire toolbox lock -// validate parameters -// call through to the implementation -// retain toolbox lock if necessary -// catch anything and return an appropriate XMP_Error object -// return null (no error if we get to here) -// -// The toolbox lock is acquired through a local wrapper object that automatically unlocks when the -// try-block is exited. The lock must be retained if the function is returning a string result. The -// output string is owned by the toolkit, the client must copy the string then release the lock. -// The lock used here is the overall toolkit lock. For simplicity at this time the lock is a simple -// mutual exclusion lock, we do not allow multiple concurrent readers. -// -// The one exception to this model is UnlockToolkit. It does not acquire the toolkit lock since this -// is the function the client calls to release the lock after copying an output string! -// -// ================================================================================================= /* class static */ void WXMPMeta_GetGlobalOptions_1 ( WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_GetGlobalOptions_1" ) + XMP_ENTER_Static ( "WXMPMeta_GetGlobalOptions_1" ) XMP_OptionBits options = XMPMeta::GetGlobalOptions(); wResult->int32Result = options; - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -158,11 +137,11 @@ WXMPMeta_GetGlobalOptions_1 ( WXMP_Result * wResult ) WXMPMeta_SetGlobalOptions_1 ( XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_SetGlobalOptions_1" ) + XMP_ENTER_Static ( "WXMPMeta_SetGlobalOptions_1" ) XMPMeta::SetGlobalOptions ( options ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -171,109 +150,85 @@ WXMPMeta_DumpNamespaces_1 ( XMP_TextOutputProc outProc, void * refCon, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_DumpNamespaces_1" ) + XMP_ENTER_Static ( "WXMPMeta_DumpNamespaces_1" ) if ( outProc == 0 ) XMP_Throw ( "Null client output routine", kXMPErr_BadParam ); XMP_Status status = XMPMeta::DumpNamespaces ( outProc, refCon ); wResult->int32Result = status; - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- /* class static */ void -WXMPMeta_DumpAliases_1 ( XMP_TextOutputProc outProc, - void * refCon, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_DumpAliases_1" ) - - if ( outProc == 0 ) XMP_Throw ( "Null client output routine", kXMPErr_BadParam ); - - XMP_Status status = XMPMeta::DumpAliases ( outProc, refCon ); - wResult->int32Result = status; - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_Unlock_1 ( XMP_OptionBits options ) -{ - WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_Unlock_1" ) - - XMPMeta::Unlock ( options ); - - XMP_EXIT_WRAPPER_NO_THROW -} - -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_RegisterNamespace_1 ( XMP_StringPtr namespaceURI, - XMP_StringPtr suggestedPrefix, - XMP_StringPtr * registeredPrefix, - XMP_StringLen * prefixSize, - WXMP_Result * wResult ) +WXMPMeta_RegisterNamespace_1 ( XMP_StringPtr namespaceURI, + XMP_StringPtr suggestedPrefix, + void * actualPrefix, + SetClientStringProc SetClientString, + WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_RegisterNamespace_1" ) + XMP_ENTER_Static ( "WXMPMeta_RegisterNamespace_1" ) if ( (namespaceURI == 0) || (*namespaceURI == 0) ) XMP_Throw ( "Empty namespace URI", kXMPErr_BadSchema ); if ( (suggestedPrefix == 0) || (*suggestedPrefix == 0) ) XMP_Throw ( "Empty suggested prefix", kXMPErr_BadSchema ); - if ( registeredPrefix == 0 ) registeredPrefix = &voidStringPtr; - if ( prefixSize == 0 ) prefixSize = &voidStringLen; + XMP_StringPtr prefixPtr = 0; + XMP_StringLen prefixSize = 0; - bool prefixMatch = XMPMeta::RegisterNamespace ( namespaceURI, suggestedPrefix, registeredPrefix, prefixSize ); + bool prefixMatch = XMPMeta::RegisterNamespace ( namespaceURI, suggestedPrefix, &prefixPtr, &prefixSize ); wResult->int32Result = prefixMatch; + + if ( actualPrefix != 0 ) (*SetClientString) ( actualPrefix, prefixPtr, prefixSize ); - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) // ! Always keep the lock, a string is always returned! + XMP_EXIT } // ------------------------------------------------------------------------------------------------- /* class static */ void -WXMPMeta_GetNamespacePrefix_1 ( XMP_StringPtr namespaceURI, - XMP_StringPtr * namespacePrefix, - XMP_StringLen * prefixSize, - WXMP_Result * wResult ) +WXMPMeta_GetNamespacePrefix_1 ( XMP_StringPtr namespaceURI, + void * namespacePrefix, + SetClientStringProc SetClientString, + WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_GetNamespacePrefix_1" ) + XMP_ENTER_Static ( "WXMPMeta_GetNamespacePrefix_1" ) if ( (namespaceURI == 0) || (*namespaceURI == 0) ) XMP_Throw ( "Empty namespace URI", kXMPErr_BadSchema ); - if ( namespacePrefix == 0 ) namespacePrefix = &voidStringPtr; - if ( prefixSize == 0 ) prefixSize = &voidStringLen; + XMP_StringPtr prefixPtr = 0; + XMP_StringLen prefixSize = 0; - bool found = XMPMeta::GetNamespacePrefix ( namespaceURI, namespacePrefix, prefixSize ); + bool found = XMPMeta::GetNamespacePrefix ( namespaceURI, &prefixPtr, &prefixSize ); wResult->int32Result = found; - XMP_EXIT_WRAPPER_KEEP_LOCK ( found ) + if ( found && (namespacePrefix != 0) ) (*SetClientString) ( namespacePrefix, prefixPtr, prefixSize ); + + XMP_EXIT } // ------------------------------------------------------------------------------------------------- /* class static */ void -WXMPMeta_GetNamespaceURI_1 ( XMP_StringPtr namespacePrefix, - XMP_StringPtr * namespaceURI, - XMP_StringLen * uriSize, - WXMP_Result * wResult ) +WXMPMeta_GetNamespaceURI_1 ( XMP_StringPtr namespacePrefix, + void * namespaceURI, + SetClientStringProc SetClientString, + WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_GetNamespaceURI_1" ) + XMP_ENTER_Static ( "WXMPMeta_GetNamespaceURI_1" ) if ( (namespacePrefix == 0) || (*namespacePrefix == 0) ) XMP_Throw ( "Empty namespace prefix", kXMPErr_BadSchema ); - if ( namespaceURI == 0 ) namespaceURI = &voidStringPtr; - if ( uriSize == 0 ) uriSize = &voidStringLen; + XMP_StringPtr uriPtr = 0; + XMP_StringLen uriSize = 0; - bool found = XMPMeta::GetNamespaceURI ( namespacePrefix, namespaceURI, uriSize ); + bool found = XMPMeta::GetNamespaceURI ( namespacePrefix, &uriPtr, &uriSize ); wResult->int32Result = found; + + if ( found && (namespaceURI != 0) ) (*SetClientString) ( namespaceURI, uriPtr, uriSize ); - XMP_EXIT_WRAPPER_KEEP_LOCK ( found ) + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -282,263 +237,162 @@ WXMPMeta_GetNamespaceURI_1 ( XMP_StringPtr namespacePrefix, WXMPMeta_DeleteNamespace_1 ( XMP_StringPtr namespaceURI, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteNamespace_1" ) + XMP_ENTER_Static ( "WXMPMeta_DeleteNamespace_1" ) if ( (namespaceURI == 0) || (*namespaceURI == 0) ) XMP_Throw ( "Empty namespace URI", kXMPErr_BadSchema ); XMPMeta::DeleteNamespace ( namespaceURI ); - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_RegisterAlias_1 ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - XMP_StringPtr actualNS, - XMP_StringPtr actualProp, - XMP_OptionBits arrayForm, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_RegisterAlias_1" ) - - if ( (aliasNS == 0) || (*aliasNS == 0) ) XMP_Throw ( "Empty alias namespace URI", kXMPErr_BadSchema ); - if ( (aliasProp == 0) || (*aliasProp == 0) ) XMP_Throw ( "Empty alias property name", kXMPErr_BadXPath ); - if ( (actualNS == 0) || (*actualNS == 0) ) XMP_Throw ( "Empty actual namespace URI", kXMPErr_BadSchema ); - if ( (actualProp == 0) || (*actualProp == 0) ) XMP_Throw ( "Empty actual property name", kXMPErr_BadXPath ); - - XMPMeta::RegisterAlias ( aliasNS, aliasProp, actualNS, actualProp, arrayForm ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_ResolveAlias_1 ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - XMP_StringPtr * actualNS, - XMP_StringLen * nsSize, - XMP_StringPtr * actualProp, - XMP_StringLen * propSize, - XMP_OptionBits * arrayForm, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_ResolveAlias_1" ) - - if ( (aliasNS == 0) || (*aliasNS == 0) ) XMP_Throw ( "Empty alias namespace URI", kXMPErr_BadSchema ); - if ( (aliasProp == 0) || (*aliasProp == 0) ) XMP_Throw ( "Empty alias property name", kXMPErr_BadXPath ); - - if ( actualNS == 0 ) actualNS = &voidStringPtr; - if ( nsSize == 0 ) nsSize = &voidStringLen; - if ( actualProp == 0 ) actualProp = &voidStringPtr; - if ( propSize == 0 ) propSize = &voidStringLen; - if ( arrayForm == 0 ) arrayForm = &voidOptionBits; - - bool found = XMPMeta::ResolveAlias ( aliasNS, aliasProp, actualNS, nsSize, actualProp, propSize, arrayForm ); - wResult->int32Result = found; - - XMP_EXIT_WRAPPER_KEEP_LOCK ( found ) -} - -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_DeleteAlias_1 ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteAlias_1" ) - - if ( (aliasNS == 0) || (*aliasNS == 0) ) XMP_Throw ( "Empty alias namespace URI", kXMPErr_BadSchema ); - if ( (aliasProp == 0) || (*aliasProp == 0) ) XMP_Throw ( "Empty alias property name", kXMPErr_BadXPath ); - - XMPMeta::DeleteAlias ( aliasNS, aliasProp ); - - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -/* class static */ void -WXMPMeta_RegisterStandardAliases_1 ( XMP_StringPtr schemaNS, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPMeta_RegisterStandardAliases_1" ) - - if ( schemaNS == 0 ) schemaNS = ""; - - XMPMeta::RegisterStandardAliases ( schemaNS ); - - XMP_EXIT_WRAPPER + XMP_EXIT } // ================================================================================================= // Class Method Wrappers // ===================== -// -// These are DLL-entry wrappers for the methods. They all follow a simple pattern: -// -// validate parameters -// try -// acquire object lock -// call through to the implementation -// retain object lock if necessary -// catch anything and return an appropriate XMP_Error object -// return null (no error if we get to here) -// -// The object lock is acquired through a local wrapper object that automatically unlocks when the -// try-block is exited. The lock must be retained if the function is returning a string result. The -// output string is owned by the object, the client must copy the string then release the lock. The -// lock used here is the per-object lock. For simplicity at this time the lock is a simple mutual -// exclusion lock, we do not allow multiple concurrent readers. -// -// The one exception to this model is UnlockObject. It does not acquire the object lock since this -// is the function the client calls to release the lock after copying an output string! -// -// ================================================================================================= void -WXMPMeta_GetProperty_1 ( XMPMetaRef xmpRef, +WXMPMeta_GetProperty_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr propName, - XMP_StringPtr * propValue, - XMP_StringLen * valueSize, + void * propValue, XMP_OptionBits * options, + SetClientStringProc SetClientString, WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_GetProperty_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetProperty_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - if ( propValue == 0 ) propValue = &voidStringPtr; - if ( valueSize == 0 ) valueSize = &voidStringLen; + XMP_StringPtr valuePtr = 0; + XMP_StringLen valueSize = 0; if ( options == 0 ) options = &voidOptionBits; - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.GetProperty ( schemaNS, propName, propValue, valueSize, options ); + bool found = thiz.GetProperty ( schemaNS, propName, &valuePtr, &valueSize, options ); wResult->int32Result = found; + + if ( found && (propValue != 0) ) (*SetClientString) ( propValue, valuePtr, valueSize ); - XMP_EXIT_WRAPPER_KEEP_LOCK ( found ) + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_GetArrayItem_1 ( XMPMetaRef xmpRef, +WXMPMeta_GetArrayItem_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex, - XMP_StringPtr * itemValue, - XMP_StringLen * valueSize, + void * itemValue, XMP_OptionBits * options, + SetClientStringProc SetClientString, WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_GetArrayItem_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetArrayItem_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - if ( itemValue == 0 ) itemValue = &voidStringPtr; - if ( valueSize == 0 ) valueSize = &voidStringLen; + XMP_StringPtr valuePtr = 0; + XMP_StringLen valueSize = 0; if ( options == 0 ) options = &voidOptionBits; - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.GetArrayItem ( schemaNS, arrayName, itemIndex, itemValue, valueSize, options ); + bool found = thiz.GetArrayItem ( schemaNS, arrayName, itemIndex, &valuePtr, &valueSize, options ); wResult->int32Result = found; + + if ( found && (itemValue != 0) ) (*SetClientString) ( itemValue, valuePtr, valueSize ); - XMP_EXIT_WRAPPER_KEEP_LOCK ( found ) + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_GetStructField_1 ( XMPMetaRef xmpRef, +WXMPMeta_GetStructField_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, - XMP_StringPtr * fieldValue, - XMP_StringLen * valueSize, + void * fieldValue, XMP_OptionBits * options, + SetClientStringProc SetClientString, WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_GetStructField_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetStructField_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath ); if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema ); if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath ); - if ( fieldValue == 0 ) fieldValue = &voidStringPtr; - if ( valueSize == 0 ) valueSize = &voidStringLen; + XMP_StringPtr valuePtr = 0; + XMP_StringLen valueSize = 0; if ( options == 0 ) options = &voidOptionBits; - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.GetStructField ( schemaNS, structName, fieldNS, fieldName, fieldValue, valueSize, options ); + bool found = thiz.GetStructField ( schemaNS, structName, fieldNS, fieldName, &valuePtr, &valueSize, options ); wResult->int32Result = found; + + if ( found && (fieldValue != 0) ) (*SetClientString) ( fieldValue, valuePtr, valueSize ); - XMP_EXIT_WRAPPER_KEEP_LOCK ( found ) + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_GetQualifier_1 ( XMPMetaRef xmpRef, +WXMPMeta_GetQualifier_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, XMP_StringPtr qualName, - XMP_StringPtr * qualValue, - XMP_StringLen * valueSize, + void * qualValue, XMP_OptionBits * options, + SetClientStringProc SetClientString, WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_GetQualifier_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetQualifier_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema ); if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath ); - if ( qualValue == 0 ) qualValue = &voidStringPtr; - if ( valueSize == 0 ) valueSize = &voidStringLen; + XMP_StringPtr valuePtr = 0; + XMP_StringLen valueSize = 0; if ( options == 0 ) options = &voidOptionBits; - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.GetQualifier ( schemaNS, propName, qualNS, qualName, qualValue, valueSize, options ); + bool found = thiz.GetQualifier ( schemaNS, propName, qualNS, qualName, &valuePtr, &valueSize, options ); wResult->int32Result = found; + + if ( found && (qualValue != 0) ) (*SetClientString) ( qualValue, valuePtr, valueSize ); - XMP_EXIT_WRAPPER_KEEP_LOCK ( found ) + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_SetProperty_1 ( XMPMetaRef xmpRef, +WXMPMeta_SetProperty_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr propValue, XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_SetProperty_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetProperty_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetProperty ( schemaNS, propName, propValue, options ); + thiz->SetProperty ( schemaNS, propName, propValue, options ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_SetArrayItem_1 ( XMPMetaRef xmpRef, +WXMPMeta_SetArrayItem_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex, @@ -546,21 +400,20 @@ WXMPMeta_SetArrayItem_1 ( XMPMetaRef xmpRef, XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_SetArrayItem_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetArrayItem_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetArrayItem ( schemaNS, arrayName, itemIndex, itemValue, options ); + thiz->SetArrayItem ( schemaNS, arrayName, itemIndex, itemValue, options ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_AppendArrayItem_1 ( XMPMetaRef xmpRef, +WXMPMeta_AppendArrayItem_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_OptionBits arrayOptions, @@ -568,21 +421,20 @@ WXMPMeta_AppendArrayItem_1 ( XMPMetaRef xmpRef, XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_AppendArrayItem_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_AppendArrayItem_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->AppendArrayItem ( schemaNS, arrayName, arrayOptions, itemValue, options ); + thiz->AppendArrayItem ( schemaNS, arrayName, arrayOptions, itemValue, options ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_SetStructField_1 ( XMPMetaRef xmpRef, +WXMPMeta_SetStructField_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, @@ -591,23 +443,22 @@ WXMPMeta_SetStructField_1 ( XMPMetaRef xmpRef, XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_SetStructField_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetStructField_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath ); if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema ); if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath ); - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetStructField ( schemaNS, structName, fieldNS, fieldName, fieldValue, options ); + thiz->SetStructField ( schemaNS, structName, fieldNS, fieldName, fieldValue, options ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_SetQualifier_1 ( XMPMetaRef xmpRef, +WXMPMeta_SetQualifier_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, @@ -616,233 +467,227 @@ WXMPMeta_SetQualifier_1 ( XMPMetaRef xmpRef, XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_SetQualifier_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetQualifier_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema ); if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath ); - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetQualifier ( schemaNS, propName, qualNS, qualName, qualValue, options ); + thiz->SetQualifier ( schemaNS, propName, qualNS, qualName, qualValue, options ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_DeleteProperty_1 ( XMPMetaRef xmpRef, +WXMPMeta_DeleteProperty_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr propName, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteProperty_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_DeleteProperty_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->DeleteProperty ( schemaNS, propName ); + thiz->DeleteProperty ( schemaNS, propName ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_DeleteArrayItem_1 ( XMPMetaRef xmpRef, +WXMPMeta_DeleteArrayItem_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteArrayItem_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_DeleteArrayItem_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->DeleteArrayItem ( schemaNS, arrayName, itemIndex ); + thiz->DeleteArrayItem ( schemaNS, arrayName, itemIndex ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_DeleteStructField_1 ( XMPMetaRef xmpRef, +WXMPMeta_DeleteStructField_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteStructField_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_DeleteStructField_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath ); if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema ); if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath ); - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->DeleteStructField ( schemaNS, structName, fieldNS, fieldName ); + thiz->DeleteStructField ( schemaNS, structName, fieldNS, fieldName ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_DeleteQualifier_1 ( XMPMetaRef xmpRef, +WXMPMeta_DeleteQualifier_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, XMP_StringPtr qualName, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_DeleteQualifier_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_DeleteQualifier_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema ); if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath ); - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->DeleteQualifier ( schemaNS, propName, qualNS, qualName ); + thiz->DeleteQualifier ( schemaNS, propName, qualNS, qualName ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_DoesPropertyExist_1 ( XMPMetaRef xmpRef, +WXMPMeta_DoesPropertyExist_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr propName, WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_DoesPropertyExist_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_DoesPropertyExist_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.DoesPropertyExist ( schemaNS, propName ); + bool found = thiz.DoesPropertyExist ( schemaNS, propName ); wResult->int32Result = found; - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_DoesArrayItemExist_1 ( XMPMetaRef xmpRef, +WXMPMeta_DoesArrayItemExist_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex, WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_DoesArrayItemExist_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_DoesArrayItemExist_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.DoesArrayItemExist ( schemaNS, arrayName, itemIndex ); + bool found = thiz.DoesArrayItemExist ( schemaNS, arrayName, itemIndex ); wResult->int32Result = found; - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_DoesStructFieldExist_1 ( XMPMetaRef xmpRef, +WXMPMeta_DoesStructFieldExist_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_DoesStructFieldExist_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_DoesStructFieldExist_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath ); if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema ); if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath ); - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.DoesStructFieldExist ( schemaNS, structName, fieldNS, fieldName ); + bool found = thiz.DoesStructFieldExist ( schemaNS, structName, fieldNS, fieldName ); wResult->int32Result = found; - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_DoesQualifierExist_1 ( XMPMetaRef xmpRef, +WXMPMeta_DoesQualifierExist_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, XMP_StringPtr qualName, WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_DoesQualifierExist_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_DoesQualifierExist_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema ); if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath ); - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.DoesQualifierExist ( schemaNS, propName, qualNS, qualName ); + bool found = thiz.DoesQualifierExist ( schemaNS, propName, qualNS, qualName ); wResult->int32Result = found; - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_GetLocalizedText_1 ( XMPMetaRef xmpRef, +WXMPMeta_GetLocalizedText_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_StringPtr genericLang, XMP_StringPtr specificLang, - XMP_StringPtr * actualLang, - XMP_StringLen * langSize, - XMP_StringPtr * itemValue, - XMP_StringLen * valueSize, + void * actualLang, + void * itemValue, XMP_OptionBits * options, + SetClientStringProc SetClientString, WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_GetLocalizedText_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetLocalizedText_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); if ( genericLang == 0 ) genericLang = ""; if ( (specificLang == 0) ||(*specificLang == 0) ) XMP_Throw ( "Empty specific language", kXMPErr_BadParam ); - if ( actualLang == 0 ) actualLang = &voidStringPtr; - if ( langSize == 0 ) langSize = &voidStringLen; - if ( itemValue == 0 ) itemValue = &voidStringPtr; - if ( valueSize == 0 ) valueSize = &voidStringLen; + XMP_StringPtr langPtr = 0; + XMP_StringLen langSize = 0; + XMP_StringPtr valuePtr = 0; + XMP_StringLen valueSize = 0; if ( options == 0 ) options = &voidOptionBits; - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.GetLocalizedText ( schemaNS, arrayName, genericLang, specificLang, - actualLang, langSize, itemValue, valueSize, options ); + bool found = thiz.GetLocalizedText ( schemaNS, arrayName, genericLang, specificLang, + &langPtr, &langSize, &valuePtr, &valueSize, options ); wResult->int32Result = found; + + if ( found ) { + if ( actualLang != 0 ) (*SetClientString) ( actualLang, langPtr, langSize ); + if ( itemValue != 0 ) (*SetClientString) ( itemValue, valuePtr, valueSize ); + } - XMP_EXIT_WRAPPER_KEEP_LOCK ( found ) + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_SetLocalizedText_1 ( XMPMetaRef xmpRef, +WXMPMeta_SetLocalizedText_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_StringPtr genericLang, @@ -851,7 +696,7 @@ WXMPMeta_SetLocalizedText_1 ( XMPMetaRef xmpRef, XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_SetLocalizedText_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetLocalizedText_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); @@ -859,23 +704,43 @@ WXMPMeta_SetLocalizedText_1 ( XMPMetaRef xmpRef, if ( (specificLang == 0) ||(*specificLang == 0) ) XMP_Throw ( "Empty specific language", kXMPErr_BadParam ); if ( itemValue == 0 ) itemValue = ""; - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetLocalizedText ( schemaNS, arrayName, genericLang, specificLang, itemValue, options ); + thiz->SetLocalizedText ( schemaNS, arrayName, genericLang, specificLang, itemValue, options ); + + XMP_EXIT +} + +void +WXMPMeta_DeleteLocalizedText_1 ( XMPMetaRef xmpObjRef, + XMP_StringPtr schemaNS, + XMP_StringPtr arrayName, + XMP_StringPtr genericLang, + XMP_StringPtr specificLang, + WXMP_Result * wResult ) +{ + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_DeleteLocalizedText_1" ) - XMP_EXIT_WRAPPER + if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); + if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); + if ( genericLang == 0 ) genericLang = ""; + if ( (specificLang == 0) ||(*specificLang == 0) ) XMP_Throw ( "Empty specific language", kXMPErr_BadParam ); + + thiz->DeleteLocalizedText ( schemaNS, arrayName, genericLang, specificLang ); + + XMP_EXIT } + // ------------------------------------------------------------------------------------------------- void -WXMPMeta_GetProperty_Bool_1 ( XMPMetaRef xmpRef, +WXMPMeta_GetProperty_Bool_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_Bool * propValue, XMP_OptionBits * options, WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_GetProperty_Bool_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetProperty_Bool_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); @@ -883,26 +748,25 @@ WXMPMeta_GetProperty_Bool_1 ( XMPMetaRef xmpRef, if ( propValue == 0 ) propValue = &voidByte; if ( options == 0 ) options = &voidOptionBits; - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); bool value; - bool found = meta.GetProperty_Bool ( schemaNS, propName, &value, options ); + bool found = thiz.GetProperty_Bool ( schemaNS, propName, &value, options ); if ( propValue != 0 ) *propValue = value; wResult->int32Result = found; - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_GetProperty_Int_1 ( XMPMetaRef xmpRef, +WXMPMeta_GetProperty_Int_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_Int32 * propValue, XMP_OptionBits * options, WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_GetProperty_Int_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetProperty_Int_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); @@ -910,24 +774,23 @@ WXMPMeta_GetProperty_Int_1 ( XMPMetaRef xmpRef, if ( propValue == 0 ) propValue = &voidInt32; if ( options == 0 ) options = &voidOptionBits; - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.GetProperty_Int ( schemaNS, propName, propValue, options ); + bool found = thiz.GetProperty_Int ( schemaNS, propName, propValue, options ); wResult->int32Result = found; - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_GetProperty_Int64_1 ( XMPMetaRef xmpRef, - XMP_StringPtr schemaNS, - XMP_StringPtr propName, - XMP_Int64 * propValue, +WXMPMeta_GetProperty_Int64_1 ( XMPMetaRef xmpObjRef, + XMP_StringPtr schemaNS, + XMP_StringPtr propName, + XMP_Int64 * propValue, XMP_OptionBits * options, - WXMP_Result * wResult ) /* const */ + WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_GetProperty_Int64_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetProperty_Int64_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); @@ -935,24 +798,23 @@ WXMPMeta_GetProperty_Int64_1 ( XMPMetaRef xmpRef, if ( propValue == 0 ) propValue = &voidInt64; if ( options == 0 ) options = &voidOptionBits; - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.GetProperty_Int64 ( schemaNS, propName, propValue, options ); + bool found = thiz.GetProperty_Int64 ( schemaNS, propName, propValue, options ); wResult->int32Result = found; - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_GetProperty_Float_1 ( XMPMetaRef xmpRef, +WXMPMeta_GetProperty_Float_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr propName, double * propValue, XMP_OptionBits * options, WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_GetProperty_Float_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetProperty_Float_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); @@ -960,24 +822,23 @@ WXMPMeta_GetProperty_Float_1 ( XMPMetaRef xmpRef, if ( propValue == 0 ) propValue = &voidDouble; if ( options == 0 ) options = &voidOptionBits; - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.GetProperty_Float ( schemaNS, propName, propValue, options ); + bool found = thiz.GetProperty_Float ( schemaNS, propName, propValue, options ); wResult->int32Result = found; - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_GetProperty_Date_1 ( XMPMetaRef xmpRef, +WXMPMeta_GetProperty_Date_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_DateTime * propValue, XMP_OptionBits * options, WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_GetProperty_Date_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetProperty_Date_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); @@ -985,326 +846,295 @@ WXMPMeta_GetProperty_Date_1 ( XMPMetaRef xmpRef, if ( propValue == 0 ) propValue = &voidDateTime; if ( options == 0 ) options = &voidOptionBits; - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - bool found = meta.GetProperty_Date ( schemaNS, propName, propValue, options ); + bool found = thiz.GetProperty_Date ( schemaNS, propName, propValue, options ); wResult->int32Result = found; - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_SetProperty_Bool_1 ( XMPMetaRef xmpRef, +WXMPMeta_SetProperty_Bool_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_Bool propValue, XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_SetProperty_Bool_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetProperty_Bool_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetProperty_Bool ( schemaNS, propName, propValue, options ); + thiz->SetProperty_Bool ( schemaNS, propName, propValue, options ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_SetProperty_Int_1 ( XMPMetaRef xmpRef, +WXMPMeta_SetProperty_Int_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_Int32 propValue, XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_SetProperty_Int_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetProperty_Int_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetProperty_Int ( schemaNS, propName, propValue, options ); + thiz->SetProperty_Int ( schemaNS, propName, propValue, options ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_SetProperty_Int64_1 ( XMPMetaRef xmpRef, +WXMPMeta_SetProperty_Int64_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_Int64 propValue, XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_SetProperty_Int64_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetProperty_Int64_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetProperty_Int64 ( schemaNS, propName, propValue, options ); + thiz->SetProperty_Int64 ( schemaNS, propName, propValue, options ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_SetProperty_Float_1 ( XMPMetaRef xmpRef, +WXMPMeta_SetProperty_Float_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr propName, double propValue, XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_SetProperty_Float_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetProperty_Float_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetProperty_Float ( schemaNS, propName, propValue, options ); + thiz->SetProperty_Float ( schemaNS, propName, propValue, options ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_SetProperty_Date_1 ( XMPMetaRef xmpRef, +WXMPMeta_SetProperty_Date_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr propName, const XMP_DateTime & propValue, XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_SetProperty_Date_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetProperty_Date_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetProperty_Date ( schemaNS, propName, propValue, options ); + thiz->SetProperty_Date ( schemaNS, propName, propValue, options ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_DumpObject_1 ( XMPMetaRef xmpRef, +WXMPMeta_DumpObject_1 ( XMPMetaRef xmpObjRef, XMP_TextOutputProc outProc, void * refCon, WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_DumpObject_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_DumpObject_1" ) if ( outProc == 0 ) XMP_Throw ( "Null client output routine", kXMPErr_BadParam ); - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - XMP_Status status = meta.DumpObject ( outProc, refCon ); - wResult->int32Result = status; + thiz.DumpObject ( outProc, refCon ); + wResult->int32Result = 0; - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_Sort_1 ( XMPMetaRef xmpRef, +WXMPMeta_Sort_1 ( XMPMetaRef xmpObjRef, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_Sort_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_Sort_1" ) - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->Sort(); + thiz->Sort(); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_Erase_1 ( XMPMetaRef xmpRef, +WXMPMeta_Erase_1 ( XMPMetaRef xmpObjRef, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_Erase_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_Erase_1" ) - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->Erase(); + thiz->Erase(); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_Clone_1 ( XMPMetaRef xmpRef, +WXMPMeta_Clone_1 ( XMPMetaRef xmpObjRef, XMP_OptionBits options, WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_Clone_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_Clone_1" ) - const XMPMeta & xOriginal = WtoXMPMeta_Ref ( xmpRef ); - XMPMeta * xClone = new XMPMeta; - xOriginal.Clone ( xClone, options ); + XMPMeta * xClone = new XMPMeta; // ! Don't need an output lock, final ref assignment in client glue. + thiz.Clone ( xClone, options ); XMP_Assert ( xClone->clientRefs == 0 ); // ! Gets incremented in TXMPMeta::Clone. wResult->ptrResult = xClone; - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_CountArrayItems_1 ( XMPMetaRef xmpRef, +WXMPMeta_CountArrayItems_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr schemaNS, XMP_StringPtr arrayName, WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_CountArrayItems_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_CountArrayItems_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - XMP_Index count = meta.CountArrayItems ( schemaNS, arrayName ); + XMP_Index count = thiz.CountArrayItems ( schemaNS, arrayName ); wResult->int32Result = count; - XMP_EXIT_WRAPPER -} - -// ------------------------------------------------------------------------------------------------- - -void -WXMPMeta_UnlockObject_1 ( XMPMetaRef xmpRef, - XMP_OptionBits options ) /* const */ -{ - WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPMeta_UnlockObject_1" ) - - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - meta.UnlockObject ( options ); - - XMP_EXIT_WRAPPER_NO_THROW + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_GetObjectName_1 ( XMPMetaRef xmpRef, - XMP_StringPtr * namePtr, - XMP_StringLen * nameLen, - WXMP_Result * wResult ) /* const */ +WXMPMeta_GetObjectName_1 ( XMPMetaRef xmpObjRef, + void * objName, + SetClientStringProc SetClientString, + WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_GetObjectName_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetObjectName_1" ) - if ( namePtr == 0 ) namePtr = &voidStringPtr; - if ( nameLen == 0 ) nameLen = &voidStringLen; + XMP_StringPtr namePtr = 0; + XMP_StringLen nameSize = 0; - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - meta.GetObjectName ( namePtr, nameLen ); + thiz.GetObjectName ( &namePtr, &nameSize ); + if ( objName != 0 ) (*SetClientString) ( objName, namePtr, nameSize ); - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) // ! Always keep the lock, a string is always returned! + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_SetObjectName_1 ( XMPMetaRef xmpRef, +WXMPMeta_SetObjectName_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr name, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_SetObjectName_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetObjectName_1" ) if ( name == 0 ) name = ""; - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetObjectName ( name ); + thiz->SetObjectName ( name ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_GetObjectOptions_1 ( XMPMetaRef xmpRef, +WXMPMeta_GetObjectOptions_1 ( XMPMetaRef xmpObjRef, WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_GetObjectOptions_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_GetObjectOptions_1" ) - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - XMP_OptionBits options = meta.GetObjectOptions(); + XMP_OptionBits options = thiz.GetObjectOptions(); wResult->int32Result = options; - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_SetObjectOptions_1 ( XMPMetaRef xmpRef, +WXMPMeta_SetObjectOptions_1 ( XMPMetaRef xmpObjRef, XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_SetObjectOptions_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_SetObjectOptions_1" ) - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->SetObjectOptions ( options ); + thiz->SetObjectOptions ( options ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_ParseFromBuffer_1 ( XMPMetaRef xmpRef, +WXMPMeta_ParseFromBuffer_1 ( XMPMetaRef xmpObjRef, XMP_StringPtr buffer, XMP_StringLen bufferSize, XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPMeta_ParseFromBuffer_1" ) + XMP_ENTER_ObjWrite ( XMPMeta, "WXMPMeta_ParseFromBuffer_1" ) - XMPMeta * meta = WtoXMPMeta_Ptr ( xmpRef ); - meta->ParseFromBuffer ( buffer, bufferSize, options ); + thiz->ParseFromBuffer ( buffer, bufferSize, options ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPMeta_SerializeToBuffer_1 ( XMPMetaRef xmpRef, - XMP_StringPtr * rdfString, - XMP_StringLen * rdfSize, - XMP_OptionBits options, - XMP_StringLen padding, - XMP_StringPtr newline, - XMP_StringPtr indent, - XMP_Index baseIndent, - WXMP_Result * wResult ) /* const */ +WXMPMeta_SerializeToBuffer_1 ( XMPMetaRef xmpObjRef, + void * pktString, + XMP_OptionBits options, + XMP_StringLen padding, + XMP_StringPtr newline, + XMP_StringPtr indent, + XMP_Index baseIndent, + SetClientStringProc SetClientString, + WXMP_Result * wResult ) /* const */ { - XMP_ENTER_WRAPPER ( "WXMPMeta_SerializeToBuffer_1" ) + XMP_ENTER_ObjRead ( XMPMeta, "WXMPMeta_SerializeToBuffer_1" ) - if ( rdfString == 0 ) rdfString = &voidStringPtr; - if ( rdfSize == 0 ) rdfSize = &voidStringLen; + XMP_VarString localStr; if ( newline == 0 ) newline = ""; if ( indent == 0 ) indent = ""; - const XMPMeta & meta = WtoXMPMeta_Ref ( xmpRef ); - meta.SerializeToBuffer ( rdfString, rdfSize, options, padding, newline, indent, baseIndent ); + thiz.SerializeToBuffer ( &localStr, options, padding, newline, indent, baseIndent ); + if ( pktString != 0 ) (*SetClientString) ( pktString, localStr.c_str(), localStr.size() ); - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) // ! Always keep the lock, a string is always returned! + XMP_EXIT } // ================================================================================================= diff --git a/source/XMPCore/WXMPUtils.cpp b/source/XMPCore/WXMPUtils.cpp index dac093a..b8a96ff 100644 --- a/source/XMPCore/WXMPUtils.cpp +++ b/source/XMPCore/WXMPUtils.cpp @@ -1,5 +1,5 @@ // ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated +// Copyright 2004 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms @@ -9,11 +9,13 @@ // *** Should change "type * inParam" to "type & inParam" #include "XMP_Environment.h" // ! This must be the first include! -#include "XMPCore_Impl.hpp" +#include "XMP_Const.h" -#include "XMPUtils.hpp" #include "client-glue/WXMPUtils.hpp" +#include "XMPCore_Impl.hpp" +#include "XMPUtils.hpp" + #if XMP_WinBuild #pragma warning ( disable : 4101 ) // unreferenced local variable #pragma warning ( disable : 4189 ) // local variable is initialized but not referenced @@ -32,37 +34,24 @@ extern "C" { // ===================== void -WXMPUtils_Unlock_1 ( XMP_OptionBits options ) -{ - WXMP_Result * wResult = &void_wResult; // ! Needed to "fool" the EnterWrapper macro. - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_Unlock_1" ) - - XMPUtils::Unlock ( options ); - - XMP_EXIT_WRAPPER_NO_THROW -} - -// ================================================================================================= - -void WXMPUtils_ComposeArrayItemPath_1 ( XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize, + void * itemPath, + SetClientStringProc SetClientString, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPUtils_ComposeArrayItemPath_1" ) - + XMP_ENTER_Static ( "WXMPUtils_ComposeArrayItemPath_1" ) + if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - - if ( fullPath == 0 ) fullPath = &voidStringPtr; - if ( pathSize == 0 ) pathSize = &voidStringLen; - XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, fullPath, pathSize ); + XMP_VarString localStr; - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) + XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &localStr ); + if ( itemPath != 0 ) (*SetClientString) ( itemPath, localStr.c_str(), localStr.size() ); + + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -72,23 +61,23 @@ WXMPUtils_ComposeStructFieldPath_1 ( XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize, + void * fieldPath, + SetClientStringProc SetClientString, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPUtils_ComposeStructFieldPath_1" ) + XMP_ENTER_Static ( "WXMPUtils_ComposeStructFieldPath_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (structName == 0) || (*structName == 0) ) XMP_Throw ( "Empty struct name", kXMPErr_BadXPath ); if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema ); if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath ); - - if ( fullPath == 0 ) fullPath = &voidStringPtr; - if ( pathSize == 0 ) pathSize = &voidStringLen; - XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, fullPath, pathSize ); + XMP_VarString localStr; + + XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &localStr ); + if ( fieldPath != 0 ) (*SetClientString) ( fieldPath, localStr.c_str(), localStr.size() ); - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -98,23 +87,23 @@ WXMPUtils_ComposeQualifierPath_1 ( XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, XMP_StringPtr qualName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize, + void * qualPath, + SetClientStringProc SetClientString, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPUtils_ComposeQualifierPath_1" ) - + XMP_ENTER_Static ( "WXMPUtils_ComposeQualifierPath_1" ) + if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (propName == 0) || (*propName == 0) ) XMP_Throw ( "Empty property name", kXMPErr_BadXPath ); if ( (qualNS == 0) || (*qualNS == 0) ) XMP_Throw ( "Empty qualifier namespace URI", kXMPErr_BadSchema ); if ( (qualName == 0) || (*qualName == 0) ) XMP_Throw ( "Empty qualifier name", kXMPErr_BadXPath ); - - if ( fullPath == 0 ) fullPath = &voidStringPtr; - if ( pathSize == 0 ) pathSize = &voidStringLen; - XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, fullPath, pathSize ); + XMP_VarString localStr; + + XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &localStr ); + if ( qualPath != 0 ) (*SetClientString) ( qualPath, localStr.c_str(), localStr.size() ); - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -123,22 +112,22 @@ void WXMPUtils_ComposeLangSelector_1 ( XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_StringPtr langName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize, + void * selPath, + SetClientStringProc SetClientString, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPUtils_ComposeLangSelector_1" ) - + XMP_ENTER_Static ( "WXMPUtils_ComposeLangSelector_1" ) + if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); if ( (langName == 0) || (*langName == 0) ) XMP_Throw ( "Empty language name", kXMPErr_BadParam ); - - if ( fullPath == 0 ) fullPath = &voidStringPtr; - if ( pathSize == 0 ) pathSize = &voidStringLen; - XMPUtils::ComposeLangSelector ( schemaNS, arrayName, langName, fullPath, pathSize ); + XMP_VarString localStr; + + XMPUtils::ComposeLangSelector ( schemaNS, arrayName, langName, &localStr ); + if ( selPath != 0 ) (*SetClientString) ( selPath, localStr.c_str(), localStr.size() ); - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -149,123 +138,123 @@ WXMPUtils_ComposeFieldSelector_1 ( XMP_StringPtr schemaNS, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, XMP_StringPtr fieldValue, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize, + void * selPath, + SetClientStringProc SetClientString, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPUtils_ComposeFieldSelector_1" ) - + XMP_ENTER_Static ( "WXMPUtils_ComposeFieldSelector_1" ) + if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); if ( (fieldNS == 0) || (*fieldNS == 0) ) XMP_Throw ( "Empty field namespace URI", kXMPErr_BadSchema ); if ( (fieldName == 0) || (*fieldName == 0) ) XMP_Throw ( "Empty field name", kXMPErr_BadXPath ); if ( fieldValue == 0 ) fieldValue = ""; - - if ( fullPath == 0 ) fullPath = &voidStringPtr; - if ( pathSize == 0 ) pathSize = &voidStringLen; - XMPUtils::ComposeFieldSelector ( schemaNS, arrayName, fieldNS, fieldName, fieldValue, fullPath, pathSize ); + XMP_VarString localStr; - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) + XMPUtils::ComposeFieldSelector ( schemaNS, arrayName, fieldNS, fieldName, fieldValue, &localStr ); + if ( selPath != 0 ) (*SetClientString) ( selPath, localStr.c_str(), localStr.size() ); + + XMP_EXIT } // ================================================================================================= void -WXMPUtils_ConvertFromBool_1 ( XMP_Bool binValue, - XMP_StringPtr * strValue, - XMP_StringLen * strSize, - WXMP_Result * wResult ) +WXMPUtils_ConvertFromBool_1 ( XMP_Bool binValue, + void * strValue, + SetClientStringProc SetClientString, + WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromBool_1" ) + XMP_ENTER_Static ( "WXMPUtils_ConvertFromBool_1" ) - if ( strValue == 0 ) strValue = &voidStringPtr; - if ( strSize == 0 ) strSize = &voidStringLen; + XMP_VarString localStr; - XMPUtils::ConvertFromBool ( binValue, strValue, strSize ); + XMPUtils::ConvertFromBool ( binValue, &localStr ); + if ( strValue != 0 ) (*SetClientString) ( strValue, localStr.c_str(), localStr.size() ); - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPUtils_ConvertFromInt_1 ( XMP_Int32 binValue, - XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize, - WXMP_Result * wResult ) +WXMPUtils_ConvertFromInt_1 ( XMP_Int32 binValue, + XMP_StringPtr format, + void * strValue, + SetClientStringProc SetClientString, + WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromInt_1" ) + XMP_ENTER_Static ( "WXMPUtils_ConvertFromInt_1" ) if ( format == 0 ) format = ""; - - if ( strValue == 0 ) strValue = &voidStringPtr; - if ( strSize == 0 ) strSize = &voidStringLen; - XMPUtils::ConvertFromInt ( binValue, format, strValue, strSize ); + XMP_VarString localStr; - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) + XMPUtils::ConvertFromInt ( binValue, format, &localStr ); + if ( strValue != 0 ) (*SetClientString) ( strValue, localStr.c_str(), localStr.size() ); + + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPUtils_ConvertFromInt64_1 ( XMP_Int64 binValue, - XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize, - WXMP_Result * wResult ) +WXMPUtils_ConvertFromInt64_1 ( XMP_Int64 binValue, + XMP_StringPtr format, + void * strValue, + SetClientStringProc SetClientString, + WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromInt64_1" ) + XMP_ENTER_Static ( "WXMPUtils_ConvertFromInt64_1" ) if ( format == 0 ) format = ""; - - if ( strValue == 0 ) strValue = &voidStringPtr; - if ( strSize == 0 ) strSize = &voidStringLen; - XMPUtils::ConvertFromInt64 ( binValue, format, strValue, strSize ); + XMP_VarString localStr; + + XMPUtils::ConvertFromInt64 ( binValue, format, &localStr ); + if ( strValue != 0 ) (*SetClientString) ( strValue, localStr.c_str(), localStr.size() ); - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPUtils_ConvertFromFloat_1 ( double binValue, - XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize, - WXMP_Result * wResult ) +WXMPUtils_ConvertFromFloat_1 ( double binValue, + XMP_StringPtr format, + void * strValue, + SetClientStringProc SetClientString, + WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromFloat_1" ) + XMP_ENTER_Static ( "WXMPUtils_ConvertFromFloat_1" ) if ( format == 0 ) format = ""; - - if ( strValue == 0 ) strValue = &voidStringPtr; - if ( strSize == 0 ) strSize = &voidStringLen; - XMPUtils::ConvertFromFloat ( binValue, format, strValue, strSize ); + XMP_VarString localStr; - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) + XMPUtils::ConvertFromFloat ( binValue, format, &localStr ); + if ( strValue != 0 ) (*SetClientString) ( strValue, localStr.c_str(), localStr.size() ); + + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void WXMPUtils_ConvertFromDate_1 ( const XMP_DateTime & binValue, - XMP_StringPtr * strValue, - XMP_StringLen * strSize, + void * strValue, + SetClientStringProc SetClientString, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPUtils_ConvertFromDate_1" ) + XMP_ENTER_Static ( "WXMPUtils_ConvertFromDate_1" ) - if ( strValue == 0 ) strValue = &voidStringPtr; - if ( strSize == 0 ) strSize = &voidStringLen; + XMP_VarString localStr; - XMPUtils::ConvertFromDate( binValue, strValue, strSize ); + XMPUtils::ConvertFromDate( binValue, &localStr ); + if ( strValue != 0 ) (*SetClientString) ( strValue, localStr.c_str(), localStr.size() ); - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) + XMP_EXIT } // ================================================================================================= @@ -274,13 +263,13 @@ void WXMPUtils_ConvertToBool_1 ( XMP_StringPtr strValue, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToBool_1" ) + XMP_ENTER_Static ( "WXMPUtils_ConvertToBool_1" ) if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty string value", kXMPErr_BadParam); XMP_Bool result = XMPUtils::ConvertToBool ( strValue ); wResult->int32Result = result; - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -289,13 +278,13 @@ void WXMPUtils_ConvertToInt_1 ( XMP_StringPtr strValue, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToInt_1" ) + XMP_ENTER_Static ( "WXMPUtils_ConvertToInt_1" ) if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty string value", kXMPErr_BadParam); XMP_Int32 result = XMPUtils::ConvertToInt ( strValue ); wResult->int32Result = result; - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -304,13 +293,13 @@ void WXMPUtils_ConvertToInt64_1 ( XMP_StringPtr strValue, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToInt64_1" ) + XMP_ENTER_Static ( "WXMPUtils_ConvertToInt64_1" ) if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty string value", kXMPErr_BadParam); XMP_Int64 result = XMPUtils::ConvertToInt64 ( strValue ); wResult->int64Result = result; - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -319,13 +308,13 @@ void WXMPUtils_ConvertToFloat_1 ( XMP_StringPtr strValue, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToFloat_1") + XMP_ENTER_Static ( "WXMPUtils_ConvertToFloat_1") if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty string value", kXMPErr_BadParam); double result = XMPUtils::ConvertToFloat ( strValue ); wResult->floatResult = result; - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -335,12 +324,12 @@ WXMPUtils_ConvertToDate_1 ( XMP_StringPtr strValue, XMP_DateTime * binValue, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToDate_1" ) + XMP_ENTER_Static ( "WXMPUtils_ConvertToDate_1" ) if ( binValue == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam); // ! Pointer is from the client. XMPUtils::ConvertToDate ( strValue, binValue ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ================================================================================================= @@ -349,12 +338,12 @@ void WXMPUtils_CurrentDateTime_1 ( XMP_DateTime * time, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_CurrentDateTime_1" ) - + XMP_ENTER_Static ( "WXMPUtils_CurrentDateTime_1" ) + if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam); XMPUtils::CurrentDateTime ( time ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -363,12 +352,12 @@ void WXMPUtils_SetTimeZone_1 ( XMP_DateTime * time, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_SetTimeZone_1" ) + XMP_ENTER_Static ( "WXMPUtils_SetTimeZone_1" ) if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam); XMPUtils::SetTimeZone ( time ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -377,12 +366,12 @@ void WXMPUtils_ConvertToUTCTime_1 ( XMP_DateTime * time, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToUTCTime_1" ) + XMP_ENTER_Static ( "WXMPUtils_ConvertToUTCTime_1" ) if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam); XMPUtils::ConvertToUTCTime ( time ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -391,12 +380,12 @@ void WXMPUtils_ConvertToLocalTime_1 ( XMP_DateTime * time, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_ConvertToLocalTime_1" ) + XMP_ENTER_Static ( "WXMPUtils_ConvertToLocalTime_1" ) if ( time == 0 ) XMP_Throw ( "Null output date", kXMPErr_BadParam); XMPUtils::ConvertToLocalTime ( time ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -406,77 +395,77 @@ WXMPUtils_CompareDateTime_1 ( const XMP_DateTime & left, const XMP_DateTime & right, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER_NO_LOCK ( "WXMPUtils_CompareDateTime_1" ) + XMP_ENTER_Static ( "WXMPUtils_CompareDateTime_1" ) int result = XMPUtils::CompareDateTime ( left, right ); wResult->int32Result = result; - XMP_EXIT_WRAPPER + XMP_EXIT } // ================================================================================================= void -WXMPUtils_EncodeToBase64_1 ( XMP_StringPtr rawStr, - XMP_StringLen rawLen, - XMP_StringPtr * encodedStr, - XMP_StringLen * encodedLen, - WXMP_Result * wResult ) +WXMPUtils_EncodeToBase64_1 ( XMP_StringPtr rawStr, + XMP_StringLen rawLen, + void * encodedStr, + SetClientStringProc SetClientString, + WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPUtils_EncodeToBase64_1" ) - - if ( encodedStr == 0 ) encodedStr = &voidStringPtr; - if ( encodedLen == 0 ) encodedLen = &voidStringLen; + XMP_ENTER_Static ( "WXMPUtils_EncodeToBase64_1" ) + + XMP_VarString localStr; - XMPUtils::EncodeToBase64 ( rawStr, rawLen, encodedStr, encodedLen ); + XMPUtils::EncodeToBase64 ( rawStr, rawLen, &localStr ); + if ( encodedStr != 0 ) (*SetClientString) ( encodedStr, localStr.c_str(), localStr.size() ); - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) + XMP_EXIT } // ------------------------------------------------------------------------------------------------- void -WXMPUtils_DecodeFromBase64_1 ( XMP_StringPtr encodedStr, - XMP_StringLen encodedLen, - XMP_StringPtr * rawStr, - XMP_StringLen * rawLen, - WXMP_Result * wResult ) +WXMPUtils_DecodeFromBase64_1 ( XMP_StringPtr encodedStr, + XMP_StringLen encodedLen, + void * rawStr, + SetClientStringProc SetClientString, + WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPUtils_DecodeFromBase64_1" ) + XMP_ENTER_Static ( "WXMPUtils_DecodeFromBase64_1" ) - if ( rawStr == 0 ) rawStr = &voidStringPtr; - if ( rawLen == 0 ) rawLen = &voidStringLen; + XMP_VarString localStr; - XMPUtils::DecodeFromBase64 ( encodedStr, encodedLen, rawStr, rawLen ); + XMPUtils::DecodeFromBase64 ( encodedStr, encodedLen, &localStr ); + if ( rawStr != 0 ) (*SetClientString) ( rawStr, localStr.c_str(), localStr.size() ); - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) + XMP_EXIT } // ================================================================================================= void -WXMPUtils_PackageForJPEG_1 ( XMPMetaRef wxmpObj, - XMP_StringPtr * stdStr, - XMP_StringLen * stdLen, - XMP_StringPtr * extStr, - XMP_StringLen * extLen, - XMP_StringPtr * digestStr, - XMP_StringLen * digestLen, - WXMP_Result * wResult ) +WXMPUtils_PackageForJPEG_1 ( XMPMetaRef wxmpObj, + void * stdStr, + void * extStr, + void * digestStr, + SetClientStringProc SetClientString, + WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPUtils_PackageForJPEG_1" ) + XMP_ENTER_Static ( "WXMPUtils_PackageForJPEG_1" ) - if ( stdStr == 0 ) stdStr = &voidStringPtr; - if ( stdLen == 0 ) stdLen = &voidStringLen; - if ( extStr == 0 ) extStr = &voidStringPtr; - if ( extLen == 0 ) extLen = &voidStringLen; - if ( digestStr == 0 ) digestStr = &voidStringPtr; - if ( digestLen == 0 ) digestLen = &voidStringLen; + XMP_VarString localStdStr; + XMP_VarString localExtStr; + XMP_VarString localDigestStr; const XMPMeta & xmpObj = WtoXMPMeta_Ref ( wxmpObj ); - XMPUtils::PackageForJPEG ( xmpObj, stdStr, stdLen, extStr, extLen, digestStr, digestLen ); + XMP_AutoLock metaLock ( &xmpObj.lock, kXMP_ReadLock ); - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) + XMPUtils::PackageForJPEG ( xmpObj, &localStdStr, &localExtStr, &localDigestStr ); + if ( stdStr != 0 ) (*SetClientString) ( stdStr, localStdStr.c_str(), localStdStr.size() ); + if ( extStr != 0 ) (*SetClientString) ( extStr, localExtStr.c_str(), localExtStr.size() ); + if ( digestStr != 0 ) (*SetClientString) ( digestStr, localDigestStr.c_str(), localDigestStr.size() ); + + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -486,45 +475,52 @@ WXMPUtils_MergeFromJPEG_1 ( XMPMetaRef wfullXMP, XMPMetaRef wextendedXMP, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPUtils_MergeFromJPEG_1" ) + XMP_ENTER_Static ( "WXMPUtils_MergeFromJPEG_1" ) if ( wfullXMP == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam ); + if ( wfullXMP == wextendedXMP ) XMP_Throw ( "Full and extended XMP pointers match", kXMPErr_BadParam ); XMPMeta * fullXMP = WtoXMPMeta_Ptr ( wfullXMP ); + XMP_AutoLock fullXMPLock ( &fullXMP->lock, kXMP_WriteLock ); + const XMPMeta & extendedXMP = WtoXMPMeta_Ref ( wextendedXMP ); + XMP_AutoLock extendedXMPLock ( &extendedXMP.lock, kXMP_ReadLock ); + XMPUtils::MergeFromJPEG ( fullXMP, extendedXMP ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ================================================================================================= void -WXMPUtils_CatenateArrayItems_1 ( XMPMetaRef wxmpObj, - XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr separator, - XMP_StringPtr quotes, - XMP_OptionBits options, - XMP_StringPtr * catedStr, - XMP_StringLen * catedLen, - WXMP_Result * wResult ) +WXMPUtils_CatenateArrayItems_1 ( XMPMetaRef wxmpObj, + XMP_StringPtr schemaNS, + XMP_StringPtr arrayName, + XMP_StringPtr separator, + XMP_StringPtr quotes, + XMP_OptionBits options, + void * catedStr, + SetClientStringProc SetClientString, + WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPUtils_CatenateArrayItems_1" ) + XMP_ENTER_Static ( "WXMPUtils_CatenateArrayItems_1" ) if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); - + if ( separator == 0 ) separator = "; "; if ( quotes == 0 ) quotes = "\""; - - if ( catedStr == 0 ) catedStr = &voidStringPtr; - if ( catedLen == 0 ) catedLen = &voidStringLen; + + XMP_VarString localStr; const XMPMeta & xmpObj = WtoXMPMeta_Ref ( wxmpObj ); - XMPUtils::CatenateArrayItems ( xmpObj, schemaNS, arrayName, separator, quotes, options, catedStr, catedLen ); + XMP_AutoLock metaLock ( &xmpObj.lock, kXMP_ReadLock ); + + XMPUtils::CatenateArrayItems ( xmpObj, schemaNS, arrayName, separator, quotes, options, &localStr ); + if ( catedStr != 0 ) (*SetClientString) ( catedStr, localStr.c_str(), localStr.size() ); - XMP_EXIT_WRAPPER_KEEP_LOCK ( true ) + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -537,17 +533,42 @@ WXMPUtils_SeparateArrayItems_1 ( XMPMetaRef wxmpObj, XMP_StringPtr catedStr, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPUtils_SeparateArrayItems_1" ) + XMP_ENTER_Static ( "WXMPUtils_SeparateArrayItems_1" ) if ( wxmpObj == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam ); if ( (schemaNS == 0) || (*schemaNS == 0) ) XMP_Throw ( "Empty schema namespace URI", kXMPErr_BadSchema ); if ( (arrayName == 0) || (*arrayName == 0) ) XMP_Throw ( "Empty array name", kXMPErr_BadXPath ); if ( catedStr == 0 ) catedStr = ""; - + XMPMeta * xmpObj = WtoXMPMeta_Ptr ( wxmpObj ); + XMP_AutoLock metaLock ( &xmpObj->lock, kXMP_WriteLock ); + XMPUtils::SeparateArrayItems ( xmpObj, schemaNS, arrayName, options, catedStr ); - XMP_EXIT_WRAPPER + XMP_EXIT +} + +// ------------------------------------------------------------------------------------------------- + +void +WXMPUtils_ApplyTemplate_1 ( XMPMetaRef wWorkingXMP, + XMPMetaRef wTemplateXMP, + XMP_OptionBits actions, + WXMP_Result * wResult ) +{ + XMP_ENTER_Static ( "WXMPUtils_ApplyTemplate_1" ) + + XMP_Assert ( (wWorkingXMP != 0) && (wTemplateXMP != 0) ); // Client glue enforced. + + XMPMeta * workingXMP = WtoXMPMeta_Ptr ( wWorkingXMP ); + XMP_AutoLock workingLock ( &workingXMP->lock, kXMP_WriteLock ); + + const XMPMeta & templateXMP = WtoXMPMeta_Ref ( wTemplateXMP ); + XMP_AutoLock templateLock ( &templateXMP.lock, kXMP_ReadLock ); + + XMPUtils::ApplyTemplate ( workingXMP, templateXMP, actions ); + + XMP_EXIT } // ------------------------------------------------------------------------------------------------- @@ -559,37 +580,22 @@ WXMPUtils_RemoveProperties_1 ( XMPMetaRef wxmpObj, XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPUtils_RemoveProperties_1" ) + XMP_ENTER_Static ( "WXMPUtils_RemoveProperties_1" ) if ( wxmpObj == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam ); if ( schemaNS == 0 ) schemaNS = ""; if ( propName == 0 ) propName = ""; - + XMPMeta * xmpObj = WtoXMPMeta_Ptr ( wxmpObj ); + XMP_AutoLock metaLock ( &xmpObj->lock, kXMP_WriteLock ); + XMPUtils::RemoveProperties ( xmpObj, schemaNS, propName, options ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ------------------------------------------------------------------------------------------------- -void -WXMPUtils_AppendProperties_1 ( XMPMetaRef wSource, - XMPMetaRef wDest, - XMP_OptionBits options, - WXMP_Result * wResult ) -{ - XMP_ENTER_WRAPPER ( "WXMPUtils_AppendProperties_1" ) - - if ( wDest == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam ); - - const XMPMeta & source = WtoXMPMeta_Ref ( wSource ); - XMPMeta * dest = WtoXMPMeta_Ptr ( wDest ); - XMPUtils::AppendProperties ( source, dest, options ); - - XMP_EXIT_WRAPPER -} - // ------------------------------------------------------------------------------------------------- void @@ -602,8 +608,8 @@ WXMPUtils_DuplicateSubtree_1 ( XMPMetaRef wSource, XMP_OptionBits options, WXMP_Result * wResult ) { - XMP_ENTER_WRAPPER ( "WXMPUtils_DuplicateSubtree_1" ) - + XMP_ENTER_Static ( "WXMPUtils_DuplicateSubtree_1" ) + if ( wDest == 0 ) XMP_Throw ( "Output XMP pointer is null", kXMPErr_BadParam ); if ( (sourceNS == 0) || (*sourceNS == 0) ) XMP_Throw ( "Empty source schema URI", kXMPErr_BadSchema ); if ( (sourceRoot == 0) || (*sourceRoot == 0) ) XMP_Throw ( "Empty source root name", kXMPErr_BadXPath ); @@ -611,10 +617,14 @@ WXMPUtils_DuplicateSubtree_1 ( XMPMetaRef wSource, if ( destRoot == 0 ) destRoot = sourceRoot; const XMPMeta & source = WtoXMPMeta_Ref ( wSource ); + XMP_AutoLock sourceLock ( &source.lock, kXMP_ReadLock, (wSource != wDest) ); + XMPMeta * dest = WtoXMPMeta_Ptr ( wDest ); + XMP_AutoLock destLock ( &dest->lock, kXMP_WriteLock ); + XMPUtils::DuplicateSubtree ( source, dest, sourceNS, sourceRoot, destNS, destRoot, options ); - XMP_EXIT_WRAPPER + XMP_EXIT } // ================================================================================================= diff --git a/source/XMPCore/XMPCore_Impl.cpp b/source/XMPCore/XMPCore_Impl.cpp index 1cf92c6..757fe72 100644 --- a/source/XMPCore/XMPCore_Impl.cpp +++ b/source/XMPCore/XMPCore_Impl.cpp @@ -1,5 +1,5 @@ // ================================================================================================= -// Copyright 2002-2007 Adobe Systems Incorporated +// Copyright 2004 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms @@ -48,21 +48,9 @@ using namespace std; XMP_Int32 sXMP_InitCount = 0; -XMP_StringMap * sNamespaceURIToPrefixMap = 0; -XMP_StringMap * sNamespacePrefixToURIMap = 0; +XMP_NamespaceTable * sRegisteredNamespaces = 0; -XMP_AliasMap * sRegisteredAliasMap = 0; // Needed by XMPIterator. - -XMP_VarString * sOutputNS = 0; -XMP_VarString * sOutputStr = 0; -XMP_VarString * sExceptionMessage = 0; - -XMP_Mutex sXMPCoreLock; -int sLockCount = 0; - -#if TraceXMPCalls - FILE * xmpOut = stderr; -#endif +XMP_AliasMap * sRegisteredAliasMap = 0; void * voidVoidPtr = 0; // Used to backfill null output parameters. XMP_StringPtr voidStringPtr = 0; @@ -77,60 +65,6 @@ XMP_DateTime voidDateTime; WXMP_Result void_wResult; // ================================================================================================= -// Mutex Utilities -// =============== - -// ! Note that the mutex need not be "recursive", allowing the same thread to acquire it multiple -// ! times. There is a single XMP lock which is acquired in the wrapper classes. Internal calls -// ! never go back out to the wrappers. - -#if XMP_WinBuild - - bool XMP_InitMutex ( XMP_Mutex * mutex ) { - InitializeCriticalSection ( mutex ); - return true; - } - - void XMP_TermMutex ( XMP_Mutex & mutex ) { - DeleteCriticalSection ( &mutex ); - } - - void XMP_EnterCriticalRegion ( XMP_Mutex & mutex ) { - EnterCriticalSection ( &mutex ); - } - - void XMP_ExitCriticalRegion ( XMP_Mutex & mutex ) { - LeaveCriticalSection ( &mutex ); - } - -#else - - // Use pthread for both Mac and generic UNIX. - // ! Would be nice to specify PTHREAD_MUTEX_ERRORCHECK, but the POSIX documentation is useless. - // ! Would be OK but overkill to specify PTHREAD_MUTEX_RECURSIVE. - - bool XMP_InitMutex ( XMP_Mutex * mutex ) { - int err = pthread_mutex_init ( mutex, 0 ); - return (err == 0 ); - } - - void XMP_TermMutex ( XMP_Mutex & mutex ) { - (void) pthread_mutex_destroy ( &mutex ); - } - - void XMP_EnterCriticalRegion ( XMP_Mutex & mutex ) { - int err = pthread_mutex_lock ( &mutex ); - if ( err != 0 ) XMP_Throw ( "XMP_EnterCriticalRegion - pthread_mutex_lock failure", kXMPErr_ExternalFailure ); - } - - void XMP_ExitCriticalRegion ( XMP_Mutex & mutex ) { - int err = pthread_mutex_unlock ( &mutex ); - if ( err != 0 ) XMP_Throw ( "XMP_ExitCriticalRegion - pthread_mutex_unlock failure", kXMPErr_ExternalFailure ); - } - -#endif - -// ================================================================================================= // Local Utilities // =============== @@ -166,10 +100,9 @@ VerifyXPathRoot ( XMP_StringPtr schemaURI, } } - XMP_StringMapPos uriPos = sNamespaceURIToPrefixMap->find ( XMP_VarString ( schemaURI ) ); - if ( uriPos == sNamespaceURIToPrefixMap->end() ) { - XMP_Throw ( "Unregistered schema namespace URI", kXMPErr_BadSchema ); - } + XMP_StringPtr schemaPrefix; + bool nsFound = sRegisteredNamespaces->GetPrefix ( schemaURI, &schemaPrefix, 0 ); + if ( ! nsFound ) XMP_Throw ( "Unregistered schema namespace URI", kXMPErr_BadSchema ); XMP_StringPtr colonPos = propName; while ( (*colonPos != 0) && (*colonPos != ':') ) ++colonPos; @@ -182,7 +115,7 @@ VerifyXPathRoot ( XMP_StringPtr schemaURI, // The propName is unqualified, use the schemaURI and associated prefix. expandedXPath->push_back ( XPathStepInfo ( schemaURI, kXMP_SchemaNode ) ); - expandedXPath->push_back ( XPathStepInfo ( uriPos->second, 0 ) ); + expandedXPath->push_back ( XPathStepInfo ( schemaPrefix, 0 ) ); (*expandedXPath)[kRootPropStep].step += propName; } else { @@ -193,13 +126,7 @@ VerifyXPathRoot ( XMP_StringPtr schemaURI, VerifySimpleXMLName ( colonPos+1, colonPos+strlen(colonPos) ); XMP_VarString prefix ( propName, prefixLen ); - XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( prefix ); - if ( prefixPos == sNamespacePrefixToURIMap->end() ) { - XMP_Throw ( "Unknown schema namespace prefix", kXMPErr_BadSchema ); - } - if ( prefix != uriPos->second ) { - XMP_Throw ( "Schema namespace URI and prefix mismatch", kXMPErr_BadSchema ); - } + if ( prefix != schemaPrefix ) XMP_Throw ( "Schema namespace URI and prefix mismatch", kXMPErr_BadSchema ); expandedXPath->push_back ( XPathStepInfo ( schemaURI, kXMP_SchemaNode ) ); expandedXPath->push_back ( XPathStepInfo ( propName, 0 ) ); @@ -226,10 +153,8 @@ VerifyQualName ( XMP_StringPtr qualName, XMP_StringPtr nameEnd ) size_t prefixLen = colonPos - qualName + 1; // ! Include the colon. XMP_VarString prefix ( qualName, prefixLen ); - XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( prefix ); - if ( prefixPos == sNamespacePrefixToURIMap->end() ) { - XMP_Throw ( "Unknown namespace prefix for qualified name", kXMPErr_BadXPath ); - } + bool nsFound = sRegisteredNamespaces->GetURI ( prefix.c_str(), 0, 0 ); + if ( ! nsFound ) XMP_Throw ( "Unknown namespace prefix for qualified name", kXMPErr_BadXPath ); } // VerifyQualName @@ -498,9 +423,7 @@ CheckImplicitStruct ( XMP_Node * node, // DeleteSubtree // ------------- -// *** Might be useful elsewhere? - -static void +void DeleteSubtree ( XMP_NodePtrPos rootNodePos ) { XMP_Node * rootNode = *rootNodePos; @@ -1171,7 +1094,7 @@ EXIT: // ============== void -CloneOffspring ( const XMP_Node * origParent, XMP_Node * cloneParent ) +CloneOffspring ( const XMP_Node * origParent, XMP_Node * cloneParent, bool skipEmpty /* = false */ ) { size_t qualCount = origParent->qualifiers.size(); size_t childCount = origParent->children.size(); @@ -1182,8 +1105,14 @@ CloneOffspring ( const XMP_Node * origParent, XMP_Node * cloneParent ) for ( size_t qualNum = 0, qualLim = qualCount; qualNum != qualLim; ++qualNum ) { const XMP_Node * origQual = origParent->qualifiers[qualNum]; - XMP_Node * cloneQual = new XMP_Node ( cloneParent, origQual->name, origQual->value, origQual->options ); - CloneOffspring ( origQual, cloneQual ); + if ( skipEmpty && origQual->value.empty() && origQual->children.empty() ) continue; + XMP_Node * cloneQual = new XMP_Node ( cloneParent, origQual->name, origQual->value, origQual->options ); + CloneOffspring ( origQual, cloneQual, skipEmpty ); + if ( skipEmpty && cloneQual->value.empty() && cloneQual->children.empty() ) { + // Check again, might have had an array or struct with all empty children. + delete cloneQual; + continue; + } cloneParent->qualifiers.push_back ( cloneQual ); } @@ -1195,8 +1124,14 @@ CloneOffspring ( const XMP_Node * origParent, XMP_Node * cloneParent ) for ( size_t childNum = 0, childLim = childCount; childNum != childLim; ++childNum ) { const XMP_Node * origChild = origParent->children[childNum]; - XMP_Node * cloneChild = new XMP_Node ( cloneParent, origChild->name, origChild->value, origChild->options ); - CloneOffspring ( origChild, cloneChild ); + if ( skipEmpty && origChild->value.empty() && origChild->children.empty() ) continue; + XMP_Node * cloneChild = new XMP_Node ( cloneParent, origChild->name, origChild->value, origChild->options ); + CloneOffspring ( origChild, cloneChild, skipEmpty ); + if ( skipEmpty && cloneChild->value.empty() && cloneChild->children.empty() ) { + // Check again, might have had an array or struct with all empty children. + delete cloneChild; + continue; + } cloneParent->children.push_back ( cloneChild ); } @@ -1209,7 +1144,7 @@ CloneOffspring ( const XMP_Node * origParent, XMP_Node * cloneParent ) // ============ XMP_Node * -CloneSubtree ( const XMP_Node * origRoot, XMP_Node * cloneParent ) +CloneSubtree ( const XMP_Node * origRoot, XMP_Node * cloneParent, bool skipEmpty /* = false */ ) { #if XMP_DebugBuild if ( cloneParent->parent == 0 ) { @@ -1224,9 +1159,15 @@ CloneSubtree ( const XMP_Node * origRoot, XMP_Node * cloneParent ) #endif XMP_Node * cloneRoot = new XMP_Node ( cloneParent, origRoot->name, origRoot->value, origRoot->options ); - CloneOffspring ( origRoot, cloneRoot ) ; + CloneOffspring ( origRoot, cloneRoot, skipEmpty ) ; + + if ( skipEmpty && cloneRoot->value.empty() && cloneRoot->children.empty() ) { + // ! Can't do earlier, CloneOffspring might be skipping empty children. + delete cloneRoot; + return 0; + } + cloneParent->children.push_back ( cloneRoot ); - return cloneRoot; } // CloneSubtree diff --git a/source/XMPCore/XMPCore_Impl.hpp b/source/XMPCore/XMPCore_Impl.hpp index d1be1c3..9a5314a 100644 --- a/source/XMPCore/XMPCore_Impl.hpp +++ b/source/XMPCore/XMPCore_Impl.hpp @@ -1,8 +1,8 @@ #ifndef __XMPCore_Impl_hpp__ -#define __XMPCore_Impl_hpp__ +#define __XMPCore_Impl_hpp__ 1 // ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated +// Copyright 2004 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms @@ -12,8 +12,9 @@ #include "XMP_Environment.h" // ! Must be the first #include! #include "XMP_Const.h" #include "XMP_BuildInfo.h" +#include "XMP_LibUtils.hpp" -#include "client-glue/WXMPMeta.hpp" +#include "client-glue/WXMP_Common.hpp" #include <vector> #include <string> @@ -22,13 +23,6 @@ #include <cassert> #if XMP_WinBuild - #include <Windows.h> -#else - // Use pthread for both Mac and generic UNIX. - #include <pthread.h> -#endif - -#if XMP_WinBuild #pragma warning ( disable : 4244 ) // possible loss of data (temporary for 64 bit builds) #pragma warning ( disable : 4267 ) // possible loss of data (temporary for 64 bit builds) #endif @@ -45,16 +39,9 @@ typedef XMP_Node * XMP_NodePtr; typedef std::vector<XMP_Node*> XMP_NodeOffspring; typedef XMP_NodeOffspring::iterator XMP_NodePtrPos; -typedef std::string XMP_VarString; typedef XMP_VarString::iterator XMP_VarStringPos; typedef XMP_VarString::const_iterator XMP_cVarStringPos; -typedef std::pair < XMP_VarString, XMP_VarString > XMP_StringPair; - -typedef std::map < XMP_VarString, XMP_VarString > XMP_StringMap; -typedef XMP_StringMap::iterator XMP_StringMapPos; -typedef XMP_StringMap::const_iterator XMP_cStringMapPos; - typedef std::vector < XPathStepInfo > XMP_ExpandedXPath; typedef XMP_ExpandedXPath::iterator XMP_ExpandedXPathPos; typedef XMP_ExpandedXPath::const_iterator XMP_cExpandedXPathPos; @@ -68,13 +55,14 @@ typedef XMP_AliasMap::const_iterator XMP_cAliasMapPos; extern XMP_Int32 sXMP_InitCount; -extern XMP_AliasMap * sRegisteredAliasMap; +extern XMP_NamespaceTable * sRegisteredNamespaces; -extern XMP_StringMap * sNamespaceURIToPrefixMap; -extern XMP_StringMap * sNamespacePrefixToURIMap; +extern XMP_AliasMap * sRegisteredAliasMap; -extern XMP_VarString * sOutputNS; -extern XMP_VarString * sOutputStr; +#define WtoXMPMeta_Ref(xmpRef) (const XMPMeta &) (*((XMPMeta*)(xmpRef))) +#define WtoXMPMeta_Ptr(xmpRef) ((XMPMeta*)(xmpRef)) + +#define WtoXMPDocOps_Ptr(docRef) ((XMPDocOps*)(docRef)) extern void * voidVoidPtr; // Used to backfill null output parameters. extern XMP_StringPtr voidStringPtr; @@ -94,25 +82,10 @@ extern WXMP_Result void_wResult; #define XMP_LitNMatch(s,l,n) (std::strncmp((s),(l),(n)) == 0) // *** Use the above macros! -#define kTab ((char)0x09) -#define kLF ((char)0x0A) -#define kCR ((char)0x0D) - #if XMP_WinBuild #define snprintf _snprintf #endif -#define WtoXMPMeta_Ref(xmpRef) *((const XMPMeta *)(xmpRef)) -#define WtoXMPMeta_Ptr(xmpRef) (((xmpRef) == 0) ? 0 : (XMPMeta *)(xmpRef)) - -#define WtoXMPIterator_Ref(iterRef) *((const XMPIterator *)(iterRef)) -#define WtoXMPIterator_Ptr(iterRef) (((iterRef) == 0) ? 0 : (XMPIterator *)(iterRef)) - -#define WtoXMPDocOps_Ref(docRef) *((const XMPDocOps *)(docRef)) -#define WtoXMPDocOps_Ptr(docRef) (((docRef) == 0) ? 0 : (XMPDocOps *)(docRef)) - -#define IgnoreParam(p) voidVoidPtr = (void*)&p - // ================================================================================================= // Version info @@ -130,158 +103,40 @@ extern WXMP_Result void_wResult; #define kXMPCoreName "XMP Core" #define kXMPCore_VersionMessage kXMPCoreName " " XMP_API_VERSION_STRING // ================================================================================================= -// Support for asserts +// Support for call tracing -#define _MakeStr(p) #p -#define _NotifyMsg(n,c,f,l) #n " failed: " #c " in " f " at line " _MakeStr(l) - -#if ! XMP_DebugBuild - #define XMP_Assert(c) ((void) 0) -#else - #define XMP_Assert(c) assert ( c ) +#ifndef XMP_TraceCoreCalls + #define XMP_TraceCoreCalls 0 + #define XMP_TraceCoreCallsToFile 0 #endif - #define XMP_Enforce(c) \ - if ( ! (c) ) { \ - const char * assert_msg = _NotifyMsg ( XMP_Enforce, (c), __FILE__, __LINE__ ); \ - XMP_Throw ( assert_msg , kXMPErr_EnforceFailure ); \ - } -// ================================================================================================= -// Support for exceptions and thread locking - -#ifndef TraceXMPCalls - #define TraceXMPCalls 0 -#endif +#if XMP_TraceCoreCalls -#if ! TraceXMPCalls + #undef AnnounceThrow + #undef AnnounceCatch - #define AnnounceThrow(msg) /* Do nothing. */ - #define AnnounceCatch(msg) /* Do nothing. */ + #undef AnnounceEntry + #undef AnnounceNoLock + #undef AnnounceExit - #define AnnounceEntry(proc) /* Do nothing. */ - #define AnnounceNoLock(proc) /* Do nothing. */ - #define AnnounceExit() /* Do nothing. */ - - #define ReportLock() ++sLockCount - #define ReportUnlock() --sLockCount - #define ReportKeepLock() /* Do nothing. */ - -#else - - extern FILE * xmpCoreOut; + extern FILE * xmpCoreLog; #define AnnounceThrow(msg) \ - fprintf ( xmpCoreOut, "XMP_Throw: %s\n", msg ); fflush ( xmpOut ) + fprintf ( xmpCoreLog, "XMP_Throw: %s\n", msg ); fflush ( xmpCoreLog ) #define AnnounceCatch(msg) \ - fprintf ( xmpCoreOut, "Catch in %s: %s\n", procName, msg ); fflush ( xmpOut ) + fprintf ( xmpCoreLog, "Catch in %s: %s\n", procName, msg ); fflush ( xmpCoreLog ) #define AnnounceEntry(proc) \ const char * procName = proc; \ - fprintf ( xmpCoreOut, "Entering %s\n", procName ); fflush ( xmpOut ) + fprintf ( xmpCoreLog, "Entering %s\n", procName ); fflush ( xmpCoreLog ) #define AnnounceNoLock(proc) \ const char * procName = proc; \ - fprintf ( xmpCoreOut, "Entering %s (no lock)\n", procName ); fflush ( xmpOut ) + fprintf ( xmpCoreLog, "Entering %s (no lock)\n", procName ); fflush ( xmpCoreLog ) #define AnnounceExit() \ - fprintf ( xmpCoreOut, "Exiting %s\n", procName ); fflush ( xmpOut ) - - #define ReportLock() \ - ++sLockCount; fprintf ( xmpCoreOut, " Auto lock, count = %d\n", sLockCount ); fflush ( xmpOut ) - #define ReportUnlock() \ - --sLockCount; fprintf ( xmpCoreOut, " Auto unlock, count = %d\n", sLockCount ); fflush ( xmpOut ) - #define ReportKeepLock() \ - fprintf ( xmpCoreOut, " Keeping lock, count = %d\n", sLockCount ); fflush ( xmpOut ) + fprintf ( xmpCoreLog, "Exiting %s\n", procName ); fflush ( xmpCoreLog ) #endif -#define XMP_Throw(msg,id) { AnnounceThrow ( msg ); throw XMP_Error ( id, msg ); } - -// ------------------------------------------------------------------------------------------------- - -#if XMP_WinBuild - typedef CRITICAL_SECTION XMP_Mutex; -#else - // Use pthread for both Mac and generic UNIX. - typedef pthread_mutex_t XMP_Mutex; -#endif - -extern XMP_Mutex sXMPCoreLock; -extern int sLockCount; // Keep signed to catch unlock errors. -extern XMP_VarString * sExceptionMessage; - -extern bool XMP_InitMutex ( XMP_Mutex * mutex ); -extern void XMP_TermMutex ( XMP_Mutex & mutex ); - -extern void XMP_EnterCriticalRegion ( XMP_Mutex & mutex ); -extern void XMP_ExitCriticalRegion ( XMP_Mutex & mutex ); - -class XMP_AutoMutex { -public: - XMP_AutoMutex() : mutex(&sXMPCoreLock) { XMP_EnterCriticalRegion ( *mutex ); ReportLock(); }; - ~XMP_AutoMutex() { if ( mutex != 0 ) { ReportUnlock(); XMP_ExitCriticalRegion ( *mutex ); mutex = 0; } }; - void KeepLock() { ReportKeepLock(); mutex = 0; }; -private: - XMP_Mutex * mutex; -}; - -// *** Switch to XMPEnterObjectWrapper & XMPEnterStaticWrapper, to allow for per-object locks. - -// ! Don't do the initialization check (sXMP_InitCount > 0) for the no-lock case. That macro is used -// ! by WXMPMeta_Initialize_1. - -#define XMP_ENTER_WRAPPER_NO_LOCK(proc) \ - AnnounceNoLock ( proc ); \ - XMP_Assert ( (0 <= sLockCount) && (sLockCount <= 1) ); \ - try { \ - wResult->errMessage = 0; - -#define XMP_ENTER_WRAPPER(proc) \ - AnnounceEntry ( proc ); \ - XMP_Assert ( sXMP_InitCount > 0 ); \ - XMP_Assert ( (0 <= sLockCount) && (sLockCount <= 1) ); \ - try { \ - XMP_AutoMutex mutex; \ - wResult->errMessage = 0; - -#define XMP_EXIT_WRAPPER \ - XMP_CATCH_EXCEPTIONS \ - AnnounceExit(); - -#define XMP_EXIT_WRAPPER_KEEP_LOCK(keep) \ - if ( keep ) mutex.KeepLock(); \ - XMP_CATCH_EXCEPTIONS \ - AnnounceExit(); - -#define XMP_EXIT_WRAPPER_NO_THROW \ - } catch ( ... ) { \ - AnnounceCatch ( "no-throw catch-all" ); \ - /* Do nothing. */ \ - } \ - AnnounceExit(); - -#define XMP_CATCH_EXCEPTIONS \ - } catch ( XMP_Error & xmpErr ) { \ - wResult->int32Result = xmpErr.GetID(); \ - wResult->ptrResult = (void*)"XMP"; \ - wResult->errMessage = xmpErr.GetErrMsg(); \ - if ( wResult->errMessage == 0 ) wResult->errMessage = ""; \ - AnnounceCatch ( wResult->errMessage ); \ - } catch ( std::exception & stdErr ) { \ - wResult->int32Result = kXMPErr_StdException; \ - wResult->errMessage = stdErr.what(); \ - if ( wResult->errMessage == 0 ) wResult->errMessage = ""; \ - AnnounceCatch ( wResult->errMessage ); \ - } catch ( ... ) { \ - wResult->int32Result = kXMPErr_UnknownException; \ - wResult->errMessage = "Caught unknown exception"; \ - AnnounceCatch ( wResult->errMessage ); \ - } - -#if XMP_DebugBuild - #define RELEASE_NO_THROW /* empty */ -#else - #define RELEASE_NO_THROW throw() -#endif - // ================================================================================================= // ExpandXPath, FindNode, and related support @@ -341,15 +196,18 @@ extern XMP_Index LookupFieldSelector ( const XMP_Node * arrayNode, XMP_StringPtr fieldName, XMP_StringPtr fieldValue ); extern void -CloneOffspring ( const XMP_Node * origParent, XMP_Node * cloneParent ); +CloneOffspring ( const XMP_Node * origParent, XMP_Node * cloneParent, bool skipEmpty = false ); extern XMP_Node * -CloneSubtree ( const XMP_Node * origRoot, XMP_Node * cloneParent ); +CloneSubtree ( const XMP_Node * origRoot, XMP_Node * cloneParent, bool skipEmpty = false ); extern bool CompareSubtrees ( const XMP_Node & leftNode, const XMP_Node & rightNode ); extern void +DeleteSubtree ( XMP_NodePtrPos rootNodePos ); + +extern void DeleteEmptySchema ( XMP_Node * schemaNode ); extern void diff --git a/source/XMPCore/XMPIterator.cpp b/source/XMPCore/XMPIterator.cpp index 8032bfa..08e03fa 100644 --- a/source/XMPCore/XMPIterator.cpp +++ b/source/XMPCore/XMPIterator.cpp @@ -1,5 +1,5 @@ // ================================================================================================= -// Copyright 2002-2007 Adobe Systems Incorporated +// Copyright 2003 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms @@ -61,47 +61,6 @@ AddSchemaProps ( IterInfo & info, IterNode & iterSchema, const XMP_Node * xmpSch } // AddSchemaProps // ------------------------------------------------------------------------------------------------- -// AddSchemaAliases -// ---------------- -// -// Add the aliases to the IterNode for a schema, if the corresponding actual exists. - -static void -AddSchemaAliases ( IterInfo & info, IterNode & iterSchema, XMP_StringPtr schemaURI ) -{ - - // We're showing the aliases also. Look them up by their namespace prefix. Yes, the alias map is - // sorted so we could process just that portion. But that takes more code and the extra speed - // isn't worth it. (Plus this way we avoid a dependence on the map implementation.) Lookup the - // XMP node from the alias, to make sure the actual exists. - - #if TraceIterators - printf ( " Adding aliases\n", schemaURI ); - #endif - - XMP_StringPtr nsPrefix; - XMP_StringLen nsLen; - bool found = XMPMeta::GetNamespacePrefix ( schemaURI, &nsPrefix, &nsLen ); - if ( ! found ) XMP_Throw ( "Unknown iteration namespace", kXMPErr_BadSchema ); - - XMP_AliasMapPos currAlias = sRegisteredAliasMap->begin(); - XMP_AliasMapPos endAlias = sRegisteredAliasMap->end(); - - for ( ; currAlias != endAlias; ++currAlias ) { - if ( XMP_LitNMatch ( currAlias->first.c_str(), nsPrefix, nsLen ) ) { - const XMP_Node * actualProp = FindConstNode ( &info.xmpObj->tree, currAlias->second ); - if ( actualProp != 0 ) { - iterSchema.children.push_back ( IterNode ( (actualProp->options | kXMP_PropIsAlias), currAlias->first, 0 ) ); - #if TraceIterators - printf ( " %s => %s\n", currAlias->first.c_str(), actualProp->name.c_str() ); - #endif - } - } - } - -} // AddSchemaAliases - -// ------------------------------------------------------------------------------------------------- // AddNodeOffspring // ---------------- // @@ -156,7 +115,7 @@ AddNodeOffspring ( IterInfo & info, IterNode & iterParent, const XMP_Node * xmpP currPath += xmpChild->name; } else { char buffer [32]; // AUDIT: Using sizeof(buffer) below for snprintf length is safe. - snprintf ( buffer, sizeof(buffer), "[%d]", childNum+1 ); // ! XPath indices are one-based. + snprintf ( buffer, sizeof(buffer), "[%lu]", childNum+1 ); // ! XPath indices are one-based. currPath += buffer; } iterParent.children.push_back ( IterNode ( xmpChild->options, currPath, leafOffset ) ); @@ -390,19 +349,6 @@ XMPIterator::Terminate() RELEASE_NO_THROW } // Terminate -// ------------------------------------------------------------------------------------------------- -// Unlock -// ------ - -void -XMPIterator::Unlock ( XMP_OptionBits options ) -{ - options = options; // Avoid unused parameter warning. - - XMPMeta::Unlock ( 0 ); - -} // Unlock - // ================================================================================================= // Constructors // ================================================================================================= @@ -480,8 +426,6 @@ XMPIterator::XMPIterator ( const XMPMeta & xmpObj, XMP_Node * xmpSchema = FindConstSchema ( &xmpObj.tree, schemaNS ); if ( xmpSchema != 0 ) AddSchemaProps ( info, iterSchema, xmpSchema ); - if ( info.options & kXMP_IterIncludeAliases ) AddSchemaAliases ( info, iterSchema, schemaNS ); - if ( iterSchema.children.empty() ) { info.tree.children.pop_back(); // No properties, remove the schema node. } else { @@ -509,40 +453,10 @@ XMPIterator::XMPIterator ( const XMPMeta & xmpObj, if ( ! (info.options & kXMP_IterJustChildren) ) { AddSchemaProps ( info, iterSchema, xmpSchema ); - if ( info.options & kXMP_IterIncludeAliases ) AddSchemaAliases ( info, iterSchema, xmpSchema->name.c_str() ); if ( iterSchema.children.empty() ) info.tree.children.pop_back(); // No properties, remove the schema node. } } - - if ( info.options & kXMP_IterIncludeAliases ) { - - // Add the schema that only have aliases. The most convenient, and safest way, is to go - // through the registered namespaces, see if it exists, and let AddSchemaAliases do its - // thing if not. Don't combine with the above loop, it is nicer to have the "real" stuff - // be in storage order (not subject to the namespace map order). - - // ! We don't do the kXMP_IterJustChildren handing in the same way here as above. The - // ! existing schema (presumably) have actual children. We need to call AddSchemaAliases - // ! here to determine if the namespace has any aliases to existing properties. We then - // ! strip the children if necessary. - - XMP_cStringMapPos currNS = sNamespaceURIToPrefixMap->begin(); - XMP_cStringMapPos endNS = sNamespaceURIToPrefixMap->end(); - for ( ; currNS != endNS; ++currNS ) { - XMP_StringPtr schemaName = currNS->first.c_str(); - if ( FindConstSchema ( &xmpObj.tree, schemaName ) != 0 ) continue; - info.tree.children.push_back ( IterNode ( kXMP_SchemaNode, schemaName, 0 ) ); - IterNode & iterSchema = info.tree.children.back(); - AddSchemaAliases ( info, iterSchema, schemaName ); - if ( iterSchema.children.empty() ) { - info.tree.children.pop_back(); // No aliases, remove the schema node. - } else if ( info.options & kXMP_IterJustChildren ) { - iterSchema.children.clear(); // Get rid of the children. - } - } - - } } @@ -719,17 +633,4 @@ XMPIterator::Skip ( XMP_OptionBits iterOptions ) } // Skip -// ------------------------------------------------------------------------------------------------- -// UnlockIter -// ---------- - -void -XMPIterator::UnlockIter ( XMP_OptionBits options ) -{ - options = options; // Avoid unused parameter warning. - - XMPMeta::Unlock ( 0 ); - -} // UnlockIter - // ================================================================================================= diff --git a/source/XMPCore/XMPIterator.hpp b/source/XMPCore/XMPIterator.hpp index b72b975..d55f721 100644 --- a/source/XMPCore/XMPIterator.hpp +++ b/source/XMPCore/XMPIterator.hpp @@ -2,7 +2,7 @@ #define __XMPIterator_hpp__ // ================================================================================================= -// Copyright 2002-2007 Adobe Systems Incorporated +// Copyright 2003 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms @@ -97,9 +97,6 @@ public: static void Terminate() RELEASE_NO_THROW; // ! For internal use only! - static void - Unlock ( XMP_OptionBits options ); - XMPIterator ( const XMPMeta & xmpObj, // Construct a property iterator. XMP_StringPtr schemaNS, XMP_StringPtr propName, @@ -123,12 +120,11 @@ public: void Skip ( XMP_OptionBits options ); - void - UnlockIter ( XMP_OptionBits options ); - // ! Expose so that wrappers and file static functions can see the data. XMP_Int32 clientRefs; // ! Must be signed to allow decrement from 0. + XMP_ReadWriteLock lock; + IterInfo info; private: diff --git a/source/XMPCore/XMPMeta-GetSet.cpp b/source/XMPCore/XMPMeta-GetSet.cpp index 41b01d5..3ec0997 100644 --- a/source/XMPCore/XMPMeta-GetSet.cpp +++ b/source/XMPCore/XMPMeta-GetSet.cpp @@ -1,5 +1,5 @@ // ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated +// Copyright 2003 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms @@ -79,10 +79,11 @@ SetNodeValue ( XMP_Node * node, XMP_StringPtr value ) } #endif - node->value = value; + std::string newValue = value; // Need a local copy to tweak and not change node.value for errors. - XMP_Uns8* chPtr = (XMP_Uns8*) node->value.c_str(); // Check for valid UTF-8, replace ASCII controls with a space. + XMP_Uns8* chPtr = (XMP_Uns8*) newValue.c_str(); // Check for valid UTF-8, replace ASCII controls with a space. while ( *chPtr != 0 ) { + while ( (*chPtr != 0) && (*chPtr < 0x80) ) { if ( *chPtr < 0x20 ) { if ( (*chPtr != kTab) && (*chPtr != kLF) && (*chPtr != kCR) ) *chPtr = 0x20; @@ -91,11 +92,21 @@ SetNodeValue ( XMP_Node * node, XMP_StringPtr value ) } ++chPtr; } + XMP_Assert ( (*chPtr == 0) || (*chPtr >= 0x80) ); - if ( *chPtr != 0 ) (void) GetCodePoint ( (const XMP_Uns8 **) &chPtr ); // Throws for bad UTF-8. + + if ( *chPtr != 0 ) { + XMP_Uns32 cp = GetCodePoint ( (const XMP_Uns8 **) &chPtr ); // Throws for bad UTF-8. + if ( (cp == 0xFFFE) || (cp == 0xFFFF) ) { + XMP_Throw ( "U+FFFE and U+FFFF are not allowed in XML", kXMPErr_BadXML ); + } + } + } - if ( XMP_PropIsQualifier(node->options) && (node->name == "xml:lang") ) NormalizeLangValue ( &node->value ); + if ( XMP_PropIsQualifier(node->options) && (node->name == "xml:lang") ) NormalizeLangValue ( &newValue ); + + node->value.swap ( newValue ); #if 0 // *** XMP_DebugBuild node->_valuePtr = node->value.c_str(); @@ -314,8 +325,18 @@ ChooseLocalizedText ( const XMP_Node * arrayNode, static void AppendLangItem ( XMP_Node * arrayNode, XMP_StringPtr itemLang, XMP_StringPtr itemValue ) { - XMP_Node * newItem = new XMP_Node ( arrayNode, kXMP_ArrayItemName, itemValue, (kXMP_PropHasQualifiers | kXMP_PropHasLang) ); - XMP_Node * langQual = new XMP_Node ( newItem, "xml:lang", itemLang, kXMP_PropIsQualifier ); + XMP_Node * newItem = new XMP_Node ( arrayNode, kXMP_ArrayItemName, (kXMP_PropHasQualifiers | kXMP_PropHasLang) ); + XMP_Node * langQual = new XMP_Node ( newItem, "xml:lang", kXMP_PropIsQualifier ); + + try { // ! Use SetNodeValue, not constructors above, to get the character checks. + SetNodeValue ( newItem, itemValue ); + SetNodeValue ( langQual, itemLang ); + } catch (...) { + delete newItem; + delete langQual; + throw; + } + newItem->qualifiers.push_back ( langQual ); if ( (arrayNode->children.empty()) || (langQual->value != "x-default") ) { @@ -373,17 +394,19 @@ XMPMeta::GetArrayItem ( XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex, XMP_StringPtr * itemValue, - XMP_StringLen * valueSize, + XMP_StringLen * valueSize, XMP_OptionBits * options ) const { XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper. - XMP_Assert ( (itemValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper. + XMP_Assert ( (itemValue != 0) && (options != 0) ); // Enforced by wrapper. - XMP_StringPtr itemPath; - XMP_StringLen pathLen; + // ! Special case check to make errors consistent if the array does not exist. The other array + // ! functions and existing array here (empty or not) already throw. + if ( (itemIndex <= 0) && (itemIndex != kXMP_ArrayLastItem) ) XMP_Throw ( "Array index must be larger than zero", kXMPErr_BadXPath ); - XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath, &pathLen ); - return GetProperty ( schemaNS, itemPath, itemValue, valueSize, options ); + XMP_VarString itemPath; + XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath ); + return GetProperty ( schemaNS, itemPath.c_str(), itemValue, valueSize, options ); } // GetArrayItem @@ -402,13 +425,11 @@ XMPMeta::GetStructField ( XMP_StringPtr schemaNS, XMP_OptionBits * options ) const { XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper. - XMP_Assert ( (fieldValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper. - - XMP_StringPtr fieldPath; - XMP_StringLen pathLen; + XMP_Assert ( (fieldValue != 0) && (options != 0) ); // Enforced by wrapper. - XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen ); - return GetProperty ( schemaNS, fieldPath, fieldValue, valueSize, options ); + XMP_VarString fieldPath; + XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath ); + return GetProperty ( schemaNS, fieldPath.c_str(), fieldValue, valueSize, options ); } // GetStructField @@ -423,17 +444,15 @@ XMPMeta::GetQualifier ( XMP_StringPtr schemaNS, XMP_StringPtr qualNS, XMP_StringPtr qualName, XMP_StringPtr * qualValue, - XMP_StringLen * valueSize, + XMP_StringLen * valueSize, XMP_OptionBits * options ) const { XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper. - XMP_Assert ( (qualValue != 0) && (valueSize != 0) && (options != 0) ); // Enforced by wrapper. + XMP_Assert ( (qualValue != 0) && (options != 0) ); // Enforced by wrapper. - XMP_StringPtr qualPath; - XMP_StringLen pathLen; - - XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen ); - return GetProperty ( schemaNS, qualPath, qualValue, valueSize, options ); + XMP_VarString qualPath; + XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath ); + return GetProperty ( schemaNS, qualPath.c_str(), qualValue, valueSize, options ); } // GetQualifier @@ -550,11 +569,9 @@ XMPMeta::SetStructField ( XMP_StringPtr schemaNS, { XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper. - XMP_StringPtr fieldPath; - XMP_StringLen pathLen; - - XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen ); - SetProperty ( schemaNS, fieldPath, fieldValue, options ); + XMP_VarString fieldPath; + XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath ); + SetProperty ( schemaNS, fieldPath.c_str(), fieldValue, options ); } // SetStructField @@ -573,16 +590,14 @@ XMPMeta::SetQualifier ( XMP_StringPtr schemaNS, { XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper. - XMP_StringPtr qualPath; - XMP_StringLen pathLen; - XMP_ExpandedXPath expPath; ExpandXPath ( schemaNS, propName, &expPath ); XMP_Node * propNode = FindNode ( &tree, expPath, kXMP_ExistingOnly ); if ( propNode == 0 ) XMP_Throw ( "Specified property does not exist", kXMPErr_BadXPath ); - XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen ); - SetProperty ( schemaNS, qualPath, qualValue, options ); + XMP_VarString qualPath; + XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath ); + SetProperty ( schemaNS, qualPath.c_str(), qualValue, options ); } // SetQualifier @@ -644,11 +659,9 @@ XMPMeta::DeleteArrayItem ( XMP_StringPtr schemaNS, { XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper. - XMP_StringPtr itemPath; - XMP_StringLen pathLen; - - XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath, &pathLen ); - DeleteProperty ( schemaNS, itemPath ); + XMP_VarString itemPath; + XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath ); + DeleteProperty ( schemaNS, itemPath.c_str() ); } // DeleteArrayItem @@ -665,11 +678,9 @@ XMPMeta::DeleteStructField ( XMP_StringPtr schemaNS, { XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper. - XMP_StringPtr fieldPath; - XMP_StringLen pathLen; - - XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen ); - DeleteProperty ( schemaNS, fieldPath ); + XMP_VarString fieldPath; + XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath ); + DeleteProperty ( schemaNS, fieldPath.c_str() ); } // DeleteStructField @@ -686,11 +697,9 @@ XMPMeta::DeleteQualifier ( XMP_StringPtr schemaNS, { XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper. - XMP_StringPtr qualPath; - XMP_StringLen pathLen; - - XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen ); - DeleteProperty ( schemaNS, qualPath ); + XMP_VarString qualPath; + XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath ); + DeleteProperty ( schemaNS, qualPath.c_str() ); } // DeleteQualifier @@ -725,11 +734,9 @@ XMPMeta::DoesArrayItemExist ( XMP_StringPtr schemaNS, { XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // Enforced by wrapper. - XMP_StringPtr itemPath; - XMP_StringLen pathLen; - - XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath, &pathLen ); - return DoesPropertyExist ( schemaNS, itemPath ); + XMP_VarString itemPath; + XMPUtils::ComposeArrayItemPath ( schemaNS, arrayName, itemIndex, &itemPath ); + return DoesPropertyExist ( schemaNS, itemPath.c_str() ); } // DoesArrayItemExist @@ -746,11 +753,9 @@ XMPMeta::DoesStructFieldExist ( XMP_StringPtr schemaNS, { XMP_Assert ( (schemaNS != 0) && (structName != 0) && (fieldNS != 0) && (fieldName != 0) ); // Enforced by wrapper. - XMP_StringPtr fieldPath; - XMP_StringLen pathLen; - - XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath, &pathLen ); - return DoesPropertyExist ( schemaNS, fieldPath ); + XMP_VarString fieldPath; + XMPUtils::ComposeStructFieldPath ( schemaNS, structName, fieldNS, fieldName, &fieldPath ); + return DoesPropertyExist ( schemaNS, fieldPath.c_str() ); } // DoesStructFieldExist @@ -767,11 +772,9 @@ XMPMeta::DoesQualifierExist ( XMP_StringPtr schemaNS, { XMP_Assert ( (schemaNS != 0) && (propName != 0) && (qualNS != 0) && (qualName != 0) ); // Enforced by wrapper. - XMP_StringPtr qualPath; - XMP_StringLen pathLen; - - XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath, &pathLen ); - return DoesPropertyExist ( schemaNS, qualPath ); + XMP_VarString qualPath; + XMPUtils::ComposeQualifierPath ( schemaNS, propName, qualNS, qualName, &qualPath ); + return DoesPropertyExist ( schemaNS, qualPath.c_str() ); } // DoesQualifierExist @@ -971,6 +974,107 @@ XMPMeta::SetLocalizedText ( XMP_StringPtr schemaNS, } // SetLocalizedText +// ------------------------------------------------------------------------------------------------- +// DeleteLocalizedText +// ------------------- + +void +XMPMeta::DeleteLocalizedText ( XMP_StringPtr schemaNS, + XMP_StringPtr arrayName, + XMP_StringPtr _genericLang, + XMP_StringPtr _specificLang ) +{ + XMP_Assert ( (schemaNS != 0) && (arrayName != 0) && (_genericLang != 0) && (_specificLang != 0) ); // Enforced by wrapper. + + XMP_VarString zGenericLang ( _genericLang ); + XMP_VarString zSpecificLang ( _specificLang ); + NormalizeLangValue ( &zGenericLang ); + NormalizeLangValue ( &zSpecificLang ); + + XMP_StringPtr genericLang = zGenericLang.c_str(); + XMP_StringPtr specificLang = zSpecificLang.c_str(); + + XMP_ExpandedXPath arrayPath; + ExpandXPath ( schemaNS, arrayName, &arrayPath ); + + // Find the LangAlt array and the selected array item. + + XMP_Node * arrayNode = FindNode ( &tree, arrayPath, kXMP_ExistingOnly ); + if ( arrayNode == 0 ) return; + size_t arraySize = arrayNode->children.size(); + + XMP_CLTMatch match; + XMP_Node * itemNode; + + match = ChooseLocalizedText ( arrayNode, genericLang, specificLang, (const XMP_Node **) &itemNode ); + if ( match != kXMP_CLT_SpecificMatch ) return; + + size_t itemIndex = 0; + for ( ; itemIndex < arraySize; ++itemIndex ) { + if ( arrayNode->children[itemIndex] == itemNode ) break; + } + XMP_Enforce ( itemIndex < arraySize ); + + // Decide if the selected item is x-default or not, find relevant matching item. + + bool itemIsXDefault = false; + if ( ! itemNode->qualifiers.empty() ) { + XMP_Node * qualNode = itemNode->qualifiers[0]; + if ( (qualNode->name == "xml:lang") && (qualNode->value == "x-default") ) itemIsXDefault = true; + } + + if ( itemIsXDefault && (itemIndex != 0) ) { // Enforce the x-default is first policy. + XMP_Node * temp = arrayNode->children[0]; + arrayNode->children[0] = arrayNode->children[itemIndex]; + arrayNode->children[itemIndex] = temp; + itemIndex = 0; + } + + XMP_Node * assocNode = 0; + size_t assocIndex; + size_t assocIsXDefault = false; + + if ( itemIsXDefault ) { + + for ( assocIndex = 1; assocIndex < arraySize; ++assocIndex ) { + if ( arrayNode->children[assocIndex]->value == itemNode->value ) { + assocNode = arrayNode->children[assocIndex]; + break; + } + } + + } else if ( itemIndex > 0 ) { + + XMP_Node * itemZero = arrayNode->children[0]; + if ( itemZero->value == itemNode->value ) { + XMP_Node * qualNode = itemZero->qualifiers[0]; + if ( (qualNode->name == "xml:lang") && (qualNode->value == "x-default") ) { + assocNode = arrayNode->children[0]; + assocIndex = 0; + assocIsXDefault = true; + } + } + + } + + // Delete the appropriate nodes. + + XMP_NodePtrPos arrayBegin = arrayNode->children.begin(); + + if ( assocNode == 0 ) { + arrayNode->children.erase ( arrayBegin + itemIndex ); + } else if ( itemIndex < assocIndex ) { + arrayNode->children.erase ( arrayBegin + assocIndex ); + arrayNode->children.erase ( arrayBegin + itemIndex ); + } else { + arrayNode->children.erase ( arrayBegin + itemIndex ); + arrayNode->children.erase ( arrayBegin + assocIndex ); + } + + delete itemNode; + if ( assocNode != 0 ) delete assocNode; + +} // DeleteLocalizedText // ------------------------------------------------------------------------------------------------- // GetProperty_Bool @@ -1114,11 +1218,9 @@ XMPMeta::SetProperty_Bool ( XMP_StringPtr schemaNS, { XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - XMP_StringPtr valueStr; - XMP_StringLen valueLen; - - XMPUtils::ConvertFromBool ( propValue, &valueStr, &valueLen ); - SetProperty ( schemaNS, propName, valueStr, options ); + XMP_VarString valueStr; + XMPUtils::ConvertFromBool ( propValue, &valueStr ); + SetProperty ( schemaNS, propName, valueStr.c_str(), options ); } // SetProperty_Bool @@ -1135,11 +1237,9 @@ XMPMeta::SetProperty_Int ( XMP_StringPtr schemaNS, { XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - XMP_StringPtr valueStr; - XMP_StringLen valueLen; - - XMPUtils::ConvertFromInt ( propValue, "", &valueStr, &valueLen ); - SetProperty ( schemaNS, propName, valueStr, options ); + XMP_VarString valueStr; + XMPUtils::ConvertFromInt ( propValue, "", &valueStr ); + SetProperty ( schemaNS, propName, valueStr.c_str(), options ); } // SetProperty_Int @@ -1156,11 +1256,9 @@ XMPMeta::SetProperty_Int64 ( XMP_StringPtr schemaNS, { XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - XMP_StringPtr valueStr; - XMP_StringLen valueLen; - - XMPUtils::ConvertFromInt64 ( propValue, "", &valueStr, &valueLen ); - SetProperty ( schemaNS, propName, valueStr, options ); + XMP_VarString valueStr; + XMPUtils::ConvertFromInt64 ( propValue, "", &valueStr ); + SetProperty ( schemaNS, propName, valueStr.c_str(), options ); } // SetProperty_Int64 @@ -1177,11 +1275,9 @@ XMPMeta::SetProperty_Float ( XMP_StringPtr schemaNS, { XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - XMP_StringPtr valueStr; - XMP_StringLen valueLen; - - XMPUtils::ConvertFromFloat ( propValue, "", &valueStr, &valueLen ); - SetProperty ( schemaNS, propName, valueStr, options ); + XMP_VarString valueStr; + XMPUtils::ConvertFromFloat ( propValue, "", &valueStr ); + SetProperty ( schemaNS, propName, valueStr.c_str(), options ); } // SetProperty_Float @@ -1198,11 +1294,9 @@ XMPMeta::SetProperty_Date ( XMP_StringPtr schemaNS, { XMP_Assert ( (schemaNS != 0) && (propName != 0) ); // Enforced by wrapper. - XMP_StringPtr valueStr; - XMP_StringLen valueLen; - - XMPUtils::ConvertFromDate ( propValue, &valueStr, &valueLen ); - SetProperty ( schemaNS, propName, valueStr, options ); + XMP_VarString valueStr; + XMPUtils::ConvertFromDate ( propValue, &valueStr ); + SetProperty ( schemaNS, propName, valueStr.c_str(), options ); } // SetProperty_Date diff --git a/source/XMPCore/XMPMeta-Parse.cpp b/source/XMPCore/XMPMeta-Parse.cpp index 5ff64f4..a70efff 100644 --- a/source/XMPCore/XMPMeta-Parse.cpp +++ b/source/XMPCore/XMPMeta-Parse.cpp @@ -1,5 +1,5 @@ // ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated +// Copyright 2003 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms @@ -258,18 +258,27 @@ NormalizeDCArrays ( XMP_Node * xmpTree ) arrayForm = VerifySetOptions ( arrayForm, 0 ); // Set the implicit array bits. XMP_Node * newArray = new XMP_Node ( dcSchema, currProp->name.c_str(), arrayForm ); dcSchema->children[propNum] = newArray; - newArray->children.push_back ( currProp ); - currProp->parent = newArray; - currProp->name = kXMP_ArrayItemName; - if ( XMP_ArrayIsAltText ( arrayForm ) && (! (currProp->options & kXMP_PropHasLang)) ) { - XMP_Node * newLang = new XMP_Node ( currProp, "xml:lang", "x-default", kXMP_PropIsQualifier ); - currProp->options |= (kXMP_PropHasQualifiers | kXMP_PropHasLang); - if ( currProp->qualifiers.empty() ) { // *** Need a util? - currProp->qualifiers.push_back ( newLang ); - } else { - currProp->qualifiers.insert ( currProp->qualifiers.begin(), newLang ); + if ( currProp->value.empty() ) { // Don't add an empty item, leave the array empty. + + delete ( currProp ); + + } else { + + newArray->children.push_back ( currProp ); + currProp->parent = newArray; + currProp->name = kXMP_ArrayItemName; + + if ( XMP_ArrayIsAltText ( arrayForm ) && (! (currProp->options & kXMP_PropHasLang)) ) { + XMP_Node * newLang = new XMP_Node ( currProp, "xml:lang", "x-default", kXMP_PropIsQualifier ); + currProp->options |= (kXMP_PropHasQualifiers | kXMP_PropHasLang); + if ( currProp->qualifiers.empty() ) { // *** Need a util? + currProp->qualifiers.push_back ( newLang ); + } else { + currProp->qualifiers.insert ( currProp->qualifiers.begin(), newLang ); + } } + } } @@ -496,11 +505,7 @@ FixGPSTimeStamp ( XMP_Node * exifSchema, XMP_Node * gpsDateTime ) binGPSStamp.month = binOtherDate.month; binGPSStamp.day = binOtherDate.day; - XMP_StringPtr goodStr; - XMP_StringLen goodLen; - XMPUtils::ConvertFromDate ( binGPSStamp, &goodStr, &goodLen ); - - gpsDateTime->value.assign ( goodStr, goodLen ); + XMPUtils::ConvertFromDate ( binGPSStamp, &gpsDateTime->value ); } // FixGPSTimeStamp @@ -1086,7 +1091,7 @@ XMPMeta::ParseFromBuffer ( XMP_StringPtr buffer, if ( this->xmlParser == 0 ) { if ( (xmpSize == 0) && lastClientCall ) return; // Tolerate empty parse. Expat complains if there are no XML elements. - this->xmlParser = XMP_NewExpatAdapter(); + this->xmlParser = XMP_NewExpatAdapter ( ExpatAdapter::kUseGlobalNamespaces ); } XMLParserAdapter& parser = *this->xmlParser; diff --git a/source/XMPCore/XMPMeta-Serialize.cpp b/source/XMPCore/XMPMeta-Serialize.cpp index 0aa75ae..0ae2d12 100644 --- a/source/XMPCore/XMPMeta-Serialize.cpp +++ b/source/XMPCore/XMPMeta-Serialize.cpp @@ -1,5 +1,5 @@ // ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated +// Copyright 2003-2009 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms @@ -43,7 +43,7 @@ using namespace std; static const char * kPacketHeader = "<?xpacket begin=\"\xEF\xBB\xBF\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>"; static const char * kPacketTrailer = "<?xpacket end=\"w\"?>"; // ! The w/r is at [size-4]. -static const char * kPXMP_SchemaGroup = "XMP_SchemaGroup"; +static const char * kTXMP_SchemaGroup = "XMP_SchemaGroup"; static const char * kRDF_XMPMetaStart = "<x:xmpmeta xmlns:x=\"adobe:ns:meta/\" x:xmptk=\""; static const char * kRDF_XMPMetaEnd = "</x:xmpmeta>"; @@ -134,13 +134,13 @@ EstimateRDFSize ( const XMP_Node * currNode, XMP_Index indent, size_t indentLen // ------------------- static void -DeclareOneNamespace ( const XMP_VarString & nsPrefix, - const XMP_VarString & nsURI, - XMP_VarString & usedNS, // ! A catenation of the prefixes with colons. - XMP_VarString & outputStr, - XMP_StringPtr newline, - XMP_StringPtr indentStr, - XMP_Index indent ) +DeclareOneNamespace ( XMP_StringPtr nsPrefix, + XMP_StringPtr nsURI, + XMP_VarString & usedNS, // ! A catenation of the prefixes with colons. + XMP_VarString & outputStr, + XMP_StringPtr newline, + XMP_StringPtr indentStr, + XMP_Index indent ) { size_t nsPos = usedNS.find ( nsPrefix ); @@ -178,9 +178,10 @@ DeclareElemNamespace ( const XMP_VarString & elemName, if ( colonPos != XMP_VarString::npos ) { XMP_VarString nsPrefix ( elemName.substr ( 0, colonPos+1 ) ); - XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( nsPrefix ); - XMP_Enforce ( prefixPos != sNamespacePrefixToURIMap->end() ); - DeclareOneNamespace ( nsPrefix, prefixPos->second, usedNS, outputStr, newline, indentStr, indent ); + XMP_StringPtr nsURI; + bool nsFound = sRegisteredNamespaces->GetURI ( nsPrefix.c_str(), &nsURI, 0 ); + XMP_Enforce ( nsFound ); + DeclareOneNamespace ( nsPrefix.c_str(), nsURI, usedNS, outputStr, newline, indentStr, indent ); } } // DeclareElemNamespace @@ -190,8 +191,6 @@ DeclareElemNamespace ( const XMP_VarString & elemName, // DeclareUsedNamespaces // --------------------- -// ??? Should iterators be passed by reference to avoid temp copies? - static void DeclareUsedNamespaces ( const XMP_Node * currNode, XMP_VarString & usedNS, @@ -203,7 +202,7 @@ DeclareUsedNamespaces ( const XMP_Node * currNode, if ( currNode->options & kXMP_SchemaNode ) { // The schema node name is the URI, the value is the prefix. - DeclareOneNamespace ( currNode->value, currNode->name, usedNS, outputStr, newline, indentStr, indent ); + DeclareOneNamespace ( currNode->value.c_str(), currNode->name.c_str(), usedNS, outputStr, newline, indentStr, indent ); } else if ( currNode->options & kXMP_PropValueIsStruct ) { for ( size_t fieldNum = 0, fieldLim = currNode->children.size(); fieldNum < fieldLim; ++fieldNum ) { const XMP_Node * currField = currNode->children[fieldNum]; @@ -228,8 +227,6 @@ DeclareUsedNamespaces ( const XMP_Node * currNode, // EmitRDFArrayTag // --------------- -// ??? Should iterators be passed by reference to avoid temp copies? - enum { kIsStartTag = true, kIsEndTag = false @@ -438,9 +435,8 @@ SerializePrettyRDFProperty ( const XMP_Node * propNode, for ( level = indent; level > 0; --level ) outputStr += indentStr; outputStr += '<'; outputStr += elemName; - - #define isCompact false - bool hasGeneralQualifiers = isCompact; // Might also become true later. + + bool hasGeneralQualifiers = false; bool hasRDFResourceQual = false; for ( size_t qualNum = 0, qualLim = propNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) { @@ -476,7 +472,7 @@ SerializePrettyRDFProperty ( const XMP_Node * propNode, outputStr += newline; SerializePrettyRDFProperty ( propNode, outputStr, newline, indentStr, indent+1, true ); - + for ( size_t qualNum = 0, qualLim = propNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) { const XMP_Node * currQual = propNode->qualifiers[qualNum]; if ( IsRDFAttrQualifier ( currQual->name ) ) continue; @@ -618,13 +614,8 @@ SerializePrettyRDFSchema ( const XMP_VarString & treeName, outputStr += treeName; outputStr += '"'; - size_t totalLen = 8; // Start at 8 for "xml:rdf:". - XMP_cStringMapPos currPos = sNamespacePrefixToURIMap->begin(); - XMP_cStringMapPos endPos = sNamespacePrefixToURIMap->end(); - for ( ; currPos != endPos; ++currPos ) totalLen += currPos->first.size(); - XMP_VarString usedNS; - usedNS.reserve ( totalLen ); + usedNS.reserve ( 400 ); // The predefined prefixes add up to about 320 bytes. usedNS = "xml:rdf:"; DeclareUsedNamespaces ( schemaNode, usedNS, outputStr, newline, indentStr, baseIndent+4 ); @@ -632,36 +623,6 @@ SerializePrettyRDFSchema ( const XMP_VarString & treeName, outputStr += newline; // Write alias comments, if wanted. - - if ( options & kXMP_WriteAliasComments ) { // *** Hoist into a routine, used for Plain XMP also. - - #if 0 // *** Buggy, disable for now. - - XMP_cAliasMapPos aliasPos = sRegisteredAliasMap->begin(); - XMP_cAliasMapPos aliasEnd = sRegisteredAliasMap->end(); - - for ( ; aliasPos != aliasEnd; ++aliasPos ) { - - size_t nsPos = aliasPos->first.find ( schemaNode->value ); - if ( nsPos == XMP_VarString::npos ) continue; - XMP_Assert ( nsPos == 0 ); - - for ( level = baseIndent+3; level > 0; --level ) outputStr += indentStr; - - outputStr += "<!-- "; - outputStr += aliasPos->first; - outputStr += " is aliased to "; - for ( size_t step = 1, stepLim = aliasPos->second.size(); step != stepLim; ++step ) { - outputStr += aliasPos->second[step].step; - } - outputStr += " -->"; - outputStr += newline; - - } - - #endif - - } // Write each of the schema's actual properties. for ( size_t propNum = 0, propLim = schemaNode->children.size(); propNum < propLim; ++propNum ) { @@ -785,9 +746,8 @@ SerializeCompactRDFElemProps ( const XMP_Node * parentNode, for ( level = indent; level > 0; --level ) outputStr += indentStr; outputStr += '<'; outputStr += elemName; - - #define isCompact false - bool hasGeneralQualifiers = isCompact; // Might also become true later. + + bool hasGeneralQualifiers = false; bool hasRDFResourceQual = false; for ( size_t qualNum = 0, qualLim = propNode->qualifiers.size(); qualNum < qualLim; ++qualNum ) { @@ -821,7 +781,7 @@ SerializeCompactRDFElemProps ( const XMP_Node * parentNode, outputStr += newline; SerializePrettyRDFProperty ( propNode, outputStr, newline, indentStr, indent+1, true ); - + size_t qualNum = 0; size_t qualLim = propNode->qualifiers.size(); if ( propNode->options & kXMP_PropHasLang ) ++qualNum; @@ -993,14 +953,9 @@ SerializeCompactRDFSchemas ( const XMP_Node & xmpTree, outputStr += '"'; // Write all necessary xmlns attributes. - - size_t totalLen = 8; // Start at 8 for "xml:rdf:". - XMP_cStringMapPos currPos = sNamespacePrefixToURIMap->begin(); - XMP_cStringMapPos endPos = sNamespacePrefixToURIMap->end(); - for ( ; currPos != endPos; ++currPos ) totalLen += currPos->first.size(); XMP_VarString usedNS; - usedNS.reserve ( totalLen ); + usedNS.reserve ( 400 ); // The predefined prefixes add up to about 320 bytes. usedNS = "xml:rdf:"; for ( schema = 0, schemaLim = xmpTree.children.size(); schema != schemaLim; ++schema ) { @@ -1166,16 +1121,16 @@ SerializeAsRDF ( const XMPMeta & xmpObj, // ----------------- void -XMPMeta::SerializeToBuffer ( XMP_StringPtr * rdfString, - XMP_StringLen * rdfSize, +XMPMeta::SerializeToBuffer ( XMP_VarString * rdfString, XMP_OptionBits options, XMP_StringLen padding, XMP_StringPtr newline, XMP_StringPtr indentStr, XMP_Index baseIndent ) const { - XMP_Assert ( (rdfString != 0) && (rdfSize != 0) && (newline != 0) && (indentStr != 0) ); - + XMP_Assert ( (rdfString != 0) && (newline != 0) && (indentStr != 0) ); + rdfString->erase(); + // Fix up some default parameters. enum { kDefaultPad = 2048 }; @@ -1222,7 +1177,11 @@ XMPMeta::SerializeToBuffer ( XMP_StringPtr * rdfString, } padding = 0; } else { - if ( padding == 0 ) padding = kDefaultPad * unicodeUnitSize; + if ( padding == 0 ) { + padding = kDefaultPad * unicodeUnitSize; + } else if ( (padding >> 28) != 0 ) { + XMP_Throw ( "Outrageously large padding size", kXMPErr_BadOptions ); // Bigger than 256 MB. + } if ( options & kXMP_IncludeThumbnailPad ) { if ( ! this->DoesPropertyExist ( kXMP_NS_XMP, "Thumbnails" ) ) padding += (10000 * unicodeUnitSize); // *** Need a better estimate. } @@ -1232,11 +1191,11 @@ XMPMeta::SerializeToBuffer ( XMP_StringPtr * rdfString, std::string tailStr; - SerializeAsRDF ( *this, *sOutputStr, tailStr, options, newline, indentStr, baseIndent ); + SerializeAsRDF ( *this, *rdfString, tailStr, options, newline, indentStr, baseIndent ); if ( charEncoding == kXMP_EncodeUTF8 ) { if ( options & kXMP_ExactPacketLength ) { - size_t minSize = sOutputStr->size() + tailStr.size(); + size_t minSize = rdfString->size() + tailStr.size(); if ( minSize > padding ) XMP_Throw ( "Can't fit into specified packet size", kXMPErr_BadSerialize ); padding -= minSize; // Now the actual amount of padding to add. } @@ -1244,19 +1203,19 @@ XMPMeta::SerializeToBuffer ( XMP_StringPtr * rdfString, size_t newlineLen = strlen ( newline ); if ( padding < newlineLen ) { - sOutputStr->append ( padding, ' ' ); + rdfString->append ( padding, ' ' ); } else { padding -= newlineLen; // Write this newline last. while ( padding >= (100 + newlineLen) ) { - sOutputStr->append ( 100, ' ' ); - *sOutputStr += newline; + rdfString->append ( 100, ' ' ); + *rdfString += newline; padding -= (100 + newlineLen); } - sOutputStr->append ( padding, ' ' ); - *sOutputStr += newline; + rdfString->append ( padding, ' ' ); + *rdfString += newline; } - *sOutputStr += tailStr; + *rdfString += tailStr; } else { @@ -1269,13 +1228,13 @@ XMPMeta::SerializeToBuffer ( XMP_StringPtr * rdfString, std::string padStr ( " " ); padStr[0] = 0; // Assume big endian. - utf8Str.swap ( *sOutputStr ); - ToUTF16 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), sOutputStr, bigEndian ); + utf8Str.swap ( *rdfString ); + ToUTF16 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), rdfString, bigEndian ); utf8Str.swap ( tailStr ); ToUTF16 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), &tailStr, bigEndian ); if ( options & kXMP_ExactPacketLength ) { - size_t minSize = sOutputStr->size() + tailStr.size(); + size_t minSize = rdfString->size() + tailStr.size(); if ( minSize > padding ) XMP_Throw ( "Can't fit into specified packet size", kXMPErr_BadSerialize ); padding -= minSize; // Now the actual amount of padding to add (in bytes). } @@ -1285,19 +1244,19 @@ XMPMeta::SerializeToBuffer ( XMP_StringPtr * rdfString, size_t newlineLen = newlineStr.size(); if ( padding < newlineLen ) { - for ( int i = padding/2; i > 0; --i ) *sOutputStr += padStr; + for ( int i = padding/2; i > 0; --i ) *rdfString += padStr; } else { padding -= newlineLen; // Write this newline last. while ( padding >= (200 + newlineLen) ) { - for ( int i = 100; i > 0; --i ) *sOutputStr += padStr; - *sOutputStr += newlineStr; + for ( int i = 100; i > 0; --i ) *rdfString += padStr; + *rdfString += newlineStr; padding -= (200 + newlineLen); } - for ( int i = padding/2; i > 0; --i ) *sOutputStr += padStr; - *sOutputStr += newlineStr; + for ( int i = padding/2; i > 0; --i ) *rdfString += padStr; + *rdfString += newlineStr; } - *sOutputStr += tailStr; + *rdfString += tailStr; } else { @@ -1309,13 +1268,13 @@ XMPMeta::SerializeToBuffer ( XMP_StringPtr * rdfString, Converter = UTF8_to_UTF32LE; } - utf8Str.swap ( *sOutputStr ); - ToUTF32 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), sOutputStr, bigEndian ); + utf8Str.swap ( *rdfString ); + ToUTF32 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), rdfString, bigEndian ); utf8Str.swap ( tailStr ); ToUTF32 ( (UTF8Unit*)utf8Str.c_str(), utf8Str.size(), &tailStr, bigEndian ); if ( options & kXMP_ExactPacketLength ) { - size_t minSize = sOutputStr->size() + tailStr.size(); + size_t minSize = rdfString->size() + tailStr.size(); if ( minSize > padding ) XMP_Throw ( "Can't fit into specified packet size", kXMPErr_BadSerialize ); padding -= minSize; // Now the actual amount of padding to add (in bytes). } @@ -1325,29 +1284,24 @@ XMPMeta::SerializeToBuffer ( XMP_StringPtr * rdfString, size_t newlineLen = newlineStr.size(); if ( padding < newlineLen ) { - for ( int i = padding/4; i > 0; --i ) *sOutputStr += padStr; + for ( int i = padding/4; i > 0; --i ) *rdfString += padStr; } else { padding -= newlineLen; // Write this newline last. while ( padding >= (400 + newlineLen) ) { - for ( int i = 100; i > 0; --i ) *sOutputStr += padStr; - *sOutputStr += newlineStr; + for ( int i = 100; i > 0; --i ) *rdfString += padStr; + *rdfString += newlineStr; padding -= (400 + newlineLen); } - for ( int i = padding/4; i > 0; --i ) *sOutputStr += padStr; - *sOutputStr += newlineStr; + for ( int i = padding/4; i > 0; --i ) *rdfString += padStr; + *rdfString += newlineStr; } - *sOutputStr += tailStr; + *rdfString += tailStr; } } - // Return the finished string. - - *rdfString = sOutputStr->c_str(); - *rdfSize = sOutputStr->size(); - } // SerializeToBuffer // ================================================================================================= diff --git a/source/XMPCore/XMPMeta.cpp b/source/XMPCore/XMPMeta.cpp index c5def31..44bee16 100644 --- a/source/XMPCore/XMPMeta.cpp +++ b/source/XMPCore/XMPMeta.cpp @@ -1,5 +1,5 @@ // ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated +// Copyright 2003 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms @@ -52,7 +52,7 @@ using namespace std; // Static Variables // ================ -XMP_VarString * xdefaultName = 0; +XMP_VarString * xdefaultName = 0; // Needed in XMPMeta-Parse.cpp, MoveExplicitAliases. // These are embedded version strings. @@ -63,134 +63,16 @@ const char * kXMPCore_EmbeddedCopyright = kXMPCoreName " " kXMP_CopyrightStr; // Local Utilities // =============== -#define IsHexDigit(ch) ( (('0' <= (ch)) && ((ch) <= '9')) || (('A' <= (ch)) && ((ch) <= 'F')) ) -#define HexDigitValue(ch) ( (((ch) - '0') < 10) ? ((ch) - '0') : ((ch) - 'A' + 10) ) - -static const char * kTenSpaces = " "; -#define OutProcPadding(pad) { size_t padLen = (pad); \ - for ( ; padLen >= 10; padLen -= 10 ) OutProcNChars ( kTenSpaces, 10 ); \ - for ( ; padLen > 0; padLen -= 1 ) OutProcNChars ( " ", 1 ); } - - -#define OutProcNewline() { status = (*outProc) ( refCon, "\n", 1 ); if ( status != 0 ) goto EXIT; } - -#define OutProcNChars(p,n) { status = (*outProc) ( refCon, (p), (n) ); if ( status != 0 ) goto EXIT; } - -#define OutProcLiteral(lit) { status = (*outProc) ( refCon, (lit), strlen(lit) ); if ( status != 0 ) goto EXIT; } - -#define OutProcString(str) { status = (*outProc) ( refCon, (str).c_str(), (str).size() ); if ( status != 0 ) goto EXIT; } - -#define OutProcDecInt(num) { snprintf ( buffer, sizeof(buffer), "%d", (num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \ - status = (*outProc) ( refCon, buffer, strlen(buffer) ); if ( status != 0 ) goto EXIT; } - -#define OutProcHexInt(num) { snprintf ( buffer, sizeof(buffer), "%X", (num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \ - status = (*outProc) ( refCon, buffer, strlen(buffer) ); if ( status != 0 ) goto EXIT; } - -#define OutProcHexByte(num) { snprintf ( buffer, sizeof(buffer), "%.2X", (num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \ - status = (*outProc) ( refCon, buffer, strlen(buffer) ); if ( status != 0 ) goto EXIT; } - -static const char * kIndent = " "; -#define OutProcIndent(lev) { for ( size_t i = 0; i < (lev); ++i ) OutProcNChars ( kIndent, 3 ); } - - -// ------------------------------------------------------------------------------------------------- -// DumpClearString -// --------------- - -static XMP_Status -DumpClearString ( const XMP_VarString & value, XMP_TextOutputProc outProc, void * refCon ) -{ - - char buffer [20]; - bool prevNormal; - XMP_Status status = 0; - - XMP_StringPtr spanStart, spanEnd; - XMP_StringPtr valueEnd = &value[0] + value.size(); - - spanStart = &value[0]; - while ( spanStart < valueEnd ) { - - // Output the next span of regular characters. - for ( spanEnd = spanStart; spanEnd < valueEnd; ++spanEnd ) { - if ( *spanEnd > 0x7F ) break; - if ( (*spanEnd < 0x20) && (*spanEnd != kTab) && (*spanEnd != kLF) ) break; - } - if ( spanStart != spanEnd ) status = (*outProc) ( refCon, spanStart, (spanEnd-spanStart) ); - if ( status != 0 ) break; - spanStart = spanEnd; - - // Output the next span of irregular characters. - prevNormal = true; - for ( spanEnd = spanStart; spanEnd < valueEnd; ++spanEnd ) { - if ( ((0x20 <= *spanEnd) && (*spanEnd <= 0x7F)) || (*spanEnd == kTab) || (*spanEnd == kLF) ) break; - char space = ' '; - if ( prevNormal ) space = '<'; - status = (*outProc) ( refCon, &space, 1 ); - if ( status != 0 ) break; - OutProcHexByte ( *spanEnd ); - prevNormal = false; - } - if ( ! prevNormal ) { - status = (*outProc) ( refCon, ">", 1 ); - if ( status != 0 ) return status; - } - spanStart = spanEnd; - - } - -EXIT: - return status; - -} // DumpClearString - - -// ------------------------------------------------------------------------------------------------- -// DumpStringMap -// ------------- - -static XMP_Status -DumpStringMap ( const XMP_StringMap & map, XMP_StringPtr label, XMP_TextOutputProc outProc, void * refCon ) -{ - XMP_Status status; - XMP_cStringMapPos currPos; - XMP_cStringMapPos endPos = map.end(); - - size_t maxLen = 0; - for ( currPos = map.begin(); currPos != endPos; ++currPos ) { - size_t currLen = currPos->first.size(); - if ( currLen > maxLen ) maxLen = currLen; - } - - OutProcNewline(); - OutProcLiteral ( label ); - OutProcNewline(); - - for ( currPos = map.begin(); currPos != endPos; ++currPos ) { - OutProcNChars ( " ", 2 ); - DumpClearString ( currPos->first, outProc, refCon ); - OutProcPadding ( maxLen - currPos->first.size() ); - OutProcNChars ( " => ", 4 ); - DumpClearString ( currPos->second, outProc, refCon ); - OutProcNewline(); - } - -EXIT: - return status; - -} // DumpStringMap - // ------------------------------------------------------------------------------------------------- // DumpNodeOptions // --------------- -static XMP_Status +static void DumpNodeOptions ( XMP_OptionBits options, XMP_TextOutputProc outProc, void * refCon ) { - XMP_Status status; char buffer [32]; // Decimal of a 64 bit int is at most about 20 digits. static const char * optNames[] = { " schema", // 0x8000_0000 @@ -244,9 +126,6 @@ DumpNodeOptions ( XMP_OptionBits options, OutProcNChars ( ")", 1 ); } - -EXIT: - return status; } // DumpNodeOptions @@ -257,15 +136,14 @@ EXIT: // *** Extract the validation code into a separate routine to call on exit in debug builds. -static XMP_Status +static void DumpPropertyTree ( const XMP_Node * currNode, int indent, size_t itemIndex, XMP_TextOutputProc outProc, void * refCon ) { - XMP_Status status; - char buffer [32]; // Decimal of a 64 bit int is at most about 20 digits. + char buffer [32]; // Decimal of a 64 bit int is at most about 20 digits. OutProcIndent ( (size_t)indent ); if ( itemIndex == 0 ) { @@ -285,8 +163,7 @@ DumpPropertyTree ( const XMP_Node * currNode, if ( currNode->options != 0 ) { OutProcNChars ( " ", 2 ); - status = DumpNodeOptions ( currNode->options, outProc, refCon ); - if ( status != 0 ) goto EXIT; + DumpNodeOptions ( currNode->options, outProc, refCon ); } if ( currNode->options & kXMP_PropHasLang ) { @@ -322,8 +199,7 @@ DumpPropertyTree ( const XMP_Node * currNode, if ( (qualNum != 0) || (! (currNode->options & kXMP_PropHasLang)) ) OutProcLiteral ( "** bad lang qual => " ); } - status = DumpPropertyTree ( currQual, indent+2, 0, outProc, refCon ); - if ( status != 0 ) goto EXIT; + DumpPropertyTree ( currQual, indent+2, 0, outProc, refCon ); } @@ -342,13 +218,9 @@ DumpPropertyTree ( const XMP_Node * currNode, if ( currChild->name == kXMP_ArrayItemName ) OutProcLiteral ( "** bad field name => " ); } - status = DumpPropertyTree ( currChild, indent+1, itemIndex, outProc, refCon ); - if ( status != 0 ) goto EXIT; + DumpPropertyTree ( currChild, indent+1, itemIndex, outProc, refCon ); } - -EXIT: - return status; } // DumpPropertyTree @@ -575,6 +447,191 @@ SortWithinOffspring ( XMP_NodeOffspring & nodeVec ) } // SortWithinOffspring +// ------------------------------------------------------------------------------------------------- +// RegisterAlias +// ------------- +// +// Allow 3 kinds of alias: +// TopProp => TopProp +// TopProp => TopArray[1] +// TopProp => TopArray[@xml:lang='x-default'] +// +// A new alias can be made to something that is already aliased, as long as the net result is one of +// the legitimate forms. The new alias can already have aliases to it, also as long as result of +// adjusting all of the exiting aliases leaves them legal. +// +// ! The caller assumes all risk that new aliases do not invalidate existing XMPMeta objects. Any +// ! conflicts will result in later references throwing bad XPath exceptions. + +static void +RegisterAlias ( XMP_StringPtr aliasNS, + XMP_StringPtr aliasProp, + XMP_StringPtr actualNS, + XMP_StringPtr actualProp, + XMP_OptionBits arrayForm ) +{ + XMP_ExpandedXPath expAlias, expActual; + XMP_AliasMapPos mapPos; + XMP_ExpandedXPath * regActual = 0; + + XMP_Assert ( (aliasNS != 0) && (aliasProp != 0) && (actualNS != 0) && (actualProp != 0) ); // Enforced by wrapper. + + // Expand the alias and actual names, make sure they are one of the basic 3 forms. When counting + // the expanded XPath size remember that the schema URI is the first component. We don't have to + // compare the schema URIs though, the (unique) prefix is part of the top property name. + + ExpandXPath ( aliasNS, aliasProp, &expAlias ); + ExpandXPath ( actualNS, actualProp, &expActual ); + if ( (expAlias.size() != 2) || (expActual.size() != 2) ) { + XMP_Throw ( "Alias and actual property names must be simple", kXMPErr_BadXPath ); + } + + arrayForm = VerifySetOptions ( arrayForm, 0 ); + if ( arrayForm != 0 ) { + if ( (arrayForm & ~kXMP_PropArrayFormMask) != 0 ) XMP_Throw ( "Only array form flags are allowed", kXMPErr_BadOptions ); + expActual[1].options |= arrayForm; // Set the array form for the top level step. + if ( ! (arrayForm & kXMP_PropArrayIsAltText) ) { + expActual.push_back ( XPathStepInfo ( "[1]", kXMP_ArrayIndexStep ) ); + } else { + expActual.push_back ( XPathStepInfo ( "[?xml:lang=\"x-default\"]", kXMP_QualSelectorStep ) ); + } + } + + // See if there are any conflicts with existing aliases. A couple of the checks are easy. If the + // alias is already aliased it is only OK to reregister an identical alias. If the actual is + // already aliased to something else and the new chain is legal, just swap in the old base. + + mapPos = sRegisteredAliasMap->find ( expAlias[kRootPropStep].step ); + if ( mapPos != sRegisteredAliasMap->end() ) { + + // This alias is already registered to something, make sure it is the same something. + + regActual = &mapPos->second; + if ( arrayForm != (mapPos->second[1].options & kXMP_PropArrayFormMask) ) { + XMP_Throw ( "Mismatch with existing alias array form", kXMPErr_BadParam ); + } + if ( expActual.size() != regActual->size() ) { + XMP_Throw ( "Mismatch with existing actual path", kXMPErr_BadParam ); + } + if ( expActual[kRootPropStep].step != (*regActual)[kRootPropStep].step ) { + XMP_Throw ( "Mismatch with existing actual name", kXMPErr_BadParam ); + } + if ( (expActual.size() == 3) && (expActual[kAliasIndexStep].step != (*regActual)[kAliasIndexStep].step) ) { + XMP_Throw ( "Mismatch with existing actual array item", kXMPErr_BadParam ); + } + return; + + } + + mapPos = sRegisteredAliasMap->find ( expActual[kRootPropStep].step ); + if ( mapPos != sRegisteredAliasMap->end() ) { + + // The actual is already aliased to something else. + + regActual = &mapPos->second; + if ( expActual.size() == 2 ) { + expActual = *regActual; // TopProp => TopProp => anything : substitute the entire old base. + } else if ( regActual->size() != 2 ) { + XMP_Throw ( "Can't alias an array item to an array item", kXMPErr_BadParam ); // TopProp => TopArray[] => TopArray[] : nope. + } else { + expActual[kSchemaStep].step = (*regActual)[kSchemaStep].step; // TopProp => TopArray[] => TopProp : + expActual[kRootPropStep].step = (*regActual)[kRootPropStep].step; // substitute the old base name. + } + + } + + // Checking for existing aliases to this one is touchier. This involves updating the alias map, + // which must not be done unless all of the changes are legal. So we need 2 loops, one to verify + // that everything is OK, and one to make the changes. The bad case is: + // TopProp => TopArray[] => TopArray[] + // In the valid cases we back substitute the new base. + + for ( mapPos = sRegisteredAliasMap->begin(); mapPos != sRegisteredAliasMap->end(); ++mapPos ) { + regActual = &mapPos->second; + if ( expAlias[kRootPropStep].step == (*regActual)[kRootPropStep].step ) { + if ( (regActual->size() == 2) && (expAlias.size() == 2) ) { + XMP_Throw ( "Can't alias an array item to an array item", kXMPErr_BadParam ); + } + } + } + + for ( mapPos = sRegisteredAliasMap->begin(); mapPos != sRegisteredAliasMap->end(); ++mapPos ) { + regActual = &mapPos->second; + if ( expAlias[kRootPropStep].step == (*regActual)[kRootPropStep].step ) { + + if ( regActual->size() == 1 ) { + *regActual = expActual; // TopProp => TopProp => anything : substitute the entire new base. + } else { + (*regActual)[kSchemaStep].step = expActual[kSchemaStep].step; // TopProp => TopArray[] => TopProp : + (*regActual)[kRootPropStep].step = expActual[kRootPropStep].step; // substitute the new base name. + } + + } + } + + // Finally, all is OK to register the new alias. + + (void) sRegisteredAliasMap->insert ( XMP_AliasMap::value_type ( expAlias[kRootPropStep].step, expActual ) ); + +} // RegisterAlias + + +// ------------------------------------------------------------------------------------------------- +// RegisterStandardAliases +// ----------------------- + +static void +RegisterStandardAliases() +{ + + // Aliases from XMP to DC. + RegisterAlias ( kXMP_NS_XMP, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered ); + RegisterAlias ( kXMP_NS_XMP, "Authors", kXMP_NS_DC, "creator", 0 ); + RegisterAlias ( kXMP_NS_XMP, "Description", kXMP_NS_DC, "description", 0 ); + RegisterAlias ( kXMP_NS_XMP, "Format", kXMP_NS_DC, "format", 0 ); + RegisterAlias ( kXMP_NS_XMP, "Keywords", kXMP_NS_DC, "subject", 0 ); + RegisterAlias ( kXMP_NS_XMP, "Locale", kXMP_NS_DC, "language", 0 ); + RegisterAlias ( kXMP_NS_XMP, "Title", kXMP_NS_DC, "title", 0 ); + RegisterAlias ( kXMP_NS_XMP_Rights, "Copyright", kXMP_NS_DC, "rights", 0 ); + + // Aliases from PDF to DC and XMP. + RegisterAlias ( kXMP_NS_PDF, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered ); + RegisterAlias ( kXMP_NS_PDF, "BaseURL", kXMP_NS_XMP, "BaseURL", 0 ); + RegisterAlias ( kXMP_NS_PDF, "CreationDate", kXMP_NS_XMP, "CreateDate", 0 ); + RegisterAlias ( kXMP_NS_PDF, "Creator", kXMP_NS_XMP, "CreatorTool", 0 ); + RegisterAlias ( kXMP_NS_PDF, "ModDate", kXMP_NS_XMP, "ModifyDate", 0 ); + RegisterAlias ( kXMP_NS_PDF, "Subject", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText ); + RegisterAlias ( kXMP_NS_PDF, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText ); + + // Aliases from Photoshop to DC and XMP. + RegisterAlias ( kXMP_NS_Photoshop, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered ); + RegisterAlias ( kXMP_NS_Photoshop, "Caption", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText ); + RegisterAlias ( kXMP_NS_Photoshop, "Copyright", kXMP_NS_DC, "rights", kXMP_PropArrayIsAltText ); + RegisterAlias ( kXMP_NS_Photoshop, "Keywords", kXMP_NS_DC, "subject", 0 ); + RegisterAlias ( kXMP_NS_Photoshop, "Marked", kXMP_NS_XMP_Rights, "Marked", 0 ); + RegisterAlias ( kXMP_NS_Photoshop, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText ); + RegisterAlias ( kXMP_NS_Photoshop, "WebStatement", kXMP_NS_XMP_Rights, "WebStatement", 0 ); + + // Aliases from TIFF and EXIF to DC and XMP. + RegisterAlias ( kXMP_NS_TIFF, "Artist", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered); + RegisterAlias ( kXMP_NS_TIFF, "Copyright", kXMP_NS_DC, "rights", 0 ); + RegisterAlias ( kXMP_NS_TIFF, "DateTime", kXMP_NS_XMP, "ModifyDate", 0 ); + RegisterAlias ( kXMP_NS_EXIF, "DateTimeDigitized", kXMP_NS_XMP, "CreateDate", 0 ); + RegisterAlias ( kXMP_NS_TIFF, "ImageDescription", kXMP_NS_DC, "description", 0 ); + RegisterAlias ( kXMP_NS_TIFF, "Software", kXMP_NS_XMP, "CreatorTool", 0 ); + + // Aliases from PNG to DC and XMP. + RegisterAlias ( kXMP_NS_PNG, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered); + RegisterAlias ( kXMP_NS_PNG, "Copyright", kXMP_NS_DC, "rights", kXMP_PropArrayIsAltText); + RegisterAlias ( kXMP_NS_PNG, "CreationTime", kXMP_NS_XMP, "CreateDate", 0 ); + RegisterAlias ( kXMP_NS_PNG, "Description", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText); + RegisterAlias ( kXMP_NS_PNG, "ModificationTime", kXMP_NS_XMP, "ModifyDate", 0 ); + RegisterAlias ( kXMP_NS_PNG, "Software", kXMP_NS_XMP, "CreatorTool", 0 ); + RegisterAlias ( kXMP_NS_PNG, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText); + +} // RegisterStandardAliases + + // ================================================================================================= // Constructors // ============ @@ -634,6 +691,14 @@ XMPMeta::GetVersionInfo ( XMP_VersionInfo * info ) // Initialize // ---------- +#if XMP_TraceCoreCalls + FILE * xmpCoreLog = stderr; +#endif + +#if UseGlobalLibraryLock + XMP_BasicMutex sLibraryLock; +#endif + /* class-static */ bool XMPMeta::Initialize() { @@ -642,21 +707,21 @@ XMPMeta::Initialize() ++sXMP_InitCount; if ( sXMP_InitCount > 1 ) return true; - #if TraceXMPCalls - // xmpOut = fopen ( "xmp.out", "w" ); // Coordinate with client glue in WXMP_Common.hpp - fprintf ( xmpOut, "XMP initializing\n" ); fflush ( xmpOut ); + #if XMP_TraceCoreCallsToFile + xmpCoreLog = fopen ( "XMPCoreLog.txt", "w" ); + if ( xmpCoreLog == 0 ) xmpCoreLog = stderr; #endif - sExceptionMessage = new XMP_VarString(); - XMP_InitMutex ( &sXMPCoreLock ); - sOutputNS = new XMP_VarString; - sOutputStr = new XMP_VarString; + #if UseGlobalLibraryLock + InitializeBasicMutex ( sLibraryLock ); + #endif + + if ( ! Initialize_LibUtils() ) return false; xdefaultName = new XMP_VarString ( "x-default" ); - sNamespaceURIToPrefixMap = new XMP_StringMap; - sNamespacePrefixToURIMap = new XMP_StringMap; - sRegisteredAliasMap = new XMP_AliasMap; + sRegisteredNamespaces = new XMP_NamespaceTable; + sRegisteredAliasMap = new XMP_AliasMap; InitializeUnicodeConversions(); @@ -692,6 +757,8 @@ XMPMeta::Initialize() (void) RegisterNamespace ( kXMP_NS_XMP_Note, "xmpNote", &voidPtr, &voidLen ); (void) RegisterNamespace ( kXMP_NS_DM, "xmpDM", &voidPtr, &voidLen ); + (void) RegisterNamespace ( kXMP_NS_Script, "xmpScript", &voidPtr, &voidLen ); + (void) RegisterNamespace ( kXMP_NS_BWF, "bext", &voidPtr, &voidLen ); (void) RegisterNamespace ( kXMP_NS_XMP_Text, "xmpT", &voidPtr, &voidLen ); (void) RegisterNamespace ( kXMP_NS_XMP_PagedFile, "xmpTPg", &voidPtr, &voidLen ); (void) RegisterNamespace ( kXMP_NS_XMP_Graphics, "xmpG", &voidPtr, &voidLen ); @@ -723,7 +790,7 @@ XMPMeta::Initialize() (void) RegisterNamespace ( "adobe:ns:meta/", "x", &voidPtr, &voidLen ); (void) RegisterNamespace ( "http://ns.adobe.com/iX/1.0/", "iX", &voidPtr, &voidLen ); - XMPMeta::RegisterStandardAliases ( "" ); + RegisterStandardAliases(); // Initialize the other core classes. @@ -741,13 +808,13 @@ XMPMeta::Initialize() XMP_Assert ( sizeof(XMP_Uns64) == 8 ); XMP_Assert ( sizeof(XMP_OptionBits) == 4 ); // Check that option masking work on all 32 bits. - XMP_OptionBits flag = ~0UL; + XMP_OptionBits flag = (XMP_OptionBits) (~0UL); XMP_Assert ( flag == (XMP_OptionBits)(-1L) ); XMP_Assert ( (flag ^ kXMP_PropHasLang) == 0xFFFFFFBFUL ); XMP_Assert ( (flag & ~kXMP_PropHasLang) == 0xFFFFFFBFUL ); XMP_OptionBits opt1 = 0; // Check the general option bit macros. - XMP_OptionBits opt2 = ~0UL; + XMP_OptionBits opt2 = (XMP_OptionBits)~0UL; XMP_SetOption ( opt1, kXMP_PropValueIsArray ); XMP_ClearOption ( opt2, kXMP_PropValueIsArray ); XMP_Assert ( opt1 == ~opt2 ); @@ -803,66 +870,31 @@ XMPMeta::Initialize() // Terminate // --------- -#define EliminateGlobal(g) delete ( g ); g = 0 - /* class-static */ void XMPMeta::Terminate() RELEASE_NO_THROW { --sXMP_InitCount; - if ( sXMP_InitCount > 0 ) return; + if ( sXMP_InitCount != 0 ) return; // Not ready to terminate, or already terminated. - #if TraceXMPCalls - fprintf ( xmpOut, "XMP terminating\n" ); fflush ( xmpOut ); - // fclose ( xmpOut ); // Coordinate with fopen in XMPMeta::Initialize. - #endif - XMPIterator::Terminate(); XMPUtils::Terminate(); - EliminateGlobal ( sNamespaceURIToPrefixMap ); - EliminateGlobal ( sNamespacePrefixToURIMap ); + EliminateGlobal ( sRegisteredNamespaces ); EliminateGlobal ( sRegisteredAliasMap ); EliminateGlobal ( xdefaultName ); - EliminateGlobal ( sOutputNS ); - EliminateGlobal ( sOutputStr ); - EliminateGlobal ( sExceptionMessage ); - - XMP_TermMutex ( sXMPCoreLock ); - -} // Terminate - -// ------------------------------------------------------------------------------------------------- -// Unlock -// ------ + Terminate_LibUtils(); -/* class-static */ void -XMPMeta::Unlock ( XMP_OptionBits options ) -{ - options = options; // Avoid unused parameter warning. // *** Need IgnoreParam macro. - - #if TraceXMPLocking - fprintf ( xmpOut, " Unlocking XMP toolkit, count = %d\n", sLockCount ); fflush ( xmpOut ); + #if UseGlobalLibraryLock + TerminateBasicMutex ( sLibraryLock ); #endif - --sLockCount; - XMP_Assert ( sLockCount == 0 ); - XMP_ExitCriticalRegion ( sXMPCoreLock ); - -} // Unlock - - -// ------------------------------------------------------------------------------------------------- -// UnlockObject -// ------------ - -void -XMPMeta::UnlockObject ( XMP_OptionBits options ) const -{ - options = options; // Avoid unused parameter warning. - - XMPMeta::Unlock ( 0 ); - -} // UnlockObject + + #if XMP_TraceCoreCallsToFile + if ( xmpCoreLog != stderr ) fclose ( xmpCoreLog ); + xmpCoreLog = stderr; + #endif + +} // Terminate // ------------------------------------------------------------------------------------------------- @@ -877,128 +909,11 @@ XMPMeta::UnlockObject ( XMP_OptionBits options ) const XMPMeta::DumpNamespaces ( XMP_TextOutputProc outProc, void * refCon ) { - XMP_Assert ( outProc != 0 ); // ! Enforced by wrapper. - XMP_Status status = 0; - - XMP_StringMapPos p2uEnd = sNamespacePrefixToURIMap->end(); // ! Move up to avoid gcc complaints. - XMP_StringMapPos u2pEnd = sNamespaceURIToPrefixMap->end(); - - status = DumpStringMap ( *sNamespacePrefixToURIMap, "Dumping namespace prefix to URI map", outProc, refCon ); - if ( status != 0 ) goto EXIT; - - if ( sNamespacePrefixToURIMap->size() != sNamespaceURIToPrefixMap->size() ) { - OutProcLiteral ( "** bad namespace map sizes **" ); - XMP_Throw ( "Fatal namespace map problem", kXMPErr_InternalFailure ); - } - - for ( XMP_StringMapPos nsLeft = sNamespacePrefixToURIMap->begin(); nsLeft != p2uEnd; ++nsLeft ) { - - XMP_StringMapPos nsOther = sNamespaceURIToPrefixMap->find ( nsLeft->second ); - if ( (nsOther == u2pEnd) || (nsLeft != sNamespacePrefixToURIMap->find ( nsOther->second )) ) { - OutProcLiteral ( " ** bad namespace URI ** " ); - DumpClearString ( nsLeft->second, outProc, refCon ); - goto FAILURE; - } - - for ( XMP_StringMapPos nsRight = nsLeft; nsRight != p2uEnd; ++nsRight ) { - if ( nsRight == nsLeft ) continue; // ! Can't start at nsLeft+1, no operator+! - if ( nsLeft->second == nsRight->second ) { - OutProcLiteral ( " ** duplicate namespace URI ** " ); - DumpClearString ( nsLeft->second, outProc, refCon ); - goto FAILURE; - } - } - - } - - for ( XMP_StringMapPos nsLeft = sNamespaceURIToPrefixMap->begin(); nsLeft != u2pEnd; ++nsLeft ) { - - XMP_StringMapPos nsOther = sNamespacePrefixToURIMap->find ( nsLeft->second ); - if ( (nsOther == p2uEnd) || (nsLeft != sNamespaceURIToPrefixMap->find ( nsOther->second )) ) { - OutProcLiteral ( " ** bad namespace prefix ** " ); - DumpClearString ( nsLeft->second, outProc, refCon ); - goto FAILURE; - } - - for ( XMP_StringMapPos nsRight = nsLeft; nsRight != u2pEnd; ++nsRight ) { - if ( nsRight == nsLeft ) continue; // ! Can't start at nsLeft+1, no operator+! - if ( nsLeft->second == nsRight->second ) { - OutProcLiteral ( " ** duplicate namespace prefix ** " ); - DumpClearString ( nsLeft->second, outProc, refCon ); - goto FAILURE; - } - } - - } -EXIT: - return status; - -FAILURE: - OutProcNewline(); - (void) DumpStringMap ( *sNamespaceURIToPrefixMap, "Dumping namespace URI to prefix map", outProc, refCon ); - XMP_Throw ( "Fatal namespace map problem", kXMPErr_InternalFailure ); + sRegisteredNamespaces->Dump ( outProc, refCon ); return 0; - -} // DumpNamespaces - - -// ------------------------------------------------------------------------------------------------- -// DumpAliases -// ----------- - -/* class-static */ XMP_Status -XMPMeta::DumpAliases ( XMP_TextOutputProc outProc, - void * refCon ) -{ - XMP_Assert ( outProc != 0 ); // ! Enforced by wrapper. - XMP_Status status = 0; - - XMP_Assert ( sRegisteredAliasMap != 0 ); - - XMP_cAliasMapPos aliasPos; - XMP_cAliasMapPos aliasEnd = sRegisteredAliasMap->end(); - - size_t maxLen = 0; - for ( aliasPos = sRegisteredAliasMap->begin(); aliasPos != aliasEnd; ++aliasPos ) { - size_t currLen = aliasPos->first.size(); - if ( currLen > maxLen ) maxLen = currLen; - } - - OutProcLiteral ( "Dumping alias name to actual path map" ); - OutProcNewline(); - - for ( aliasPos = sRegisteredAliasMap->begin(); aliasPos != aliasEnd; ++aliasPos ) { - OutProcNChars ( " ", 3 ); - DumpClearString ( aliasPos->first, outProc, refCon ); - OutProcPadding ( maxLen - aliasPos->first.size() ); - OutProcNChars ( " => ", 4 ); - - size_t actualPathSize = aliasPos->second.size(); - for ( size_t stepNum = 1; stepNum < actualPathSize; ++stepNum ) OutProcString ( aliasPos->second[stepNum].step ); - - XMP_OptionBits arrayForm = aliasPos->second[1].options & kXMP_PropArrayFormMask; - - if ( arrayForm == 0 ) { - if ( actualPathSize != 2 ) OutProcLiteral ( " ** bad actual path **" ); - } else { - OutProcNChars ( " ", 2 ); - DumpNodeOptions ( arrayForm, outProc, refCon ); - if ( ! (arrayForm & kXMP_PropValueIsArray) ) OutProcLiteral ( " ** bad array form **" ); - if ( actualPathSize != 3 ) OutProcLiteral ( " ** bad actual path **" ); - } - - if ( aliasPos->second[0].options != kXMP_SchemaNode ) OutProcLiteral ( " ** bad schema form **" ); - - OutProcNewline(); - - } - -EXIT: - return status; - -} // DumpAliases +} // DumpNamespaces // ------------------------------------------------------------------------------------------------- @@ -1039,55 +954,9 @@ XMPMeta::RegisterNamespace ( XMP_StringPtr namespaceURI, XMP_StringPtr * registeredPrefix, XMP_StringLen * prefixSize ) { - bool prefixMatches = false; - - XMP_Assert ( (registeredPrefix != 0) && (prefixSize != 0) ); // ! Enforced by wrapper. - if ( (*namespaceURI == 0) || (*suggestedPrefix == 0) ) { - XMP_Throw ( "Empty namespace URI or prefix", kXMPErr_BadParam ); - } - - XMP_VarString nsURI ( namespaceURI ); - XMP_VarString suggPrefix ( suggestedPrefix ); - if ( suggPrefix[suggPrefix.size()-1] != ':' ) suggPrefix += ':'; - VerifySimpleXMLName ( suggestedPrefix, suggestedPrefix+suggPrefix.size()-1 ); // Exclude the colon. - - XMP_StringMapPos uriPos = sNamespaceURIToPrefixMap->find ( nsURI ); - - if ( uriPos == sNamespaceURIToPrefixMap->end() ) { - - // The URI is not yet registered, make sure we use a unique prefix. - - XMP_VarString uniqPrefix ( suggPrefix ); - int suffix = 0; - char buffer [32]; - - while ( true ) { - if ( sNamespacePrefixToURIMap->find ( uniqPrefix ) == sNamespacePrefixToURIMap->end() ) break; - ++suffix; - snprintf ( buffer, sizeof(buffer), "_%d_:", suffix ); // AUDIT: Using sizeof for snprintf length is safe. - uniqPrefix = suggPrefix; - uniqPrefix.erase ( uniqPrefix.size()-1 ); // ! Remove the trailing ':'. - uniqPrefix += buffer; - } - - // Add the new namespace to both maps. - - XMP_StringPair newNS ( nsURI, uniqPrefix ); - uriPos = sNamespaceURIToPrefixMap->insert ( sNamespaceURIToPrefixMap->end(), newNS ); - - newNS.first.swap ( newNS.second ); - (void) sNamespacePrefixToURIMap->insert ( sNamespacePrefixToURIMap->end(), newNS ); - } - - // Return the actual prefix and see if it matches the suggested prefix. - - *registeredPrefix = uriPos->second.c_str(); - *prefixSize = uriPos->second.size(); - - prefixMatches = ( uriPos->second == suggPrefix ); - return prefixMatches; - + return sRegisteredNamespaces->Define ( namespaceURI, suggestedPrefix, registeredPrefix, prefixSize ); + } // RegisterNamespace @@ -1100,22 +969,9 @@ XMPMeta::GetNamespacePrefix ( XMP_StringPtr namespaceURI, XMP_StringPtr * namespacePrefix, XMP_StringLen * prefixSize ) { - bool found = false; - - XMP_Assert ( *namespaceURI != 0 ); // ! Enforced by wrapper. - XMP_Assert ( (namespacePrefix != 0) && (prefixSize != 0) ); // ! Enforced by wrapper. - XMP_VarString nsURI ( namespaceURI ); - XMP_StringMapPos uriPos = sNamespaceURIToPrefixMap->find ( nsURI ); - - if ( uriPos != sNamespaceURIToPrefixMap->end() ) { - *namespacePrefix = uriPos->second.c_str(); - *prefixSize = uriPos->second.size(); - found = true; - } - - return found; - + return sRegisteredNamespaces->GetPrefix ( namespaceURI, namespacePrefix, prefixSize ); + } // GetNamespacePrefix @@ -1128,24 +984,9 @@ XMPMeta::GetNamespaceURI ( XMP_StringPtr namespacePrefix, XMP_StringPtr * namespaceURI, XMP_StringLen * uriSize ) { - bool found = false; - - XMP_Assert ( *namespacePrefix != 0 ); // ! Enforced by wrapper. - XMP_Assert ( (namespacePrefix != 0) && (namespaceURI != 0) ); // ! Enforced by wrapper. - XMP_VarString nsPrefix ( namespacePrefix ); - if ( nsPrefix[nsPrefix.size()-1] != ':' ) nsPrefix += ':'; - - XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( nsPrefix ); - - if ( prefixPos != sNamespacePrefixToURIMap->end() ) { - *namespaceURI = prefixPos->second.c_str(); - *uriSize = prefixPos->second.size(); - found = true; - } - - return found; - + return sRegisteredNamespaces->GetURI ( namespacePrefix, namespaceURI, uriSize ); + } // GetNamespaceURI @@ -1161,291 +1002,11 @@ XMPMeta::GetNamespaceURI ( XMP_StringPtr namespacePrefix, XMPMeta::DeleteNamespace ( XMP_StringPtr namespaceURI ) { - XMP_StringMapPos uriPos = sNamespaceURIToPrefixMap->find ( namespaceURI ); - if ( uriPos == sNamespaceURIToPrefixMap->end() ) return; - - XMP_StringMapPos prefixPos = sNamespacePrefixToURIMap->find ( uriPos->second ); - XMP_Assert ( prefixPos != sNamespacePrefixToURIMap->end() ); - - sNamespaceURIToPrefixMap->erase ( uriPos ); - sNamespacePrefixToURIMap->erase ( prefixPos ); + XMP_Throw ( "Unimplemented method XMPMeta::DeleteNamespace", kXMPErr_Unimplemented ); } // DeleteNamespace -// ------------------------------------------------------------------------------------------------- -// RegisterAlias -// ------------- -// -// Allow 3 kinds of alias: -// TopProp => TopProp -// TopProp => TopArray[1] -// TopProp => TopArray[@xml:lang='x-default'] -// -// A new alias can be made to something that is already aliased, as long as the net result is one of -// the legitimate forms. The new alias can already have aliases to it, also as long as result of -// adjusting all of the exiting aliases leaves them legal. -// -// ! The caller assumes all risk that new aliases do not invalidate existing XMPMeta objects. Any -// ! conflicts will result in later references throwing bad XPath exceptions. - -/* class-static */ void -XMPMeta::RegisterAlias ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - XMP_StringPtr actualNS, - XMP_StringPtr actualProp, - XMP_OptionBits arrayForm ) -{ - XMP_ExpandedXPath expAlias, expActual; - XMP_AliasMapPos mapPos; - XMP_ExpandedXPath * regActual = 0; - - XMP_Assert ( (aliasNS != 0) && (aliasProp != 0) && (actualNS != 0) && (actualProp != 0) ); // Enforced by wrapper. - - // Expand the alias and actual names, make sure they are one of the basic 3 forms. When counting - // the expanded XPath size remember that the schema URI is the first component. We don't have to - // compare the schema URIs though, the (unique) prefix is part of the top property name. - - ExpandXPath ( aliasNS, aliasProp, &expAlias ); - ExpandXPath ( actualNS, actualProp, &expActual ); - if ( (expAlias.size() != 2) || (expActual.size() != 2) ) { - XMP_Throw ( "Alias and actual property names must be simple", kXMPErr_BadXPath ); - } - - arrayForm = VerifySetOptions ( arrayForm, 0 ); - if ( arrayForm != 0 ) { - if ( (arrayForm & ~kXMP_PropArrayFormMask) != 0 ) XMP_Throw ( "Only array form flags are allowed", kXMPErr_BadOptions ); - expActual[1].options |= arrayForm; // Set the array form for the top level step. - if ( ! (arrayForm & kXMP_PropArrayIsAltText) ) { - expActual.push_back ( XPathStepInfo ( "[1]", kXMP_ArrayIndexStep ) ); - } else { - expActual.push_back ( XPathStepInfo ( "[?xml:lang=\"x-default\"]", kXMP_QualSelectorStep ) ); - } - } - - // See if there are any conflicts with existing aliases. A couple of the checks are easy. If the - // alias is already aliased it is only OK to reregister an identical alias. If the actual is - // already aliased to something else and the new chain is legal, just swap in the old base. - - mapPos = sRegisteredAliasMap->find ( expAlias[kRootPropStep].step ); - if ( mapPos != sRegisteredAliasMap->end() ) { - - // This alias is already registered to something, make sure it is the same something. - - regActual = &mapPos->second; - if ( arrayForm != (mapPos->second[1].options & kXMP_PropArrayFormMask) ) { - XMP_Throw ( "Mismatch with existing alias array form", kXMPErr_BadParam ); - } - if ( expActual.size() != regActual->size() ) { - XMP_Throw ( "Mismatch with existing actual path", kXMPErr_BadParam ); - } - if ( expActual[kRootPropStep].step != (*regActual)[kRootPropStep].step ) { - XMP_Throw ( "Mismatch with existing actual name", kXMPErr_BadParam ); - } - if ( (expActual.size() == 3) && (expActual[kAliasIndexStep].step != (*regActual)[kAliasIndexStep].step) ) { - XMP_Throw ( "Mismatch with existing actual array item", kXMPErr_BadParam ); - } - return; - - } - - mapPos = sRegisteredAliasMap->find ( expActual[kRootPropStep].step ); - if ( mapPos != sRegisteredAliasMap->end() ) { - - // The actual is already aliased to something else. - - regActual = &mapPos->second; - if ( expActual.size() == 2 ) { - expActual = *regActual; // TopProp => TopProp => anything : substitute the entire old base. - } else if ( regActual->size() != 2 ) { - XMP_Throw ( "Can't alias an array item to an array item", kXMPErr_BadParam ); // TopProp => TopArray[] => TopArray[] : nope. - } else { - expActual[kSchemaStep].step = (*regActual)[kSchemaStep].step; // TopProp => TopArray[] => TopProp : - expActual[kRootPropStep].step = (*regActual)[kRootPropStep].step; // substitute the old base name. - } - - } - - // Checking for existing aliases to this one is touchier. This involves updating the alias map, - // which must not be done unless all of the changes are legal. So we need 2 loops, one to verify - // that everything is OK, and one to make the changes. The bad case is: - // TopProp => TopArray[] => TopArray[] - // In the valid cases we back substitute the new base. - - for ( mapPos = sRegisteredAliasMap->begin(); mapPos != sRegisteredAliasMap->end(); ++mapPos ) { - regActual = &mapPos->second; - if ( expAlias[kRootPropStep].step == (*regActual)[kRootPropStep].step ) { - if ( (regActual->size() == 2) && (expAlias.size() == 2) ) { - XMP_Throw ( "Can't alias an array item to an array item", kXMPErr_BadParam ); - } - } - } - - for ( mapPos = sRegisteredAliasMap->begin(); mapPos != sRegisteredAliasMap->end(); ++mapPos ) { - regActual = &mapPos->second; - if ( expAlias[kRootPropStep].step == (*regActual)[kRootPropStep].step ) { - - if ( regActual->size() == 1 ) { - *regActual = expActual; // TopProp => TopProp => anything : substitute the entire new base. - } else { - (*regActual)[kSchemaStep].step = expActual[kSchemaStep].step; // TopProp => TopArray[] => TopProp : - (*regActual)[kRootPropStep].step = expActual[kRootPropStep].step; // substitute the new base name. - } - - } - } - - // Finally, all is OK to register the new alias. - - (void) sRegisteredAliasMap->insert ( XMP_AliasMap::value_type ( expAlias[kRootPropStep].step, expActual ) ); - -} // RegisterAlias - - -// ------------------------------------------------------------------------------------------------- -// ResolveAlias -// ------------ - -/* class-static */ bool -XMPMeta::ResolveAlias ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - XMP_StringPtr * actualNS, - XMP_StringLen * nsSize, - XMP_StringPtr * actualProp, - XMP_StringLen * propSize, - XMP_OptionBits * arrayForm ) -{ - XMP_Assert ( (aliasNS != 0) && (aliasProp != 0) ); // Enforced by wrapper. - XMP_Assert ( (actualNS != 0) && (nsSize != 0) && (actualProp != 0) && (propSize != 0) && (arrayForm != 0) ); // Enforced by wrapper. - - // Expand the input path and look up the first component in the alias table. Return if not an alias. - - XMP_ExpandedXPath fullPath, minPath; - ExpandXPath ( aliasNS, aliasProp, &fullPath ); - XMP_Assert ( fullPath.size() >= 2 ); - - minPath.push_back ( fullPath[kSchemaStep] ); - minPath.push_back ( fullPath[kRootPropStep] ); - XMP_AliasMapPos mapPos = sRegisteredAliasMap->find ( minPath[kRootPropStep].step ); - if ( mapPos == sRegisteredAliasMap->end() ) return false; - - // Replace the alias portion of the full expanded path. Compose the output path string. - - const XMP_ExpandedXPath & actualPath = mapPos->second; - - fullPath[kSchemaStep] = actualPath[kSchemaStep]; - fullPath[kRootPropStep] = actualPath[kRootPropStep]; - if ( actualPath.size() > 2 ) { // This is an alias to an array item. - XMP_ExpandedXPathPos insertPos = fullPath.begin() + kAliasIndexStep; - fullPath.insert ( insertPos, actualPath[kAliasIndexStep] ); - } - - *sOutputNS = fullPath[kSchemaStep].step; - *actualNS = sOutputNS->c_str(); - *nsSize = sOutputNS->size(); - - ComposeXPath ( fullPath, sOutputStr ); - *actualProp = sOutputStr->c_str(); - *propSize = sOutputStr->size(); - - *arrayForm = actualPath[kRootPropStep].options & kXMP_PropArrayFormMask; - - #if XMP_DebugBuild // Test that the output string is valid and unchanged by round trip expand/compose. - XMP_ExpandedXPath rtPath; - ExpandXPath ( *actualNS, *actualProp, &rtPath ); - std::string rtString; - ComposeXPath ( rtPath, &rtString ); - XMP_Assert ( rtString == *sOutputStr ); - #endif - - return true; - -} // ResolveAlias - - -// ------------------------------------------------------------------------------------------------- -// DeleteAlias -// ----------- - -/* class-static */ void -XMPMeta::DeleteAlias ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp ) -{ - - XMP_Assert ( (aliasNS != 0) && (aliasProp != 0) ); // Enforced by wrapper. - XMP_Throw ( "Unimplemented method XMPMeta::DeleteAlias", kXMPErr_Unimplemented ); // *** #error "write me" - void * p; p = &aliasNS; p = &aliasProp; // Avoid unused param warnings. - -} // DeleteAlias - - -// ------------------------------------------------------------------------------------------------- -// RegisterStandardAliases -// ----------------------- - -/* class-static */ void -XMPMeta::RegisterStandardAliases ( XMP_StringPtr schemaNS ) -{ - XMP_Assert ( schemaNS != 0 ); // Enforced by wrapper. - - const bool doAll = (*schemaNS == 0); - - if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_XMP ) ) { - // Aliases from XMP to DC. - XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered ); - XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Authors", kXMP_NS_DC, "creator", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Description", kXMP_NS_DC, "description", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Format", kXMP_NS_DC, "format", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Keywords", kXMP_NS_DC, "subject", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Locale", kXMP_NS_DC, "language", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_XMP, "Title", kXMP_NS_DC, "title", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_XMP_Rights, "Copyright", kXMP_NS_DC, "rights", 0 ); - } - - if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_PDF ) ) { - // Aliases from PDF to DC and XMP. - XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered ); - XMPMeta::RegisterAlias ( kXMP_NS_PDF, "BaseURL", kXMP_NS_XMP, "BaseURL", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_PDF, "CreationDate", kXMP_NS_XMP, "CreateDate", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Creator", kXMP_NS_XMP, "CreatorTool", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_PDF, "ModDate", kXMP_NS_XMP, "ModifyDate", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Subject", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText ); - XMPMeta::RegisterAlias ( kXMP_NS_PDF, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText ); - } - - if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_Photoshop ) ) { - // Aliases from PHOTOSHOP to DC and XMP. - XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered ); - XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Caption", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText ); - XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Copyright", kXMP_NS_DC, "rights", kXMP_PropArrayIsAltText ); - XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Keywords", kXMP_NS_DC, "subject", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Marked", kXMP_NS_XMP_Rights, "Marked", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText ); - XMPMeta::RegisterAlias ( kXMP_NS_Photoshop, "WebStatement", kXMP_NS_XMP_Rights, "WebStatement", 0 ); - } - - if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_TIFF ) || XMP_LitMatch ( schemaNS, kXMP_NS_EXIF ) ) { - // Aliases from TIFF and EXIF to DC and XMP. - XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "Artist", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered); - XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "Copyright", kXMP_NS_DC, "rights", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "DateTime", kXMP_NS_XMP, "ModifyDate", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "ImageDescription", kXMP_NS_DC, "description", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_TIFF, "Software", kXMP_NS_XMP, "CreatorTool", 0 ); - } - - if ( doAll || XMP_LitMatch ( schemaNS, kXMP_NS_PNG ) ) { // ! From Acrobat ImageCapture: - XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Author", kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered); - XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Copyright", kXMP_NS_DC, "rights", kXMP_PropArrayIsAltText); - XMPMeta::RegisterAlias ( kXMP_NS_PNG, "CreationTime", kXMP_NS_XMP, "CreateDate", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Description", kXMP_NS_DC, "description", kXMP_PropArrayIsAltText); - XMPMeta::RegisterAlias ( kXMP_NS_PNG, "ModificationTime", kXMP_NS_XMP, "ModifyDate", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Software", kXMP_NS_XMP, "CreatorTool", 0 ); - XMPMeta::RegisterAlias ( kXMP_NS_PNG, "Title", kXMP_NS_DC, "title", kXMP_PropArrayIsAltText); - } - -} // RegisterStandardAliases - - // ================================================================================================= // Class Methods // ============= @@ -1458,18 +1019,16 @@ XMPMeta::RegisterStandardAliases ( XMP_StringPtr schemaNS ) // DumpObject // ---------- -XMP_Status +void XMPMeta::DumpObject ( XMP_TextOutputProc outProc, void * refCon ) const { XMP_Assert ( outProc != 0 ); // ! Enforced by wrapper. - XMP_Status status = 0; OutProcLiteral ( "Dumping XMPMeta object \"" ); DumpClearString ( tree.name, outProc, refCon ); OutProcNChars ( "\" ", 3 ); - status = DumpNodeOptions ( tree.options, outProc, refCon ); - if ( status != 0 ) goto EXIT; + DumpNodeOptions ( tree.options, outProc, refCon ); #if 0 // *** XMP_DebugBuild if ( (tree._namePtr != tree.name.c_str()) || (tree._valuePtr != tree.value.c_str()) ) OutProcLiteral ( " ** bad debug string **" ); @@ -1487,7 +1046,7 @@ XMPMeta::DumpObject ( XMP_TextOutputProc outProc, OutProcLiteral ( "** bad root qualifiers **" ); OutProcNewline(); for ( size_t qualNum = 0, qualLim = tree.qualifiers.size(); qualNum < qualLim; ++qualNum ) { - status = DumpPropertyTree ( tree.qualifiers[qualNum], 3, 0, outProc, refCon ); + DumpPropertyTree ( tree.qualifiers[qualNum], 3, 0, outProc, refCon ); } } @@ -1503,8 +1062,7 @@ XMPMeta::DumpObject ( XMP_TextOutputProc outProc, OutProcNChars ( " ", 2 ); DumpClearString ( currSchema->name, outProc, refCon ); OutProcNChars ( " ", 2 ); - status = DumpNodeOptions ( currSchema->options, outProc, refCon ); - if ( status != 0 ) goto EXIT; + DumpNodeOptions ( currSchema->options, outProc, refCon ); #if 0 // *** XMP_DebugBuild if ( (currSchema->_namePtr != currSchema->name.c_str()) || (currSchema->_valuePtr != currSchema->value.c_str()) ) OutProcLiteral ( " ** bad debug string **" ); @@ -1531,9 +1089,6 @@ XMPMeta::DumpObject ( XMP_TextOutputProc outProc, } } - -EXIT: - return status; } // DumpObject diff --git a/source/XMPCore/XMPMeta.hpp b/source/XMPCore/XMPMeta.hpp index dca2c2a..e2d1693 100644 --- a/source/XMPCore/XMPMeta.hpp +++ b/source/XMPCore/XMPMeta.hpp @@ -2,7 +2,7 @@ #define __XMPMeta_hpp__ // ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated +// Copyright 2003 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms @@ -20,7 +20,7 @@ #define DumpXMLParseTree 0 #endif -extern XMP_VarString * xdefaultName; +extern XMP_VarString * xdefaultName; // Needed in XMPMeta-Parse.cpp, MoveExplicitAliases. class XMPIterator; class XMPUtils; @@ -37,9 +37,6 @@ public: Initialize(); static void Terminate() RELEASE_NO_THROW; - - static void - Unlock ( XMP_OptionBits options ); // --------------------------------------------------------------------------------------------- @@ -61,10 +58,6 @@ public: DumpNamespaces ( XMP_TextOutputProc outProc, void * refCon ); - static XMP_Status - DumpAliases ( XMP_TextOutputProc outProc, - void * refCon ); - // --------------------------------------------------------------------------------------------- static bool @@ -88,36 +81,6 @@ public: // --------------------------------------------------------------------------------------------- - static void - RegisterAlias ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - XMP_StringPtr actualNS, - XMP_StringPtr actualProp, - XMP_OptionBits arrayForm ); - - static bool - ResolveAlias ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp, - XMP_StringPtr * actualNS, - XMP_StringLen * nsSize, - XMP_StringPtr * actualProp, - XMP_StringLen * propSize, - XMP_OptionBits * arrayForm ); - - static void - DeleteAlias ( XMP_StringPtr aliasNS, - XMP_StringPtr aliasProp ); - - static void - RegisterStandardAliases ( XMP_StringPtr schemaNS ); - - // --------------------------------------------------------------------------------------------- - - void - UnlockObject ( XMP_OptionBits options ) const; - - // --------------------------------------------------------------------------------------------- - bool GetProperty ( XMP_StringPtr schemaNS, XMP_StringPtr propName, @@ -256,6 +219,12 @@ public: XMP_StringPtr itemValue, XMP_OptionBits options ); + void + DeleteLocalizedText ( XMP_StringPtr schemaNS, + XMP_StringPtr altTextName, + XMP_StringPtr genericLang, + XMP_StringPtr specificLang); + // --------------------------------------------------------------------------------------------- bool @@ -348,7 +317,7 @@ public: CountArrayItems ( XMP_StringPtr schemaNS, XMP_StringPtr arrayName ) const; - XMP_Status + void DumpObject ( XMP_TextOutputProc outProc, void * refCon ) const; @@ -360,8 +329,7 @@ public: XMP_OptionBits options ); void - SerializeToBuffer ( XMP_StringPtr * rdfString, - XMP_StringLen * rdfSize, + SerializeToBuffer ( XMP_VarString * rdfString, XMP_OptionBits options, XMP_StringLen padding, XMP_StringPtr newline, @@ -396,6 +364,10 @@ public: // ! Expose the implementation so that file static functions can see the data. XMP_Int32 clientRefs; // ! Must be signed to allow decrement from 0. + XMP_ReadWriteLock lock; + + // ! Any data member changes must be propagted to the Clone function! + XMP_Int32 prevTkVer; // Previous toolkit version as MMmmuubbb (major, minor, micro, build). XMP_Node tree; diff --git a/source/XMPCore/XMPUtils-FileInfo.cpp b/source/XMPCore/XMPUtils-FileInfo.cpp index ebfb9a5..c8d1e90 100644 --- a/source/XMPCore/XMPUtils-FileInfo.cpp +++ b/source/XMPCore/XMPUtils-FileInfo.cpp @@ -1,5 +1,5 @@ // ================================================================================================= -// Copyright 2002-2008 Adobe Systems Incorporated +// Copyright 2003 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms @@ -11,6 +11,8 @@ #include "XMPUtils.hpp" +#include <algorithm> // For binary_search. + #include <time.h> #include <string.h> #include <stdlib.h> @@ -431,6 +433,47 @@ ApplyQuotes ( XMP_VarString * item, UniCodePoint openQuote, UniCodePoint closeQu // *** Need static checks of the schema prefixes! +static const char * kExternalxmpDM[] = + { "xmpDM:album", + "xmpDM:altTapeName", + "xmpDM:altTimecode", + "xmpDM:artist", + "xmpDM:cameraAngle", + "xmpDM:cameraLabel", + "xmpDM:cameraModel", + "xmpDM:cameraMove", + "xmpDM:client", + "xmpDM:comment", + "xmpDM:composer", + "xmpDM:director", + "xmpDM:directorPhotography", + "xmpDM:engineer", + "xmpDM:genre", + "xmpDM:good", + "xmpDM:instrument", + "xmpDM:logComment", + "xmpDM:projectName", + "xmpDM:releaseDate", + "xmpDM:scene", + "xmpDM:shotDate", + "xmpDM:shotDay", + "xmpDM:shotLocation", + "xmpDM:shotName", + "xmpDM:shotNumber", + "xmpDM:shotSize", + "xmpDM:speakerPlacement", + "xmpDM:takeNumber", + "xmpDM:tapeName", + "xmpDM:trackNumber", + "xmpDM:videoAlphaMode", + "xmpDM:videoAlphaPremultipleColor", + 0 }; // ! Must have zero sentinel! + +typedef const char ** CharStarIterator; // Used for binary search of kExternalxmpDM; +static const char ** kLastExternalxmpDM = 0; // Set on first use. +static int CharStarLess (const char * left, const char * right ) + { return (strcmp ( left, right ) < 0); } + #define IsExternalProperty(s,p) (! IsInternalProperty ( s, p )) static bool @@ -490,12 +533,28 @@ IsInternalProperty ( const XMP_VarString & schema, const XMP_VarString & prop ) } else if ( schema == kXMP_NS_CameraRaw ) { - if ( (prop == "crs:Version") || - (prop == "crs:RawFileName") || - (prop == "crs:ToneCurveName") ) { - isInternal = true; + isInternal = true; // All of crs: is internal, they are processing settings. + + } else if ( schema == kXMP_NS_DM ) { + + // ! Most of the xmpDM schema is internal, and unknown properties default to internal. + if ( kLastExternalxmpDM == 0 ) { + for ( kLastExternalxmpDM = &kExternalxmpDM[0]; *kLastExternalxmpDM != 0; ++kLastExternalxmpDM ) {} } + isInternal = (! std::binary_search ( &kExternalxmpDM[0], kLastExternalxmpDM, prop.c_str(), CharStarLess )); + + } else if ( schema == kXMP_NS_Script ) { + + isInternal = true; // ! Most of the xmpScript schema is internal, and unknown properties default to internal. + if ( (prop == "xmpScript:action") || (prop == "xmpScript:character") || (prop == "xmpScript:dialog") || + (prop == "xmpScript:sceneSetting") || (prop == "xmpScript:sceneTimeOfDay") ) { + isInternal = false; + } + + } else if ( schema == kXMP_NS_BWF ) { + if ( prop == "bext:version" ) isInternal = true; + } else if ( schema == kXMP_NS_AdobeStockPhoto ) { isInternal = true; // ! The bmsp schema has only internal properties. @@ -634,127 +693,153 @@ ItemValuesMatch ( const XMP_Node * leftNode, const XMP_Node * rightNode ) // The main implementation of XMPUtils::AppendProperties. See the description in TXMPMeta.hpp. static void -AppendSubtree ( const XMP_Node * sourceNode, XMP_Node * destParent, const bool replaceOld, const bool deleteEmpty ) +AppendSubtree ( const XMP_Node * sourceNode, XMP_Node * destParent, + const bool mergeCompound, const bool replaceOld, const bool deleteEmpty ) { XMP_NodePtrPos destPos; XMP_Node * destNode = FindChildNode ( destParent, sourceNode->name.c_str(), kXMP_ExistingOnly, &destPos ); bool valueIsEmpty = false; - if ( deleteEmpty ) { - if ( XMP_PropIsSimple ( sourceNode->options ) ) { - valueIsEmpty = sourceNode->value.empty(); - } else { - valueIsEmpty = sourceNode->children.empty(); - } + if ( XMP_PropIsSimple ( sourceNode->options ) ) { + valueIsEmpty = sourceNode->value.empty(); + } else { + valueIsEmpty = sourceNode->children.empty(); } - - if ( deleteEmpty & valueIsEmpty ) { - - if ( destNode != 0 ) { + + if ( valueIsEmpty ) { + if ( deleteEmpty && (destNode != 0) ) { delete ( destNode ); destParent->children.erase ( destPos ); } + return; // ! Done, empty values are either ignored or cause deletions. + } - } else if ( destNode == 0 ) { - + if ( destNode == 0 ) { // The one easy case, the destination does not exist. - CloneSubtree ( sourceNode, destParent ); + destNode = CloneSubtree ( sourceNode, destParent, true /* skipEmpty */ ); + XMP_Assert ( (destNode == 0) || (! destNode->value.empty()) || (! destNode->children.empty()) ); + return; + } + + // If we get here we're going to modify an existing property, either replacing or merging. + + XMP_Assert ( (! valueIsEmpty) && (destNode != 0) ); - } else if ( replaceOld ) { + XMP_OptionBits sourceForm = sourceNode->options & kXMP_PropCompositeMask; + XMP_OptionBits destForm = destNode->options & kXMP_PropCompositeMask; - // The destination exists and should be replaced. + bool replaceThis = replaceOld; // ! Don't modify replaceOld, it gets passed to inner calls. + if ( mergeCompound && (! XMP_PropIsSimple ( sourceForm )) ) replaceThis = false; + + if ( replaceThis ) { destNode->value = sourceNode->value; // *** Should use SetNode. destNode->options = sourceNode->options; destNode->RemoveChildren(); destNode->RemoveQualifiers(); - CloneOffspring ( sourceNode, destNode ); + CloneOffspring ( sourceNode, destNode, true /* skipEmpty */ ); + + if ( (! XMP_PropIsSimple ( destNode->options )) && destNode->children.empty() ) { + // Don't keep an empty array or struct. The source might be implicitly empty due to + // all children being empty. In this case CloneOffspring should skip them. + DeleteSubtree ( destPos ); + } - #if 0 // *** XMP_DebugBuild - destNode->_valuePtr = destNode->value.c_str(); - #endif - - } else { + return; - // The destination exists and is not totally replaced. Structs and arrays are merged. + } + + // From here on are cases for merging arrays or structs. + + if ( XMP_PropIsSimple ( sourceForm ) || (sourceForm != destForm) ) return; + + if ( sourceForm == kXMP_PropValueIsStruct ) { + + // To merge a struct process the fields recursively. E.g. add simple missing fields. The + // recursive call to AppendSubtree will handle deletion for fields with empty values. - XMP_OptionBits sourceForm = sourceNode->options & kXMP_PropCompositeMask; - XMP_OptionBits destForm = destNode->options & kXMP_PropCompositeMask; - if ( sourceForm != destForm ) return; - - if ( sourceForm == kXMP_PropValueIsStruct ) { - - // To merge a struct process the fields recursively. E.g. add simple missing fields. The - // recursive call to AppendSubtree will handle deletion for fields with empty values. - - for ( size_t sourceNum = 0, sourceLim = sourceNode->children.size(); sourceNum != sourceLim; ++sourceNum ) { - const XMP_Node * sourceField = sourceNode->children[sourceNum]; - AppendSubtree ( sourceField, destNode, replaceOld, deleteEmpty ); - if ( deleteEmpty && destNode->children.empty() ) { - delete ( destNode ); - destParent->children.erase ( destPos ); - } + for ( size_t sourceNum = 0, sourceLim = sourceNode->children.size(); sourceNum != sourceLim; ++sourceNum ) { + const XMP_Node * sourceField = sourceNode->children[sourceNum]; + AppendSubtree ( sourceField, destNode, mergeCompound, replaceOld, deleteEmpty ); + if ( deleteEmpty && destNode->children.empty() ) { + delete ( destNode ); + destParent->children.erase ( destPos ); } - - } else if ( sourceForm & kXMP_PropArrayIsAltText ) { + } - // Merge AltText arrays by the xml:lang qualifiers. Make sure x-default is first. Make a - // special check for deletion of empty values. Meaningful in AltText arrays because the - // xml:lang qualifier provides unambiguous source/dest correspondence. + } else if ( sourceForm & kXMP_PropArrayIsAltText ) { + + // Merge AltText arrays by the xml:lang qualifiers. Make sure x-default is first. Make a + // special check for deletion of empty values. Meaningful in AltText arrays because the + // xml:lang qualifier provides unambiguous source/dest correspondence. + + XMP_Assert ( mergeCompound ); - for ( size_t sourceNum = 0, sourceLim = sourceNode->children.size(); sourceNum != sourceLim; ++sourceNum ) { + for ( size_t sourceNum = 0, sourceLim = sourceNode->children.size(); sourceNum != sourceLim; ++sourceNum ) { - const XMP_Node * sourceItem = sourceNode->children[sourceNum]; - if ( sourceItem->qualifiers.empty() || (sourceItem->qualifiers[0]->name != "xml:lang") ) continue; - - XMP_Index destIndex = LookupLangItem ( destNode, sourceItem->qualifiers[0]->value ); - - if ( deleteEmpty && sourceItem->value.empty() ) { - - if ( destIndex != -1 ) { - delete ( destNode->children[destIndex] ); - destNode->children.erase ( destNode->children.begin() + destIndex ); - if ( destNode->children.empty() ) { - delete ( destNode ); - destParent->children.erase ( destPos ); - } + const XMP_Node * sourceItem = sourceNode->children[sourceNum]; + if ( sourceItem->qualifiers.empty() || (sourceItem->qualifiers[0]->name != "xml:lang") ) continue; + + XMP_Index destIndex = LookupLangItem ( destNode, sourceItem->qualifiers[0]->value ); + + if ( sourceItem->value.empty() ) { + + if ( deleteEmpty && (destIndex != -1) ) { + delete ( destNode->children[destIndex] ); + destNode->children.erase ( destNode->children.begin() + destIndex ); + if ( destNode->children.empty() ) { + delete ( destNode ); + destParent->children.erase ( destPos ); } + } - } else { + } else { + + if ( destIndex != -1 ) { - if ( destIndex != -1 ) continue; // Not replacing, keep the existing item. + // The source and dest arrays both have this language item. + + if ( replaceOld ) { // ! Yes, check replaceOld not replaceThis! + destNode->children[destIndex]->value = sourceItem->value; + } + + } else { + // The dest array does not have this language item, add it. + if ( (sourceItem->qualifiers[0]->value != "x-default") || destNode->children.empty() ) { - CloneSubtree ( sourceItem, destNode ); + // Typical case, empty dest array or not "x-default". Non-empty should always have "x-default". + CloneSubtree ( sourceItem, destNode, true /* skipEmpty */ ); } else { + // Edge case, non-empty dest array had no "x-default", insert that at the beginning. XMP_Node * destItem = new XMP_Node ( destNode, sourceItem->name, sourceItem->value, sourceItem->options ); - CloneOffspring ( sourceItem, destItem ); + CloneOffspring ( sourceItem, destItem, true /* skipEmpty */ ); destNode->children.insert ( destNode->children.begin(), destItem ); - } + } } - + } - - } else if ( sourceForm & kXMP_PropValueIsArray ) { - - // Merge other arrays by item values. Don't worry about order or duplicates. Source - // items with empty values do not cause deletion, that conflicts horribly with merging. - for ( size_t sourceNum = 0, sourceLim = sourceNode->children.size(); sourceNum != sourceLim; ++sourceNum ) { - const XMP_Node * sourceItem = sourceNode->children[sourceNum]; + } + + } else if ( sourceForm & kXMP_PropValueIsArray ) { + + // Merge other arrays by item values. Don't worry about order or duplicates. Source + // items with empty values do not cause deletion, that conflicts horribly with merging. - size_t destNum, destLim; - for ( destNum = 0, destLim = destNode->children.size(); destNum != destLim; ++destNum ) { - const XMP_Node * destItem = destNode->children[destNum]; - if ( ItemValuesMatch ( sourceItem, destItem ) ) break; - } - if ( destNum == destLim ) CloneSubtree ( sourceItem, destNode ); + for ( size_t sourceNum = 0, sourceLim = sourceNode->children.size(); sourceNum != sourceLim; ++sourceNum ) { + const XMP_Node * sourceItem = sourceNode->children[sourceNum]; + size_t destNum, destLim; + for ( destNum = 0, destLim = destNode->children.size(); destNum != destLim; ++destNum ) { + const XMP_Node * destItem = destNode->children[destNum]; + if ( ItemValuesMatch ( sourceItem, destItem ) ) break; } - - } + if ( destNum == destLim ) CloneSubtree ( sourceItem, destNode, true /* skipEmpty */ ); + } + } } // AppendSubtree @@ -775,11 +860,10 @@ XMPUtils::CatenateArrayItems ( const XMPMeta & xmpObj, XMP_StringPtr separator, XMP_StringPtr quotes, XMP_OptionBits options, - XMP_StringPtr * catedStr, - XMP_StringLen * catedLen ) + XMP_VarString * catedStr ) { XMP_Assert ( (schemaNS != 0) && (arrayName != 0) ); // ! Enforced by wrapper. - XMP_Assert ( (separator != 0) && (quotes != 0) && (catedStr != 0) && (catedLen != 0) ); // ! Enforced by wrapper. + XMP_Assert ( (separator != 0) && (quotes != 0) && (catedStr != 0) ); // ! Enforced by wrapper. size_t strLen, strPos, charLen; UniCharKind charKind; @@ -828,19 +912,19 @@ XMPUtils::CatenateArrayItems ( const XMPMeta & xmpObj, // Return an empty result if the array does not exist, hurl if it isn't the right form. - sCatenatedItems->erase(); + catedStr->erase(); XMP_ExpandedXPath arrayPath; ExpandXPath ( schemaNS, arrayName, &arrayPath ); arrayNode = FindConstNode ( &xmpObj.tree, arrayPath ); - if ( arrayNode == 0 ) goto EXIT; // ! Need to set the output pointer and length. + if ( arrayNode == 0 ) return; arrayForm = arrayNode->options & kXMP_PropCompositeMask; if ( (! (arrayForm & kXMP_PropValueIsArray)) || (arrayForm & kXMP_PropArrayIsAlternate) ) { XMP_Throw ( "Named property must be non-alternate array", kXMPErr_BadParam ); } - if ( arrayNode->children.empty() ) goto EXIT; // ! Need to set the output pointer and length. + if ( arrayNode->children.empty() ) return; // Build the result, quoting the array items, adding separators. Hurl if any item isn't simple. // Start the result with the first value, then add the rest with a preceeding separator. @@ -848,21 +932,17 @@ XMPUtils::CatenateArrayItems ( const XMPMeta & xmpObj, currItem = arrayNode->children[0]; if ( (currItem->options & kXMP_PropCompositeMask) != 0 ) XMP_Throw ( "Array items must be simple", kXMPErr_BadParam ); - *sCatenatedItems = currItem->value; - ApplyQuotes ( sCatenatedItems, openQuote, closeQuote, allowCommas ); + *catedStr = currItem->value; + ApplyQuotes ( catedStr, openQuote, closeQuote, allowCommas ); for ( size_t itemNum = 1, itemLim = arrayNode->children.size(); itemNum != itemLim; ++itemNum ) { const XMP_Node * currItem = arrayNode->children[itemNum]; if ( (currItem->options & kXMP_PropCompositeMask) != 0 ) XMP_Throw ( "Array items must be simple", kXMPErr_BadParam ); XMP_VarString tempStr ( currItem->value ); ApplyQuotes ( &tempStr, openQuote, closeQuote, allowCommas ); - *sCatenatedItems += separator; - *sCatenatedItems += tempStr; + *catedStr += separator; + *catedStr += tempStr; } - -EXIT: - *catedStr = sCatenatedItems->c_str(); - *catedLen = sCatenatedItems->size(); } // CatenateArrayItems @@ -1037,6 +1117,120 @@ XMPUtils::SeparateArrayItems ( XMPMeta * xmpObj, // ------------------------------------------------------------------------------------------------- +// ApplyTemplate +// ------------- + +/* class static */ void +XMPUtils::ApplyTemplate ( XMPMeta * workingXMP, + const XMPMeta & templateXMP, + XMP_OptionBits actions ) +{ + bool doClear = XMP_OptionIsSet ( actions, kXMPTemplate_ClearUnnamedProperties ); + bool doAdd = XMP_OptionIsSet ( actions, kXMPTemplate_AddNewProperties ); + bool doReplace = XMP_OptionIsSet ( actions, kXMPTemplate_ReplaceExistingProperties ); + + bool deleteEmpty = XMP_OptionIsSet ( actions, kXMPTemplate_ReplaceWithDeleteEmpty ); + doReplace |= deleteEmpty; // Delete-empty implies Replace. + deleteEmpty &= (! doClear); // Clear implies not delete-empty, but keep the implicit Replace. + + bool doAll = XMP_OptionIsSet ( actions, kXMPTemplate_IncludeInternalProperties ); + + // ! In several places we do loops backwards so that deletions do not perturb the remaining indices. + // ! These loops use ordinals (size .. 1), we must use a zero based index inside the loop. + + if ( doClear ) { + + // Visit the top level working properties, delete if not in the template. + + for ( size_t schemaOrdinal = workingXMP->tree.children.size(); schemaOrdinal > 0; --schemaOrdinal ) { + + size_t schemaNum = schemaOrdinal-1; // ! Convert ordinal to index! + XMP_Node * workingSchema = workingXMP->tree.children[schemaNum]; + const XMP_Node * templateSchema = FindConstSchema ( &templateXMP.tree, workingSchema->name.c_str() ); + + if ( templateSchema == 0 ) { + + // The schema is not in the template, delete all properties or just all external ones. + + if ( doAll ) { + + workingSchema->RemoveChildren(); // Remove the properties here, delete the schema below. + + } else { + + for ( size_t propOrdinal = workingSchema->children.size(); propOrdinal > 0; --propOrdinal ) { + size_t propNum = propOrdinal-1; // ! Convert ordinal to index! + XMP_Node * workingProp = workingSchema->children[propNum]; + if ( IsExternalProperty ( workingSchema->name, workingProp->name ) ) { + delete ( workingProp ); + workingSchema->children.erase ( workingSchema->children.begin() + propNum ); + } + } + + } + + } else { + + // Check each of the working XMP's properties to see if it is in the template. + + for ( size_t propOrdinal = workingSchema->children.size(); propOrdinal > 0; --propOrdinal ) { + size_t propNum = propOrdinal-1; // ! Convert ordinal to index! + XMP_Node * workingProp = workingSchema->children[propNum]; + if ( (doAll || IsExternalProperty ( workingSchema->name, workingProp->name )) && + (FindConstChild ( templateSchema, workingProp->name.c_str() ) == 0) ) { + delete ( workingProp ); + workingSchema->children.erase ( workingSchema->children.begin() + propNum ); + } + } + + } + + if ( workingSchema->children.empty() ) { + delete ( workingSchema ); + workingXMP->tree.children.erase ( workingXMP->tree.children.begin() + schemaNum ); + } + + } + + } + + if ( doAdd | doReplace ) { + + for ( size_t schemaNum = 0, schemaLim = templateXMP.tree.children.size(); schemaNum < schemaLim; ++schemaNum ) { + + const XMP_Node * templateSchema = templateXMP.tree.children[schemaNum]; + + // Make sure we have an output schema node, then process the top level template properties. + + XMP_NodePtrPos workingSchemaPos; + XMP_Node * workingSchema = FindSchemaNode ( &workingXMP->tree, templateSchema->name.c_str(), + kXMP_ExistingOnly, &workingSchemaPos ); + if ( workingSchema == 0 ) { + workingSchema = new XMP_Node ( &workingXMP->tree, templateSchema->name, templateSchema->value, kXMP_SchemaNode ); + workingXMP->tree.children.push_back ( workingSchema ); + workingSchemaPos = workingXMP->tree.children.end() - 1; + } + + for ( size_t propNum = 0, propLim = templateSchema->children.size(); propNum < propLim; ++propNum ) { + const XMP_Node * templateProp = templateSchema->children[propNum]; + if ( doAll || IsExternalProperty ( templateSchema->name, templateProp->name ) ) { + AppendSubtree ( templateProp, workingSchema, doAdd, doReplace, deleteEmpty ); + } + } + + if ( workingSchema->children.empty() ) { + delete ( workingSchema ); + workingXMP->tree.children.erase ( workingSchemaPos ); + } + + } + + } + +} // ApplyTemplate + + +// ------------------------------------------------------------------------------------------------- // RemoveProperties // ---------------- @@ -1136,58 +1330,6 @@ XMPUtils::RemoveProperties ( XMPMeta * xmpObj, // ------------------------------------------------------------------------------------------------- -// AppendProperties -// ---------------- - -/* class static */ void -XMPUtils::AppendProperties ( const XMPMeta & source, - XMPMeta * dest, - XMP_OptionBits options ) -{ - XMP_Assert ( dest != 0 ); // ! Enforced by wrapper. - - const bool doAll = ((options & kXMPUtil_DoAllProperties) != 0); - const bool replaceOld = ((options & kXMPUtil_ReplaceOldValues) != 0); - const bool deleteEmpty = ((options & kXMPUtil_DeleteEmptyValues) != 0); - - for ( size_t schemaNum = 0, schemaLim = source.tree.children.size(); schemaNum != schemaLim; ++schemaNum ) { - - const XMP_Node * sourceSchema = source.tree.children[schemaNum]; - - // Make sure we have a destination schema node. Remember if it is newly created. - - XMP_Node * destSchema = FindSchemaNode ( &dest->tree, sourceSchema->name.c_str(), kXMP_ExistingOnly ); - const bool newDestSchema = (destSchema == 0); - if ( newDestSchema ) { - destSchema = new XMP_Node ( &dest->tree, sourceSchema->name, sourceSchema->value, kXMP_SchemaNode ); - dest->tree.children.push_back ( destSchema ); - } - - // Process the source schema's children. Do this backwards in case deleteEmpty is set. - - for ( long propNum = ((long)sourceSchema->children.size() - 1); propNum >= 0; --propNum ) { - const XMP_Node * sourceProp = sourceSchema->children[propNum]; - if ( doAll || IsExternalProperty ( sourceSchema->name, sourceProp->name ) ) { - AppendSubtree ( sourceProp, destSchema, replaceOld, deleteEmpty ); -// *** RemoveMultiValueInfo ( dest, sourceSchema->name.c_str(), sourceProp->name.c_str() ); - } - } - - if ( destSchema->children.empty() ) { - if ( newDestSchema ) { - delete ( destSchema ); - dest->tree.children.pop_back(); - } else if ( deleteEmpty ) { - DeleteEmptySchema ( destSchema ); - } - } - - } - -} // AppendProperties - - -// ------------------------------------------------------------------------------------------------- // DuplicateSubtree // ---------------- diff --git a/source/XMPCore/XMPUtils.cpp b/source/XMPCore/XMPUtils.cpp index 0cfe497..3729ed1 100644 --- a/source/XMPCore/XMPUtils.cpp +++ b/source/XMPCore/XMPUtils.cpp @@ -1,5 +1,5 @@ // ================================================================================================= -// Copyright 2002-2007 Adobe Systems Incorporated +// Copyright 2003 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms @@ -28,7 +28,6 @@ #pragma warning ( disable : 4996 ) // '...' was declared deprecated #endif - // ================================================================================================= // Local Types and Constants // ========================= @@ -36,30 +35,17 @@ static const char * sBase64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; // ================================================================================================= -// Static Variables -// ================ - -XMP_VarString * sComposedPath = 0; // *** Only really need 1 string. Shrink periodically? -XMP_VarString * sConvertedValue = 0; -XMP_VarString * sBase64Str = 0; -XMP_VarString * sCatenatedItems = 0; -XMP_VarString * sStandardXMP = 0; -XMP_VarString * sExtendedXMP = 0; -XMP_VarString * sExtendedDigest = 0; - -// ================================================================================================= // Local Utilities // =============== - // ------------------------------------------------------------------------------------------------- // ANSI Time Functions // ------------------- // // A bit of hackery to use the best available time functions. Mac and UNIX have thread safe versions -// of gmtime and localtime. On Mac the CodeWarrior functions are buggy, use Apple's. +// of gmtime and localtime. -#if XMP_UNIXBuild +#if XMP_MacBuild | XMP_UNIXBuild typedef time_t ansi_tt; typedef struct tm ansi_tm; @@ -101,69 +87,22 @@ XMP_VarString * sExtendedDigest = 0; } #endif -#elif XMP_MacBuild - - #if ! __MWERKS__ - - typedef time_t ansi_tt; - typedef struct tm ansi_tm; - - #define ansi_time time - #define ansi_mktime mktime - #define ansi_difftime difftime - - #define ansi_gmtime gmtime_r - #define ansi_localtime localtime_r - - #else - - // ! The CW versions are buggy. Use Apple's code, time_t, and "struct tm". - - #include <mach-o/dyld.h> - - typedef _BSD_TIME_T_ ansi_tt; - - typedef struct apple_tm { - int tm_sec; /* seconds after the minute [0-60] */ - int tm_min; /* minutes after the hour [0-59] */ - int tm_hour; /* hours since midnight [0-23] */ - int tm_mday; /* day of the month [1-31] */ - int tm_mon; /* months since January [0-11] */ - int tm_year; /* years since 1900 */ - int tm_wday; /* days since Sunday [0-6] */ - int tm_yday; /* days since January 1 [0-365] */ - int tm_isdst; /* Daylight Savings Time flag */ - long tm_gmtoff; /* offset from CUT in seconds */ - char *tm_zone; /* timezone abbreviation */ - } ansi_tm; - - - typedef ansi_tt (* GetTimeProc) ( ansi_tt * ttTime ); - typedef ansi_tt (* MakeTimeProc) ( ansi_tm * tmTime ); - typedef double (* DiffTimeProc) ( ansi_tt t1, ansi_tt t0 ); - - typedef void (* ConvertTimeProc) ( const ansi_tt * ttTime, ansi_tm * tmTime ); +#endif - static GetTimeProc ansi_time = 0; - static MakeTimeProc ansi_mktime = 0; - static DiffTimeProc ansi_difftime = 0; +// ------------------------------------------------------------------------------------------------- +// VerifyDateTimeFlags +// ------------------- - static ConvertTimeProc ansi_gmtime = 0; - static ConvertTimeProc ansi_localtime = 0; - - static void LookupTimeProcs() - { - _dyld_lookup_and_bind_with_hint ( "_time", "libSystem", (XMP_Uns32*)&ansi_time, 0 ); - _dyld_lookup_and_bind_with_hint ( "_mktime", "libSystem", (XMP_Uns32*)&ansi_mktime, 0 ); - _dyld_lookup_and_bind_with_hint ( "_difftime", "libSystem", (XMP_Uns32*)&ansi_difftime, 0 ); - _dyld_lookup_and_bind_with_hint ( "_gmtime_r", "libSystem", (XMP_Uns32*)&ansi_gmtime, 0 ); - _dyld_lookup_and_bind_with_hint ( "_localtime_r", "libSystem", (XMP_Uns32*)&ansi_localtime, 0 ); - } - - #endif +static void +VerifyDateTimeFlags ( XMP_DateTime * dt ) +{ -#endif + if ( (dt->year != 0) || (dt->month != 0) || (dt->day != 0) ) dt->hasDate = true; + if ( (dt->hour != 0) || (dt->minute != 0) || (dt->second != 0) || (dt->nanoSecond != 0) ) dt->hasTime = true; + if ( (dt->tzSign != 0) || (dt->tzHour != 0) || (dt->tzMinute != 0) ) dt->hasTimeZone = true; + if ( dt->hasTimeZone ) dt->hasTime = true; // ! Don't combine with above line, UTC has zero values. +} // VerifyDateTimeFlags // ------------------------------------------------------------------------------------------------- // IsLeapYear @@ -183,7 +122,6 @@ IsLeapYear ( long year ) } // IsLeapYear - // ------------------------------------------------------------------------------------------------- // DaysInMonth // ----------- @@ -202,7 +140,6 @@ DaysInMonth ( XMP_Int32 year, XMP_Int32 month ) } // DaysInMonth - // ------------------------------------------------------------------------------------------------- // AdjustTimeOverflow // ------------------ @@ -356,7 +293,6 @@ AdjustTimeOverflow ( XMP_DateTime * time ) } // AdjustTimeOverflow - // ------------------------------------------------------------------------------------------------- // GatherInt // --------- @@ -369,6 +305,7 @@ GatherInt ( XMP_StringPtr strValue, size_t * _pos, const char * errMsg ) for ( char ch = strValue[pos]; ('0' <= ch) && (ch <= '9'); ++pos, ch = strValue[pos] ) { value = (value * 10) + (ch - '0'); + if ( value < 0 ) XMP_Throw ( errMsg, kXMPErr_BadValue ); } if ( pos == *_pos ) XMP_Throw ( errMsg, kXMPErr_BadParam ); @@ -377,7 +314,6 @@ GatherInt ( XMP_StringPtr strValue, size_t * _pos, const char * errMsg ) } // GatherInt - // ------------------------------------------------------------------------------------------------- static void FormatFullDateTime ( XMP_DateTime & tempDate, char * buffer, size_t bufferLen ) @@ -410,7 +346,6 @@ static void FormatFullDateTime ( XMP_DateTime & tempDate, char * buffer, size_t } // FormatFullDateTime - // ------------------------------------------------------------------------------------------------- // DecodeBase64Char // ---------------- @@ -450,7 +385,6 @@ DecodeBase64Char ( XMP_Uns8 ch ) } // DecodeBase64Char (); - // ------------------------------------------------------------------------------------------------- // EstimateSizeForJPEG // ------------------- @@ -497,7 +431,6 @@ EstimateSizeForJPEG ( const XMP_Node * xmpNode ) } // EstimateSizeForJPEG - // ------------------------------------------------------------------------------------------------- // MoveOneProperty // --------------- @@ -529,7 +462,6 @@ static bool MoveOneProperty ( XMPMeta & stdXMP, XMPMeta * extXMP, } // MoveOneProperty - // ------------------------------------------------------------------------------------------------- // CreateEstimatedSizeMap // ---------------------- @@ -572,7 +504,6 @@ static void CreateEstimatedSizeMap ( XMPMeta & stdXMP, PropSizeMap * propSizes ) } // CreateEstimatedSizeMap - // ------------------------------------------------------------------------------------------------- // MoveLargestProperty // ------------------- @@ -608,12 +539,10 @@ static size_t MoveLargestProperty ( XMPMeta & stdXMP, XMPMeta * extXMP, PropSize } // MoveLargestProperty - // ================================================================================================= // Class Static Functions // ====================== - // ------------------------------------------------------------------------------------------------- // Initialize // ---------- @@ -621,58 +550,25 @@ static size_t MoveLargestProperty ( XMPMeta & stdXMP, XMPMeta * extXMP, PropSize /* class static */ bool XMPUtils::Initialize() { - sComposedPath = new XMP_VarString(); - sConvertedValue = new XMP_VarString(); - sBase64Str = new XMP_VarString(); - sCatenatedItems = new XMP_VarString(); - sStandardXMP = new XMP_VarString(); - sExtendedXMP = new XMP_VarString(); - sExtendedDigest = new XMP_VarString(); - - #if XMP_MacBuild && __MWERKS__ - LookupTimeProcs(); - #endif + // Nothing at present. return true; } // Initialize - // ------------------------------------------------------------------------------------------------- // Terminate // --------- -#define EliminateGlobal(g) delete ( g ); g = 0 - /* class static */ void XMPUtils::Terminate() RELEASE_NO_THROW { - EliminateGlobal ( sComposedPath ); - EliminateGlobal ( sConvertedValue ); - EliminateGlobal ( sBase64Str ); - EliminateGlobal ( sCatenatedItems ); - EliminateGlobal ( sStandardXMP ); - EliminateGlobal ( sExtendedXMP ); - EliminateGlobal ( sExtendedDigest ); + // Nothing at present. return; } // Terminate - -// ------------------------------------------------------------------------------------------------- -// Unlock -// ------ - -/* class static */ void -XMPUtils::Unlock ( XMP_OptionBits options ) -{ - options = options; // Avoid unused parameter warning. - - XMPMeta::Unlock ( 0 ); - -} // Unlock - // ------------------------------------------------------------------------------------------------- // ComposeArrayItemPath // -------------------- @@ -683,12 +579,11 @@ XMPUtils::Unlock ( XMP_OptionBits options ) XMPUtils::ComposeArrayItemPath ( XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ) + XMP_VarString * _fullPath ) { XMP_Assert ( schemaNS != 0 ); // Enforced by wrapper. - XMP_Assert ( *arrayName != 0 ); // Enforced by wrapper. - XMP_Assert ( (fullPath != 0) && (pathSize != 0) ); // Enforced by wrapper. + XMP_Assert ( (arrayName != 0) && (*arrayName != 0) ); // Enforced by wrapper. + XMP_Assert ( _fullPath != 0 ); // Enforced by wrapper. XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path. ExpandXPath ( schemaNS, arrayName, &expPath ); @@ -697,27 +592,23 @@ XMPUtils::ComposeArrayItemPath ( XMP_StringPtr schemaNS, XMP_StringLen reserveLen = strlen(arrayName) + 2 + 32; // Room plus padding. - sComposedPath->erase(); - sComposedPath->reserve ( reserveLen ); - sComposedPath->append ( reserveLen, ' ' ); + XMP_VarString fullPath; // ! Allow for arrayName to be the incoming _fullPath.c_str(). + fullPath.reserve ( reserveLen ); + fullPath = arrayName; - if ( itemIndex != kXMP_ArrayLastItem ) { - // AUDIT: Using string->size() for the snprintf length is safe. - snprintf ( const_cast<char*>(sComposedPath->c_str()), sComposedPath->size(), "%s[%d]", arrayName, itemIndex ); + if ( itemIndex == kXMP_ArrayLastItem ) { + fullPath += "[last()]"; } else { - *sComposedPath = arrayName; - *sComposedPath += "[last()] "; - (*sComposedPath)[sComposedPath->size()-1] = 0; // ! Final null is for the strlen at exit. + // AUDIT: Using sizeof(buffer) for the snprintf length is safe. + char buffer [32]; // A 32 byte buffer is plenty, even for a 64-bit integer. + snprintf ( buffer, sizeof(buffer), "[%d]", itemIndex ); + fullPath += buffer; } - *fullPath = sComposedPath->c_str(); - *pathSize = strlen ( *fullPath ); // ! Don't use sComposedPath->size()! - - XMP_Enforce ( *pathSize < sComposedPath->size() ); // Rather late, but complain about buffer overflow. + *_fullPath = fullPath; } // ComposeArrayItemPath - // ------------------------------------------------------------------------------------------------- // ComposeStructFieldPath // ---------------------- @@ -729,12 +620,12 @@ XMPUtils::ComposeStructFieldPath ( XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ) + XMP_VarString * _fullPath ) { XMP_Assert ( (schemaNS != 0) && (fieldNS != 0) ); // Enforced by wrapper. - XMP_Assert ( (*structName != 0) && (*fieldName != 0) ); // Enforced by wrapper. - XMP_Assert ( (fullPath != 0) && (pathSize != 0) ); // Enforced by wrapper. + XMP_Assert ( (structName != 0) && (*structName != 0) ); // Enforced by wrapper. + XMP_Assert ( (fieldName != 0) && (*fieldName != 0) ); // Enforced by wrapper. + XMP_Assert ( _fullPath != 0 ); // Enforced by wrapper. XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path. ExpandXPath ( schemaNS, structName, &expPath ); @@ -745,18 +636,16 @@ XMPUtils::ComposeStructFieldPath ( XMP_StringPtr schemaNS, XMP_StringLen reserveLen = strlen(structName) + fieldPath[kRootPropStep].step.size() + 1; - sComposedPath->erase(); - sComposedPath->reserve ( reserveLen ); - *sComposedPath = structName; - *sComposedPath += '/'; - *sComposedPath += fieldPath[kRootPropStep].step; + XMP_VarString fullPath; // ! Allow for arrayName to be the incoming _fullPath.c_str(). + fullPath.reserve ( reserveLen ); + fullPath = structName; + fullPath += '/'; + fullPath += fieldPath[kRootPropStep].step; - *fullPath = sComposedPath->c_str(); - *pathSize = sComposedPath->size(); + *_fullPath = fullPath; } // ComposeStructFieldPath - // ------------------------------------------------------------------------------------------------- // ComposeQualifierPath // -------------------- @@ -768,12 +657,12 @@ XMPUtils::ComposeQualifierPath ( XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, XMP_StringPtr qualName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ) + XMP_VarString * _fullPath ) { - XMP_Assert ( (schemaNS != 0) && (qualNS != 0) ); // Enforced by wrapper. - XMP_Assert ( (*propName != 0) && (*qualName != 0) ); // Enforced by wrapper. - XMP_Assert ( (fullPath != 0) && (pathSize != 0) ); // Enforced by wrapper. + XMP_Assert ( (schemaNS != 0) && (qualNS != 0) ); // Enforced by wrapper. + XMP_Assert ( (propName != 0) && (*propName != 0) ); // Enforced by wrapper. + XMP_Assert ( (qualName != 0) && (*qualName != 0) ); // Enforced by wrapper. + XMP_Assert ( _fullPath != 0 ); // Enforced by wrapper. XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path. ExpandXPath ( schemaNS, propName, &expPath ); @@ -784,18 +673,16 @@ XMPUtils::ComposeQualifierPath ( XMP_StringPtr schemaNS, XMP_StringLen reserveLen = strlen(propName) + qualPath[kRootPropStep].step.size() + 2; - sComposedPath->erase(); - sComposedPath->reserve ( reserveLen ); - *sComposedPath = propName; - *sComposedPath += "/?"; - *sComposedPath += qualPath[kRootPropStep].step; + XMP_VarString fullPath; // ! Allow for arrayName to be the incoming _fullPath.c_str(). + fullPath.reserve ( reserveLen ); + fullPath = propName; + fullPath += "/?"; + fullPath += qualPath[kRootPropStep].step; - *fullPath = sComposedPath->c_str(); - *pathSize = sComposedPath->size(); + *_fullPath = fullPath; } // ComposeQualifierPath - // ------------------------------------------------------------------------------------------------- // ComposeLangSelector // ------------------- @@ -808,12 +695,12 @@ XMPUtils::ComposeQualifierPath ( XMP_StringPtr schemaNS, XMPUtils::ComposeLangSelector ( XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_StringPtr _langName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ) + XMP_VarString * _fullPath ) { XMP_Assert ( schemaNS != 0 ); // Enforced by wrapper. - XMP_Assert ( (*arrayName != 0) && (*_langName != 0) ); // Enforced by wrapper. - XMP_Assert ( (fullPath != 0) && (pathSize != 0) ); // Enforced by wrapper. + XMP_Assert ( (arrayName != 0) && (*arrayName != 0) ); // Enforced by wrapper. + XMP_Assert ( (_langName != 0) && (*_langName != 0) ); // Enforced by wrapper. + XMP_Assert ( _fullPath != 0 ); // Enforced by wrapper. XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path. ExpandXPath ( schemaNS, arrayName, &expPath ); @@ -823,19 +710,17 @@ XMPUtils::ComposeLangSelector ( XMP_StringPtr schemaNS, XMP_StringLen reserveLen = strlen(arrayName) + langName.size() + 14; - sComposedPath->erase(); - sComposedPath->reserve ( reserveLen ); - *sComposedPath = arrayName; - *sComposedPath += "[?xml:lang=\""; - *sComposedPath += langName; - *sComposedPath += "\"]"; + XMP_VarString fullPath; // ! Allow for arrayName to be the incoming _fullPath.c_str(). + fullPath.reserve ( reserveLen ); + fullPath = arrayName; + fullPath += "[?xml:lang=\""; + fullPath += langName; + fullPath += "\"]"; - *fullPath = sComposedPath->c_str(); - *pathSize = sComposedPath->size(); + *_fullPath = fullPath; } // ComposeLangSelector - // ------------------------------------------------------------------------------------------------- // ComposeFieldSelector // -------------------- @@ -850,12 +735,11 @@ XMPUtils::ComposeFieldSelector ( XMP_StringPtr schemaNS, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, XMP_StringPtr fieldValue, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ) + XMP_VarString * _fullPath ) { XMP_Assert ( (schemaNS != 0) && (fieldNS != 0) && (fieldValue != 0) ); // Enforced by wrapper. XMP_Assert ( (*arrayName != 0) && (*fieldName != 0) ); // Enforced by wrapper. - XMP_Assert ( (fullPath != 0) && (pathSize != 0) ); // Enforced by wrapper. + XMP_Assert ( _fullPath != 0 ); // Enforced by wrapper. XMP_ExpandedXPath expPath; // Just for side effects to check namespace and basic path. ExpandXPath ( schemaNS, arrayName, &expPath ); @@ -866,43 +750,37 @@ XMPUtils::ComposeFieldSelector ( XMP_StringPtr schemaNS, XMP_StringLen reserveLen = strlen(arrayName) + fieldPath[kRootPropStep].step.size() + strlen(fieldValue) + 5; - sComposedPath->erase(); - sComposedPath->reserve ( reserveLen ); - *sComposedPath = arrayName; - *sComposedPath += '['; - *sComposedPath += fieldPath[kRootPropStep].step; - *sComposedPath += "=\""; - *sComposedPath += fieldValue; - *sComposedPath += "\"]"; + XMP_VarString fullPath; // ! Allow for arrayName to be the incoming _fullPath.c_str(). + fullPath.reserve ( reserveLen ); + fullPath = arrayName; + fullPath += '['; + fullPath += fieldPath[kRootPropStep].step; + fullPath += "=\""; + fullPath += fieldValue; + fullPath += "\"]"; - *fullPath = sComposedPath->c_str(); - *pathSize = sComposedPath->size(); + *_fullPath = fullPath; } // ComposeFieldSelector - // ------------------------------------------------------------------------------------------------- // ConvertFromBool // --------------- /* class static */ void XMPUtils::ConvertFromBool ( bool binValue, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ) + XMP_VarString * strValue ) { - XMP_Assert ( (strValue != 0) && (strSize != 0) ); // Enforced by wrapper. + XMP_Assert ( strValue != 0 ); // Enforced by wrapper. if ( binValue ) { *strValue = kXMP_TrueStr; - *strSize = strlen ( kXMP_TrueStr ); } else { *strValue = kXMP_FalseStr; - *strSize = strlen ( kXMP_FalseStr ); } } // ConvertFromBool - // ------------------------------------------------------------------------------------------------- // ConvertFromInt // -------------- @@ -910,28 +788,21 @@ XMPUtils::ConvertFromBool ( bool binValue, /* class static */ void XMPUtils::ConvertFromInt ( XMP_Int32 binValue, XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ) + XMP_VarString * strValue ) { - XMP_Assert ( (format != 0) && (strValue != 0) && (strSize != 0) ); // Enforced by wrapper. + XMP_Assert ( (format != 0) && (strValue != 0) ); // Enforced by wrapper. + strValue->erase(); if ( *format == 0 ) format = "%d"; - sConvertedValue->erase(); - sConvertedValue->reserve ( 100 ); // More than enough for any reasonable format and value. - sConvertedValue->append ( 100, ' ' ); + // AUDIT: Using sizeof(buffer) for the snprintf length is safe. + char buffer [32]; // Big enough for a 64-bit integer; + snprintf ( buffer, sizeof(buffer), format, binValue ); - // AUDIT: Using string->size() for the snprintf length is safe. - snprintf ( const_cast<char*>(sConvertedValue->c_str()), sConvertedValue->size(), format, binValue ); - - *strValue = sConvertedValue->c_str(); - *strSize = strlen ( *strValue ); // ! Don't use sConvertedValue->size()! - - XMP_Enforce ( *strSize < sConvertedValue->size() ); // Rather late, but complain about buffer overflow. + *strValue = buffer; } // ConvertFromInt - // ------------------------------------------------------------------------------------------------- // ConvertFromInt64 // ---------------- @@ -939,28 +810,21 @@ XMPUtils::ConvertFromInt ( XMP_Int32 binValue, /* class static */ void XMPUtils::ConvertFromInt64 ( XMP_Int64 binValue, XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ) + XMP_VarString * strValue ) { - XMP_Assert ( (format != 0) && (strValue != 0) && (strSize != 0) ); // Enforced by wrapper. + XMP_Assert ( (format != 0) && (strValue != 0) ); // Enforced by wrapper. + strValue->erase(); if ( *format == 0 ) format = "%lld"; - sConvertedValue->erase(); - sConvertedValue->reserve ( 100 ); // More than enough for any reasonable format and value. - sConvertedValue->append ( 100, ' ' ); - - // AUDIT: Using string->size() for the snprintf length is safe. - snprintf ( const_cast<char*>(sConvertedValue->c_str()), sConvertedValue->size(), format, binValue ); + // AUDIT: Using sizeof(buffer) for the snprintf length is safe. + char buffer [32]; // Big enough for a 64-bit integer; + snprintf ( buffer, sizeof(buffer), format, binValue ); - *strValue = sConvertedValue->c_str(); - *strSize = strlen ( *strValue ); // ! Don't use sConvertedValue->size()! - - XMP_Enforce ( *strSize < sConvertedValue->size() ); // Rather late, but complain about buffer overflow. + *strValue = buffer; } // ConvertFromInt64 - // ------------------------------------------------------------------------------------------------- // ConvertFromFloat // ---------------- @@ -968,33 +832,26 @@ XMPUtils::ConvertFromInt64 ( XMP_Int64 binValue, /* class static */ void XMPUtils::ConvertFromFloat ( double binValue, XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ) + XMP_VarString * strValue ) { - XMP_Assert ( (format != 0) && (strValue != 0) && (strSize != 0) ); // Enforced by wrapper. + XMP_Assert ( (format != 0) && (strValue != 0) ); // Enforced by wrapper. + strValue->erase(); if ( *format == 0 ) format = "%f"; - sConvertedValue->erase(); - sConvertedValue->reserve ( 1000 ); // More than enough for any reasonable format and value. - sConvertedValue->append ( 1000, ' ' ); + // AUDIT: Using sizeof(buffer) for the snprintf length is safe. + char buffer [64]; // Ought to be plenty big enough. + snprintf ( buffer, sizeof(buffer), format, binValue ); - // AUDIT: Using string->size() for the snprintf length is safe. - snprintf ( const_cast<char*>(sConvertedValue->c_str()), sConvertedValue->size(), format, binValue ); - - *strValue = sConvertedValue->c_str(); - *strSize = strlen ( *strValue ); // ! Don't use sConvertedValue->size()! - - XMP_Enforce ( *strSize < sConvertedValue->size() ); // Rather late, but complain about buffer overflow. + *strValue = buffer; } // ConvertFromFloat - // ------------------------------------------------------------------------------------------------- // ConvertFromDate // --------------- // -// Format a date according to ISO 8601 and http://www.w3.org/TR/NOTE-datetime: +// Format a date-time string according to ISO 8601 and http://www.w3.org/TR/NOTE-datetime: // YYYY // YYYY-MM // YYYY-MM-DD @@ -1012,18 +869,16 @@ XMPUtils::ConvertFromFloat ( double binValue, // TZD = time zone designator (Z or +hh:mm or -hh:mm) // // Note that ISO 8601 does not seem to allow years less than 1000 or greater than 9999. We allow -// any year, even negative ones. The year is formatted as "%.4d". - -// *** Need to check backward compatibility for partial forms! +// any year, even negative ones. The year is formatted as "%.4d". The TZD is also optional in XMP, +// even though required in the W3C profile. Finally, Photoshop 8 (CS) sometimes created time-only +// values so we tolerate that. /* class static */ void -XMPUtils::ConvertFromDate ( const XMP_DateTime & binValue, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ) +XMPUtils::ConvertFromDate ( const XMP_DateTime & _inValue, + XMP_VarString * strValue ) { - XMP_Assert ( (strValue != 0) && (strSize != 0) ); // Enforced by wrapper. + XMP_Assert ( strValue != 0 ); // Enforced by wrapper. - bool addTimeZone = false; char buffer [100]; // Plenty long enough. // Pick the format, use snprintf to format into a local buffer, assign to static output string. @@ -1031,101 +886,82 @@ XMPUtils::ConvertFromDate ( const XMP_DateTime & binValue, // ! Photoshop 8 creates "time only" values with zeros for year, month, and day. - XMP_DateTime tempDate = binValue; + XMP_DateTime binValue = _inValue; + VerifyDateTimeFlags ( &binValue ); // Temporary fix for bug 1269463, silently fix out of range month or day. - bool haveDay = (tempDate.day != 0); - bool haveTime = ( (tempDate.hour != 0) || (tempDate.minute != 0) || - (tempDate.second != 0) || (tempDate.nanoSecond != 0) || - (tempDate.tzSign != 0) || (tempDate.tzHour != 0) || (tempDate.tzMinute != 0) ); - - if ( tempDate.month == 0 ) { - if ( haveDay || haveTime ) tempDate.month = 1; + if ( binValue.month == 0 ) { + if ( (binValue.day != 0) || binValue.hasTime ) binValue.month = 1; } else { - if ( tempDate.month < 1 ) tempDate.month = 1; - if ( tempDate.month > 12 ) tempDate.month = 12; + if ( binValue.month < 1 ) binValue.month = 1; + if ( binValue.month > 12 ) binValue.month = 12; } - if ( tempDate.day == 0 ) { - if ( haveTime ) tempDate.day = 1; + if ( binValue.day == 0 ) { + if ( binValue.hasTime ) binValue.day = 1; } else { - if ( tempDate.day < 1 ) tempDate.day = 1; - if ( tempDate.day > 31 ) tempDate.day = 31; + if ( binValue.day < 1 ) binValue.day = 1; + if ( binValue.day > 31 ) binValue.day = 31; } // Now carry on with the original logic. - if ( tempDate.month == 0 ) { + if ( binValue.month == 0 ) { // Output YYYY if all else is zero, otherwise output a full string for the quasi-bogus // "time only" values from Photoshop CS. - if ( (tempDate.day == 0) && (tempDate.hour == 0) && (tempDate.minute == 0) && - (tempDate.second == 0) && (tempDate.nanoSecond == 0) && - (tempDate.tzSign == 0) && (tempDate.tzHour == 0) && (tempDate.tzMinute == 0) ) { - snprintf ( buffer, sizeof(buffer), "%.4d", tempDate.year ); // AUDIT: Using sizeof for snprintf length is safe. - } else if ( (tempDate.year == 0) && (tempDate.day == 0) ) { - FormatFullDateTime ( tempDate, buffer, sizeof(buffer) ); - addTimeZone = true; + if ( (binValue.day == 0) && (! binValue.hasTime) ) { + snprintf ( buffer, sizeof(buffer), "%.4d", binValue.year ); // AUDIT: Using sizeof for snprintf length is safe. + } else if ( (binValue.year == 0) && (binValue.day == 0) ) { + FormatFullDateTime ( binValue, buffer, sizeof(buffer) ); } else { XMP_Throw ( "Invalid partial date", kXMPErr_BadParam); } - } else if ( tempDate.day == 0 ) { + } else if ( binValue.day == 0 ) { // Output YYYY-MM. - if ( (tempDate.month < 1) || (tempDate.month > 12) ) XMP_Throw ( "Month is out of range", kXMPErr_BadParam); - if ( (tempDate.hour != 0) || (tempDate.minute != 0) || - (tempDate.second != 0) || (tempDate.nanoSecond != 0) || - (tempDate.tzSign != 0) || (tempDate.tzHour != 0) || (tempDate.tzMinute != 0) ) { - XMP_Throw ( "Invalid partial date, non-zeros after zero month and day", kXMPErr_BadParam); - } - snprintf ( buffer, sizeof(buffer), "%.4d-%02d", tempDate.year, tempDate.month ); // AUDIT: Using sizeof for snprintf length is safe. + if ( (binValue.month < 1) || (binValue.month > 12) ) XMP_Throw ( "Month is out of range", kXMPErr_BadParam); + if ( binValue.hasTime ) XMP_Throw ( "Invalid partial date, non-zeros after zero month and day", kXMPErr_BadParam); + snprintf ( buffer, sizeof(buffer), "%.4d-%02d", binValue.year, binValue.month ); // AUDIT: Using sizeof for snprintf length is safe. - } else if ( (tempDate.hour == 0) && (tempDate.minute == 0) && - (tempDate.second == 0) && (tempDate.nanoSecond == 0) && - (tempDate.tzSign == 0) && (tempDate.tzHour == 0) && (tempDate.tzMinute == 0) ) { + } else if ( ! binValue.hasTime ) { // Output YYYY-MM-DD. - if ( (tempDate.month < 1) || (tempDate.month > 12) ) XMP_Throw ( "Month is out of range", kXMPErr_BadParam); - if ( (tempDate.day < 1) || (tempDate.day > 31) ) XMP_Throw ( "Day is out of range", kXMPErr_BadParam); - snprintf ( buffer, sizeof(buffer), "%.4d-%02d-%02d", tempDate.year, tempDate.month, tempDate.day ); // AUDIT: Using sizeof for snprintf length is safe. + if ( (binValue.month < 1) || (binValue.month > 12) ) XMP_Throw ( "Month is out of range", kXMPErr_BadParam); + if ( (binValue.day < 1) || (binValue.day > 31) ) XMP_Throw ( "Day is out of range", kXMPErr_BadParam); + snprintf ( buffer, sizeof(buffer), "%.4d-%02d-%02d", binValue.year, binValue.month, binValue.day ); // AUDIT: Using sizeof for snprintf length is safe. } else { - FormatFullDateTime ( tempDate, buffer, sizeof(buffer) ); - addTimeZone = true; + FormatFullDateTime ( binValue, buffer, sizeof(buffer) ); } - sConvertedValue->assign ( buffer ); + strValue->assign ( buffer ); - if ( addTimeZone ) { + if ( binValue.hasTimeZone ) { - if ( (tempDate.tzHour < 0) || (tempDate.tzHour > 23) || - (tempDate.tzMinute < 0 ) || (tempDate.tzMinute > 59) || - (tempDate.tzSign < -1) || (tempDate.tzSign > +1) || - ((tempDate.tzSign != 0) && (tempDate.tzHour == 0) && (tempDate.tzMinute == 0)) || - ((tempDate.tzSign == 0) && ((tempDate.tzHour != 0) || (tempDate.tzMinute != 0))) ) { + if ( (binValue.tzHour < 0) || (binValue.tzHour > 23) || + (binValue.tzMinute < 0 ) || (binValue.tzMinute > 59) || + (binValue.tzSign < -1) || (binValue.tzSign > +1) || + ((binValue.tzSign == 0) && ((binValue.tzHour != 0) || (binValue.tzMinute != 0))) ) { XMP_Throw ( "Invalid time zone values", kXMPErr_BadParam ); } - if ( tempDate.tzSign == 0 ) { - *sConvertedValue += 'Z'; + if ( binValue.tzSign == 0 ) { + *strValue += 'Z'; } else { - snprintf ( buffer, sizeof(buffer), "+%02d:%02d", tempDate.tzHour, tempDate.tzMinute ); // AUDIT: Using sizeof for snprintf length is safe. - if ( tempDate.tzSign < 0 ) buffer[0] = '-'; - *sConvertedValue += buffer; + snprintf ( buffer, sizeof(buffer), "+%02d:%02d", binValue.tzHour, binValue.tzMinute ); // AUDIT: Using sizeof for snprintf length is safe. + if ( binValue.tzSign < 0 ) buffer[0] = '-'; + *strValue += buffer; } } - *strValue = sConvertedValue->c_str(); - *strSize = sConvertedValue->size(); - } // ConvertFromDate - // ------------------------------------------------------------------------------------------------- // ConvertToBool // ------------- @@ -1157,7 +993,6 @@ XMPUtils::ConvertToBool ( XMP_StringPtr strValue ) } // ConvertToBool - // ------------------------------------------------------------------------------------------------- // ConvertToInt // ------------ @@ -1183,7 +1018,6 @@ XMPUtils::ConvertToInt ( XMP_StringPtr strValue ) } // ConvertToInt - // ------------------------------------------------------------------------------------------------- // ConvertToInt64 // -------------- @@ -1209,7 +1043,6 @@ XMPUtils::ConvertToInt64 ( XMP_StringPtr strValue ) } // ConvertToInt64 - // ------------------------------------------------------------------------------------------------- // ConvertToFloat // -------------- @@ -1237,12 +1070,11 @@ XMPUtils::ConvertToFloat ( XMP_StringPtr strValue ) } // ConvertToFloat - // ------------------------------------------------------------------------------------------------- // ConvertToDate // ------------- // -// Parse a date according to ISO 8601 and http://www.w3.org/TR/NOTE-datetime: +// Parse a date-time string according to ISO 8601 and http://www.w3.org/TR/NOTE-datetime: // YYYY // YYYY-MM // YYYY-MM-DD @@ -1260,10 +1092,9 @@ XMPUtils::ConvertToFloat ( XMP_StringPtr strValue ) // TZD = time zone designator (Z or +hh:mm or -hh:mm) // // Note that ISO 8601 does not seem to allow years less than 1000 or greater than 9999. We allow -// any year, even negative ones. The year is formatted as "%.4d". - -// ! Tolerate missing TZD, assume is UTC. Photoshop 8 writes dates like this for exif:GPSTimeStamp. -// ! Tolerate missing date portion, in case someone foolishly writes a time-only value that way. +// any year, even negative ones. The year is formatted as "%.4d". The TZD is also optional in XMP, +// even though required in the W3C profile. Finally, Photoshop 8 (CS) sometimes created time-only +// values so we tolerate that. // *** Put the ISO format comments in the header documentation. @@ -1273,18 +1104,21 @@ XMPUtils::ConvertToDate ( XMP_StringPtr strValue, { if ( (strValue == 0) || (*strValue == 0) ) XMP_Throw ( "Empty convert-from string", kXMPErr_BadValue); - size_t pos = 0; + size_t pos = 0; XMP_Int32 temp; XMP_Assert ( sizeof(*binValue) == sizeof(XMP_DateTime) ); (void) memset ( binValue, 0, sizeof(*binValue) ); // AUDIT: Safe, using sizeof destination. + size_t strSize = strlen ( strValue ); bool timeOnly = ( (strValue[0] == 'T') || - ((strlen(strValue) >= 2) && (strValue[1] == ':')) || - ((strlen(strValue) >= 3) && (strValue[2] == ':')) ); + ((strSize >= 2) && (strValue[1] == ':')) || + ((strSize >= 3) && (strValue[2] == ':')) ); if ( ! timeOnly ) { - + + binValue->hasDate = true; + if ( strValue[0] == '-' ) pos = 1; temp = GatherInt ( strValue, &pos, "Invalid year in date string" ); // Extract the year. @@ -1318,12 +1152,16 @@ XMPUtils::ConvertToDate ( XMP_StringPtr strValue, } + // If we get here there is more of the string, otherwise we would have returned above. + if ( strValue[pos] == 'T' ) { ++pos; } else if ( ! timeOnly ) { XMP_Throw ( "Invalid date string, missing 'T' after date", kXMPErr_BadParam ); } + binValue->hasTime = true; + temp = GatherInt ( strValue, &pos, "Invalid hour in date string" ); // Extract the hour. if ( strValue[pos] != ':' ) XMP_Throw ( "Invalid date string, after hour", kXMPErr_BadParam ); if ( temp > 23 ) temp = 23; // *** 1269463: XMP_Throw ( "Hour is out of range", kXMPErr_BadParam ); @@ -1372,11 +1210,15 @@ XMPUtils::ConvertToDate ( XMP_StringPtr strValue, } + if ( strValue[pos] == 0 ) return; + + binValue->hasTimeZone = true; + if ( strValue[pos] == 'Z' ) { ++pos; - } else if ( strValue[pos] != 0 ) { + } else { if ( strValue[pos] == '+' ) { binValue->tzSign = kXMP_TimeEastOfUTC; @@ -1403,7 +1245,6 @@ XMPUtils::ConvertToDate ( XMP_StringPtr strValue, } // ConvertToDate - // ------------------------------------------------------------------------------------------------- // EncodeToBase64 // -------------- @@ -1415,15 +1256,13 @@ XMPUtils::ConvertToDate ( XMP_StringPtr strValue, /* class static */ void XMPUtils::EncodeToBase64 ( XMP_StringPtr rawStr, XMP_StringLen rawLen, - XMP_StringPtr * encodedStr, - XMP_StringLen * encodedLen ) + XMP_VarString * encodedStr ) { if ( (rawStr == 0) && (rawLen != 0) ) XMP_Throw ( "Null raw data buffer", kXMPErr_BadParam ); - if ( rawLen == 0 ) { - *encodedStr = 0; - *encodedLen = 0; - return; - } + XMP_Assert ( encodedStr != 0 ); // Enforced by wrapper. + + encodedStr->erase(); + if ( rawLen == 0 ) return; char encChunk[4]; @@ -1433,8 +1272,7 @@ XMPUtils::EncodeToBase64 ( XMP_StringPtr rawStr, const size_t outputSize = (rawLen / 3) * 4; // Approximate, might be small. - sBase64Str->erase(); - sBase64Str->reserve ( outputSize ); + encodedStr->reserve ( outputSize ); // ---------------------------------------------------------------------------------------- // Each 6 bits of input produces 8 bits of output, so 3 input bytes become 4 output bytes. @@ -1455,10 +1293,10 @@ XMPUtils::EncodeToBase64 ( XMP_StringPtr rawStr, encChunk[3] = sBase64Chars [ merge & 0x3F ]; if ( out >= 76 ) { - sBase64Str->append ( 1, kLF ); + encodedStr->append ( 1, kLF ); out = 0; } - sBase64Str->append ( encChunk, 4 ); + encodedStr->append ( encChunk, 4 ); } @@ -1481,8 +1319,8 @@ XMPUtils::EncodeToBase64 ( XMP_StringPtr rawStr, encChunk[1] = sBase64Chars [ (merge >> 12) & 0x3F ]; encChunk[2] = encChunk[3] = '='; - if ( out >= 76 ) sBase64Str->append ( 1, kLF ); - sBase64Str->append ( encChunk, 4 ); + if ( out >= 76 ) encodedStr->append ( 1, kLF ); + encodedStr->append ( encChunk, 4 ); break; case 2: // Two input bytes remain. @@ -1496,21 +1334,14 @@ XMPUtils::EncodeToBase64 ( XMP_StringPtr rawStr, encChunk[2] = sBase64Chars [ (merge >> 6) & 0x3F ]; encChunk[3] = '='; - if ( out >= 76 ) sBase64Str->append ( 1, kLF ); - sBase64Str->append ( encChunk, 4 ); + if ( out >= 76 ) encodedStr->append ( 1, kLF ); + encodedStr->append ( encChunk, 4 ); break; } - - // ------------------------- - // Assign the output values. - - *encodedStr = sBase64Str->c_str(); - *encodedLen = sBase64Str->size(); } // EncodeToBase64 - // ------------------------------------------------------------------------------------------------- // DecodeFromBase64 // ---------------- @@ -1523,23 +1354,20 @@ XMPUtils::EncodeToBase64 ( XMP_StringPtr rawStr, /* class static */ void XMPUtils::DecodeFromBase64 ( XMP_StringPtr encodedStr, XMP_StringLen encodedLen, - XMP_StringPtr * rawStr, - XMP_StringLen * rawLen ) + XMP_VarString * rawStr ) { if ( (encodedStr == 0) && (encodedLen != 0) ) XMP_Throw ( "Null encoded data buffer", kXMPErr_BadParam ); - if ( encodedLen == 0 ) { - *rawStr = 0; - *rawLen = 0; - return; - } + XMP_Assert ( rawStr != 0 ); // Enforced by wrapper. + + rawStr->erase(); + if ( encodedLen == 0 ) return; unsigned char ch, rawChunk[3]; unsigned long inStr, inChunk, inLimit, merge, padding; XMP_StringLen outputSize = (encodedLen / 4) * 3; // Only a close approximation. - sBase64Str->erase(); - sBase64Str->reserve ( outputSize ); + rawStr->reserve ( outputSize ); // ---------------------------------------------------------------------------------------- @@ -1589,7 +1417,7 @@ XMPUtils::DecodeFromBase64 ( XMP_StringPtr encodedStr, rawChunk[1] = (unsigned char) ((merge >> 8) & 0xFF); rawChunk[2] = (unsigned char) (merge & 0xFF); - sBase64Str->append ( (char*)rawChunk, 3 ); + rawStr->append ( (char*)rawChunk, 3 ); } @@ -1611,69 +1439,58 @@ XMPUtils::DecodeFromBase64 ( XMP_StringPtr encodedStr, if ( padding == 2 ) { rawChunk[0] = (unsigned char) (merge >> 4); - sBase64Str->append ( (char*)rawChunk, 1 ); + rawStr->append ( (char*)rawChunk, 1 ); } else if ( padding == 1 ) { rawChunk[0] = (unsigned char) (merge >> 10); rawChunk[1] = (unsigned char) ((merge >> 2) & 0xFF); - sBase64Str->append ( (char*)rawChunk, 2 ); + rawStr->append ( (char*)rawChunk, 2 ); } else { rawChunk[0] = (unsigned char) (merge >> 16); rawChunk[1] = (unsigned char) ((merge >> 8) & 0xFF); rawChunk[2] = (unsigned char) (merge & 0xFF); - sBase64Str->append ( (char*)rawChunk, 3 ); + rawStr->append ( (char*)rawChunk, 3 ); } - - // ------------------------- - // Assign the output values. - - *rawStr = sBase64Str->c_str(); - *rawLen = sBase64Str->size(); } // DecodeFromBase64 - // ------------------------------------------------------------------------------------------------- // PackageForJPEG // -------------- /* class static */ void XMPUtils::PackageForJPEG ( const XMPMeta & origXMP, - XMP_StringPtr * stdStr, - XMP_StringLen * stdLen, - XMP_StringPtr * extStr, - XMP_StringLen * extLen, - XMP_StringPtr * digestStr, - XMP_StringLen * digestLen ) + XMP_VarString * stdStr, + XMP_VarString * extStr, + XMP_VarString * digestStr ) { + XMP_Assert ( (stdStr != 0) && (extStr != 0) && (digestStr != 0) ); // ! Enforced by wrapper. + enum { kStdXMPLimit = 65000 }; static const char * kPacketTrailer = "<?xpacket end=\"w\"?>"; static size_t kTrailerLen = strlen ( kPacketTrailer ); - XMP_StringPtr tempStr; - XMP_StringLen tempLen; - + XMP_VarString tempStr; XMPMeta stdXMP, extXMP; - - sStandardXMP->clear(); // Clear the static strings that get returned to the client. - sExtendedXMP->clear(); - sExtendedDigest->clear(); - XMP_OptionBits keepItSmall = kXMP_UseCompactFormat | kXMP_OmitAllFormatting; + stdStr->erase(); + extStr->erase(); + digestStr->erase(); + // Try to serialize everything. Note that we're making internal calls to SerializeToBuffer, so // we'll be getting back the pointer and length for its internal string. - origXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 ); + origXMP.SerializeToBuffer ( &tempStr, keepItSmall, 1, "", "", 0 ); #if Trace_PackageForJPEG - printf ( "\nXMPUtils::PackageForJPEG - Full serialize %d bytes\n", tempLen ); + printf ( "\nXMPUtils::PackageForJPEG - Full serialize %d bytes\n", tempStr.size() ); #endif - if ( tempLen > kStdXMPLimit ) { + if ( tempStr.size() > kStdXMPLimit ) { // Couldn't fit everything, make a copy of the input XMP and make sure there is no xmp:Thumbnails property. @@ -1684,15 +1501,15 @@ XMPUtils::PackageForJPEG ( const XMPMeta & origXMP, if ( stdXMP.DoesPropertyExist ( kXMP_NS_XMP, "Thumbnails" ) ) { stdXMP.DeleteProperty ( kXMP_NS_XMP, "Thumbnails" ); - stdXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 ); + stdXMP.SerializeToBuffer ( &tempStr, keepItSmall, 1, "", "", 0 ); #if Trace_PackageForJPEG - printf ( " Delete xmp:Thumbnails, %d bytes left\n", tempLen ); + printf ( " Delete xmp:Thumbnails, %d bytes left\n", tempStr.size() ); #endif } } - if ( tempLen > kStdXMPLimit ) { + if ( tempStr.size() > kStdXMPLimit ) { // Still doesn't fit, move all of the Camera Raw namespace. Add a dummy value for xmpNote:HasExtendedXMP. @@ -1705,30 +1522,30 @@ XMPUtils::PackageForJPEG ( const XMPMeta & origXMP, crSchema->parent = &extXMP.tree; extXMP.tree.children.push_back ( crSchema ); stdXMP.tree.children.erase ( crSchemaPos ); - stdXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 ); + stdXMP.SerializeToBuffer ( &tempStr, keepItSmall, 1, "", "", 0 ); #if Trace_PackageForJPEG - printf ( " Move Camera Raw schema, %d bytes left\n", tempLen ); + printf ( " Move Camera Raw schema, %d bytes left\n", tempStr.size() ); #endif } } - if ( tempLen > kStdXMPLimit ) { + if ( tempStr.size() > kStdXMPLimit ) { // Still doesn't fit, move photoshop:History. bool moved = MoveOneProperty ( stdXMP, &extXMP, kXMP_NS_Photoshop, "photoshop:History" ); if ( moved ) { - stdXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 ); + stdXMP.SerializeToBuffer ( &tempStr, keepItSmall, 1, "", "", 0 ); #if Trace_PackageForJPEG - printf ( " Move photoshop:History, %d bytes left\n", tempLen ); + printf ( " Move photoshop:History, %d bytes left\n", tempStr.size() ); #endif } } - if ( tempLen > kStdXMPLimit ) { + if ( tempStr.size() > kStdXMPLimit ) { // Still doesn't fit, move top level properties in order of estimated size. This is done by // creating a multi-map that maps the serialized size to the string pair for the schema URI @@ -1770,10 +1587,11 @@ XMPUtils::PackageForJPEG ( const XMPMeta & origXMP, // Outer loop to make sure enough is actually moved. - while ( (tempLen > kStdXMPLimit) && (! propSizes.empty()) ) { + while ( (tempStr.size() > kStdXMPLimit) && (! propSizes.empty()) ) { // Inner loop, move what seems to be enough according to the estimates. + size_t tempLen = tempStr.size(); while ( (tempLen > kStdXMPLimit) && (! propSizes.empty()) ) { size_t propSize = MoveLargestProperty ( stdXMP, &extXMP, propSizes ); @@ -1786,13 +1604,13 @@ XMPUtils::PackageForJPEG ( const XMPMeta & origXMP, // Reserialize the remaining standard XMP. - stdXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 ); + stdXMP.SerializeToBuffer ( &tempStr, keepItSmall, 1, "", "", 0 ); } } - if ( tempLen > kStdXMPLimit ) { + if ( tempStr.size() > kStdXMPLimit ) { // Still doesn't fit, throw an exception and let the client decide what to do. // ! This should never happen with the policy of moving any and all top level properties. XMP_Throw ( "Can't reduce XMP enough for JPEG file", kXMPErr_TooLargeForJPEG ); @@ -1803,59 +1621,49 @@ XMPUtils::PackageForJPEG ( const XMPMeta & origXMP, if ( extXMP.tree.children.empty() ) { // Just have the standard XMP. - sStandardXMP->assign ( tempStr, tempLen ); + *stdStr = tempStr; } else { // Have extended XMP. Serialize it, compute the digest, reset xmpNote:HasExtendedXMP, and // reserialize the standard XMP. - extXMP.SerializeToBuffer ( &tempStr, &tempLen, (keepItSmall | kXMP_OmitPacketWrapper), 0, "", "", 0 ); - sExtendedXMP->assign ( tempStr, tempLen ); + extXMP.SerializeToBuffer ( &tempStr, (keepItSmall | kXMP_OmitPacketWrapper), 0, "", "", 0 ); + *extStr = tempStr; MD5_CTX context; XMP_Uns8 digest [16]; MD5Init ( &context ); - MD5Update ( &context, (XMP_Uns8*)tempStr, tempLen ); + MD5Update ( &context, (XMP_Uns8*)tempStr.c_str(), (XMP_Uns32)tempStr.size() ); MD5Final ( digest, &context ); - sExtendedDigest->reserve ( 32 ); + digestStr->reserve ( 32 ); for ( size_t i = 0; i < 16; ++i ) { XMP_Uns8 byte = digest[i]; - sExtendedDigest->push_back ( kHexDigits [ byte>>4 ] ); - sExtendedDigest->push_back ( kHexDigits [ byte&0xF ] ); + digestStr->push_back ( kHexDigits [ byte>>4 ] ); + digestStr->push_back ( kHexDigits [ byte&0xF ] ); } - stdXMP.SetProperty ( kXMP_NS_XMP_Note, "HasExtendedXMP", sExtendedDigest->c_str(), 0 ); - stdXMP.SerializeToBuffer ( &tempStr, &tempLen, keepItSmall, 1, "", "", 0 ); - sStandardXMP->assign ( tempStr, tempLen ); + stdXMP.SetProperty ( kXMP_NS_XMP_Note, "HasExtendedXMP", digestStr->c_str(), 0 ); + stdXMP.SerializeToBuffer ( &tempStr, keepItSmall, 1, "", "", 0 ); + *stdStr = tempStr; } // Adjust the standard XMP padding to be up to 2KB. - XMP_Assert ( (sStandardXMP->size() > kTrailerLen) && (sStandardXMP->size() <= kStdXMPLimit) ); - const char * packetEnd = sStandardXMP->c_str() + sStandardXMP->size() - kTrailerLen; + XMP_Assert ( (stdStr->size() > kTrailerLen) && (stdStr->size() <= kStdXMPLimit) ); + const char * packetEnd = stdStr->c_str() + stdStr->size() - kTrailerLen; XMP_Assert ( XMP_LitMatch ( packetEnd, kPacketTrailer ) ); - size_t extraPadding = kStdXMPLimit - sStandardXMP->size(); // ! Do this before erasing the trailer. + size_t extraPadding = kStdXMPLimit - stdStr->size(); // ! Do this before erasing the trailer. if ( extraPadding > 2047 ) extraPadding = 2047; - sStandardXMP->erase ( sStandardXMP->size() - kTrailerLen ); - sStandardXMP->append ( extraPadding, ' ' ); - sStandardXMP->append ( kPacketTrailer ); - - // Assign the output pointer and sizes. - - *stdStr = sStandardXMP->c_str(); - *stdLen = sStandardXMP->size(); - *extStr = sExtendedXMP->c_str(); - *extLen = sExtendedXMP->size(); - *digestStr = sExtendedDigest->c_str(); - *digestLen = sExtendedDigest->size(); + stdStr->erase ( stdStr->size() - kTrailerLen ); + stdStr->append ( extraPadding, ' ' ); + stdStr->append ( kPacketTrailer ); } // PackageForJPEG - // ------------------------------------------------------------------------------------------------- // MergeFromJPEG // ------------- @@ -1868,12 +1676,12 @@ XMPUtils::MergeFromJPEG ( XMPMeta * fullXMP, const XMPMeta & extendedXMP ) { - XMPUtils::AppendProperties ( extendedXMP, fullXMP, kXMPUtil_DoAllProperties ); + XMP_OptionBits apFlags = (kXMPTemplate_ReplaceExistingProperties | kXMPTemplate_IncludeInternalProperties); + XMPUtils::ApplyTemplate ( fullXMP, extendedXMP, apFlags ); fullXMP->DeleteProperty ( kXMP_NS_XMP_Note, "HasExtendedXMP" ); } // MergeFromJPEG - // ------------------------------------------------------------------------------------------------- // CurrentDateTime // --------------- @@ -1891,20 +1699,22 @@ XMPUtils::CurrentDateTime ( XMP_DateTime * xmpTime ) xmpTime->year = currTime.tm_year + 1900; xmpTime->month = currTime.tm_mon + 1; xmpTime->day = currTime.tm_mday; + xmpTime->hasDate = true; + xmpTime->hour = currTime.tm_hour; xmpTime->minute = currTime.tm_min; xmpTime->second = currTime.tm_sec; - xmpTime->nanoSecond = 0; + xmpTime->hasTime = true; + xmpTime->tzSign = 0; xmpTime->tzHour = 0; xmpTime->tzMinute = 0; - + xmpTime->hasTimeZone = false; // ! Needed for SetTimeZone. XMPUtils::SetTimeZone ( xmpTime ); } // CurrentDateTime - // ------------------------------------------------------------------------------------------------- // SetTimeZone // ----------- @@ -1918,8 +1728,10 @@ XMPUtils::SetTimeZone ( XMP_DateTime * xmpTime ) { XMP_Assert ( xmpTime != 0 ); // ! Enforced by wrapper. - if ( (xmpTime->tzSign != 0) || (xmpTime->tzHour != 0) || (xmpTime->tzMinute != 0) ) { - XMP_Throw ( "SetTimeZone can only be used on \"zoneless\" times", kXMPErr_BadParam ); + VerifyDateTimeFlags ( xmpTime ); + + if ( xmpTime->hasTimeZone ) { + XMP_Throw ( "SetTimeZone can only be used on zone-less times", kXMPErr_BadParam ); } // Create ansi_tt form of the input time. Need the ansi_tm form to make the ansi_tt form. @@ -1991,6 +1803,8 @@ XMPUtils::SetTimeZone ( XMP_DateTime * xmpTime ) } xmpTime->tzHour = XMP_Int32 ( diffSecs / 3600.0 ); xmpTime->tzMinute = XMP_Int32 ( (diffSecs / 60.0) - (xmpTime->tzHour * 60.0) ); + + xmpTime->hasTimeZone = xmpTime->hasTime = true; // *** Save the tm_isdst flag in a qualifier? @@ -2002,7 +1816,6 @@ XMPUtils::SetTimeZone ( XMP_DateTime * xmpTime ) } // SetTimeZone - // ------------------------------------------------------------------------------------------------- // ConvertToUTCTime // ---------------- @@ -2012,12 +1825,16 @@ XMPUtils::ConvertToUTCTime ( XMP_DateTime * time ) { XMP_Assert ( time != 0 ); // ! Enforced by wrapper. + VerifyDateTimeFlags ( time ); + + if ( ! time->hasTimeZone ) return; // Do nothing if there is no current time zone. + XMP_Assert ( (0 <= time->tzHour) && (time->tzHour <= 23) ); XMP_Assert ( (0 <= time->tzMinute) && (time->tzMinute <= 59) ); XMP_Assert ( (-1 <= time->tzSign) && (time->tzSign <= +1) ); XMP_Assert ( (time->tzSign == 0) ? ((time->tzHour == 0) && (time->tzMinute == 0)) : ((time->tzHour != 0) || (time->tzMinute != 0)) ); - + if ( time->tzSign == kXMP_TimeEastOfUTC ) { // We are before (east of) GMT, subtract the offset from the time. time->hour -= time->tzHour; @@ -2033,7 +1850,6 @@ XMPUtils::ConvertToUTCTime ( XMP_DateTime * time ) } // ConvertToUTCTime - // ------------------------------------------------------------------------------------------------- // ConvertToLocalTime // ------------------ @@ -2043,6 +1859,10 @@ XMPUtils::ConvertToLocalTime ( XMP_DateTime * time ) { XMP_Assert ( time != 0 ); // ! Enforced by wrapper. + VerifyDateTimeFlags ( time ); + + if ( ! time->hasTimeZone ) return; // Do nothing if there is no current time zone. + XMP_Assert ( (0 <= time->tzHour) && (time->tzHour <= 23) ); XMP_Assert ( (0 <= time->tzMinute) && (time->tzMinute <= 59) ); XMP_Assert ( (-1 <= time->tzSign) && (time->tzSign <= +1) ); @@ -2050,6 +1870,7 @@ XMPUtils::ConvertToLocalTime ( XMP_DateTime * time ) ((time->tzHour != 0) || (time->tzMinute != 0)) ); ConvertToUTCTime ( time ); // The existing time zone might not be the local one. + time->hasTimeZone = false; // ! Needed for SetTimeZone. SetTimeZone ( time ); // Fill in the local timezone offset, then adjust the time. if ( time->tzSign > 0 ) { @@ -2066,7 +1887,6 @@ XMPUtils::ConvertToLocalTime ( XMP_DateTime * time ) } // ConvertToLocalTime - // ------------------------------------------------------------------------------------------------- // CompareDateTime // --------------- @@ -2075,46 +1895,69 @@ XMPUtils::ConvertToLocalTime ( XMP_DateTime * time ) XMPUtils::CompareDateTime ( const XMP_DateTime & _in_left, const XMP_DateTime & _in_right ) { - int result; + int result = 0; XMP_DateTime left = _in_left; XMP_DateTime right = _in_right; + + VerifyDateTimeFlags ( &left ); + VerifyDateTimeFlags ( &right ); + + // Can't compare if one has a date and the other does not. + if ( left.hasDate != right.hasDate ) return 0; // Throw? + + if ( left.hasTimeZone & right.hasTimeZone ) { + // If both times have zones then convert them to UTC, otherwise assume the same zone. + ConvertToUTCTime ( &left ); + ConvertToUTCTime ( &right ); + } + + if ( left.hasDate ) { + + XMP_Assert ( right.hasDate ); + + if ( left.year < right.year ) { + result = -1; + } else if ( left.year > right.year ) { + result = +1; + } else if ( left.month < right.month ) { + result = -1; + } else if ( left.month > right.month ) { + result = +1; + } else if ( left.day < right.day ) { + result = -1; + } else if ( left.day > right.day ) { + result = +1; + } + + if ( result != 0 ) return result; + + } + + if ( left.hasTime & right.hasTime ) { + + // Ignore the time parts if either value is date-only. + + if ( left.hour < right.hour ) { + result = -1; + } else if ( left.hour > right.hour ) { + result = +1; + } else if ( left.minute < right.minute ) { + result = -1; + } else if ( left.minute > right.minute ) { + result = +1; + } else if ( left.second < right.second ) { + result = -1; + } else if ( left.second > right.second ) { + result = +1; + } else if ( left.nanoSecond < right.nanoSecond ) { + result = -1; + } else if ( left.nanoSecond > right.nanoSecond ) { + result = +1; + } else { + result = 0; + } - ConvertToUTCTime ( &left ); - ConvertToUTCTime ( &right ); - - // *** We could use memcmp if the XMP_DateTime stuct has no holes. - - if ( left.year < right.year ) { - result = -1; - } else if ( left.year > right.year ) { - result = +1; - } else if ( left.month < right.month ) { - result = -1; - } else if ( left.month > right.month ) { - result = +1; - } else if ( left.day < right.day ) { - result = -1; - } else if ( left.day > right.day ) { - result = +1; - } else if ( left.hour < right.hour ) { - result = -1; - } else if ( left.hour > right.hour ) { - result = +1; - } else if ( left.minute < right.minute ) { - result = -1; - } else if ( left.minute > right.minute ) { - result = +1; - } else if ( left.second < right.second ) { - result = -1; - } else if ( left.second > right.second ) { - result = +1; - } else if ( left.nanoSecond < right.nanoSecond ) { - result = -1; - } else if ( left.nanoSecond > right.nanoSecond ) { - result = +1; - } else { - result = 0; } return result; diff --git a/source/XMPCore/XMPUtils.hpp b/source/XMPCore/XMPUtils.hpp index e1c7e78..a7d0153 100644 --- a/source/XMPCore/XMPUtils.hpp +++ b/source/XMPCore/XMPUtils.hpp @@ -2,7 +2,7 @@ #define __XMPUtils_hpp__ // ================================================================================================= -// Copyright 2002-2007 Adobe Systems Incorporated +// Copyright 2003 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms @@ -18,16 +18,6 @@ // ------------------------------------------------------------------------------------------------- -extern XMP_VarString * sComposedPath; // *** Only really need 1 string. Shrink periodically? -extern XMP_VarString * sConvertedValue; -extern XMP_VarString * sBase64Str; -extern XMP_VarString * sCatenatedItems; -extern XMP_VarString * sStandardXMP; -extern XMP_VarString * sExtendedXMP; -extern XMP_VarString * sExtendedDigest; - -// ------------------------------------------------------------------------------------------------- - class XMPUtils { public: @@ -37,40 +27,33 @@ public: static void Terminate() RELEASE_NO_THROW; // ! For internal use only! - static void - Unlock ( XMP_OptionBits options ); - // --------------------------------------------------------------------------------------------- static void ComposeArrayItemPath ( XMP_StringPtr schemaNS, XMP_StringPtr arrayName, XMP_Index itemIndex, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ); + XMP_VarString * fullPath ); static void ComposeStructFieldPath ( XMP_StringPtr schemaNS, XMP_StringPtr structName, XMP_StringPtr fieldNS, XMP_StringPtr fieldName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ); + XMP_VarString * fullPath ); static void ComposeQualifierPath ( XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_StringPtr qualNS, XMP_StringPtr qualName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ); + XMP_VarString * fullPath ); static void - ComposeLangSelector ( XMP_StringPtr schemaNS, - XMP_StringPtr arrayName, - XMP_StringPtr langName, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ); + ComposeLangSelector ( XMP_StringPtr schemaNS, + XMP_StringPtr arrayName, + XMP_StringPtr langName, + XMP_VarString * fullPath ); static void ComposeFieldSelector ( XMP_StringPtr schemaNS, @@ -78,38 +61,32 @@ public: XMP_StringPtr fieldNS, XMP_StringPtr fieldName, XMP_StringPtr fieldValue, - XMP_StringPtr * fullPath, - XMP_StringLen * pathSize ); + XMP_VarString * fullPath ); // --------------------------------------------------------------------------------------------- static void ConvertFromBool ( bool binValue, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ); + XMP_VarString * strValue ); static void ConvertFromInt ( XMP_Int32 binValue, XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ); + XMP_VarString * strValue ); static void ConvertFromInt64 ( XMP_Int64 binValue, XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ); + XMP_VarString * strValue ); static void ConvertFromFloat ( double binValue, XMP_StringPtr format, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ); + XMP_VarString * strValue ); static void ConvertFromDate ( const XMP_DateTime & binValue, - XMP_StringPtr * strValue, - XMP_StringLen * strSize ); + XMP_VarString * strValue ); // --------------------------------------------------------------------------------------------- @@ -151,25 +128,20 @@ public: static void EncodeToBase64 ( XMP_StringPtr rawStr, XMP_StringLen rawLen, - XMP_StringPtr * encodedStr, - XMP_StringLen * encodedLen ); + XMP_VarString * encodedStr ); static void DecodeFromBase64 ( XMP_StringPtr encodedStr, XMP_StringLen encodedLen, - XMP_StringPtr * rawStr, - XMP_StringLen * rawLen ); + XMP_VarString * rawStr ); // --------------------------------------------------------------------------------------------- static void PackageForJPEG ( const XMPMeta & xmpObj, - XMP_StringPtr * stdStr, - XMP_StringLen * stdLen, - XMP_StringPtr * extStr, - XMP_StringLen * extLen, - XMP_StringPtr * digestStr, - XMP_StringLen * digestLen ); + XMP_VarString * stdStr, + XMP_VarString * extStr, + XMP_VarString * digestStr ); static void MergeFromJPEG ( XMPMeta * fullXMP, @@ -184,8 +156,7 @@ public: XMP_StringPtr separator, XMP_StringPtr quotes, XMP_OptionBits options, - XMP_StringPtr * catedStr, - XMP_StringLen * catedLen ); + XMP_VarString * catedStr ); static void SeparateArrayItems ( XMPMeta * xmpObj, @@ -195,17 +166,17 @@ public: XMP_StringPtr catedStr ); static void + ApplyTemplate ( XMPMeta * workingXMP, + const XMPMeta & templateXMP, + XMP_OptionBits actions ); + + static void RemoveProperties ( XMPMeta * xmpObj, XMP_StringPtr schemaNS, XMP_StringPtr propName, XMP_OptionBits options ); static void - AppendProperties ( const XMPMeta & source, - XMPMeta * dest, - XMP_OptionBits options ); - - static void DuplicateSubtree ( const XMPMeta & source, XMPMeta * dest, XMP_StringPtr sourceNS, |