1 #ifndef __XMP_LibUtils_hpp__ 2 #define __XMP_LibUtils_hpp__ 1 3 4 // ================================================================================================= 5 // Copyright 2009 Adobe Systems Incorporated 6 // All Rights Reserved. 7 // 8 // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms 9 // of the Adobe license agreement accompanying it. 10 // ================================================================================================= 11 12 #include "public/include/XMP_Environment.h" // ! Must be the first include. 13 #include "public/include/XMP_Const.h" 14 15 #include <map> 16 #include <string> 17 #include <vector> 18 19 #if XMP_DebugBuild 20 #include <cassert> 21 #endif 22 23 #if XMP_WinBuild 24 #ifndef snprintf 25 #define snprintf _snprintf 26 #endif 27 #endif 28 29 // ================================================================================================= 30 // Basic types, constants 31 // ====================== 32 33 #define kTab ((char)0x09) 34 #define kLF ((char)0x0A) 35 #define kCR ((char)0x0D) 36 37 #if XMP_WinBuild 38 #define kDirChar '\\' 39 #else 40 #define kDirChar '/' 41 #endif 42 43 typedef std::string XMP_VarString; 44 45 #define EliminateGlobal(g) delete ( g ); g = 0 46 47 extern "C" bool Initialize_LibUtils(); 48 extern "C" void Terminate_LibUtils(); 49 50 #define IgnoreParam(p) (void)p 51 52 // The builtin offsetof macro sometimes violates C++ data member rules. 53 #define XMP_OffsetOf(struct,field) ( (char*)(&((struct*)0x100)->field) - (char*)0x100 ) 54 55 // ================================================================================================= 56 // Support for exceptions and asserts 57 // ================================== 58 59 #define AnnounceThrow(msg) /* Do nothing. */ 60 #define AnnounceCatch(msg) /* Do nothing. */ 61 62 #define XMP_Throw(msg,id) { AnnounceThrow ( msg ); throw XMP_Error ( id, msg ); } 63 64 #if XMP_DebugBuild 65 #define XMP_Throw_Verbose(msg,e,id) \ 66 { \ 67 char tmpMsg[255]; \ 68 snprintf(tmpMsg, sizeof(tmpMsg), #msg "( %d )", e); \ 69 XMP_Throw( tmpMsg, id); \ 70 } 71 #else 72 #define XMP_Throw_Verbose(msg,e,id) XMP_Throw(msg, id) 73 #endif 74 75 #define XMP_Error_Throw(error) { AnnounceThrow (error.GetErrMsg()); throw error; } 76 77 class GenericErrorCallback { 78 public: 79 // Abstract base class for XMPCore and XMPFiles internal error notification support. Needed so 80 // that the XMLParserAdapter (used by both XMPCore and XMPFiles) can send error notifications, 81 // and so that utility parts of just XMPCore or XMPFiles can avoid dependence on XMPCore.hpp or 82 // XMPFiles.hpp if that is appropriate. 83 84 XMP_Uns32 limit; 85 mutable XMP_Uns32 notifications; 86 mutable XMP_ErrorSeverity topSeverity; 87 GenericErrorCallback()88 GenericErrorCallback() : limit(1), notifications(0), topSeverity(kXMPErrSev_Recoverable) {}; ~GenericErrorCallback()89 virtual ~GenericErrorCallback() {}; 90 Clear()91 void Clear() { this->notifications = 0; this->limit = 1; this->topSeverity = kXMPErrSev_Recoverable; }; 92 CheckLimitAndSeverity(XMP_ErrorSeverity severity) const93 bool CheckLimitAndSeverity (XMP_ErrorSeverity severity ) const 94 { 95 96 if ( this->limit == 0 ) return true; // Always notify if the limit is zero. 97 if ( severity < this->topSeverity ) return false; // Don't notify, don't count. 98 99 if ( severity > this->topSeverity ) { 100 this->topSeverity = severity; 101 this->notifications = 0; 102 } 103 104 this->notifications += 1; 105 return (this->notifications <= this->limit); 106 107 } // GenericErrorCallback::CheckLimitAndSeverity 108 109 // Const so they can be used with const XMPMeta and XMPFiles objects. NotifyClient(XMP_ErrorSeverity severity,XMP_Error & error,XMP_StringPtr filePath=0) const110 void NotifyClient ( XMP_ErrorSeverity severity, XMP_Error & error, XMP_StringPtr filePath = 0 ) const 111 { 112 113 bool notifyClient = CanNotify() && !error.IsNotified(); 114 bool returnAndRecover (severity == kXMPErrSev_Recoverable); 115 116 if ( notifyClient ) { 117 error.SetNotified(); 118 notifyClient = CheckLimitAndSeverity ( severity ); 119 if ( notifyClient ) { 120 returnAndRecover &= ClientCallbackWrapper( filePath, severity, error.GetID(), error.GetErrMsg() ); 121 } 122 } 123 124 if ( ! returnAndRecover ) XMP_Error_Throw ( error ); 125 126 } // GenericErrorCallback::NotifyClient 127 128 virtual bool CanNotify ( ) const = 0; 129 virtual bool ClientCallbackWrapper ( XMP_StringPtr filePath, XMP_ErrorSeverity severity, XMP_Int32 cause, XMP_StringPtr messsage ) const = 0; 130 131 }; 132 133 // ------------------------------------------------------------------------------------------------- 134 135 struct ErrorCallbackBox 136 { 137 XMPFiles_ErrorCallbackWrapper wrapperProc; 138 XMPFiles_ErrorCallbackProc clientProc; 139 void * context; 140 XMP_Uns32 limit; 141 ErrorCallbackBoxErrorCallbackBox142 ErrorCallbackBox( XMPFiles_ErrorCallbackWrapper wrapperProcedure, 143 XMPFiles_ErrorCallbackProc clientProcedure, 144 void * contextPtr, 145 XMP_Uns32 limit32 ): wrapperProc(wrapperProcedure), clientProc(clientProcedure), context(contextPtr), limit(limit32) { } 146 }; 147 148 // ------------------------------------------------------------------------------------------------- 149 150 #define _MakeStr(p) #p 151 #define _NotifyMsg(n,c,f,l) #n " failed: " #c " in " f " at line " _MakeStr(l) 152 #define _ExplicitMsg(msg,c,e) #e " " #msg ": " #c 153 154 #define XMP_Validate(c,msg,e) \ 155 if ( ! (c) ) { \ 156 const char * validate_msg = _ExplicitMsg ( msg, c, e ); \ 157 XMP_Throw ( validate_msg, e ); \ 158 } 159 160 // This statement is needed in XMP_Assert definition to reduce warnings from 161 // static analysis tool in Visual Studio. Defined here, as platform fork not 162 // possible within macro definition below 163 #if XMP_WinBuild 164 #define analysis_assume(c) __analysis_assume( c ); 165 #else 166 #define analysis_assume(c) ((void) 0) 167 #endif 168 169 #if ! XMP_DebugBuild 170 #define XMP_Assert(c) ((void) 0) 171 #else 172 #define XMP_Assert(c) assert ( c ) 173 #endif 174 175 #define XMP_Enforce(c) \ 176 if ( ! (c) ) { \ 177 const char * assert_msg = _NotifyMsg ( XMP_Enforce, (c), __FILE__, __LINE__ ); \ 178 XMP_Throw ( assert_msg , kXMPErr_EnforceFailure ); \ 179 } 180 // ================================================================================================= 181 // Thread synchronization locks 182 // ============================ 183 184 // About XMP and thread synchronization 185 // 186 // A variety of choices are provided for thread synchronization. Exactly one method must be chosen 187 // by defining the appropriate symbol to 1. 188 // 189 // * UseNoLock - This choice turns the synchronization functions into no-ops. It must only be used 190 // by single threaded clients, or clients providing their own control at a higher level. 191 // 192 // * UseGlobalLibraryLock - This choice uses a single per-library lock. The result is thread safe 193 // but unfriendly behavior, no true concurrency. This should only be used as a debugging fallback. 194 // 195 // * UseBoostLock - This choice uses the Boost shared_mutex mechanism. It has the advantage of being 196 // robust and being available on pretty much all platforms. It has the disadvantage of requiring 197 // the developer to download, integrate, and build the Boost thread library. 198 // 199 // * UsePThreadLock - This choice uses the POSIX pthread rwlock mechanism. It has the advantage of 200 // being robust and being available on any modern UNIX platform, including Mac OS X. 201 // 202 // * UseWinSlimLock - This choice uses the Windows slim reader/writer mechanism. It is robust but 203 // only available on Vista and newer versions of Windows, it is not available on XP. 204 // 205 // * UseHomeGrownLock - This choice uses local code plus lower level synchronization primitives. It 206 // has the advantage of being usable on all platforms, and having exposed and tunable policy. It 207 // has the disadvantage of possibly being less robust than Boost or the O/S provided mechanisms. 208 // The lower level synchronization primitives are pthread mutex and condition for UNIX (including 209 // Mac OS X). For Windows there is a choice of critical section and condition variable for Vista 210 // and newer; or critical section, event, and semaphore for XP and newer. 211 212 #define UseHomeGrownLock 1 213 214 // ------------------------------------------------------------------------------------------------- 215 // A basic exclusive access mutex and atomic increment/decrement operations. 216 217 #if XMP_WinBuild 218 219 #include <Windows.h> 220 221 #define HaveAtomicIncrDecr 1 222 typedef LONG XMP_AtomicCounter; 223 224 #define XMP_AtomicIncrement(x) InterlockedIncrement ( &(x) ) 225 #define XMP_AtomicDecrement(x) InterlockedDecrement ( &(x) ) 226 227 typedef CRITICAL_SECTION XMP_BasicMutex; 228 229 #define InitializeBasicMutex(mutex) { InitializeCriticalSection ( &mutex ); } 230 #define TerminateBasicMutex(mutex) { DeleteCriticalSection ( &mutex ); } 231 #define AcquireBasicMutex(mutex) { EnterCriticalSection ( &mutex ); } 232 #define ReleaseBasicMutex(mutex) { LeaveCriticalSection ( &mutex ); } 233 234 #elif XMP_MacBuild | XMP_iOSBuild 235 236 #include <pthread.h> 237 #include <libkern/OSAtomic.h> 238 239 #define HaveAtomicIncrDecr 1 240 typedef int32_t XMP_AtomicCounter; 241 242 #define XMP_AtomicIncrement(x) OSAtomicIncrement32Barrier ( &(x) ) 243 #define XMP_AtomicDecrement(x) OSAtomicDecrement32Barrier ( &(x) ) 244 245 typedef pthread_mutex_t XMP_BasicMutex; 246 247 #define InitializeBasicMutex(mutex) { int err = pthread_mutex_init ( &mutex, 0 ); XMP_Enforce ( err == 0 ); } 248 #define TerminateBasicMutex(mutex) { int err = pthread_mutex_destroy ( &mutex ); XMP_Enforce ( err == 0 ); } 249 #define AcquireBasicMutex(mutex) { int err = pthread_mutex_lock ( &mutex ); XMP_Enforce ( err == 0 ); } 250 #define ReleaseBasicMutex(mutex) { int err = pthread_mutex_unlock ( &mutex ); XMP_Enforce ( err == 0 ); } 251 252 #elif XMP_UNIXBuild 253 254 #include <pthread.h> 255 256 // Atomic increment/decrement intrinsics should be in gcc 4.1, but Solaris seems to lack them. 257 #ifndef HaveAtomicIncrDecr 258 #define HaveAtomicIncrDecr 1 259 #endif 260 #if HaveAtomicIncrDecr 261 typedef XMP_Uns32 XMP_AtomicCounter; 262 #define XMP_AtomicIncrement(x) __sync_add_and_fetch ( &(x), 1 ) 263 #define XMP_AtomicDecrement(x) __sync_sub_and_fetch ( &(x), 1 ) 264 #endif 265 266 typedef pthread_mutex_t XMP_BasicMutex; 267 268 #define InitializeBasicMutex(mutex) { int err = pthread_mutex_init ( &mutex, 0 ); XMP_Enforce ( err == 0 ); } 269 #define TerminateBasicMutex(mutex) { int err = pthread_mutex_destroy ( &mutex ); XMP_Enforce ( err == 0 ); } 270 #define AcquireBasicMutex(mutex) { int err = pthread_mutex_lock ( &mutex ); XMP_Enforce ( err == 0 ); } 271 #define ReleaseBasicMutex(mutex) { int err = pthread_mutex_unlock ( &mutex ); XMP_Enforce ( err == 0 ); } 272 273 #endif 274 275 class XMP_AutoMutex { 276 public: XMP_AutoMutex(XMP_BasicMutex * _mutex)277 XMP_AutoMutex ( XMP_BasicMutex * _mutex ) : mutex(_mutex) { AcquireBasicMutex ( *this->mutex ); } ~XMP_AutoMutex()278 ~XMP_AutoMutex() { this->Release(); } Release()279 void Release() { if ( this->mutex != 0 ) ReleaseBasicMutex ( *this->mutex ); this->mutex = 0; } 280 private: 281 XMP_BasicMutex * mutex; XMP_AutoMutex()282 XMP_AutoMutex() {}; // ! Must not be used. 283 }; 284 285 // ------------------------------------------------------------------------------------------------- 286 // Details for the various locking mechanisms. 287 288 #if UseNoLock 289 290 typedef void* XMP_BasicRWLock; // For single threaded clients that want maximum performance. 291 292 #define XMP_BasicRWLock_Initialize(lck) /* Do nothing. */ 293 #define XMP_BasicRWLock_Terminate(lck) /* Do nothing. */ 294 295 #define XMP_BasicRWLock_AcquireForRead(lck) /* Do nothing. */ 296 #define XMP_BasicRWLock_AcquireForWrite(lck) /* Do nothing. */ 297 298 #define XMP_BasicRWLock_ReleaseFromRead(lck) /* Do nothing. */ 299 #define XMP_BasicRWLock_ReleaseFromWrite(lck) /* Do nothing. */ 300 301 #elif UseGlobalLibraryLock 302 303 extern XMP_BasicMutex sLibraryLock; 304 305 typedef void* XMP_BasicRWLock; // Use the old thread-unfriendly per-DLL mutex. 306 307 #define XMP_BasicRWLock_Initialize(lck) /* Do nothing. */ 308 #define XMP_BasicRWLock_Terminate(lck) /* Do nothing. */ 309 310 #define XMP_BasicRWLock_AcquireForRead(lck) /* Do nothing. */ 311 #define XMP_BasicRWLock_AcquireForWrite(lck) /* Do nothing. */ 312 313 #define XMP_BasicRWLock_ReleaseFromRead(lck) /* Do nothing. */ 314 #define XMP_BasicRWLock_ReleaseFromWrite(lck) /* Do nothing. */ 315 316 #elif UseBoostLock 317 318 #include <boost/thread/shared_mutex.hpp> 319 typedef boost::shared_mutex XMP_BasicRWLock; 320 321 #define XMP_BasicRWLock_Initialize(lck) /* Do nothing. */ 322 #define XMP_BasicRWLock_Terminate(lck) /* Do nothing. */ 323 324 #define XMP_BasicRWLock_AcquireForRead(lck) lck.lock_shared() 325 #define XMP_BasicRWLock_AcquireForWrite(lck) lck.lock() 326 327 #define XMP_BasicRWLock_ReleaseFromRead(lck) lck.unlock_shared() 328 #define XMP_BasicRWLock_ReleaseFromWrite(lck) lck.unlock() 329 330 #elif UsePThreadLock 331 332 #include <pthread.h> 333 typedef pthread_rwlock_t XMP_BasicRWLock; 334 335 #define XMP_BasicRWLock_Initialize(lck) \ 336 { int err = pthread_rwlock_init ( &lck, 0 ); \ 337 if ( err != 0 ) XMP_Throw ( "Initialize pthread rwlock failed", kXMPErr_ExternalFailure ); } 338 #define XMP_BasicRWLock_Terminate(lck) \ 339 { int err = pthread_rwlock_destroy ( &lck ); XMP_Assert ( err == 0 ); } 340 341 #define XMP_BasicRWLock_AcquireForRead(lck) \ 342 { int err = pthread_rwlock_rdlock ( &lck ); \ 343 if ( err != 0 ) XMP_Throw ( "Acquire pthread read lock failed", kXMPErr_ExternalFailure ); } 344 #define XMP_BasicRWLock_AcquireForWrite(lck) \ 345 { int err = pthread_rwlock_wrlock ( &lck ); \ 346 if ( err != 0 ) XMP_Throw ( "Acquire pthread write lock failed", kXMPErr_ExternalFailure ); } 347 348 #define XMP_BasicRWLock_ReleaseFromRead(lck) \ 349 { int err = pthread_rwlock_unlock ( &lck ); \ 350 if ( err != 0 ) XMP_Throw ( "Release pthread read lock failed", kXMPErr_ExternalFailure ); } 351 #define XMP_BasicRWLock_ReleaseFromWrite(lck) \ 352 { int err = pthread_rwlock_unlock ( &lck ); \ 353 if ( err != 0 ) XMP_Throw ( "Release pthread write lock failed", kXMPErr_ExternalFailure ); } 354 355 #elif UseWinSlimLock 356 357 #include <Windows.h> 358 typedef SRWLOCK XMP_BasicRWLock; 359 360 #define XMP_BasicRWLock_Initialize(lck) InitializeSRWLock ( &lck ) 361 #define XMP_BasicRWLock_Terminate(lck) /* Do nothing. */ 362 363 #define XMP_BasicRWLock_AcquireForRead(lck) AcquireSRWLockShared ( &lck ) 364 #define XMP_BasicRWLock_AcquireForWrite(lck) AcquireSRWLockExclusive ( &lck ) 365 366 #define XMP_BasicRWLock_ReleaseFromRead(lck) ReleaseSRWLockShared ( &lck ) 367 #define XMP_BasicRWLock_ReleaseFromWrite(lck) ReleaseSRWLockExclusive ( &lck ) 368 369 #elif UseHomeGrownLock 370 371 class XMP_HomeGrownLock; 372 typedef XMP_HomeGrownLock XMP_BasicRWLock; 373 374 #define XMP_BasicRWLock_Initialize(lck) /* Do nothing. */ 375 #define XMP_BasicRWLock_Terminate(lck) /* Do nothing. */ 376 #define XMP_BasicRWLock_AcquireForRead(lck) lck.AcquireForRead() 377 #define XMP_BasicRWLock_AcquireForWrite(lck) lck.AcquireForWrite() 378 #define XMP_BasicRWLock_ReleaseFromRead(lck) lck.ReleaseFromRead() 379 #define XMP_BasicRWLock_ReleaseFromWrite(lck) lck.ReleaseFromWrite() 380 381 #if XMP_MacBuild | XMP_UNIXBuild | XMP_iOSBuild 382 383 #include <pthread.h> 384 385 typedef pthread_cond_t XMP_BasicQueue; 386 387 #elif XMP_WinBuild 388 389 #include <Windows.h> 390 #ifndef BuildLocksForWinXP 391 #define BuildLocksForWinXP 1 392 #endif 393 394 #if ! BuildLocksForWinXP 395 typedef CONDITION_VARIABLE XMP_BasicQueue; // ! Requires Vista or newer. 396 #else 397 class XMP_WinXP_HGQueue { 398 public: 399 XMP_WinXP_HGQueue(); 400 ~XMP_WinXP_HGQueue(); 401 void Wait ( XMP_BasicMutex & queueMutex ); 402 void ReleaseOne(); 403 void ReleaseAll(); 404 private: 405 HANDLE queueEvent; 406 volatile XMP_Uns32 waitCount; // ! Does not need to be XMP_AtomicCounter. 407 volatile bool releaseAll; 408 }; 409 typedef XMP_WinXP_HGQueue XMP_BasicQueue; 410 #endif 411 412 #endif 413 414 class XMP_HomeGrownLock { 415 public: 416 XMP_HomeGrownLock(); 417 ~XMP_HomeGrownLock() noexcept(false); 418 void AcquireForRead(); 419 void AcquireForWrite(); 420 void ReleaseFromRead(); 421 void ReleaseFromWrite(); 422 private: 423 XMP_BasicMutex queueMutex; // Used to protect queueing operations. 424 XMP_BasicQueue readerQueue, writerQueue; 425 volatile XMP_Uns32 lockCount, readersWaiting, writersWaiting; // ! Does not need to be XMP_AtomicCounter. 426 volatile bool beingWritten; 427 }; 428 429 #else 430 431 #error "No locking mechanism chosen" 432 433 #endif 434 435 class XMP_ReadWriteLock { // For the lock objects, use XMP_AutoLock to do the locking. 436 public: 437 XMP_ReadWriteLock(); 438 ~XMP_ReadWriteLock(); 439 void Acquire ( bool forWriting ); 440 void Release(); 441 private: 442 XMP_BasicRWLock lock; 443 #if XMP_DebugBuild && HaveAtomicIncrDecr 444 volatile XMP_AtomicCounter lockCount; // ! Only for debug checks, must be XMP_AtomicCounter. 445 #endif 446 volatile bool beingWritten; 447 }; 448 449 #define kXMP_ReadLock false 450 #define kXMP_WriteLock true 451 452 class XMP_AutoLock { 453 public: XMP_AutoLock(const XMP_ReadWriteLock * _lock,bool forWriting,bool cond=true)454 XMP_AutoLock ( const XMP_ReadWriteLock * _lock, bool forWriting, bool cond = true ) : lock(0) 455 { 456 if ( cond ) { 457 // The cast below is needed because the _lock parameter might come from something 458 // like "const XMPMeta &", which would make the lock itself const. But we need to 459 // modify the lock (to acquire and release) even if the owning object is const. 460 this->lock = (XMP_ReadWriteLock*)_lock; 461 this->lock->Acquire ( forWriting ); 462 } 463 } ~XMP_AutoLock()464 ~XMP_AutoLock() { this->Release(); } Release()465 void Release() { if ( this->lock != 0 ) this->lock->Release(); this->lock = 0; } 466 private: 467 XMP_ReadWriteLock * lock; XMP_AutoLock()468 XMP_AutoLock() {}; // ! Must not be used. 469 }; 470 471 // ================================================================================================= 472 // Support for wrappers 473 // ==================== 474 475 #define AnnounceStaticEntry(proc) /* Do nothing. */ 476 #define AnnounceObjectEntry(proc,rwMode) /* Do nothing. */ 477 478 #define AnnounceExit() /* Do nothing. */ 479 480 // ------------------------------------------------------------------------------------------------- 481 482 #if UseGlobalLibraryLock 483 #define AcquireLibraryLock(lck) XMP_AutoMutex libLock ( &lck ) 484 #else 485 #define AcquireLibraryLock(lck) /* nothing */ 486 #endif 487 488 #define XMP_ENTER_NoLock(Proc) \ 489 AnnounceStaticEntry ( Proc ); \ 490 try { \ 491 wResult->SetErrMessage(0); 492 493 #define XMP_ENTER_Static(Proc) \ 494 AnnounceStaticEntry ( Proc ); \ 495 AcquireLibraryLock ( sLibraryLock ); \ 496 try { \ 497 wResult->SetErrMessage(0); 498 499 #define XMP_ENTER_ObjRead(XMPClass,Proc) \ 500 AnnounceObjectEntry ( Proc, "reader" ); \ 501 AcquireLibraryLock ( sLibraryLock ); \ 502 const XMPClass & thiz = *((XMPClass*)xmpObjRef); \ 503 XMP_AutoLock objLock ( &thiz.lock, kXMP_ReadLock ); \ 504 try { \ 505 wResult->SetErrMessage(0); 506 507 #define XMP_ENTER_ObjWrite(XMPClass,Proc) \ 508 AnnounceObjectEntry ( Proc, "writer" ); \ 509 AcquireLibraryLock ( sLibraryLock ); \ 510 XMPClass * thiz = (XMPClass*)xmpObjRef; \ 511 XMP_AutoLock objLock ( &thiz->lock, kXMP_WriteLock ); \ 512 try { \ 513 wResult->SetErrMessage(0); 514 515 #define XMP_EXIT \ 516 XMP_CATCH_EXCEPTIONS \ 517 AnnounceExit(); 518 519 #define XMP_EXIT_NoThrow \ 520 } catch ( ... ) { \ 521 AnnounceCatch ( "no-throw catch-all" ); \ 522 /* Do nothing. */ \ 523 } \ 524 AnnounceExit(); 525 526 #define XMP_CATCH_EXCEPTIONS \ 527 } catch ( XMP_Error & xmpErr ) { \ 528 wResult->int32Result = xmpErr.GetID(); \ 529 wResult->ptrResult = (void*)"XMP"; \ 530 wResult->SetErrMessage(xmpErr.GetErrMsg()); \ 531 if ( wResult->GetErrMessage() == 0 ) wResult->SetErrMessage(""); \ 532 AnnounceCatch ( wResult->GetErrMessage() ); \ 533 } catch ( std::exception & stdErr ) { \ 534 wResult->int32Result = kXMPErr_StdException; \ 535 wResult->SetErrMessage(stdErr.what()); \ 536 if ( wResult->GetErrMessage() == 0 ) wResult->SetErrMessage(""); \ 537 AnnounceCatch ( wResult->GetErrMessage() ); \ 538 } catch ( ... ) { \ 539 wResult->int32Result = kXMPErr_UnknownException; \ 540 wResult->SetErrMessage("Caught unknown exception"); \ 541 AnnounceCatch ( wResult->GetErrMessage() ); \ 542 } 543 544 #if XMP_DebugBuild 545 #define RELEASE_NO_THROW /* empty */ 546 #else 547 #define RELEASE_NO_THROW throw() 548 #endif 549 550 // ================================================================================================= 551 // Data structure dumping utilities 552 // ================================ 553 554 #define IsHexDigit(ch) ( (('0' <= (ch)) && ((ch) <= '9')) || (('A' <= (ch)) && ((ch) <= 'F')) ) 555 #define HexDigitValue(ch) ( (((ch) - '0') < 10) ? ((ch) - '0') : ((ch) - 'A' + 10) ) 556 557 #define kTenSpaces " " 558 #define OutProcPadding(pad) { size_t padLen = (pad); \ 559 for ( ; padLen >= 10; padLen -= 10 ) OutProcNChars ( kTenSpaces, 10 ); \ 560 for ( ; padLen > 0; padLen -= 1 ) OutProcNChars ( " ", 1 ); } 561 562 563 #define OutProcNewline() { XMP_Status status = (*outProc) ( refCon, "\n", 1 ); if ( status != 0 ) return; } 564 565 #define OutProcNChars(p,n) { XMP_Status status = (*outProc) ( refCon, (p), (n) ); if ( status != 0 ) return; } 566 567 #define OutProcLiteral(lit) { XMP_Status _status = (*outProc) ( refCon, (lit), (XMP_StringLen)strlen(lit) ); if ( _status != 0 ) return; } 568 569 #define OutProcString(str) { XMP_Status _status = (*outProc) ( refCon, (str).c_str(), (XMP_StringLen)(str).size() ); if ( _status != 0 ) return; } 570 571 #define OutProcDecInt(num) { snprintf ( buffer, sizeof(buffer), "%ld", (long)(num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \ 572 buffer[sizeof(buffer) -1] = 0; /* AUDIT warning C6053: Make sure buffer is terminated */ \ 573 XMP_Status _status = (*outProc) ( refCon, buffer, (XMP_StringLen)strlen(buffer) ); if ( _status != 0 ) return; } 574 575 #define OutProcHexInt(num) { snprintf ( buffer, sizeof(buffer), "%lX", (long)(num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \ 576 buffer[sizeof(buffer) -1] = 0; /* AUDIT warning C6053: Make sure buffer is terminated */ \ 577 XMP_Status _status = (*outProc) ( refCon, buffer, (XMP_StringLen)strlen(buffer) ); if ( _status != 0 ) return; } 578 579 #define OutProcHexByte(num) { snprintf ( buffer, sizeof(buffer), "%.2X", (unsigned char)(num) ); /* AUDIT: Using sizeof for snprintf length is safe */ \ 580 XMP_Status _status = (*outProc) ( refCon, buffer, (XMP_StringLen)strlen(buffer) ); if ( _status != 0 ) return; } 581 582 #define kIndent " " 583 #define OutProcIndent(lev) { for ( size_t i = 0; i < (lev); ++i ) OutProcNChars ( kIndent, 3 ); } 584 585 void DumpClearString ( const XMP_VarString & value, XMP_TextOutputProc outProc, void * refCon ); 586 587 // ================================================================================================= 588 // Namespace Tables 589 // ================ 590 typedef std::vector <XMP_VarString> XMP_StringVector; 591 typedef XMP_StringVector::iterator XMP_StringVectorPos; 592 typedef XMP_StringVector::const_iterator XMP_StringVectorCPos; 593 594 typedef std::pair < XMP_VarString, XMP_VarString > XMP_StringPair; 595 596 typedef std::map < XMP_VarString, XMP_VarString > XMP_StringMap; 597 typedef XMP_StringMap::iterator XMP_StringMapPos; 598 typedef XMP_StringMap::const_iterator XMP_cStringMapPos; 599 600 class XMP_NamespaceTable { 601 public: 602 XMP_NamespaceTable()603 XMP_NamespaceTable() {}; 604 XMP_NamespaceTable ( const XMP_NamespaceTable & presets ); ~XMP_NamespaceTable()605 virtual ~XMP_NamespaceTable() {}; 606 607 bool Define ( XMP_StringPtr uri, XMP_StringPtr suggPrefix, 608 XMP_StringPtr * prefixPtr, XMP_StringLen * prefixLen); 609 610 bool GetPrefix ( XMP_StringPtr uri, XMP_StringPtr * prefixPtr, XMP_StringLen * prefixLen ) const; 611 bool GetURI ( XMP_StringPtr prefix, XMP_StringPtr * uriPtr, XMP_StringLen * uriLen ) const; 612 613 void Dump ( XMP_TextOutputProc outProc, void * refCon ) const; 614 615 private: 616 617 XMP_ReadWriteLock lock; 618 XMP_StringMap uriToPrefixMap, prefixToURIMap; 619 620 }; 621 622 623 // Right now it supports only ^, $ and \d, in future we should use it as a wrapper over 624 // regex object once mac and Linux compilers start supporting them. 625 626 class XMP_RegExp { 627 public: XMP_RegExp(XMP_StringPtr regExp)628 XMP_RegExp ( XMP_StringPtr regExp ) 629 { 630 if ( regExp ) 631 regExpStr = regExp; 632 } 633 634 XMP_Bool Match ( XMP_StringPtr s ); 635 636 private: 637 XMP_VarString regExpStr; 638 }; 639 640 // ================================================================================================= 641 642 #endif // __XMP_LibUtils_hpp__ 643