kopia lustrzana https://github.com/gopro/gpr
620 wiersze
22 KiB
C++
620 wiersze
22 KiB
C++
#ifndef __XMP_LibUtils_hpp__
|
|
#define __XMP_LibUtils_hpp__ 1
|
|
|
|
// =================================================================================================
|
|
// Copyright 2009 Adobe Systems Incorporated
|
|
// All Rights Reserved.
|
|
//
|
|
// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
|
|
// of the Adobe license agreement accompanying it.
|
|
// =================================================================================================
|
|
|
|
#include "public/include/XMP_Environment.h" // ! Must be the first include.
|
|
#include "public/include/XMP_Const.h"
|
|
|
|
#include <map>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#if XMP_DebugBuild
|
|
#include <cassert>
|
|
#endif
|
|
|
|
#if XMP_WinBuild
|
|
#ifndef snprintf
|
|
#define snprintf _snprintf
|
|
#endif
|
|
#endif
|
|
|
|
// =================================================================================================
|
|
// Basic types, constants
|
|
// ======================
|
|
|
|
#define kTab ((char)0x09)
|
|
#define kLF ((char)0x0A)
|
|
#define kCR ((char)0x0D)
|
|
|
|
#if XMP_WinBuild
|
|
#define kDirChar '\\'
|
|
#else
|
|
#define kDirChar '/'
|
|
#endif
|
|
|
|
typedef std::string XMP_VarString;
|
|
|
|
#define EliminateGlobal(g) delete ( g ); g = 0
|
|
|
|
extern "C" bool Initialize_LibUtils();
|
|
extern "C" void Terminate_LibUtils();
|
|
|
|
#define IgnoreParam(p) (void)p
|
|
|
|
// The builtin offsetof macro sometimes violates C++ data member rules.
|
|
#define XMP_OffsetOf(struct,field) ( (char*)(&((struct*)0x100)->field) - (char*)0x100 )
|
|
|
|
// =================================================================================================
|
|
// Support for exceptions and asserts
|
|
// ==================================
|
|
|
|
#define AnnounceThrow(msg) /* Do nothing. */
|
|
#define AnnounceCatch(msg) /* Do nothing. */
|
|
|
|
#define XMP_Throw(msg,id) { AnnounceThrow ( msg ); throw XMP_Error ( id, msg ); }
|
|
|
|
#if XMP_DebugBuild
|
|
#define XMP_Throw_Verbose(msg,e,id) \
|
|
{ \
|
|
char tmpMsg[255]; \
|
|
snprintf(tmpMsg, sizeof(tmpMsg), #msg "( %d )", e); \
|
|
XMP_Throw( tmpMsg, id); \
|
|
}
|
|
#else
|
|
#define XMP_Throw_Verbose(msg,e,id) XMP_Throw(msg, id)
|
|
#endif
|
|
|
|
class GenericErrorCallback {
|
|
public:
|
|
// Abstract base class for XMPCore and XMPFiles internal error notification support. Needed so
|
|
// that the XMLParserAdapter (used by both XMPCore and XMPFiles) can send error notifications,
|
|
// and so that utility parts of just XMPCore or XMPFiles can avoid dependence on XMPCore.hpp or
|
|
// XMPFiles.hpp if that is appropriate.
|
|
|
|
XMP_Uns32 limit;
|
|
mutable XMP_Uns32 notifications;
|
|
mutable XMP_ErrorSeverity topSeverity;
|
|
|
|
GenericErrorCallback() : notifications(0), limit(1), topSeverity(kXMPErrSev_Recoverable) {};
|
|
virtual ~GenericErrorCallback() {};
|
|
|
|
void Clear() { this->notifications = 0; this->limit = 1; this->topSeverity = kXMPErrSev_Recoverable; };
|
|
|
|
bool CheckLimitAndSeverity (XMP_ErrorSeverity severity ) const;
|
|
|
|
// Const so they can be used with const XMPMeta and XMPFiles objects.
|
|
void NotifyClient ( XMP_ErrorSeverity severity, XMP_Error & error, XMP_StringPtr filePath = 0 ) const;
|
|
|
|
virtual bool CanNotify ( ) const = 0;
|
|
virtual bool ClientCallbackWrapper ( XMP_StringPtr filePath, XMP_ErrorSeverity severity, XMP_Int32 cause, XMP_StringPtr messsage ) const = 0;
|
|
|
|
};
|
|
|
|
#define XMP_Error_Throw(error) { AnnounceThrow (error.GetErrMsg()); throw error; }
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------
|
|
|
|
#define _MakeStr(p) #p
|
|
#define _NotifyMsg(n,c,f,l) #n " failed: " #c " in " f " at line " _MakeStr(l)
|
|
#define _ExplicitMsg(msg,c,e) #e " " #msg ": " #c
|
|
|
|
#define XMP_Validate(c,msg,e) \
|
|
if ( ! (c) ) { \
|
|
const char * validate_msg = _ExplicitMsg ( msg, c, e ); \
|
|
XMP_Throw ( validate_msg, e ); \
|
|
}
|
|
|
|
// This statement is needed in XMP_Assert definition to reduce warnings from
|
|
// static analysis tool in Visual Studio. Defined here, as platform fork not
|
|
// possible within macro definition below
|
|
#if XMP_WinBuild
|
|
#define analysis_assume(c) __analysis_assume( c );
|
|
#else
|
|
#define analysis_assume(c) ((void) 0)
|
|
#endif
|
|
|
|
#if ! XMP_DebugBuild
|
|
#define XMP_Assert(c) ((void) 0)
|
|
#else
|
|
#define XMP_Assert(c) assert ( c )
|
|
#endif
|
|
|
|
#define XMP_Enforce(c) \
|
|
if ( ! (c) ) { \
|
|
const char * assert_msg = _NotifyMsg ( XMP_Enforce, (c), __FILE__, __LINE__ ); \
|
|
XMP_Throw ( assert_msg , kXMPErr_EnforceFailure ); \
|
|
}
|
|
// =================================================================================================
|
|
// Thread synchronization locks
|
|
// ============================
|
|
|
|
// About XMP and thread synchronization
|
|
//
|
|
// A variety of choices are provided for thread synchronization. Exactly one method must be chosen
|
|
// by defining the appropriate symbol to 1.
|
|
//
|
|
// * UseNoLock - This choice turns the synchronization functions into no-ops. It must only be used
|
|
// by single threaded clients, or clients providing their own control at a higher level.
|
|
//
|
|
// * UseGlobalLibraryLock - This choice uses a single per-library lock. The result is thread safe
|
|
// but unfriendly behavior, no true concurrency. This should only be used as a debugging fallback.
|
|
//
|
|
// * UseBoostLock - This choice uses the Boost shared_mutex mechanism. It has the advantage of being
|
|
// robust and being available on pretty much all platforms. It has the disadvantage of requiring
|
|
// the developer to download, integrate, and build the Boost thread library.
|
|
//
|
|
// * UsePThreadLock - This choice uses the POSIX pthread rwlock mechanism. It has the advantage of
|
|
// being robust and being available on any modern UNIX platform, including Mac OS X.
|
|
//
|
|
// * UseWinSlimLock - This choice uses the Windows slim reader/writer mechanism. It is robust but
|
|
// only available on Vista and newer versions of Windows, it is not available on XP.
|
|
//
|
|
// * UseHomeGrownLock - This choice uses local code plus lower level synchronization primitives. It
|
|
// has the advantage of being usable on all platforms, and having exposed and tunable policy. It
|
|
// has the disadvantage of possibly being less robust than Boost or the O/S provided mechanisms.
|
|
// The lower level synchronization primitives are pthread mutex and condition for UNIX (including
|
|
// Mac OS X). For Windows there is a choice of critical section and condition variable for Vista
|
|
// and newer; or critical section, event, and semaphore for XP and newer.
|
|
|
|
#define UseNoLock 1
|
|
|
|
// -------------------------------------------------------------------------------------------------
|
|
// A basic exclusive access mutex and atomic increment/decrement operations.
|
|
|
|
#if XMP_WinBuild
|
|
|
|
#include <Windows.h>
|
|
|
|
#define HaveAtomicIncrDecr 1
|
|
typedef LONG XMP_AtomicCounter;
|
|
|
|
#define XMP_AtomicIncrement(x) InterlockedIncrement ( &(x) )
|
|
#define XMP_AtomicDecrement(x) InterlockedDecrement ( &(x) )
|
|
|
|
typedef CRITICAL_SECTION XMP_BasicMutex;
|
|
|
|
#define InitializeBasicMutex(mutex) { InitializeCriticalSection ( &mutex ); }
|
|
#define TerminateBasicMutex(mutex) { DeleteCriticalSection ( &mutex ); }
|
|
#define AcquireBasicMutex(mutex) { EnterCriticalSection ( &mutex ); }
|
|
#define ReleaseBasicMutex(mutex) { LeaveCriticalSection ( &mutex ); }
|
|
|
|
#elif XMP_MacBuild | XMP_iOSBuild
|
|
|
|
#include <pthread.h>
|
|
#include <libkern/OSAtomic.h>
|
|
|
|
#define HaveAtomicIncrDecr 1
|
|
typedef int32_t XMP_AtomicCounter;
|
|
|
|
#define XMP_AtomicIncrement(x) OSAtomicIncrement32 ( &(x) )
|
|
#define XMP_AtomicDecrement(x) OSAtomicDecrement32 ( &(x) )
|
|
|
|
typedef pthread_mutex_t XMP_BasicMutex;
|
|
|
|
#define InitializeBasicMutex(mutex) { int err = pthread_mutex_init ( &mutex, 0 ); XMP_Enforce ( err == 0 ); }
|
|
#define TerminateBasicMutex(mutex) { int err = pthread_mutex_destroy ( &mutex ); XMP_Enforce ( err == 0 ); }
|
|
#define AcquireBasicMutex(mutex) { int err = pthread_mutex_lock ( &mutex ); XMP_Enforce ( err == 0 ); }
|
|
#define ReleaseBasicMutex(mutex) { int err = pthread_mutex_unlock ( &mutex ); XMP_Enforce ( err == 0 ); }
|
|
|
|
#elif XMP_UNIXBuild
|
|
|
|
#include <pthread.h>
|
|
|
|
// Atomic increment/decrement intrinsics should be in gcc 4.1, but Solaris seems to lack them.
|
|
#ifndef HaveAtomicIncrDecr
|
|
#define HaveAtomicIncrDecr 1
|
|
#endif
|
|
#if HaveAtomicIncrDecr
|
|
typedef XMP_Uns32 XMP_AtomicCounter;
|
|
#define XMP_AtomicIncrement(x) __sync_add_and_fetch ( &(x), 1 )
|
|
#define XMP_AtomicDecrement(x) __sync_sub_and_fetch ( &(x), 1 )
|
|
#endif
|
|
|
|
typedef pthread_mutex_t XMP_BasicMutex;
|
|
|
|
#define InitializeBasicMutex(mutex) { int err = pthread_mutex_init ( &mutex, 0 ); XMP_Enforce ( err == 0 ); }
|
|
#define TerminateBasicMutex(mutex) { int err = pthread_mutex_destroy ( &mutex ); XMP_Enforce ( err == 0 ); }
|
|
#define AcquireBasicMutex(mutex) { int err = pthread_mutex_lock ( &mutex ); XMP_Enforce ( err == 0 ); }
|
|
#define ReleaseBasicMutex(mutex) { int err = pthread_mutex_unlock ( &mutex ); XMP_Enforce ( err == 0 ); }
|
|
|
|
#elif XMP_BanzaiBuild
|
|
|
|
#include <rtos_mutex.h>
|
|
|
|
// Atomic increment/decrement intrinsics should be in gcc 4.1, but Solaris seems to lack them.
|
|
#ifndef HaveAtomicIncrDecr
|
|
#define HaveAtomicIncrDecr 1
|
|
#endif
|
|
#if HaveAtomicIncrDecr
|
|
typedef XMP_Uns32 XMP_AtomicCounter;
|
|
#define XMP_AtomicIncrement(x) __sync_add_and_fetch ( &(x), 1 )
|
|
#define XMP_AtomicDecrement(x) __sync_sub_and_fetch ( &(x), 1 )
|
|
#endif
|
|
|
|
typedef rtos_mutex_t XMP_BasicMutex;
|
|
|
|
#define InitializeBasicMutex(mutex) { int err = rtos_mutex_create ( &mutex, "mutex"); XMP_Enforce ( err == 0 ); }
|
|
#define TerminateBasicMutex(mutex) { int err = rtos_mutex_delete ( &mutex ); XMP_Enforce ( err == 0 ); }
|
|
#define AcquireBasicMutex(mutex) { int err = rtos_mutex_acquire ( &mutex, RTOS_WAIT_FOREVER ); XMP_Enforce ( err == 0 ); }
|
|
#define ReleaseBasicMutex(mutex) { int err = rtos_mutex_release ( &mutex ); XMP_Enforce ( err == 0 ); }
|
|
|
|
#endif
|
|
|
|
class XMP_AutoMutex {
|
|
public:
|
|
XMP_AutoMutex ( XMP_BasicMutex * _mutex ) : mutex(_mutex) { AcquireBasicMutex ( *this->mutex ); }
|
|
~XMP_AutoMutex() { this->Release(); }
|
|
void Release() { if ( this->mutex != 0 ) ReleaseBasicMutex ( *this->mutex ); this->mutex = 0; }
|
|
private:
|
|
XMP_BasicMutex * mutex;
|
|
XMP_AutoMutex() {}; // ! Must not be used.
|
|
};
|
|
|
|
// -------------------------------------------------------------------------------------------------
|
|
// Details for the various locking mechanisms.
|
|
|
|
#if UseNoLock
|
|
|
|
typedef void* XMP_BasicRWLock; // For single threaded clients that want maximum performance.
|
|
|
|
#define XMP_BasicRWLock_Initialize(lck) /* Do nothing. */
|
|
#define XMP_BasicRWLock_Terminate(lck) /* Do nothing. */
|
|
|
|
#define XMP_BasicRWLock_AcquireForRead(lck) /* Do nothing. */
|
|
#define XMP_BasicRWLock_AcquireForWrite(lck) /* Do nothing. */
|
|
|
|
#define XMP_BasicRWLock_ReleaseFromRead(lck) /* Do nothing. */
|
|
#define XMP_BasicRWLock_ReleaseFromWrite(lck) /* Do nothing. */
|
|
|
|
#elif UseGlobalLibraryLock
|
|
|
|
extern XMP_BasicMutex sLibraryLock;
|
|
|
|
typedef void* XMP_BasicRWLock; // Use the old thread-unfriendly per-DLL mutex.
|
|
|
|
#define XMP_BasicRWLock_Initialize(lck) /* Do nothing. */
|
|
#define XMP_BasicRWLock_Terminate(lck) /* Do nothing. */
|
|
|
|
#define XMP_BasicRWLock_AcquireForRead(lck) /* Do nothing. */
|
|
#define XMP_BasicRWLock_AcquireForWrite(lck) /* Do nothing. */
|
|
|
|
#define XMP_BasicRWLock_ReleaseFromRead(lck) /* Do nothing. */
|
|
#define XMP_BasicRWLock_ReleaseFromWrite(lck) /* Do nothing. */
|
|
|
|
#elif UseBoostLock
|
|
|
|
#include <boost/thread/shared_mutex.hpp>
|
|
typedef boost::shared_mutex XMP_BasicRWLock;
|
|
|
|
#define XMP_BasicRWLock_Initialize(lck) /* Do nothing. */
|
|
#define XMP_BasicRWLock_Terminate(lck) /* Do nothing. */
|
|
|
|
#define XMP_BasicRWLock_AcquireForRead(lck) lck.lock_shared()
|
|
#define XMP_BasicRWLock_AcquireForWrite(lck) lck.lock()
|
|
|
|
#define XMP_BasicRWLock_ReleaseFromRead(lck) lck.unlock_shared()
|
|
#define XMP_BasicRWLock_ReleaseFromWrite(lck) lck.unlock()
|
|
|
|
#elif UsePThreadLock
|
|
|
|
#include <pthread.h>
|
|
typedef pthread_rwlock_t XMP_BasicRWLock;
|
|
|
|
#define XMP_BasicRWLock_Initialize(lck) \
|
|
{ int err = pthread_rwlock_init ( &lck, 0 ); \
|
|
if ( err != 0 ) XMP_Throw ( "Initialize pthread rwlock failed", kXMPErr_ExternalFailure ); }
|
|
#define XMP_BasicRWLock_Terminate(lck) \
|
|
{ int err = pthread_rwlock_destroy ( &lck ); XMP_Assert ( err == 0 ); }
|
|
|
|
#define XMP_BasicRWLock_AcquireForRead(lck) \
|
|
{ int err = pthread_rwlock_rdlock ( &lck ); \
|
|
if ( err != 0 ) XMP_Throw ( "Acquire pthread read lock failed", kXMPErr_ExternalFailure ); }
|
|
#define XMP_BasicRWLock_AcquireForWrite(lck) \
|
|
{ int err = pthread_rwlock_wrlock ( &lck ); \
|
|
if ( err != 0 ) XMP_Throw ( "Acquire pthread write lock failed", kXMPErr_ExternalFailure ); }
|
|
|
|
#define XMP_BasicRWLock_ReleaseFromRead(lck) \
|
|
{ int err = pthread_rwlock_unlock ( &lck ); \
|
|
if ( err != 0 ) XMP_Throw ( "Release pthread read lock failed", kXMPErr_ExternalFailure ); }
|
|
#define XMP_BasicRWLock_ReleaseFromWrite(lck) \
|
|
{ int err = pthread_rwlock_unlock ( &lck ); \
|
|
if ( err != 0 ) XMP_Throw ( "Release pthread write lock failed", kXMPErr_ExternalFailure ); }
|
|
|
|
#elif UseWinSlimLock
|
|
|
|
#include <Windows.h>
|
|
typedef SRWLOCK XMP_BasicRWLock;
|
|
|
|
#define XMP_BasicRWLock_Initialize(lck) InitializeSRWLock ( &lck )
|
|
#define XMP_BasicRWLock_Terminate(lck) /* Do nothing. */
|
|
|
|
#define XMP_BasicRWLock_AcquireForRead(lck) AcquireSRWLockShared ( &lck )
|
|
#define XMP_BasicRWLock_AcquireForWrite(lck) AcquireSRWLockExclusive ( &lck )
|
|
|
|
#define XMP_BasicRWLock_ReleaseFromRead(lck) ReleaseSRWLockShared ( &lck )
|
|
#define XMP_BasicRWLock_ReleaseFromWrite(lck) ReleaseSRWLockExclusive ( &lck )
|
|
|
|
#elif UseHomeGrownLock
|
|
|
|
class XMP_HomeGrownLock;
|
|
typedef XMP_HomeGrownLock XMP_BasicRWLock;
|
|
|
|
#define XMP_BasicRWLock_Initialize(lck) /* Do nothing. */
|
|
#define XMP_BasicRWLock_Terminate(lck) /* Do nothing. */
|
|
#define XMP_BasicRWLock_AcquireForRead(lck) lck.AcquireForRead()
|
|
#define XMP_BasicRWLock_AcquireForWrite(lck) lck.AcquireForWrite()
|
|
#define XMP_BasicRWLock_ReleaseFromRead(lck) lck.ReleaseFromRead()
|
|
#define XMP_BasicRWLock_ReleaseFromWrite(lck) lck.ReleaseFromWrite()
|
|
|
|
#if XMP_MacBuild | XMP_UNIXBuild | XMP_iOSBuild
|
|
|
|
#include <pthread.h>
|
|
|
|
typedef pthread_cond_t XMP_BasicQueue;
|
|
|
|
#elif XMP_WinBuild
|
|
|
|
#include <Windows.h>
|
|
#ifndef BuildLocksForWinXP
|
|
#define BuildLocksForWinXP 1
|
|
#endif
|
|
|
|
#if ! BuildLocksForWinXP
|
|
typedef CONDITION_VARIABLE XMP_BasicQueue; // ! Requires Vista or newer.
|
|
#else
|
|
class XMP_WinXP_HGQueue {
|
|
public:
|
|
XMP_WinXP_HGQueue();
|
|
~XMP_WinXP_HGQueue();
|
|
void Wait ( XMP_BasicMutex & queueMutex );
|
|
void ReleaseOne();
|
|
void ReleaseAll();
|
|
private:
|
|
HANDLE queueEvent;
|
|
volatile XMP_Uns32 waitCount; // ! Does not need to be XMP_AtomicCounter.
|
|
volatile bool releaseAll;
|
|
};
|
|
typedef XMP_WinXP_HGQueue XMP_BasicQueue;
|
|
#endif
|
|
|
|
#endif
|
|
|
|
class XMP_HomeGrownLock {
|
|
public:
|
|
XMP_HomeGrownLock();
|
|
~XMP_HomeGrownLock();
|
|
void AcquireForRead();
|
|
void AcquireForWrite();
|
|
void ReleaseFromRead();
|
|
void ReleaseFromWrite();
|
|
private:
|
|
XMP_BasicMutex queueMutex; // Used to protect queueing operations.
|
|
XMP_BasicQueue readerQueue, writerQueue;
|
|
volatile XMP_Uns32 lockCount, readersWaiting, writersWaiting; // ! Does not need to be XMP_AtomicCounter.
|
|
volatile bool beingWritten;
|
|
};
|
|
|
|
#else
|
|
|
|
#error "No locking mechanism chosen"
|
|
|
|
#endif
|
|
|
|
class XMP_ReadWriteLock { // For the lock objects, use XMP_AutoLock to do the locking.
|
|
public:
|
|
XMP_ReadWriteLock();
|
|
~XMP_ReadWriteLock();
|
|
void Acquire ( bool forWriting );
|
|
void Release();
|
|
private:
|
|
XMP_BasicRWLock lock;
|
|
#if XMP_DebugBuild && HaveAtomicIncrDecr
|
|
volatile XMP_AtomicCounter lockCount; // ! Only for debug checks, must be XMP_AtomicCounter.
|
|
#endif
|
|
volatile bool beingWritten;
|
|
};
|
|
|
|
#define kXMP_ReadLock false
|
|
#define kXMP_WriteLock true
|
|
|
|
class XMP_AutoLock {
|
|
public:
|
|
XMP_AutoLock ( const XMP_ReadWriteLock * _lock, bool forWriting, bool cond = true ) : lock(0)
|
|
{
|
|
if ( cond ) {
|
|
// The cast below is needed because the _lock parameter might come from something
|
|
// like "const XMPMeta &", which would make the lock itself const. But we need to
|
|
// modify the lock (to acquire and release) even if the owning object is const.
|
|
this->lock = (XMP_ReadWriteLock*)_lock;
|
|
this->lock->Acquire ( forWriting );
|
|
}
|
|
}
|
|
~XMP_AutoLock() { this->Release(); }
|
|
void Release() { if ( this->lock != 0 ) this->lock->Release(); this->lock = 0; }
|
|
private:
|
|
XMP_ReadWriteLock * lock;
|
|
XMP_AutoLock() {}; // ! Must not be used.
|
|
};
|
|
|
|
// =================================================================================================
|
|
// Support for wrappers
|
|
// ====================
|
|
|
|
#define AnnounceStaticEntry(proc) /* Do nothing. */
|
|
#define AnnounceObjectEntry(proc,rwMode) /* Do nothing. */
|
|
|
|
#define AnnounceExit() /* Do nothing. */
|
|
|
|
// -------------------------------------------------------------------------------------------------
|
|
|
|
#if UseGlobalLibraryLock
|
|
#define AcquireLibraryLock(lck) XMP_AutoMutex libLock ( &lck )
|
|
#else
|
|
#define AcquireLibraryLock(lck) /* nothing */
|
|
#endif
|
|
|
|
#define XMP_ENTER_NoLock(Proc) \
|
|
AnnounceStaticEntry ( Proc ); \
|
|
try { \
|
|
wResult->errMessage = 0;
|
|
|
|
#define XMP_ENTER_Static(Proc) \
|
|
AnnounceStaticEntry ( Proc ); \
|
|
AcquireLibraryLock ( sLibraryLock ); \
|
|
try { \
|
|
wResult->errMessage = 0;
|
|
|
|
#define XMP_ENTER_ObjRead(XMPClass,Proc) \
|
|
AnnounceObjectEntry ( Proc, "reader" ); \
|
|
AcquireLibraryLock ( sLibraryLock ); \
|
|
const XMPClass & thiz = *((XMPClass*)xmpObjRef); \
|
|
XMP_AutoLock objLock ( &thiz.lock, kXMP_ReadLock ); \
|
|
try { \
|
|
wResult->errMessage = 0;
|
|
|
|
#define XMP_ENTER_ObjWrite(XMPClass,Proc) \
|
|
AnnounceObjectEntry ( Proc, "writer" ); \
|
|
AcquireLibraryLock ( sLibraryLock ); \
|
|
XMPClass * thiz = (XMPClass*)xmpObjRef; \
|
|
XMP_AutoLock objLock ( &thiz->lock, kXMP_WriteLock ); \
|
|
try { \
|
|
wResult->errMessage = 0;
|
|
|
|
#define XMP_EXIT \
|
|
XMP_CATCH_EXCEPTIONS \
|
|
AnnounceExit();
|
|
|
|
#define XMP_EXIT_NoThrow \
|
|
} 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
|
|
|
|
// =================================================================================================
|
|
// Data structure dumping 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() { XMP_Status status = (*outProc) ( refCon, "\n", 1 ); if ( status != 0 ) return; }
|
|
|
|
#define OutProcNChars(p,n) { XMP_Status status = (*outProc) ( refCon, (p), (n) ); if ( status != 0 ) return; }
|
|
|
|
#define OutProcLiteral(lit) { XMP_Status _status = (*outProc) ( refCon, (lit), (XMP_StringLen)strlen(lit) ); if ( _status != 0 ) return; }
|
|
|
|
#define OutProcString(str) { XMP_Status _status = (*outProc) ( refCon, (str).c_str(), (XMP_StringLen)(str).size() ); if ( _status != 0 ) return; }
|
|
|
|
#define OutProcDecInt(num) { snprintf ( buffer, sizeof(buffer), "%ld", (long)(num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \
|
|
buffer[sizeof(buffer) -1] = 0; /* AUDIT warning C6053: Make sure buffer is terminated */ \
|
|
XMP_Status _status = (*outProc) ( refCon, buffer, (XMP_StringLen)strlen(buffer) ); if ( _status != 0 ) return; }
|
|
|
|
#define OutProcHexInt(num) { snprintf ( buffer, sizeof(buffer), "%lX", (long)(num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \
|
|
buffer[sizeof(buffer) -1] = 0; /* AUDIT warning C6053: Make sure buffer is terminated */ \
|
|
XMP_Status _status = (*outProc) ( refCon, buffer, (XMP_StringLen)strlen(buffer) ); if ( _status != 0 ) return; }
|
|
|
|
#define OutProcHexByte(num) { snprintf ( buffer, sizeof(buffer), "%.2X", (unsigned char)(num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \
|
|
XMP_Status _status = (*outProc) ( refCon, buffer, (XMP_StringLen)strlen(buffer) ); if ( _status != 0 ) return; }
|
|
|
|
static const char * kIndent = " ";
|
|
#define OutProcIndent(lev) { for ( size_t i = 0; i < (lev); ++i ) OutProcNChars ( kIndent, 3 ); }
|
|
|
|
void DumpClearString ( const XMP_VarString & value, XMP_TextOutputProc outProc, void * refCon );
|
|
|
|
// =================================================================================================
|
|
// Namespace Tables
|
|
// ================
|
|
typedef std::vector <XMP_VarString> XMP_StringVector;
|
|
typedef XMP_StringVector::iterator XMP_StringVectorPos;
|
|
typedef XMP_StringVector::const_iterator XMP_StringVectorCPos;
|
|
|
|
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;
|
|
|
|
class XMP_NamespaceTable {
|
|
public:
|
|
|
|
XMP_NamespaceTable() {};
|
|
XMP_NamespaceTable ( const XMP_NamespaceTable & presets );
|
|
virtual ~XMP_NamespaceTable() {};
|
|
|
|
bool Define ( XMP_StringPtr uri, XMP_StringPtr suggPrefix,
|
|
XMP_StringPtr * prefixPtr, XMP_StringLen * prefixLen);
|
|
|
|
bool GetPrefix ( XMP_StringPtr uri, XMP_StringPtr * prefixPtr, XMP_StringLen * prefixLen ) const;
|
|
bool GetURI ( XMP_StringPtr prefix, XMP_StringPtr * uriPtr, XMP_StringLen * uriLen ) const;
|
|
|
|
void Dump ( XMP_TextOutputProc outProc, void * refCon ) const;
|
|
|
|
private:
|
|
|
|
XMP_ReadWriteLock lock;
|
|
XMP_StringMap uriToPrefixMap, prefixToURIMap;
|
|
|
|
};
|
|
|
|
|
|
// Right now it supports only ^, $ and \d, in future we should use it as a wrapper over
|
|
// regex object once mac and Linux compilers start supporting them.
|
|
|
|
class XMP_RegExp {
|
|
public:
|
|
XMP_RegExp ( XMP_StringPtr regExp )
|
|
{
|
|
if ( regExp )
|
|
regExpStr = regExp;
|
|
}
|
|
|
|
XMP_Bool Match ( XMP_StringPtr s );
|
|
|
|
private:
|
|
XMP_VarString regExpStr;
|
|
};
|
|
|
|
// =================================================================================================
|
|
|
|
#endif // __XMP_LibUtils_hpp__
|