diff --git a/include/exiv2/properties.hpp b/include/exiv2/properties.hpp index 08a9ee8e..b406ff19 100644 --- a/include/exiv2/properties.hpp +++ b/include/exiv2/properties.hpp @@ -39,6 +39,7 @@ #include "metadatum.hpp" #include "tags.hpp" #include "datasets.hpp" +#include "rwlock.hpp" // + standard includes #include @@ -108,6 +109,11 @@ namespace Exiv2 { //! Prevent assignment: not implemented. XmpProperties& operator=(const XmpProperties& rhs); + private: + static const XmpNsInfo* nsInfoUnsafe(const std::string& prefix); + static void unregisterNsUnsafe(const std::string& ns); + static const XmpNsInfo* lookupNsRegistryUnsafe(const XmpNsInfo::Prefix& prefix); + public: /*! @brief Return the title (label) of the property. @@ -174,6 +180,7 @@ namespace Exiv2 { @throw Error if no namespace is registered with \em prefix. */ static const XmpNsInfo* nsInfo(const std::string& prefix); + /*! @brief Return the (preferred) prefix for schema namespace \em ns. @param ns Schema namespace @@ -206,6 +213,8 @@ namespace Exiv2 { @note This invalidates XMP keys generated in this namespace. */ static void unregisterNs(const std::string& ns); + static Internal::RWLock rwLock_; + /*! @brief Unregister all custom namespaces. diff --git a/include/exiv2/rwlock.hpp b/include/exiv2/rwlock.hpp new file mode 100644 index 00000000..617e140c --- /dev/null +++ b/include/exiv2/rwlock.hpp @@ -0,0 +1,138 @@ +#ifndef RW_LOCK_HPP +#define RW_LOCK_HPP + +#ifdef _WIN32 +#include +#else +#include +#endif + +namespace Exiv2 { + namespace Internal { +#ifdef _WIN32 + class RWLock + { + public: + RWLock() + { + InitializeSRWLock(&rwlock_); + } + + ~RWLock() + { + // do not explicitly destroy + } + + void wrlock() + { + AcquireSRWLockExclusive(&rwlock_); + } + + bool trywrlock() + { + return TryAcquireSRWLockExclusive(&rwlock_); + } + + void rdlock() + { + AcquireSRWLockShared(&rwlock_); + } + + bool tryrdlock() + { + return TryAcquireSRWLockShared(&rwlock_); + } + + void rdunlock() + { + ReleaseSRWLockShared(&rwlock_); + } + + void wrunlock() + { + ReleaseSRWLockExclusive(&rwlock_); + } + + private: + SRWLOCK rwlock_; + }; +#else + class RWLock + { + public: + RWLock(const pthread_rwlockattr_t *attr = 0) + { + pthread_rwlock_init(&rwlock_, attr); + } + + ~RWLock() + { + pthread_rwlock_destroy(&rwlock_); + } + + int wrlock() + { + return pthread_rwlock_wrlock(&rwlock_); + } + + int trywrlock() + { + return pthread_rwlock_trywrlock(&rwlock_); + } + + int rdlock() + { + return pthread_rwlock_rdlock(&rwlock_); + } + + int tryrdlock() + { + return pthread_rwlock_tryrdlock(&rwlock_); + } + + int unlock() + { + return pthread_rwlock_unlock(&rwlock_); + } + + void rdunlock() { unlock(); } + void wrunlock() { unlock(); } + + private: + pthread_rwlock_t rwlock_; + }; +#endif + + class ScopedReadLock + { + public: + ScopedReadLock(RWLock &rwlock): + rwlock_(rwlock) + { + rwlock_.rdlock(); + } + + ~ScopedReadLock() { rwlock_.rdunlock(); } + + private: + RWLock &rwlock_; + }; + + class ScopedWriteLock + { + public: + ScopedWriteLock(RWLock &rwlock): + rwlock_(rwlock) + { + rwlock_.wrlock(); + } + + ~ScopedWriteLock() { rwlock_.wrunlock(); } + + private: + RWLock &rwlock_; + }; + } +} + +#endif // RW_LOCK_HPP diff --git a/src/epsimage.cpp b/src/epsimage.cpp index 4e4a4687..6e277e8b 100644 --- a/src/epsimage.cpp +++ b/src/epsimage.cpp @@ -51,6 +51,7 @@ EXIV2_RCSID("@(#) $Id: epsimage.cpp $") namespace { using namespace Exiv2; + using Exiv2::byte; // signature of DOS EPS const std::string dosEpsSignature = "\xC5\xD0\xD3\xC6"; diff --git a/src/preview.cpp b/src/preview.cpp index 1e86df7b..bd28d523 100644 --- a/src/preview.cpp +++ b/src/preview.cpp @@ -47,6 +47,7 @@ EXIV2_RCSID("@(#) $Id$") namespace { using namespace Exiv2; + using Exiv2::byte; /*! @brief Compare two preview images by number of pixels, if width and height diff --git a/src/properties.cpp b/src/properties.cpp index 66d93fa2..d4957acc 100644 --- a/src/properties.cpp +++ b/src/properties.cpp @@ -39,6 +39,7 @@ EXIV2_RCSID("@(#) $Id$") #include "metadatum.hpp" #include "i18n.h" // NLS support. #include "xmp.hpp" +#include "rwlock.hpp" #include #include @@ -2238,8 +2239,15 @@ namespace Exiv2 { } XmpProperties::NsRegistry XmpProperties::nsRegistry_; + Internal::RWLock XmpProperties::rwLock_; const XmpNsInfo* XmpProperties::lookupNsRegistry(const XmpNsInfo::Prefix& prefix) + { + Internal::ScopedReadLock srl(rwLock_); + return lookupNsRegistryUnsafe(prefix); + } + + const XmpNsInfo* XmpProperties::lookupNsRegistryUnsafe(const XmpNsInfo::Prefix& prefix) { for (NsRegistry::const_iterator i = nsRegistry_.begin(); i != nsRegistry_.end(); ++i) { @@ -2251,11 +2259,13 @@ namespace Exiv2 { void XmpProperties::registerNs(const std::string& ns, const std::string& prefix) { + Internal::ScopedWriteLock swl(rwLock_); + std::string ns2 = ns; if ( ns2.substr(ns2.size() - 1, 1) != "/" && ns2.substr(ns2.size() - 1, 1) != "#") ns2 += "/"; // Check if there is already a registered namespace with this prefix - const XmpNsInfo* xnp = lookupNsRegistry(XmpNsInfo::Prefix(prefix)); + const XmpNsInfo* xnp = lookupNsRegistryUnsafe(XmpNsInfo::Prefix(prefix)); if (xnp) { #ifndef SUPPRESS_WARNINGS if (strcmp(xnp->ns_, ns2.c_str()) != 0) { @@ -2263,7 +2273,7 @@ namespace Exiv2 { << xnp->ns_ << " to " << ns2 << "\n"; } #endif - unregisterNs(xnp->ns_); + unregisterNsUnsafe(xnp->ns_); } // Allocated memory is freed when the namespace is unregistered. // Using malloc/free for better system compatibility in case @@ -2281,6 +2291,12 @@ namespace Exiv2 { } void XmpProperties::unregisterNs(const std::string& ns) + { + Internal::ScopedWriteLock swl(rwLock_); + unregisterNsUnsafe(ns); + } + + void XmpProperties::unregisterNsUnsafe(const std::string& ns) { NsRegistry::iterator i = nsRegistry_.find(ns); if (i != nsRegistry_.end()) { @@ -2292,15 +2308,18 @@ namespace Exiv2 { void XmpProperties::unregisterNs() { + Internal::ScopedWriteLock swl(rwLock_); + NsRegistry::iterator i = nsRegistry_.begin(); while (i != nsRegistry_.end()) { NsRegistry::iterator kill = i++; - unregisterNs(kill->first); + unregisterNsUnsafe(kill->first); } } std::string XmpProperties::prefix(const std::string& ns) { + Internal::ScopedReadLock srl(rwLock_); std::string ns2 = ns; if ( ns2.substr(ns2.size() - 1, 1) != "/" && ns2.substr(ns2.size() - 1, 1) != "#") ns2 += "/"; @@ -2318,9 +2337,10 @@ namespace Exiv2 { std::string XmpProperties::ns(const std::string& prefix) { - const XmpNsInfo* xn = lookupNsRegistry(XmpNsInfo::Prefix(prefix)); + Internal::ScopedReadLock srl(rwLock_); + const XmpNsInfo* xn = lookupNsRegistryUnsafe(XmpNsInfo::Prefix(prefix)); if (xn != 0) return xn->ns_; - return nsInfo(prefix)->ns_; + return nsInfoUnsafe(prefix)->ns_; } const char* XmpProperties::propertyTitle(const XmpKey& key) @@ -2384,8 +2404,15 @@ namespace Exiv2 { const XmpNsInfo* XmpProperties::nsInfo(const std::string& prefix) { + Internal::ScopedReadLock srl(rwLock_); + return nsInfoUnsafe(prefix); + } + + const XmpNsInfo* XmpProperties::nsInfoUnsafe(const std::string& prefix) + { + Internal::ScopedReadLock srl(rwLock_); const XmpNsInfo::Prefix pf(prefix); - const XmpNsInfo* xn = lookupNsRegistry(pf); + const XmpNsInfo* xn = lookupNsRegistryUnsafe(pf); if (!xn) xn = find(xmpNsInfo, pf); if (!xn) throw Error(35, prefix); return xn;