diff options
author | Hubert Figuière <hub@figuiere.net> | 2013-05-14 18:21:26 -0400 |
---|---|---|
committer | Hubert Figuière <hub@figuiere.net> | 2013-05-14 18:21:26 -0400 |
commit | 81a4c6bcb1879cb321246590faca595e9746f8e5 (patch) | |
tree | cf92c416eb3e41708149905abd0030680aebadf5 /XMPFiles/source/PluginHandler | |
parent | 42dbac60f15e038270d6e0c7285caba8256e86f1 (diff) |
Update to XMP SDK CS6
Diffstat (limited to 'XMPFiles/source/PluginHandler')
-rw-r--r-- | XMPFiles/source/PluginHandler/FileHandler.h | 101 | ||||
-rw-r--r-- | XMPFiles/source/PluginHandler/FileHandlerInstance.cpp | 106 | ||||
-rw-r--r-- | XMPFiles/source/PluginHandler/FileHandlerInstance.h | 47 | ||||
-rw-r--r-- | XMPFiles/source/PluginHandler/HostAPIImpl.cpp | 637 | ||||
-rw-r--r-- | XMPFiles/source/PluginHandler/Module.cpp | 169 | ||||
-rw-r--r-- | XMPFiles/source/PluginHandler/Module.h | 65 | ||||
-rw-r--r-- | XMPFiles/source/PluginHandler/ModuleUtils.h | 77 | ||||
-rw-r--r-- | XMPFiles/source/PluginHandler/OS_Utils_Linux.cpp | 230 | ||||
-rw-r--r-- | XMPFiles/source/PluginHandler/OS_Utils_Mac.cpp | 366 | ||||
-rw-r--r-- | XMPFiles/source/PluginHandler/OS_Utils_WIN.cpp | 66 | ||||
-rw-r--r-- | XMPFiles/source/PluginHandler/PluginManager.cpp | 779 | ||||
-rw-r--r-- | XMPFiles/source/PluginHandler/PluginManager.h | 190 | ||||
-rw-r--r-- | XMPFiles/source/PluginHandler/XMPAtoms.cpp | 408 | ||||
-rw-r--r-- | XMPFiles/source/PluginHandler/XMPAtoms.h | 200 |
14 files changed, 3441 insertions, 0 deletions
diff --git a/XMPFiles/source/PluginHandler/FileHandler.h b/XMPFiles/source/PluginHandler/FileHandler.h new file mode 100644 index 0000000..16e4c6b --- /dev/null +++ b/XMPFiles/source/PluginHandler/FileHandler.h @@ -0,0 +1,101 @@ +// ================================================================================================= +// ADOBE SYSTEMS INCORPORATED +// Copyright 2011 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. +// ================================================================================================= + +#ifndef PLUGINHANDLER_H +#define PLUGINHANDLER_H +#include "Module.h" + +namespace XMP_PLUGIN +{ + +/** @struct CheckFormat + * @brief Record of byte sequences. + * + * It is a static information of the file handler provided in the resource file, if the format + * can be identified by one or more sequences of fixed bytes at a fixed location within the format. + */ +struct CheckFormat +{ + XMP_Int64 mOffset; + XMP_Uns32 mLength; + std::string mByteSeq; + + CheckFormat(): mOffset( 0 ), mLength( 0 ) { } + + inline void clear() + { + mOffset = 0; mLength = 0; mByteSeq.clear(); + } + + inline bool empty() + { + return ( mLength == 0 || mByteSeq.empty() ); + } +}; + +/** @class FileHandler + * @brief File handler exposed through plugin architecture. + * + * At the initialization time of XMPFiles only static information from all the avalbale plugins + * is populated by creating instance of this class FileHandler. It's loaded later when it's actually + * required to get information from the format. + */ +class FileHandler +{ +public: + + FileHandler(std::string & uid, XMP_OptionBits handlerFlags, FileHandlerType type, ModuleSharedPtr module): + mVersion(0), mUID(uid), mHandlerFlags(handlerFlags), mType(type), mModule(module), mOverwrite(false) {} + + virtual ~FileHandler(){} + + inline XMP_Int64 getVersion() const { return mVersion; } + inline void setVersion( XMP_Uns32 version ) { mVersion = version; } + + inline const std::string& getUID() const { return mUID; } + inline XMP_OptionBits getHandlerFlags() const { return mHandlerFlags; } + inline void setHandlerFlags( XMP_OptionBits flags ) { mHandlerFlags = flags; } + + inline XMP_OptionBits getSerializeOption() const { return mSerializeOption; } + inline void setSerializeOption( XMP_OptionBits option ) { mSerializeOption = option; } + + inline bool getOverwriteHandler() const { return mOverwrite; } + inline void setOverwriteHandler( bool overwrite ) { mOverwrite = overwrite; } + + inline FileHandlerType getHandlerType() const { return mType; } + inline void setHandlerType( FileHandlerType type ) { mType = type; } + + inline bool load() { return mModule->load(); } + inline ModuleSharedPtr getModule() const { return mModule; } + + inline void addCheckFormat( const CheckFormat & checkFormat ) { mCheckFormatVec.push_back( checkFormat ); } + inline XMP_Uns32 getCheckFormatSize() const { return (XMP_Uns32) mCheckFormatVec.size(); } + inline CheckFormat getCheckFormat( XMP_Uns32 index ) const + { + CheckFormat checkFormat; + if( index < mCheckFormatVec.size() ) + checkFormat = mCheckFormatVec[index]; + return checkFormat; + } + +private: + typedef std::vector<CheckFormat> CheckFormatVec; + + CheckFormatVec mCheckFormatVec; + XMP_Uns32 mVersion; + std::string mUID; + XMP_OptionBits mHandlerFlags; + XMP_OptionBits mSerializeOption; + bool mOverwrite; + FileHandlerType mType; + ModuleSharedPtr mModule; +}; + +} //namespace XMP_PLUGIN +#endif //PLUGINHANDLER_H diff --git a/XMPFiles/source/PluginHandler/FileHandlerInstance.cpp b/XMPFiles/source/PluginHandler/FileHandlerInstance.cpp new file mode 100644 index 0000000..42de1a4 --- /dev/null +++ b/XMPFiles/source/PluginHandler/FileHandlerInstance.cpp @@ -0,0 +1,106 @@ +// ================================================================================================= +// ADOBE SYSTEMS INCORPORATED +// Copyright 2011 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 "FileHandlerInstance.h" + +namespace XMP_PLUGIN +{ + +FileHandlerInstance::FileHandlerInstance ( SessionRef object, FileHandlerSharedPtr handler, XMPFiles * _parent ): +XMPFileHandler( _parent ), mObject( object ), mHandler( handler ) +{ + this->handlerFlags = mHandler->getHandlerFlags(); + this->stdCharForm = kXMP_Char8Bit; + PluginManager::addHandlerInstance( this->mObject, this ); +} + +FileHandlerInstance::~FileHandlerInstance() +{ + WXMP_Error error; + mHandler->getModule()->getPluginAPIs()->mTerminateSessionProc( this->mObject, &error ); + PluginManager::removeHandlerInstance( this->mObject ); + CheckError( error ); +} + +bool FileHandlerInstance::GetFileModDate ( XMP_DateTime * modDate ) +{ + bool ok; + WXMP_Error error; + GetSessionFileModDateProc wGetFileModDate = mHandler->getModule()->getPluginAPIs()->mGetFileModDateProc; + wGetFileModDate ( this->mObject, &ok, modDate, &error ); + CheckError ( error ); + return ok; +} + +void FileHandlerInstance::CacheFileData() +{ + if( this->containsXMP ) return; + + WXMP_Error error; + XMP_StringPtr xmpStr = NULL; + mHandler->getModule()->getPluginAPIs()->mCacheFileDataProc( this->mObject, this->parent->ioRef, &xmpStr, &error ); + + if( error.mErrorID != kXMPErr_NoError ) + { + if ( xmpStr != 0 ) free( (void*) xmpStr ); + throw XMP_Error( kXMPErr_InternalFailure, error.mErrorMsg ); + } + + if( xmpStr != NULL ) + { + this->xmpPacket.assign( xmpStr ); + free( (void*) xmpStr ); // It should be freed as documentation of mCacheFileDataProc says so. + } + this->containsXMP = true; +} + +void FileHandlerInstance::ProcessXMP() +{ + if( !this->containsXMP || this->processedXMP ) return; + this->processedXMP = true; + + SXMPUtils::RemoveProperties ( &this->xmpObj, 0, 0, kXMPUtil_DoAllProperties ); + this->xmpObj.ParseFromBuffer ( this->xmpPacket.c_str(), (XMP_StringLen)this->xmpPacket.size() ); + + WXMP_Error error; + if( mHandler->getModule()->getPluginAPIs()->mImportToXMPProc ) + mHandler->getModule()->getPluginAPIs()->mImportToXMPProc( this->mObject, this->xmpObj.GetInternalRef(), &error ); + CheckError( error ); +} + +void FileHandlerInstance::UpdateFile ( bool doSafeUpdate ) +{ + if ( !this->needsUpdate || this->xmpPacket.size() == 0 ) return; + + WXMP_Error error; + if( mHandler->getModule()->getPluginAPIs()->mExportFromXMPProc ) + mHandler->getModule()->getPluginAPIs()->mExportFromXMPProc( this->mObject, this->xmpObj.GetInternalRef(), &error ); + CheckError( error ); + + this->xmpObj.SerializeToBuffer ( &this->xmpPacket, mHandler->getSerializeOption() ); + + mHandler->getModule()->getPluginAPIs()->mUpdateFileProc( this->mObject, this->parent->ioRef, doSafeUpdate, this->xmpPacket.c_str(), &error ); + CheckError( error ); + this->needsUpdate = false; +} + +void FileHandlerInstance::WriteTempFile( XMP_IO* tempRef ) +{ + WXMP_Error error; + if( mHandler->getModule()->getPluginAPIs()->mExportFromXMPProc ) + mHandler->getModule()->getPluginAPIs()->mExportFromXMPProc( this->mObject, this->xmpObj.GetInternalRef(), &error ); + CheckError( error ); + + this->xmpObj.SerializeToBuffer ( &this->xmpPacket, mHandler->getSerializeOption() ); + + mHandler->getModule()->getPluginAPIs()->mWriteTempFileProc( this->mObject, this->parent->ioRef, tempRef, this->xmpPacket.c_str(), &error ); + CheckError( error ); +} + +} //namespace XMP_PLUGIN diff --git a/XMPFiles/source/PluginHandler/FileHandlerInstance.h b/XMPFiles/source/PluginHandler/FileHandlerInstance.h new file mode 100644 index 0000000..5cf2420 --- /dev/null +++ b/XMPFiles/source/PluginHandler/FileHandlerInstance.h @@ -0,0 +1,47 @@ +// ================================================================================================= +// ADOBE SYSTEMS INCORPORATED +// Copyright 2011 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. +// ================================================================================================= + +#ifndef PLUGINHANDLERINSTANCE_H +#define PLUGINHANDLERINSTANCE_H +#include "FileHandler.h" + +namespace XMP_PLUGIN +{ + +/** @class FileHandlerInstance + * @brief This class is equivalent to the native file handlers like JPEG_MetaHandler or the simialr one. + * + * This class is equivalent to the native file handler. This class is supposed to support all the + * function which a native file handler support. + * As of now, it support only the functions required for OwningFileHandler. + */ +class FileHandlerInstance : public XMPFileHandler +{ +public: + FileHandlerInstance ( SessionRef object, FileHandlerSharedPtr handler, XMPFiles * parent ); + virtual ~FileHandlerInstance(); + + virtual bool GetFileModDate ( XMP_DateTime * modDate ); + + virtual void CacheFileData(); + virtual void ProcessXMP(); + //virtual XMP_OptionBits GetSerializeOptions(); //It should not be needed as its required only inside updateFile. + virtual void UpdateFile ( bool doSafeUpdate ); + virtual void WriteTempFile ( XMP_IO* tempRef ); + + inline SessionRef GetSession() const { return mObject; } + inline FileHandlerSharedPtr GetHandlerInfo() const { return mHandler; } + +private: + SessionRef mObject; + FileHandlerSharedPtr mHandler; +}; + +} //namespace XMP_PLUGIN +#endif diff --git a/XMPFiles/source/PluginHandler/HostAPIImpl.cpp b/XMPFiles/source/PluginHandler/HostAPIImpl.cpp new file mode 100644 index 0000000..04dcdd0 --- /dev/null +++ b/XMPFiles/source/PluginHandler/HostAPIImpl.cpp @@ -0,0 +1,637 @@ +// ================================================================================================= +// ADOBE SYSTEMS INCORPORATED +// Copyright 2011 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 "HostAPI.h" +#include "PluginManager.h" +#include "FileHandlerInstance.h" +#include "source/XIO.hpp" +#include "XMPFiles/source/HandlerRegistry.h" + +using namespace Common; + +namespace XMP_PLUGIN +{ + +/////////////////////////////////////////////////////////////////////////////// +// +// Exception handler +// + +static void HandleException( WXMP_Error* wError ) +{ + try + { + throw; + } + catch( XMP_Error& xmpErr ) + { + wError->mErrorMsg = xmpErr.GetErrMsg(); + wError->mErrorID = xmpErr.GetID(); + } + catch( std::exception& stdErr ) + { + wError->mErrorMsg = stdErr.what(); + } + catch( ... ) + { + wError->mErrorMsg = "Caught unknown exception"; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// FileIO_API +// + +static XMPErrorID FileSysRead( XMP_IORef io, void* buffer, XMP_Uns32 count, bool readAll, XMP_Uns32& byteRead, WXMP_Error * wError ) +{ + if( wError == NULL ) return kXMPErr_BadParam; + + wError->mErrorID = kXMPErr_InternalFailure; + + try + { + if( io != NULL ) + { + ::XMP_IO * thiz = (::XMP_IO*)io; + byteRead = thiz->Read( buffer, count, readAll ); + wError->mErrorID = kXMPErr_NoError; + } + } + catch( ... ) + { + HandleException( wError ); + } + + return wError->mErrorID; +} + +static XMPErrorID FileSysWrite( XMP_IORef io, void* buffer, XMP_Uns32 count, WXMP_Error * wError ) +{ + if( wError == NULL ) return kXMPErr_BadParam; + + wError->mErrorID = kXMPErr_InternalFailure; + + try + { + if( io != NULL ) + { + ::XMP_IO * thiz = (::XMP_IO*)io; + thiz->Write( buffer, count ); + wError->mErrorID = kXMPErr_NoError; + } + } + catch( ... ) + { + HandleException( wError ); + } + + return wError->mErrorID; +} + +static XMPErrorID FileSysSeek( XMP_IORef io, XMP_Int64& offset, SeekMode mode, WXMP_Error * wError ) +{ + if( wError == NULL ) return kXMPErr_BadParam; + + wError->mErrorID = kXMPErr_InternalFailure; + + try + { + if( io != NULL ) + { + ::XMP_IO * thiz = (::XMP_IO*)io; + thiz->Seek( offset, mode ); + wError->mErrorID = kXMPErr_NoError; + } + } + catch( ... ) + { + HandleException( wError ); + } + + return wError->mErrorID; +} + +static XMPErrorID FileSysLength( XMP_IORef io, XMP_Int64& length, WXMP_Error * wError ) +{ + if( wError == NULL ) return kXMPErr_BadParam; + + wError->mErrorID = kXMPErr_InternalFailure; + + try + { + if( io != NULL ) + { + ::XMP_IO * thiz = (::XMP_IO*)io; + length = thiz->Length(); + wError->mErrorID = kXMPErr_NoError; + } + } + catch( ... ) + { + HandleException( wError ); + } + + return wError->mErrorID; +} + +static XMPErrorID FileSysTruncate( XMP_IORef io, XMP_Int64 length, WXMP_Error * wError ) +{ + if( wError == NULL ) return kXMPErr_BadParam; + + wError->mErrorID = kXMPErr_InternalFailure; + + try + { + if( io != NULL ) + { + ::XMP_IO * thiz = (::XMP_IO*)io; + thiz->Truncate( length ); + wError->mErrorID = kXMPErr_NoError; + } + } + catch( ... ) + { + HandleException( wError ); + } + + return wError->mErrorID; +} + +static XMPErrorID FileSysDeriveTemp( XMP_IORef io, XMP_IORef& tempIO, WXMP_Error * wError ) +{ + if( wError == NULL ) return kXMPErr_BadParam; + + wError->mErrorID = kXMPErr_InternalFailure; + + try + { + if( io != NULL ) + { + ::XMP_IO * thiz = (::XMP_IO*)io; + tempIO = thiz->DeriveTemp(); + wError->mErrorID = kXMPErr_NoError; + } + } + catch( ... ) + { + HandleException( wError ); + } + + return wError->mErrorID; +} + +static XMPErrorID FileSysAbsorbTemp( XMP_IORef io, WXMP_Error * wError ) +{ + if( wError == NULL ) return kXMPErr_BadParam; + + wError->mErrorID = kXMPErr_InternalFailure; + + try + { + if( io != NULL ) + { + ::XMP_IO * thiz = (::XMP_IO*)io; + thiz->AbsorbTemp(); + wError->mErrorID = kXMPErr_NoError; + } + } + catch( ... ) + { + HandleException( wError ); + } + + return wError->mErrorID; +} + +static XMPErrorID FileSysDeleteTemp( XMP_IORef io, WXMP_Error * wError ) +{ + if( wError == NULL ) return kXMPErr_BadParam; + + wError->mErrorID = kXMPErr_InternalFailure; + + try + { + if( io != NULL ) + { + ::XMP_IO * thiz = (::XMP_IO*)io; + thiz->DeleteTemp(); + wError->mErrorID = kXMPErr_NoError; + } + } + catch( ... ) + { + HandleException( wError ); + } + + return wError->mErrorID; +} + +static void GetFileSysAPI( FileIO_API* fileSys ) +{ + if( fileSys ) + { + fileSys->mReadProc = FileSysRead; + fileSys->mWriteProc = FileSysWrite; + fileSys->mSeekProc = FileSysSeek; + fileSys->mLengthProc = FileSysLength; + fileSys->mTruncateProc = FileSysTruncate; + fileSys->mDeriveTempProc = FileSysDeriveTemp; + fileSys->mAbsorbTempProc = FileSysAbsorbTemp; + fileSys->mDeleteTempProc = FileSysDeleteTemp; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// String_API +// + +static XMPErrorID CreateBuffer( StringPtr* buffer, XMP_Uns32 size, WXMP_Error * wError ) +{ + if( wError == NULL ) return kXMPErr_BadParam; + + wError->mErrorID = kXMPErr_InternalFailure; + + try + { + if( buffer != NULL ) + { + *buffer = (StringPtr) malloc( size ); + if( *buffer != NULL ) + { + wError->mErrorID = kXMPErr_NoError; + } + else + { + wError->mErrorMsg = "Allocation failed"; + } + } + } + catch( ... ) + { + HandleException( wError ); + } + + return wError->mErrorID; +} + +static XMPErrorID ReleaseBuffer( StringPtr buffer, WXMP_Error * wError ) +{ + if( wError == NULL ) return kXMPErr_BadParam; + + wError->mErrorID = kXMPErr_InternalFailure; + + try + { + if( buffer ) + { + free( buffer ); + wError->mErrorID = kXMPErr_NoError; + } + } + catch( ... ) + { + HandleException( wError ); + } + + return wError->mErrorID; +} + +static void GetStringAPI( String_API* strAPI ) +{ + if( strAPI ) + { + strAPI->mCreateBufferProc = CreateBuffer; + strAPI->mReleaseBufferProc = ReleaseBuffer; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Abort_API +// + +static XMPErrorID CheckAbort( SessionRef session, bool* aborted, WXMP_Error* wError ) +{ + if( wError == NULL ) return kXMPErr_BadParam; + + wError->mErrorID = kXMPErr_InternalFailure; + + if( aborted ) + { + *aborted = false; + + // + // find FileHandlerInstance associated to session reference + // + FileHandlerInstancePtr instance = PluginManager::getHandlerInstance( session ); + + if( instance != NULL ) + { + // + // execute abort procedure if available + // + wError->mErrorID = kXMPErr_NoError; + XMP_AbortProc proc = instance->parent->abortProc; + void* arg = instance->parent->abortArg; + + if( proc ) + { + try + { + *aborted = proc( arg ); + } + catch( ... ) + { + HandleException( wError ); + } + } + } + } + else + { + wError->mErrorMsg = "Invalid parameter"; + } + + return wError->mErrorID; +} + +static void GetAbortAPI( Abort_API* abortAPI ) +{ + if( abortAPI ) + { + abortAPI->mCheckAbort = CheckAbort; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// StandardHandler_API +// + +static XMPErrorID CheckFormatStandardHandler( SessionRef session, XMP_FileFormat format, StringPtr path, bool& checkOK, WXMP_Error* wError ) +{ + if( wError == NULL ) return kXMPErr_BadParam; + + wError->mErrorID = kXMPErr_InternalFailure; + wError->mErrorMsg = NULL; + checkOK = false; + + // + // find FileHandlerInstance associated to session reference + // + FileHandlerInstancePtr instance = PluginManager::getHandlerInstance( session ); + + if( instance != NULL && PluginManager::getHandlerPriority( instance ) == PluginManager::kReplacementHandler ) + { + // + // find previous file handler for file format identifier + // + XMPFileHandlerInfo* hdlInfo = HandlerRegistry::getInstance().getStandardHandlerInfo( format ); + + if( hdlInfo != NULL && HandlerRegistry::getInstance().isReplaced( format ) ) + { + if( hdlInfo->checkProc != NULL ) + { + try + { + // + // setup temporary XMPFiles instance + // + XMPFiles standardClient; + standardClient.format = format; + standardClient.filePath = std::string( path ); + + if( hdlInfo->flags & kXMPFiles_FolderBasedFormat ) + { + // + // process folder based handler + // + if( path != NULL ) + { + // The following code corresponds to the one found in HandlerRegistry::selectSmartHandler, + // in the folder based handler selection section of the function + // In this case the format is already known, therefor no folder checks are needed here, + // but the path must be split into the meaningful parts to call checkFolderFormat correctly + + std::string rootPath = path; + std::string leafName; + std::string fileExt; + std::string gpName; + std::string parentName; + + XIO::SplitLeafName ( &rootPath, &leafName ); + + if( !leafName.empty() ) + { + size_t extPos = leafName.size(); + + for ( --extPos; extPos > 0; --extPos ) if ( leafName[extPos] == '.' ) break; + + if( leafName[extPos] == '.' ) + { + fileExt.assign( &leafName[extPos+1] ); + MakeLowerCase( &fileExt ); + leafName.erase( extPos ); + } + + CheckFolderFormatProc CheckProc = (CheckFolderFormatProc) (hdlInfo->checkProc); + + // The case that a logical path to a clip has been passed, which does not point to a real file + if( Host_IO::GetFileMode( path ) == Host_IO::kFMode_DoesNotExist ) + { + checkOK = CheckProc( hdlInfo->format, rootPath, gpName, parentName, leafName, &standardClient ); + } + else + { + XIO::SplitLeafName( &rootPath, &parentName ); + XIO::SplitLeafName( &rootPath, &gpName ); + std::string origGPName ( gpName ); // ! Save the original case for XDCAM-FAM. + MakeUpperCase( &parentName ); + MakeUpperCase( &gpName ); + + if( format == kXMP_XDCAM_FAMFile && ( (parentName == "CLIP") || (parentName == "EDIT") || (parentName == "SUB") ) ) + { + // ! The standard says Clip/Edit/Sub, but we just shifted to upper case. + gpName = origGPName; // ! XDCAM-FAM has just 1 level of inner folder, preserve the "MyMovie" case. + } + + checkOK = CheckProc( hdlInfo->format, rootPath, gpName, parentName, leafName, &standardClient ); + } + } + else + { + wError->mErrorID = kXMPErr_BadParam; + } + } + else + { + wError->mErrorID = kXMPErr_BadParam; + } + } + else + { + // + // file based handler (requires XMP_IO object) + // + CheckFileFormatProc CheckProc = (CheckFileFormatProc) (hdlInfo->checkProc); + XMPFiles_IO* io = XMPFiles_IO::New_XMPFiles_IO ( path, true ); + checkOK = CheckProc( hdlInfo->format, path, io, &standardClient ); + delete io; + } + + wError->mErrorID = kXMPErr_NoError; + } + catch( ... ) + { + HandleException( wError ); + } + } + } + else + { + wError->mErrorMsg = "No standard handler available"; + } + } + else + { + wError->mErrorMsg = "Standard file handler can't call prior handler"; + } + + return wError->mErrorID; +} + +static XMPErrorID GetXMPStandardHandler( SessionRef session, XMP_FileFormat format, StringPtr path, XMPMetaRef xmpRef, bool* xmpExists, WXMP_Error* wError ) +{ + if( wError == NULL ) return kXMPErr_BadParam; + + wError->mErrorID = kXMPErr_InternalFailure; + wError->mErrorMsg = NULL; + + // + // find FileHandlerInstance associated to session reference + // + FileHandlerInstancePtr instance = PluginManager::getHandlerInstance( session ); + + if( instance != NULL && PluginManager::getHandlerPriority( instance ) == PluginManager::kReplacementHandler ) + { + // + // find previous file handler for file format identifier + // + XMPFileHandlerInfo* hdlInfo = HandlerRegistry::getInstance().getStandardHandlerInfo( format ); + + if( hdlInfo != NULL && HandlerRegistry::getInstance().isReplaced( format ) ) + { + // + // check format first + // + bool suc = false; + + XMPErrorID errorID = CheckFormatStandardHandler( session, format, path, suc, wError ); + + if( errorID == kXMPErr_NoError && suc ) + { + // + // setup temporary XMPFiles instance + // + XMPFiles standardClient; + standardClient.format = format; + standardClient.filePath = std::string( path ); + + SXMPMeta meta( xmpRef ); + + try + { + // + // open with passed handler info + // + suc = standardClient.OpenFile( *hdlInfo, path, kXMPFiles_OpenForRead ); + + if( suc ) + { + // + // read meta data + // + suc = standardClient.GetXMP( &meta ); + + if( xmpExists != NULL ) *xmpExists = suc; + } + } + catch( ... ) + { + HandleException( wError ); + } + + // + // close and cleanup + // + try + { + standardClient.CloseFile(); + } + catch( ... ) + { + HandleException( wError ); + } + } + else if( errorID == kXMPErr_NoError ) + { + wError->mErrorID = kXMPErr_BadFileFormat; + wError->mErrorMsg = "Standard handler can't process file format"; + } + } + else + { + wError->mErrorID = kXMPErr_NoFileHandler; + wError->mErrorMsg = "No standard handler available"; + } + } + else + { + wError->mErrorMsg = "Standard file handler can't call prior handler"; + } + + return wError->mErrorID; +} + +static void GetStandardHandlerAPI( StandardHandler_API* standardHandlerAPI ) +{ + if( standardHandlerAPI ) + { + standardHandlerAPI->mCheckFormatStandardHandler = CheckFormatStandardHandler; + standardHandlerAPI->mGetXMPStandardHandler = GetXMPStandardHandler; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// Init/Term Host APIs +// + +void PluginManager::SetupHostAPI_V1( HostAPIRef hostAPI ) +{ + // Get XMP_IO APIs + hostAPI->mFileIOAPI = new FileIO_API(); + GetFileSysAPI( hostAPI->mFileIOAPI ); + + // Get String APIs + hostAPI->mStrAPI = new String_API(); + GetStringAPI( hostAPI->mStrAPI ); + + // Get Abort API + hostAPI->mAbortAPI = new Abort_API(); + GetAbortAPI( hostAPI->mAbortAPI ); + + // Get standard handler APIs + hostAPI->mStandardHandlerAPI = new StandardHandler_API(); + GetStandardHandlerAPI( hostAPI->mStandardHandlerAPI ); +} + +} //namespace XMP_PLUGIN diff --git a/XMPFiles/source/PluginHandler/Module.cpp b/XMPFiles/source/PluginHandler/Module.cpp new file mode 100644 index 0000000..91b8ea8 --- /dev/null +++ b/XMPFiles/source/PluginHandler/Module.cpp @@ -0,0 +1,169 @@ +// ================================================================================================= +// ADOBE SYSTEMS INCORPORATED +// Copyright 2011 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 "Module.h" + +namespace XMP_PLUGIN +{ + +PluginAPIRef Module::getPluginAPIs() +{ + // + // return ref. to Plugin API, load module if not yet loaded + // + if( !mPluginAPIs && !load() ) + { + XMP_Throw ( "Plugin API not available.", kXMPErr_Unavailable ); + } + + return mPluginAPIs; +} + +bool Module::load() +{ + if( mLoaded == kModuleNotLoaded ) + { + std::string errorMsg; + + // + // load module + // + mLoaded = kModuleErrorOnLoad; + mHandle = LoadModule(mPath, false); + + if( mHandle != NULL ) + { + // + // get entry point function pointer + // + InitializePluginProc InitializePlugin = reinterpret_cast<InitializePluginProc>( + GetFunctionPointerFromModuleImpl(mHandle, "InitializePlugin") ); + + if( InitializePlugin != NULL ) + { + // + // get module ID from plugin resource + // + std::string moduleID; + GetResourceDataFromModule(mHandle, "MODULE_IDENTIFIER", "txt", moduleID); + mPluginAPIs = new PluginAPI(); + + // + // initialize plugin by calling entry point function + // + WXMP_Error error; + InitializePlugin( moduleID.c_str(), mPluginAPIs, &error ); + + if( error.mErrorID == kXMPErr_NoError + && mPluginAPIs->mTerminatePluginProc + && mPluginAPIs->mSetHostAPIProc + && mPluginAPIs->mInitializeSessionProc + && mPluginAPIs->mTerminateSessionProc + && mPluginAPIs->mCacheFileDataProc + && mPluginAPIs->mUpdateFileProc + && mPluginAPIs->mWriteTempFileProc + ) + { + // + // set host API at plugin + // + HostAPIRef hostAPI = PluginManager::getHostAPI( mPluginAPIs->mVersion ); + mPluginAPIs->mSetHostAPIProc( hostAPI, &error ); + + if( error.mErrorID == kXMPErr_NoError ) + { + mLoaded = kModuleLoaded; + } + else + { + errorMsg = "Incompatible plugin API version. (" + moduleID + ")"; + } + } + else + { + if( error.mErrorID != kXMPErr_NoError ) + { + errorMsg = "Plugin initialization failed. (" + moduleID + ")"; + } + else + { + errorMsg = "Plugin API incomplete. (" + moduleID + ")"; + } + } + } + else + { + errorMsg = "Missing plugin entry point \"InitializePlugin\" in plugin " + mPath; + } + + if( mLoaded != kModuleLoaded ) + { + // + // plugin wasn't loaded and initialized successfully, + // so unload the module + // + this->unload(); + } + } + else + { + errorMsg = "Can't load module " + mPath; + } + + if( mLoaded != kModuleLoaded ) + { + // + // error occurred + // + throw XMP_Error( kXMPErr_InternalFailure, errorMsg.c_str() ); + } + } + + return ( mLoaded == kModuleLoaded ); +} + +void Module::unload() +{ + WXMP_Error error; + + // + // terminate plugin + // + if( mPluginAPIs != NULL ) + { + if( mPluginAPIs->mTerminatePluginProc ) + { + mPluginAPIs->mTerminatePluginProc( &error ); + } + delete mPluginAPIs; + mPluginAPIs = NULL; + } + + // + // unload plugin module + // + if( mLoaded != kModuleNotLoaded ) + { + UnloadModule(mHandle, false); + mHandle = NULL; + if( mLoaded == kModuleLoaded ) + { + // + // Reset mLoaded to kModuleNotLoaded, if the module was loaded successfully. + // Otherwise let it remain kModuleErrorOnLoad so that we won't try to load + // it again if some other handler ask to do so. + // + mLoaded = kModuleNotLoaded; + } + } + + CheckError( error ); +} + +} //namespace XMP_PLUGIN diff --git a/XMPFiles/source/PluginHandler/Module.h b/XMPFiles/source/PluginHandler/Module.h new file mode 100644 index 0000000..0e308a0 --- /dev/null +++ b/XMPFiles/source/PluginHandler/Module.h @@ -0,0 +1,65 @@ +// ================================================================================================= +// ADOBE SYSTEMS INCORPORATED +// Copyright 2011 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. +// ================================================================================================= + +#ifndef MODULE_H +#define MODULE_H +#include "ModuleUtils.h" +#include "PluginManager.h" + +namespace XMP_PLUGIN +{ + +/** @class Module + * @brief Manages module's loading and unloading. + */ +class Module +{ +public: + Module( std::string & path ): + mPath( path ), mHandle( NULL ), mPluginAPIs( NULL ), mLoaded( kModuleNotLoaded ) { } + + ~Module() { unload(); } + + inline OS_ModuleRef getHandle() const { return mHandle; } + inline const std::string & getPath() const { return mPath; } + + /** + * Returns pluginAPI. It loads the module if not already loaded. + * @return pluginAPI. + */ + PluginAPIRef getPluginAPIs(); + + /** + * It loads the module if not already loaded. + * @return true if module is loaded successfully otherwise returns false. + */ + bool load(); + + /** + * Unloads the module if it is loaded. + * @return Void. + */ + void unload(); + +private: + typedef enum + { + kModuleNotLoaded = 0, + kModuleLoaded, + kModuleErrorOnLoad + } LoadStatus; + + std::string mPath; + OS_ModuleRef mHandle; + PluginAPIRef mPluginAPIs; + LoadStatus mLoaded; +}; + +} //namespace XMP_PLUGIN +#endif //MODULE_H diff --git a/XMPFiles/source/PluginHandler/ModuleUtils.h b/XMPFiles/source/PluginHandler/ModuleUtils.h new file mode 100644 index 0000000..eedf6bf --- /dev/null +++ b/XMPFiles/source/PluginHandler/ModuleUtils.h @@ -0,0 +1,77 @@ +// ================================================================================================= +// ADOBE SYSTEMS INCORPORATED +// Copyright 2011 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. +// ================================================================================================= + +#ifndef MODULEUTILS_H +#define MODULEUTILS_H +#include "XMPFiles/source/XMPFiles_Impl.hpp" + +#if XMP_WinBuild +#include <Windows.h> +typedef HMODULE OS_ModuleRef; +#elif XMP_MacBuild +#include <CoreFoundation/CFBundle.h> +#include <tr1/memory> +typedef CFBundleRef OS_ModuleRef; +#elif XMP_UNIXBuild +#include <tr1/memory> +typedef void* OS_ModuleRef; +#else +#error Unsupported operating system +#endif + +namespace XMP_PLUGIN +{ + +/** + * Platform implementation to retrieve a function pointer of the name \param inSymbol from a module \param inOSModule + */ +void* GetFunctionPointerFromModuleImpl( OS_ModuleRef inOSModule, const char* inSymbol ); + +/** + * @return true if @param inModulePath points to a valid shared library +*/ +#if XMP_MacBuild +bool IsValidLibrary( const std::string & inModulePath ); +#endif + +/** + * Load module specified by absolute path \param inModulePath + * + * Win: + * If \param inOnlyResourceAccess = true, only the image is loaded, no referenced dlls are loaded nor initialization code is executed. + * If the module is already loaded and executable, it behaves as \param inOnlyResourceAccess = false. + * The reference count is increased, so don't forget to call UnloadModule. + * + * Mac: + * If \param inOnlyResourceAccess = true, only the CFBundleRef is created. No code is loaded and executed. + */ +OS_ModuleRef LoadModule( const std::string & inModulePath, bool inOnlyResourceAccess = false ); + +/** + * Unload module + * @param inModule + * @param inOnlyResourceAccess = true, close resource file (only relevant for Linux !!). + */ +void UnloadModule( OS_ModuleRef inModule, bool inOnlyResourceAccess = false ); + +/** @brief Read resource file and fill the data in outBuffer + * @param inOSModule Handle of the module. + * @param inResourceName Name of the resource file which needs to be read. + * @param inResourceType Type/Extension of the resource file. + * @param outBuffer Output buffer where data read from the resource file will be stored. + * @return true on success otherwise false + */ +bool GetResourceDataFromModule( + OS_ModuleRef inOSModule, + const std::string & inResourceName, + const std::string & inResourceType, + std::string & outBuffer); + +} //namespace XMP_PLUGIN +#endif diff --git a/XMPFiles/source/PluginHandler/OS_Utils_Linux.cpp b/XMPFiles/source/PluginHandler/OS_Utils_Linux.cpp new file mode 100644 index 0000000..1fe1f9f --- /dev/null +++ b/XMPFiles/source/PluginHandler/OS_Utils_Linux.cpp @@ -0,0 +1,230 @@ +// ================================================================================================= +// ADOBE SYSTEMS INCORPORATED +// Copyright 2011 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 "ModuleUtils.h" +#include "source/UnicodeConversions.hpp" +#include "source/XIO.hpp" + +#include <iostream> +#include <map> +#include <limits> +#include <dlfcn.h> +#include <errno.h> + +namespace XMP_PLUGIN +{ + +// global map of loaded modules (handle, full path) +typedef std::map<OS_ModuleRef, std::string> ModuleRefToPathMap; +static ModuleRefToPathMap sMapModuleRefToPath; +//typedef std::map<void*, std::string> ResourceFileToPathMap; +typedef std::map<OS_ModuleRef, std::string> ResourceFileToPathMap; +static ResourceFileToPathMap sMapResourceFileToPath; + +typedef std::tr1::shared_ptr<int> FilePtr; + +static std::string GetModulePath( OS_ModuleRef inOSModule ); +/** ************************************************************************************************************************ +** CloseFile() +*/ +void CloseFile( + int* inFilePtr) +{ + close(*inFilePtr); + delete inFilePtr; +} + +/** ************************************************************************************************************************ +** OpenResourceFile() +*/ +static FilePtr OpenResourceFile( + OS_ModuleRef inOSModule, + const std::string& inResourceName, + const std::string& inResourceType) +{ + // It is assumed, that all resources reside in a folder with + // the same name as the shared object plus '.resources' extension + std::string path( GetModulePath(inOSModule) ); + + XMP_StringPtr extPos = path.c_str() + path.size(); + for ( ; (extPos != path.c_str()) && (*extPos != '.'); --extPos ) {} + path.erase( extPos - path.c_str() ); // Remove extension + + path += ".resources"; + path += kDirChar; + path += inResourceName + "." + inResourceType; + + FilePtr file; + if( Host_IO::GetFileMode(path.c_str()) == Host_IO::kFMode_IsFile ) + { + int fileRef = ::open( path.c_str(), O_RDONLY ); + if (fileRef != -1) + { + file.reset(new int(fileRef), CloseFile); + } + } + return file; +} + +OS_ModuleRef LoadModule( const std::string & inModulePath, bool inOnlyResourceAccess) +{ + OS_ModuleRef result = NULL; + if( inOnlyResourceAccess ) + { + int fileHandle = open(reinterpret_cast<const char*>(inModulePath.c_str()), O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if( !fileHandle ) + { + std::cerr << "Cannot open library for resource access: " << strerror(errno) << std::endl; + } + else + { // success ! + result = (void*) fileHandle; + ResourceFileToPathMap::const_iterator iter = sMapResourceFileToPath.find(result); + if (iter == sMapResourceFileToPath.end()) + { + // not found, so insert + sMapResourceFileToPath.insert(std::make_pair(result, inModulePath)); + } + } + + } + else + { + result = dlopen(reinterpret_cast<const char*>(inModulePath.c_str()), RTLD_LAZY/*RTLD_NOW*/); + + if( !result ) + { + std::cerr << "Cannot open library: " << dlerror() << std::endl; + } + else + { // success ! + ModuleRefToPathMap::const_iterator iter = sMapModuleRefToPath.find(result); + if( iter == sMapModuleRefToPath.end() ) + { + // not found, so insert + sMapModuleRefToPath.insert(std::make_pair(result, inModulePath)); + } + } + } + + return result; +} + +void UnloadModule( OS_ModuleRef inModule, bool inOnlyResourceAccess ) +{ + if( inModule != NULL ) + { + // we bluntly assume, that only one instance of the same library is loaded ad therefore added to the global map ! + if( inOnlyResourceAccess ) + { + ResourceFileToPathMap::iterator iter = sMapResourceFileToPath.find(inModule); + if( iter != sMapResourceFileToPath.end() ) + { + close((long) inModule); + sMapResourceFileToPath.erase(iter); + } + else + { + XMP_Throw("OS_Utils_Linux::UnloadModule called with invalid module handle", kXMPErr_InternalFailure); + } + } + else + { + ModuleRefToPathMap::iterator iter = sMapModuleRefToPath.find(inModule); + if( iter != sMapModuleRefToPath.end() ) + { + dlclose(inModule); + sMapModuleRefToPath.erase(iter); + } + else + { + XMP_Throw("OS_Utils_Linux::UnloadModule called with invalid module handle", kXMPErr_InternalFailure); + } + } + } +} + +/** ************************************************************************************************************************ +** GetModulePath() +*/ +static std::string GetModulePath( + OS_ModuleRef inOSModule) +{ + std::string result; + + if( inOSModule != NULL ) + { + ModuleRefToPathMap::const_iterator iter = sMapModuleRefToPath.find(inOSModule); + ResourceFileToPathMap::const_iterator iter2 = sMapResourceFileToPath.find(inOSModule); + if( (iter != sMapModuleRefToPath.end()) && (iter2 != sMapResourceFileToPath.end()) ) + { + XMP_Throw("OS_Utils_Linux::GetModulePath: Module handle is present in both global maps", kXMPErr_InternalFailure); + } + if (iter != sMapModuleRefToPath.end()) + { + result = iter->second; + } + else if (iter2 != sMapResourceFileToPath.end()) + { + result = iter2->second; + } + else + { + XMP_Throw("OS_Utils_Linux::GetModulePath: Failed to find inOSModule in global map !", kXMPErr_InternalFailure); + } + } + + return result; +} + +void* GetFunctionPointerFromModuleImpl( OS_ModuleRef inOSModule, const char* inSymbol ) +{ + void* proc = NULL; + if( inOSModule != NULL ) + { + proc = dlsym(inOSModule, inSymbol); + if( !proc ) + { + std::cerr << "Cannot get function " << inSymbol << " : " << dlerror() << std::endl; + } + } + return proc; +} + +bool GetResourceDataFromModule( + OS_ModuleRef inOSModule, + const std::string & inResourceName, + const std::string & inResourceType, + std::string & outBuffer) +{ + bool success = false; + FilePtr file = OpenResourceFile( inOSModule, inResourceName, inResourceType ); + + if( file ) + { + ssize_t size = 0; + ssize_t file_size = ::lseek(*file.get(), 0, SEEK_END); + // presumingly we don't want to load more than 2GByte at once (!) + if( file_size < std::numeric_limits<XMP_Int32>::max() ) + { + size = file_size; + if( size > 0 ) + { + outBuffer.resize(size); + + ::lseek(*file.get(), 0, SEEK_SET); + ssize_t bytesRead = ::read( *file.get(), (unsigned char*)&outBuffer[0], size ); + success = bytesRead == size; + } + } + } + return success; +} + +} //namespace XMP_PLUGIN diff --git a/XMPFiles/source/PluginHandler/OS_Utils_Mac.cpp b/XMPFiles/source/PluginHandler/OS_Utils_Mac.cpp new file mode 100644 index 0000000..c042eb7 --- /dev/null +++ b/XMPFiles/source/PluginHandler/OS_Utils_Mac.cpp @@ -0,0 +1,366 @@ +// ================================================================================================= +// ADOBE SYSTEMS INCORPORATED +// Copyright 2011 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 "ModuleUtils.h" +#include "source/UnicodeConversions.hpp" +#include "source/XIO.hpp" + +#include <CoreFoundation/CFBundle.h> +#include <CoreFoundation/CFDate.h> +#include <CoreFoundation/CFNumber.h> +#include <CoreFoundation/CFError.h> +#include <string> + + +namespace XMP_PLUGIN +{ + +/** ************************************************************************************************************************ +** Auto-releasing wrapper for Core Foundation objects +** AutoCFRef is an auto-releasing wrapper for any Core Foundation data type that can be passed +** to CFRetain and CFRelease. When constructed with a Core Foundation object, it is assumed it +** has just been created; that constructor does not call CFRetain. This supports reference counting +** through Core Foundation's own mechanism. +*/ +template <class T> +class AutoCFRef +{ + +public: + /// Default constructor creates NULL reference + AutoCFRef() + { + mCFTypeRef = NULL; + } + + /// Construct with any CFXXXRef type. + explicit AutoCFRef(const T& value) + { + mCFTypeRef = value; + } + + /// Copy constructor + AutoCFRef(const AutoCFRef<T>& rhs) + { + mCFTypeRef = rhs.mCFTypeRef; + if (mCFTypeRef) + CFRetain(mCFTypeRef); + } + + /// Destructor + ~AutoCFRef() + { + if (mCFTypeRef) + CFRelease(mCFTypeRef); + } + + /// Assignment operator + void operator=(const AutoCFRef<T>& rhs) + { + if (!Same(rhs)) + { + if (mCFTypeRef) + CFRelease(mCFTypeRef); + mCFTypeRef = rhs.mCFTypeRef; + if (mCFTypeRef) + CFRetain(mCFTypeRef); + } + } + + /// Equivalence operator + /** operator== returns logical equivalence, the meaning of which varies from class to class + in Core Foundation. See also AutoCFRef::Same. + @param rhs The AutoCFRef<T> to compare to + @return true if objects are logically equivalent. + */ + bool operator==(const AutoCFRef<T>& rhs) const + { + if (mCFTypeRef && rhs.mCFTypeRef) + return CFEqual(mCFTypeRef, rhs.mCFTypeRef); + else + return mCFTypeRef == rhs.mCFTypeRef; + } + + /// Non-equivalence operator + /** operator!= returns logical equivalence, the meaning of which varies from class to class + in Core Foundation. See also AutoCFRef::Same. + @param rhs The AutoCFRef<T> to compare to + @return true if objects are not logically equivalent. + */ + bool operator!=(const AutoCFRef<T>& rhs) const + { + return !operator==(rhs); + } + + /// References same CF object + /** Same returns true if both objects reference the same CF object (or both are NULL). + For logical equivalence (CFEqual) use == operator. + @param rhs The AutoCFRef<T> to compare to + @return true if AutoRefs reference the same object. + */ + bool Same(const AutoCFRef<T>& rhs) const + { + return mCFTypeRef == rhs.mCFTypeRef; + } + + /// Change the object referenced + /** Reset is used to put a new CF object into a preexisting AutoCFRef. Does NOT call CFRetain, + so if its ref count is 1 on entry, it will delete on destruction, barring other influences. + @param value (optional) the new CFXXXRef to set, default is NULL. + */ + void Reset(T value = NULL) + { + if (value != mCFTypeRef) + { + if (mCFTypeRef) + CFRelease(mCFTypeRef); + mCFTypeRef = value; + } + } + + /// Return true if no object referenced. + bool IsNull() const + { + return mCFTypeRef == NULL; + } + + /// Return retain count. + /** Returns retain count of referenced object from Core Foundation. Can be used to track down + failures in reference management, but be aware that some objects might be returned to your + code by the operating system with a retain count already greater than one. + @return Referenced object's retain count. + */ + CFIndex RetainCount() + { + return mCFTypeRef ? CFGetRetainCount(mCFTypeRef) : 0; + } + + /// Const dereference operator + /** operator* returns a reference to the contained CFTypeRef. Use this to pass the object into + Core Foundation functions. DO NOT use this to create a new AutoCFRef; copy construct instead. + */ + const T& operator*() const + { + return mCFTypeRef; + } + + /// Nonconst dereference operator + /** operator* returns a reference to the contained CFTypeRef. Use this to pass the object into + Core Foundation functions. DO NOT use this to create a new AutoCFRef; copy construct instead. + */ + T& operator*() + { + return mCFTypeRef; + } + +private: + T mCFTypeRef; +}; + +typedef AutoCFRef<CFURLRef> AutoCFURL; +typedef AutoCFRef<CFStringRef> AutoCFString; + +typedef std::tr1::shared_ptr<FSIORefNum> FilePtr; + + +/** ************************************************************************************************************************ +** Convert string into CFString +*/ +static inline CFStringRef MakeCFString(const std::string& inString, CFStringEncoding inEncoding = kCFStringEncodingUTF8) +{ + CFStringRef str = ::CFStringCreateWithCString( NULL, inString.c_str(), inEncoding ); + return str; +} + +/** ************************************************************************************************************************ +** Convert CFString into std::string +*/ +static std::string MacToSTDString(CFStringRef inCFString) +{ + std::string result; + + if (inCFString == NULL) + { + return result; + } + + // The CFStringGetLength returns the length of the string in UTF-16 encoding units. + ::CFIndex const stringUtf16Length = ::CFStringGetLength(inCFString); + if (stringUtf16Length == 0) + { + return result; + } + + // Check if the CFStringRef can allow fast-return. + char const* ptr = ::CFStringGetCStringPtr(inCFString, kCFStringEncodingUTF8); + if (ptr != NULL) + { + result = std::string( ptr ); // This kind of assign expects '\0' termination. + return result; + } + + // Since this is an encoding conversion, the converted string may not be the same length in bytes + // as the CFStringRef in UTF-16 encoding units. + + ::UInt8 const noLossByte = 0; + ::Boolean const internalRepresentation = FALSE; // TRUE is external representation, with a BOM. FALSE means no BOM. + ::CFRange const range = ::CFRangeMake(0, stringUtf16Length); // [NOTE] length is in UTF-16 encoding units, not bytes. + ::CFIndex const maxBufferLength = ::CFStringGetMaximumSizeForEncoding(stringUtf16Length, kCFStringEncodingUTF8); // Convert from UTF-16 encoding units to UTF-8 worst-case-scenario encoding units, in bytes. + ::CFIndex usedBufferLength = 0; // In byte count. + char buffer[1024]; + memset( buffer, 0, 1024 ); + ::CFIndex numberOfUtf16EncodingUnitsConverted = ::CFStringGetBytes(inCFString, range, ::kCFStringEncodingUTF8, noLossByte, internalRepresentation, (UInt8*)buffer, maxBufferLength, &usedBufferLength); + result = std::string( buffer ); + + return result; +} + + +static void CloseFile( FSIORefNum* inFilePtr ) +{ + FSCloseFork(*inFilePtr); + delete inFilePtr; +} + +static FilePtr OpenResourceFile( OS_ModuleRef inOSModule, const std::string& inResourceName, const std::string& inResourceType, bool inSearchInSubFolderWithNameOfResourceType) +{ + FilePtr file; + if (inOSModule != nil) + { + AutoCFString resourceName( MakeCFString( inResourceName ) ); + AutoCFString resourceType( MakeCFString( inResourceType ) ); + AutoCFString subfolderName(inSearchInSubFolderWithNameOfResourceType ? MakeCFString( inResourceType ) : nil); + + AutoCFURL url( + ::CFBundleCopyResourceURL(inOSModule, *resourceName, *resourceType, *subfolderName)); + + FSRef fileReference; + if (!url.IsNull() && ::CFURLGetFSRef(*url, &fileReference)) + { + HFSUniStr255 str; + if (::FSGetDataForkName(&str) == noErr) + { + FSIORefNum forkRef; + if (::FSOpenFork(&fileReference, str.length, str.unicode, fsRdPerm, &forkRef) == noErr) + { + file.reset(new FSIORefNum(forkRef), CloseFile); + } + } + } + } + return file; +} + +bool IsValidLibrary( const std::string & inModulePath ) +{ + bool result = false; + AutoCFURL bundleURL(::CFURLCreateFromFileSystemRepresentation( + kCFAllocatorDefault, + (const UInt8*) inModulePath.c_str(), + inModulePath.size(), + false)); + if (*bundleURL != NULL) + { + CFBundleRef bundle = ::CFBundleCreate(kCFAllocatorDefault, *bundleURL); + if (bundle != NULL) + { + CFArrayRef arrayRef = ::CFBundleCopyExecutableArchitectures(bundle); + if (arrayRef != NULL) + { + result = true; + ::CFRelease(arrayRef); + } + + ::CFRelease(bundle); + } + } + return result; +} + +OS_ModuleRef LoadModule( const std::string & inModulePath, bool inOnlyResourceAccess ) +{ + OS_ModuleRef result = NULL; + AutoCFURL bundleURL(::CFURLCreateFromFileSystemRepresentation( + kCFAllocatorDefault, + (const UInt8*) inModulePath.c_str(), + inModulePath.size(), + false)); + if (*bundleURL != NULL) + { + result = ::CFBundleCreate(kCFAllocatorDefault, *bundleURL); + if (!inOnlyResourceAccess && (result != NULL)) + { + ::CFErrorRef errorRef = NULL; + Boolean loaded = ::CFBundleIsExecutableLoaded(result); + if (!loaded) + { + loaded = ::CFBundleLoadExecutableAndReturnError(result, &errorRef); + if(!loaded || errorRef != NULL) + { + AutoCFString errorDescr(::CFErrorCopyDescription(errorRef)); + throw XMP_Error( kXMPErr_InternalFailure, MacToSTDString(*errorDescr).c_str() ); + ::CFRelease(errorRef); + // release bundle and return NULL + ::CFRelease(result); + result = NULL; + } + } + } + } + return result; +} + +void UnloadModule( OS_ModuleRef inModule, bool inOnlyResourceAccess ) +{ + if (inModule != NULL) + { + ::CFRelease(inModule); + } +} + +void* GetFunctionPointerFromModuleImpl( OS_ModuleRef inOSModule, const char* inSymbol ) +{ + void* proc = NULL; + if( inOSModule != NULL) + { + proc = ::CFBundleGetFunctionPointerForName( inOSModule, *AutoCFString(MakeCFString(inSymbol)) ); + } + return proc; +} + +bool GetResourceDataFromModule( + OS_ModuleRef inOSModule, + const std::string & inResourceName, + const std::string & inResourceType, + std::string & outBuffer) +{ + bool success = false; + + if (FilePtr file = OpenResourceFile(inOSModule, inResourceName, inResourceType, false)) + { + ByteCount size = 0; + SInt64 fork_size = 0; + ::FSGetForkSize(*file.get(), &fork_size); + // presumingly we don't want to load more than 2GByte at once (!) + if( fork_size < std::numeric_limits<XMP_Int32>::max() ) + { + size = static_cast<ByteCount>(fork_size); + if (size > 0) + { + outBuffer.resize(size); + ::FSReadFork(*file.get(), fsFromStart, 0, size, (unsigned char*)&outBuffer[0], (ByteCount*)&size); + } + success = true; + } + } + + return success; +} + +} //namespace XMP_PLUGIN diff --git a/XMPFiles/source/PluginHandler/OS_Utils_WIN.cpp b/XMPFiles/source/PluginHandler/OS_Utils_WIN.cpp new file mode 100644 index 0000000..66df45a --- /dev/null +++ b/XMPFiles/source/PluginHandler/OS_Utils_WIN.cpp @@ -0,0 +1,66 @@ +// ================================================================================================= +// ADOBE SYSTEMS INCORPORATED +// Copyright 2011 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 "ModuleUtils.h" +#include "source/UnicodeConversions.hpp" + +namespace XMP_PLUGIN +{ + +OS_ModuleRef LoadModule( const std::string & inModulePath, bool inOnlyResourceAccess) +{ + std::string wideString; + ToUTF16 ( (UTF8Unit*)inModulePath.c_str(), inModulePath.size() + 1, &wideString, false ); // need +1 character otherwise \0 won't be converted into UTF16 + + DWORD flags = inOnlyResourceAccess ? LOAD_LIBRARY_AS_IMAGE_RESOURCE : 0; + OS_ModuleRef result = ::LoadLibraryEx((WCHAR*) wideString.c_str(), NULL, flags); + + // anything below indicates error in LoadLibrary + if((result != NULL) && (result < OS_ModuleRef(32))) + { + result = NULL; + } + return result; +} + +void UnloadModule( OS_ModuleRef inModule, bool inOnlyResourceAccess ) +{ + ::FreeLibrary(inModule); +} + +void* GetFunctionPointerFromModuleImpl( OS_ModuleRef inOSModule, const char* inSymbol ) +{ + return reinterpret_cast<void*>( ::GetProcAddress( inOSModule, inSymbol ) ); +} + +bool GetResourceDataFromModule( + OS_ModuleRef inOSModule, + const std::string & inResourceName, + const std::string & inResourceType, + std::string & outBuffer) +{ + HRSRC src = ::FindResourceA(inOSModule, reinterpret_cast<LPCSTR>(inResourceName.c_str()), reinterpret_cast<LPCSTR>(inResourceType.c_str())); + if( src != NULL ) + { + HGLOBAL resource = (::LoadResource(inOSModule, src)); + HGLOBAL data = (::LockResource(resource)); + std::size_t size = (std::size_t)(::SizeofResource(inOSModule, src)); + if (size) + { + outBuffer.assign((const char*)data, size); + } + UnlockResource(data); + ::FreeResource(resource); + + return true; + } + return false; +} + +} //namespace XMP_PLUGIN
\ No newline at end of file diff --git a/XMPFiles/source/PluginHandler/PluginManager.cpp b/XMPFiles/source/PluginHandler/PluginManager.cpp new file mode 100644 index 0000000..af60388 --- /dev/null +++ b/XMPFiles/source/PluginHandler/PluginManager.cpp @@ -0,0 +1,779 @@ +// ================================================================================================= +// ADOBE SYSTEMS INCORPORATED +// Copyright 2011 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 "PluginManager.h" +#include "FileHandler.h" +#include <algorithm> +#include "XMPAtoms.h" +#include "XMPFiles/source/HandlerRegistry.h" +#include "FileHandlerInstance.h" +#include "HostAPI.h" + +using namespace Common; +using namespace std; + +// ================================================================================================= + +namespace XMP_PLUGIN +{ + +const char* kResourceName_UIDs = "XMPPLUGINUIDS"; +const char* kLibraryExtensions[] = { "xpi" }; + +struct FileHandlerPair +{ + FileHandlerSharedPtr mStandardHandler; + FileHandlerSharedPtr mReplacementHandler; +}; + +// ================================================================================================= + +static XMP_FileFormat GetXMPFileFormatFromFilePath( XMP_StringPtr filePath ) +{ + XMP_StringPtr pathName = filePath + strlen(filePath); + for ( ; pathName > filePath; --pathName ) { + if ( *pathName == '.' ) break; + } + + XMP_StringPtr fileExt = pathName + 1; + return HandlerRegistry::getInstance().getFileFormat ( fileExt ); +} + +// ================================================================================================= + +static XMPFileHandler* Plugin_MetaHandlerCTor ( FileHandlerSharedPtr handler, XMPFiles* parent ) +{ + SessionRef object; + WXMP_Error error; + + if( (handler == 0) || (! handler->load()) ) + { + XMP_Throw ( "Plugin not loaded", kXMPErr_InternalFailure ); + } + + handler->getModule()->getPluginAPIs()->mInitializeSessionProc ( handler->getUID().c_str(), parent->filePath.c_str(), (XMP_Uns32)parent->format, (XMP_Uns32)handler->getHandlerFlags(), (XMP_Uns32)parent->openFlags, &object, &error ); + CheckError ( error ); + + FileHandlerInstance* instance = new FileHandlerInstance ( object, handler, parent ); + return instance; +} + +static XMPFileHandler* Plugin_MetaHandlerCTor_Standard( XMPFiles * parent ) +{ + FileHandlerSharedPtr handler = PluginManager::getFileHandler( parent->format, PluginManager::kStandardHandler ); + + return Plugin_MetaHandlerCTor( handler, parent ); +} + +static XMPFileHandler* Plugin_MetaHandlerCTor_Replacement( XMPFiles * parent ) +{ + FileHandlerSharedPtr handler = PluginManager::getFileHandler( parent->format, PluginManager::kReplacementHandler ); + + return Plugin_MetaHandlerCTor( handler, parent ); +} + +// ================================================================================================= + +static bool Plugin_CheckFileFormat ( FileHandlerSharedPtr handler, XMP_StringPtr filePath, XMP_IO * fileRef, XMPFiles * parent ) +{ + if ( handler != 0 ) { + + // call into plugin if owning handler or if manifest has no CheckFormat entry + if ( fileRef == 0 || handler->getCheckFormatSize() == 0) { + + bool ok; + WXMP_Error error; + CheckSessionFileFormatProc checkProc = handler->getModule()->getPluginAPIs()->mCheckFileFormatProc; + checkProc ( handler->getUID().c_str(), filePath, fileRef, &ok, &error ); + CheckError ( error ); + return ok; + + } else { + + // all CheckFormat manifest entries must match + for ( XMP_Uns32 i=0; i < handler->getCheckFormatSize(); i++ ) { + + CheckFormat checkFormat = handler->getCheckFormat ( i ); + + if ( checkFormat.empty() ) return false; + + XMP_Uns8 buffer[1024]; + + if ( checkFormat.mLength > 1024 ) { + //Ideally check format string should not be that long. + //The check is here to handle only malicious data. + checkFormat.mLength = 1024; + } + + fileRef->Seek ( checkFormat.mOffset, kXMP_SeekFromStart ); + XMP_Uns32 len = fileRef->Read ( buffer, checkFormat.mLength ); + + if ( len != checkFormat.mLength ) { + + // Not enough byte read from the file. + return false; + + } else { + + // Check if byteSeq is hexadecimal byte sequence, e.g 0x03045100 + + bool isHex = ( (checkFormat.mLength > 2) && + (checkFormat.mByteSeq[0] == '0') && + (checkFormat.mByteSeq[1] == 'x') && + (checkFormat.mByteSeq.size() == (2 + 2*checkFormat.mLength)) ); + + if ( ! isHex ) { + + if ( memcmp ( buffer, checkFormat.mByteSeq.c_str(), checkFormat.mLength ) != 0 ) return false; + + } else { + + for ( XMP_Uns32 current = 0; current < checkFormat.mLength; current++ ) { + + char oneByteBuffer[3]; + oneByteBuffer[0] = checkFormat.mByteSeq [ 2 + 2*current ]; + oneByteBuffer[1] = checkFormat.mByteSeq [ 2 + 2*current + 1 ]; + oneByteBuffer[2] = '\0'; + + XMP_Uns8 oneByte = (XMP_Uns8) strtoul ( oneByteBuffer, 0, 16 ); + if ( oneByte != buffer[current] ) return false; + + } + + } + + } + + } + + return true; // The checkFormat string comparison passed. + + } + + } + + return false; // Should never get here. +} // Plugin_CheckFileFormat + +static bool Plugin_CheckFileFormat_Standard( XMP_FileFormat format, XMP_StringPtr filePath, XMP_IO* fileRef, XMPFiles* parent ) +{ + FileHandlerSharedPtr handler = PluginManager::getFileHandler( format, PluginManager::kStandardHandler ); + + return Plugin_CheckFileFormat( handler, filePath, fileRef, parent ); +} + +static bool Plugin_CheckFileFormat_Replacement( XMP_FileFormat format, XMP_StringPtr filePath, XMP_IO* fileRef, XMPFiles* parent ) +{ + FileHandlerSharedPtr handler = PluginManager::getFileHandler( format, PluginManager::kReplacementHandler ); + + return Plugin_CheckFileFormat( handler, filePath, fileRef, parent ); +} + +// ================================================================================================= + +static bool Plugin_CheckFolderFormat( FileHandlerSharedPtr handler, + const std::string & rootPath, + const std::string & gpName, + const std::string & parentName, + const std::string & leafName, + XMPFiles * parent ) +{ + bool result = false; + + if ( handler != 0 ) + { + WXMP_Error error; + CheckSessionFolderFormatProc checkProc = handler->getModule()->getPluginAPIs()->mCheckFolderFormatProc; + checkProc ( handler->getUID().c_str(), rootPath.c_str(), gpName.c_str(), parentName.c_str(), leafName.c_str(), &result, &error ); + CheckError( error ); + } + + return result; + +} + +static bool Plugin_CheckFolderFormat_Standard( XMP_FileFormat format, + const std::string & rootPath, + const std::string & gpName, + const std::string & parentName, + const std::string & leafName, + XMPFiles * parent ) +{ + FileHandlerSharedPtr handler = PluginManager::getFileHandler( format, PluginManager::kStandardHandler ); + + return Plugin_CheckFolderFormat( handler, rootPath, gpName, parentName, leafName, parent ); +} + +static bool Plugin_CheckFolderFormat_Replacement( XMP_FileFormat format, + const std::string & rootPath, + const std::string & gpName, + const std::string & parentName, + const std::string & leafName, + XMPFiles * parent ) +{ + FileHandlerSharedPtr handler = PluginManager::getFileHandler( format, PluginManager::kReplacementHandler ); + + return Plugin_CheckFolderFormat( handler, rootPath, gpName, parentName, leafName, parent ); +} + +// ================================================================================================= + +PluginManager* PluginManager::msPluginManager = 0; + +PluginManager::PluginManager( const std::string& pluginDir, const std::string& plugins ) : mPluginDir ( pluginDir ) +{ + + const std::size_t count = sizeof(kLibraryExtensions) / sizeof(kLibraryExtensions[0]); + + for ( std::size_t i = 0; i<count; ++i ) { + mExtensions.push_back ( std::string ( kLibraryExtensions[i] ) ); + } + + size_t pos = std::string::npos; + + #if XMP_WinBuild + // convert to Win kDirChar + while ( (pos = mPluginDir.find ('/')) != string::npos ) { + mPluginDir.replace (pos, 1, "\\"); + } + #else + while ( (pos = mPluginDir.find ('\\')) != string::npos ) { + mPluginDir.replace (pos, 1, "/"); + } + #endif + + if ( ! mPluginDir.empty() && Host_IO::Exists( mPluginDir.c_str() ) ) { + + XMP_StringPtr strPtr = plugins.c_str(); + size_t pos = 0; + size_t length = 0; + + for ( ; ; ++strPtr, ++length ) { + + if ( (*strPtr == ',') || (*strPtr == '\0') ) { + + if ( length != 0 ) { + + //Remove white spaces from front + while ( plugins[pos] == ' ' ) { + ++pos; + --length; + } + + std::string pluginName; + pluginName.assign ( plugins, pos, length ); + + //Remove extension from the plugin name + size_t found = pluginName.find ( '.' ); + if ( found != string::npos ) pluginName.erase ( found ); + + //Remove white spaces from the back + found = pluginName.find ( ' ' ); + if ( found != string::npos ) pluginName.erase ( found ); + + MakeLowerCase ( &pluginName ); + mPluginsNeeded.push_back ( pluginName ); + + //Reset for next plugin + pos = pos + length + 1; + length = 0; + + } + + if ( *strPtr == '\0' ) break; + + } + + } + + } + +} // PluginManager::PluginManager + +// ================================================================================================= + +PluginManager::~PluginManager() +{ + mPluginDir.clear(); + mExtensions.clear(); + mPluginsNeeded.clear(); + mModules.clear(); + mHandlers.clear(); + mSessions.clear(); + + terminateHostAPI(); +} + +// ================================================================================================= + +static bool registerHandler( XMP_FileFormat format, FileHandlerSharedPtr handler ) +{ + bool ret = false; + + HandlerRegistry& hdlrReg = HandlerRegistry::getInstance(); + FileHandlerType type = handler->getHandlerType(); + CheckFileFormatProc chkFileFormat = NULL; + CheckFolderFormatProc chkFolderFormat = NULL; + XMPFileHandlerCTor hdlCtor = NULL; + + if( handler->getOverwriteHandler() ) + { + // + // ctor, checkformat function pointers for replacement handler + // + hdlCtor = Plugin_MetaHandlerCTor_Replacement; + chkFileFormat = Plugin_CheckFileFormat_Replacement; + chkFolderFormat = Plugin_CheckFolderFormat_Replacement; + } + else + { + // + // ctor, checkformat function pointers for standard handler + // + hdlCtor = Plugin_MetaHandlerCTor_Standard; + chkFileFormat = Plugin_CheckFileFormat_Standard; + chkFolderFormat = Plugin_CheckFolderFormat_Standard; + } + + // + // register handler according to its type + // + switch( handler->getHandlerType() ) + { + case NormalHandler_K: + ret = hdlrReg.registerNormalHandler( format, handler->getHandlerFlags(), chkFileFormat, + hdlCtor, handler->getOverwriteHandler() ); + break; + + case OwningHandler_K: + ret = hdlrReg.registerOwningHandler( format, handler->getHandlerFlags(), chkFileFormat, + hdlCtor, handler->getOverwriteHandler() ); + break; + + case FolderHandler_K: + ret = hdlrReg.registerFolderHandler( format, handler->getHandlerFlags(), chkFolderFormat, + hdlCtor, handler->getOverwriteHandler() ); + break; + + default: + break; + } + + return ret; +} + +void PluginManager::initialize( const std::string& pluginDir, const std::string& plugins ) +{ + try + { + HandlerRegistry & hdlrReg = HandlerRegistry::getInstance(); + if( msPluginManager == 0 ) msPluginManager = new PluginManager( pluginDir, plugins ); + + msPluginManager->doScan( 2 ); + + // + // Register all the found plugin based file handler + // + for( PluginHandlerMap::iterator it = msPluginManager->mHandlers.begin(); it != msPluginManager->mHandlers.end(); ++it ) + { + XMP_FileFormat format = it->first; + FileHandlerPair handlers = it->second; + + if( handlers.mStandardHandler != NULL ) + { + registerHandler( format, handlers.mStandardHandler ); + } + + if( handlers.mReplacementHandler != NULL ) + { + registerHandler( format, handlers.mReplacementHandler ); + } + } + } + catch( ... ) + { + // Absorb exceptions. This is the plugin-architecture entry point. + } + +} // PluginManager::initialize + +// ================================================================================================= + +void PluginManager::terminate() +{ + delete msPluginManager; + msPluginManager = 0; + ResourceParser::terminate(); +} + +// ================================================================================================= + +void PluginManager::addFileHandler( XMP_FileFormat format, FileHandlerSharedPtr handler ) +{ + if ( msPluginManager != 0 ) + { + PluginHandlerMap & handlerMap = msPluginManager->mHandlers; + + // + // Create placeholder in map for format + // + if ( handlerMap.find(format) == handlerMap.end() ) + { + FileHandlerPair pair; + handlerMap.insert( handlerMap.end(), std::pair<XMP_FileFormat, FileHandlerPair>( format, pair) ); + } + + // + // if there is already a standard handler or a replacement handler for the file format + // then just ignore it. The first one wins. + // + if( handler->getOverwriteHandler() ) + { + if( handlerMap[format].mReplacementHandler.get() == NULL ) handlerMap[format].mReplacementHandler = handler; + } + else + { + if( handlerMap[format].mStandardHandler.get() == NULL ) handlerMap[format].mStandardHandler = handler; + } + } +} + +// ================================================================================================= + +FileHandlerSharedPtr PluginManager::getFileHandler( XMP_FileFormat format, HandlerPriority priority /*= kStandardHandler*/ ) +{ + if ( msPluginManager != 0 ) + { + PluginHandlerMap::iterator it = msPluginManager->mHandlers.find( format ); + + if( it != msPluginManager->mHandlers.end() ) + { + if( priority == kStandardHandler ) + { + return it->second.mStandardHandler; + } + else if( priority == kReplacementHandler ) + { + return it->second.mReplacementHandler; + } + } + } + + return FileHandlerSharedPtr(); +} + +// ================================================================================================= + +static XMP_ReadWriteLock sPluginManagerRWLock; + +void PluginManager::addHandlerInstance( SessionRef session, FileHandlerInstancePtr handler ) +{ + if ( msPluginManager != 0 ) { + XMP_AutoLock(&sPluginManagerRWLock, kXMP_WriteLock); + SessionMap & sessionMap = msPluginManager->mSessions; + if ( sessionMap.find(session) == sessionMap.end() ) { + sessionMap[session] = handler; + } + } +} + +// ================================================================================================= + +void PluginManager::removeHandlerInstance( SessionRef session ) +{ + if ( msPluginManager != 0 ) { + XMP_AutoLock(&sPluginManagerRWLock, kXMP_WriteLock); + SessionMap & sessionMap = msPluginManager->mSessions; + sessionMap.erase ( session ); + } +} + +// ================================================================================================= + +FileHandlerInstancePtr PluginManager::getHandlerInstance( SessionRef session ) +{ + FileHandlerInstancePtr ret = 0; + if ( msPluginManager != 0 ) { + XMP_AutoLock(&sPluginManagerRWLock, kXMP_ReadLock); + ret = msPluginManager->mSessions[session]; + } + return ret; +} + +// ================================================================================================= + +PluginManager::HandlerPriority PluginManager::getHandlerPriority( FileHandlerInstancePtr handler ) +{ + if( handler != NULL ) + { + for( PluginHandlerMap::iterator it=msPluginManager->mHandlers.begin(); + it != msPluginManager->mHandlers.end(); it++ ) + { + if( it->second.mStandardHandler == handler->GetHandlerInfo() ) return kStandardHandler; + if( it->second.mReplacementHandler == handler->GetHandlerInfo() ) return kReplacementHandler; + } + } + + return kUnknown; +} + +// ================================================================================================= + +static bool CheckPluginArchitecture ( XMLParserAdapter * xmlParser ) { + + #if XMP_MacBuild + bool okArchitecture = true; // Missing Architecture attribute means load on Mac. + #else + bool okArchitecture = false; // Missing Architecture attribute means do not load elsewhere. + #endif + + #if XMP_64 + const char * nativeArchitecture = "x64"; + #else + const char * nativeArchitecture = "x86"; + #endif + + size_t i, limit; + XML_Node & xmlTree = xmlParser->tree; + XML_NodePtr rootElem = 0; + + // Find the outermost XML element and see if it is PluginResource. + for ( i = 0, limit = xmlTree.content.size(); i < limit; ++i ) { + if ( xmlTree.content[i]->kind == kElemNode ) { + rootElem = xmlTree.content[i]; + break; + } + } + + if ( (rootElem == 0) || (rootElem->name != "PluginResource") ) return okArchitecture; + + // Look for the Architecture attribute and see if it matches. + + XML_NodePtr archAttr = 0; + for ( i = 0, limit = rootElem->attrs.size(); i < limit; ++i ) { + if ( rootElem->attrs[i]->name == "Architecture" ) { + archAttr = rootElem->attrs[i]; + break; + } + } + + if ( archAttr != 0 ) okArchitecture = (archAttr->value == nativeArchitecture); + + return okArchitecture; + +} // CheckPluginArchitecture + +// ================================================================================================= + +void PluginManager::loadResourceFile( ModuleSharedPtr module ) +{ + + OS_ModuleRef moduleRef = LoadModule ( module->getPath(), true ); + + if ( moduleRef != 0 ) { + + XMLParserAdapter* parser = 0; + + try { + + std::string buffer; + if ( GetResourceDataFromModule ( moduleRef, kResourceName_UIDs, "txt", buffer ) ) { + + ResourceParser::initialize(); // Initialize XMPAtoms before processing resource file. + + parser = XMP_NewExpatAdapter ( ExpatAdapter::kUseGlobalNamespaces ); + parser->ParseBuffer ( (XMP_Uns8*)buffer.c_str(), buffer.size(), true ); + + if ( CheckPluginArchitecture ( parser ) ) { + ResourceParser resource ( module ); + resource.parseElementList ( &parser->tree, true ); + } + + delete parser; + + } + + } catch ( ... ) { + + if ( parser != 0 ) delete parser; + // Otherwise ignore errors. + + } + + UnloadModule ( moduleRef, true ); + + } + +} // PluginManager::loadResourceFile + +// ================================================================================================= + +void PluginManager::scanRecursive( const std::string & tempPath, std::vector<std::string>& ioFoundLibs, XMP_Int32 inLevel, XMP_Int32 inMaxNestingLevel ) +{ + ++inLevel; + Host_IO::AutoFolder aFolder; + if ( Host_IO::GetFileMode( tempPath.c_str() ) != Host_IO::kFMode_IsFolder ) return; + + aFolder.folder = Host_IO::OpenFolder( tempPath.c_str() ); + std::string childPath, childName; + + while ( Host_IO::GetNextChild ( aFolder.folder, &childName ) ) { + + // Make sure the children of CONTENTS are legit. + childPath = tempPath; + childPath += kDirChar; + childPath += childName; + Host_IO::FileMode clientMode = Host_IO::GetFileMode ( childPath.c_str() ); + + bool okFolder = (clientMode == Host_IO::kFMode_IsFolder); + #if XMP_MacBuild + if ( okFolder ) okFolder = ( ! IsValidLibrary ( childPath ) ); + #endif + + // only step into non-packages (neither bundle nor framework) on Mac + if ( okFolder ) { + + if ( inLevel < inMaxNestingLevel ) { + scanRecursive ( childPath + kDirChar, ioFoundLibs, inLevel, inMaxNestingLevel ); + } + + } else { + + if ( childName[0] == '~' ) continue; // ignore plug-ins like "~PDFL.xpi" + + std::string fileExt; + XMP_StringPtr extPos = childName.c_str() + childName.size(); + for ( ; (extPos != childName.c_str()) && (*extPos != '.'); --extPos ) {} + if ( *extPos == '.' ) { + fileExt.assign ( extPos+1 ); + MakeLowerCase ( &fileExt ); + } + + StringVec::const_iterator iterFound = + std::find_if ( mExtensions.begin(), mExtensions.end(), + std::bind2nd ( std::equal_to<std::string>(), fileExt ) ); + + if ( iterFound != mExtensions.end() ) { + + //Check if the found plugin is present in the user's demanding plugin list. + childName.erase ( extPos - childName.c_str() ); + MakeLowerCase ( &childName ); + + StringVec::const_iterator pluginNeeded = + std::find_if ( mPluginsNeeded.begin(), mPluginsNeeded.end(), + std::bind2nd ( std::equal_to<std::string>(), childName ) ); + + if ( (pluginNeeded != mPluginsNeeded.end()) || mPluginsNeeded.empty() ) { + ioFoundLibs.push_back ( childPath ); + } + + } + + } + + } + + aFolder.Close(); + +} // PluginManager::scanRecursive + +// ================================================================================================= + +void PluginManager::doScan( const XMP_Int32 inMaxNumOfNestedFolder ) +{ + XMP_Assert(inMaxNumOfNestedFolder > 0); + if ( inMaxNumOfNestedFolder < 1 ) return; // noop, wrong parameter + + // scan directory + std::vector<std::string> foundLibs; + XMP_Int32 iteration = 0; + scanRecursive ( mPluginDir, foundLibs, iteration, inMaxNumOfNestedFolder ); + + // add found modules + std::vector<std::string>::const_iterator iter = foundLibs.begin(); + std::vector<std::string>::const_iterator iterEnd = foundLibs.end(); + for ( ; iter != iterEnd; ++iter ) { + std::string path ( *iter ); + ModuleSharedPtr module ( new Module ( path ) ); + loadResourceFile ( module ); + } + +} // PluginManager::doScan + +// ================================================================================================= + +HostAPIRef PluginManager::getHostAPI( XMP_Uns32 version ) +{ + HostAPIRef hostAPI = NULL; + + if( msPluginManager == NULL ) return NULL; + if( version < 1 ) return NULL; + + HostAPIMap::iterator iter = msPluginManager->mHostAPIs.find( version ); + + if( iter != msPluginManager->mHostAPIs.end() ) + { + hostAPI = iter->second; + } + else + { + hostAPI = new HostAPI(); + hostAPI->mSize = sizeof( HostAPI ); + hostAPI->mVersion = version; + + switch( version ) + { + case 1: SetupHostAPI_V1( hostAPI ); break; + + default: + { + delete hostAPI; + hostAPI = NULL; + } + } + + if( hostAPI != NULL ) + { + msPluginManager->mHostAPIs[ version ] = hostAPI; + } + } + + return hostAPI; +} + +// ================================================================================================= + +void PluginManager::terminateHostAPI() +{ + for( HostAPIMap::iterator it = msPluginManager->mHostAPIs.begin(); it != msPluginManager->mHostAPIs.end(); ++it ) + { + XMP_Uns32 version = it->first; + HostAPIRef hostAPI = it->second; + + switch( version ) + { + case 1: + { + delete hostAPI->mFileIOAPI; + delete hostAPI->mStrAPI; + delete hostAPI->mAbortAPI; + delete hostAPI->mStandardHandlerAPI; + delete hostAPI; + } + break; + + default: + { + delete hostAPI; + } + } + } +} + +} // namespace XMP_PLUGIN diff --git a/XMPFiles/source/PluginHandler/PluginManager.h b/XMPFiles/source/PluginHandler/PluginManager.h new file mode 100644 index 0000000..9b2240e --- /dev/null +++ b/XMPFiles/source/PluginHandler/PluginManager.h @@ -0,0 +1,190 @@ +// ================================================================================================= +// ADOBE SYSTEMS INCORPORATED +// Copyright 2011 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. +// ================================================================================================= + +#ifndef PLUGINMANAGER_H +#define PLUGINMANAGER_H +#include "PluginHandler.h" +#include "ModuleUtils.h" + +namespace XMP_PLUGIN +{ + +typedef XMP_Uns32 XMPAtom; +typedef XMPAtom FileHandlerType; + +class Module; +typedef std::tr1::shared_ptr<Module> ModuleSharedPtr; + +class FileHandler; +typedef std::tr1::shared_ptr<FileHandler> FileHandlerSharedPtr; + +class FileHandlerInstance; +typedef FileHandlerInstance* FileHandlerInstancePtr; + +typedef std::vector<std::string> StringVec; +typedef std::vector<ModuleSharedPtr> ModuleVec; +typedef std::vector<XMP_FileFormat> XMP_FileFormatVec; + +struct FileHandlerPair; + +inline void CheckError( WXMP_Error & error ) +{ + if( error.mErrorID != kXMPErr_NoError ) + { + if( error.mErrorID >= 500 /* kXMPErr_PluginInternal */ + || error.mErrorID <= 512 /* kXMPErr_SetHostAPI */ ) + { + throw XMP_Error( kXMPErr_InternalFailure, error.mErrorMsg ); + } + else + { + throw XMP_Error( error.mErrorID, error.mErrorMsg ); + } + } +} + +/** @class PluginManager + * @brief Register all file handlers from all the plugins available in Plugin directory. + * + * At the initialization time of XMPFiles, PluginManager loads all the avalbale plugins + */ +class PluginManager +{ +public: + enum HandlerPriority + { + kStandardHandler, + kReplacementHandler, + kUnknown + }; + + /** + * Initialize the plugin manager. It's a singleton class which manages the plugins. + * @param pluginDir The directory where to search for the plugins. + * @param plugins Comma separated list of the plugins which should be loaded from the plugin directory. + * By default, all plug-ins available in the pluginDir will be loaded. + */ + static void initialize( const std::string& pluginDir, const std::string& plugins = std::string() ); + + /** + * Terminate the plugin manager. + */ + static void terminate(); + + /** + * Add file handler corresponding to the given format + * @param format FileFormat supported by the file handler + * @param handler shared pointer to the file handler which is to be added. + * @return Void. + */ + static void addFileHandler( XMP_FileFormat format, FileHandlerSharedPtr handler ); + + /** + * Returns file handler corresponding to the given format and priority + * + * @param format FileFormat supported by the file handler + * @param priority The priority of the handler (there could be one standard and + * one replacing handler, use the enums kStandardHandler or kReplacementHandler) + * @return shared pointer to the file handler. It does not need to be freed. + */ + static FileHandlerSharedPtr getFileHandler( XMP_FileFormat format, HandlerPriority priority = kStandardHandler ); + + /** + * Store mapping between session reference (comes from plugin) and + * FileHandlerInstance. + * @param session Session reference from plugin + * @param handler FileHandlerInstance related to the session + */ + static void addHandlerInstance( SessionRef session, FileHandlerInstancePtr handler ); + + /** + * Remove mapping between session reference (comes from plugin) and + * FilehandlerInstance + * @param session Session reference from plugin + */ + static void removeHandlerInstance( SessionRef session ); + + /** + * Return FileHandlerInstance that is associated to the session reference + * @param session Session reference from plugin + * @return FileHandlerInstance + */ + static FileHandlerInstancePtr getHandlerInstance( SessionRef session ); + + /** + * Return the priority of the handler + * @param handler Instance of file handler + * @return Return kStandardHandler or kReplacementHandler + */ + static HandlerPriority getHandlerPriority( FileHandlerInstancePtr handler ); + + /** + * Return Host API + */ + static HostAPIRef getHostAPI( XMP_Uns32 version ); + +private: + PluginManager( const std::string& pluginDir, const std::string& plugins ); + ~PluginManager(); + + /** + * Terminate host API + */ + void terminateHostAPI(); + + /** + * Load resource file of the given module. + * @param module + * @return Void. + */ + void loadResourceFile( ModuleSharedPtr module ); + + /** + * Scan mPluginDir for the plugins. It also scans nested folder upto level inMaxNumOfNestedFolder. + * @param inMaxNumOfNestedFolder Nested level where to scan. + * @return Void. + */ + void doScan( const XMP_Int32 inMaxNumOfNestedFolder = 1 ); + + /** + * Scan recursively the directory /a inPath and insert the found plug-in in ioFoundLibs. + * @param inPath Full path of the directory name to be scanned. + * @param ioFoundLibs Vector of string. Found plug-in will be inserted in this vector. + * @param inLevel The current level + * @param inMaxNumOfNestedFolder Nested level where to scan upto. + * @return Void. + */ + void scanRecursive( + const std::string& inPath, + std::vector<std::string>& ioFoundLibs, + XMP_Int32 inLevel, + XMP_Int32 inMaxNestingLevel ); + + /** + * Setup passed in HostAPI structure for the host API v1 + */ + static void SetupHostAPI_V1( HostAPIRef hostAPI ); + + typedef std::map<XMP_FileFormat, FileHandlerPair> PluginHandlerMap; + typedef std::map<XMP_Uns32, HostAPIRef> HostAPIMap; + typedef std::map<SessionRef, FileHandlerInstancePtr> SessionMap; + + std::string mPluginDir; + StringVec mExtensions; + StringVec mPluginsNeeded; + ModuleVec mModules; + PluginHandlerMap mHandlers; + SessionMap mSessions; + HostAPIMap mHostAPIs; + + static PluginManager* msPluginManager; +}; + +} //namespace XMP_PLUGIN +#endif //PLUGINMANAGER_H diff --git a/XMPFiles/source/PluginHandler/XMPAtoms.cpp b/XMPFiles/source/PluginHandler/XMPAtoms.cpp new file mode 100644 index 0000000..ed01027 --- /dev/null +++ b/XMPFiles/source/PluginHandler/XMPAtoms.cpp @@ -0,0 +1,408 @@ +// ================================================================================================= +// ADOBE SYSTEMS INCORPORATED +// Copyright 2011 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 "XMPAtoms.h" +#include "XMPFiles/source/HandlerRegistry.h" + +using namespace Common; + +namespace XMP_PLUGIN +{ + +struct XMPAtomMapping +{ + XMP_StringPtr name; + XMPAtom atom; +}; + +const XMPAtomMapping kXMPAtomVec[] = +{ + { "", emptyStr_K }, + { "Handler", Handler_K }, + { "Extensions", Extensions_K }, + { "Extension", Extension_K }, + { "FormatIDs", FormatIDs_K }, + { "FormatID", FormatID_K }, + { "HandlerType", HandlerType_K }, + { "Priority", OverwriteHdl_K }, + { "HandlerFlags", HandlerFlags_K }, + { "HandlerFlag", HandlerFlag_K }, + { "SerializeOptions", SerializeOptions_K }, + { "SerializeOption", SerializeOption_K }, + { "Version", Version_K }, + { "CheckFormat", CheckFormat_K }, + { "Name", Name_K }, + { "Offset", Offset_K }, + { "Length", Length_K }, + { "ByteSeq", ByteSeq_K }, + + // Handler types + { "NormalHandler", NormalHandler_K }, + { "OwningHandler", OwningHandler_K }, + { "FolderHandler", FolderHandler_K }, + + // Handler flags + { "kXMPFiles_CanInjectXMP", kXMPFiles_CanInjectXMP_K }, + { "kXMPFiles_CanExpand", kXMPFiles_CanExpand_K }, + { "kXMPFiles_CanRewrite", kXMPFiles_CanRewrite_K }, + { "kXMPFiles_PrefersInPlace", kXMPFiles_PrefersInPlace_K }, + { "kXMPFiles_CanReconcile", kXMPFiles_CanReconcile_K }, + { "kXMPFiles_AllowsOnlyXMP", kXMPFiles_AllowsOnlyXMP_K }, + { "kXMPFiles_ReturnsRawPacket", kXMPFiles_ReturnsRawPacket_K }, + { "kXMPFiles_HandlerOwnsFile", kXMPFiles_HandlerOwnsFile_K }, + { "kXMPFiles_AllowsSafeUpdate", kXMPFiles_AllowsSafeUpdate_K }, + { "kXMPFiles_NeedsReadOnlyPacket", kXMPFiles_NeedsReadOnlyPacket_K }, + { "kXMPFiles_UsesSidecarXMP", kXMPFiles_UsesSidecarXMP_K }, + { "kXMPFiles_FolderBasedFormat", kXMPFiles_FolderBasedFormat_K }, + + // Serialize option + { "kXMP_OmitPacketWrapper", kXMP_OmitPacketWrapper_K }, + { "kXMP_ReadOnlyPacket", kXMP_ReadOnlyPacket_K }, + { "kXMP_UseCompactFormat", kXMP_UseCompactFormat_K }, + { "kXMP_UseCanonicalFormat", kXMP_UseCanonicalFormat_K }, + { "kXMP_IncludeThumbnailPad", kXMP_IncludeThumbnailPad_K }, + { "kXMP_ExactPacketLength", kXMP_ExactPacketLength_K }, + { "kXMP_OmitAllFormatting", kXMP_OmitAllFormatting_K }, + { "kXMP_OmitXMPMetaElement", kXMP_OmitXMPMetaElement_K }, + { "kXMP_EncodingMask", kXMP_EncodingMask_K }, + { "kXMP_EncodeUTF8", kXMP_EncodeUTF8_K }, + { "kXMP_EncodeUTF16Big", kXMP_EncodeUTF16Big_K }, + { "kXMP_EncodeUTF16Little", kXMP_EncodeUTF16Little_K }, + { "kXMP_EncodeUTF32Big", kXMP_EncodeUTF32Big_K }, + { "kXMP_EncodeUTF32Little", kXMP_EncodeUTF32Little_K } + +}; + + +XMPAtomsMap* ResourceParser::msXMPAtoms = NULL; +void ResourceParser::clear() +{ + mUID.clear(); + mFileExtensions.clear(); + mFormatIDs.clear(); + mCheckFormat.clear(); + mHandler = FileHandlerSharedPtr(); + mFlags = mSerializeOption = mType = mVersion = 0; +} + +void ResourceParser::addHandler() +{ + if( mUID.empty() || ( mFileExtensions.empty() && mFormatIDs.empty() ) || !isValidHandlerType( mType ) || mFlags == 0 ) + { + XMP_Throw( "Atleast one of uid, format, ext, typeStr, flags non-valid ...", kXMPErr_Unavailable ); + } + else + { + mHandler->setHandlerFlags( mFlags ); + mHandler->setHandlerType( mType ); + mHandler->setSerializeOption( mSerializeOption ); + mHandler->setOverwriteHandler( mOverwriteHandler ); + if( mVersion != 0) mHandler->setVersion( mVersion ); + + // A plugin could define the XMP_FileFormat value in manifest file through keyword "FormatID" and + // file extensions for NormalHandler and OwningHandler through keyword "Extension". + // If Both are defined then give priority to FormatID. + + std::set<XMP_FileFormat> formatIDs = mFormatIDs.empty() ? mFileExtensions : mFormatIDs; + for( std::set<XMP_FileFormat>::const_iterator it = formatIDs.begin(); it != formatIDs.end(); ++it ) + { + PluginManager::addFileHandler(*it, mHandler); + } + } +} + +bool ResourceParser::parseElementAttrs( const XML_Node * xmlNode, bool isTopLevel ) +{ + XMP_OptionBits exclusiveAttrs = 0; // Used to detect attributes that are mutually exclusive. + + XMPAtom nodeAtom = getXMPAtomFromString( xmlNode->name ); + if( nodeAtom == Handler_K ) + this->clear(); + + XML_cNodePos currAttr = xmlNode->attrs.begin(); + XML_cNodePos endAttr = xmlNode->attrs.end(); + + for( ; currAttr != endAttr; ++currAttr ) + { + XMP_OptionBits oneflag=0; + XMP_FileFormat formatID = kXMP_UnknownFile; + std::string formatStr; + XMPAtom attrAtom = getXMPAtomFromString( (*currAttr)->name ); + switch(nodeAtom) + { + case Handler_K: + switch(attrAtom) + { + case Name_K: + this->mUID = (*currAttr)->value; + mHandler = FileHandlerSharedPtr( new FileHandler( this->mUID, 0, 0, mModule ) ); + break; + case Version_K: + this->mVersion = atoi( (*currAttr)->value.c_str() ); + break; + case HandlerType_K: + this->mType = getXMPAtomFromString( (*currAttr)->value ); + break; + case OverwriteHdl_K: + this->mOverwriteHandler = ( (*currAttr)->value == "true" ); + break; + default: + XMP_Throw( "Invalid Attr in Handler encountered in resource file", kXMPErr_Unavailable ); + } + break; + case CheckFormat_K: + switch(attrAtom) + { + case Offset_K: + this->mCheckFormat.mOffset = atoi( (*currAttr)->value.c_str() ); + break; + case Length_K: + this->mCheckFormat.mLength = atoi( (*currAttr)->value.c_str() ); + break; + case ByteSeq_K: + this->mCheckFormat.mByteSeq = (*currAttr)->value; + break; + default: + XMP_Throw( "Invalid Attr in CheckFormat encountered in resource file", kXMPErr_Unavailable ); + } + break; + case Extension_K: + switch(attrAtom) + { + case Name_K: + this->mFileExtensions.insert( HandlerRegistry::getInstance().getFileFormat( (*currAttr)->value, true) ); + break; + default: + XMP_Throw( "Invalid Attr in Extension encountered in resource file", kXMPErr_Unavailable ); + } + break; + case FormatID_K: + switch(attrAtom) + { + case Name_K: + formatStr.assign( (*currAttr)->value ); + + // Convert string into 4-byte string by appending space '0x20' character. + for( size_t j=formatStr.size(); j<4; j++ ) + formatStr.push_back(' '); + + formatID = GetUns32BE( formatStr.c_str() ); + this->mFormatIDs.insert( formatID ); + break; + default: + XMP_Throw( "Invalid Attr in FormatID encountered in resource file", kXMPErr_Unavailable ); + } + break; + case HandlerFlag_K: + switch(attrAtom) + { + case Name_K: + oneflag = getHandlerFlag( (*currAttr)->value ); + if( 0 == oneflag ) + XMP_Throw( "Invalid handler flag found in resource file...", kXMPErr_Unavailable ); + this->mFlags |= oneflag; + break; + default: + XMP_Throw( "Invalid handler flag found in resource file...", kXMPErr_Unavailable ); + } + break; + case SerializeOption_K: + switch(attrAtom) + { + case Name_K: + oneflag = getSerializeOption( (*currAttr)->value ); + if( 0 == oneflag ) + XMP_Throw( "Invalid serialize option found in resource file...", kXMPErr_Unavailable ); + this->mSerializeOption |= oneflag; + break; + default: + XMP_Throw( "Invalid handler flag found in resource file...", kXMPErr_Unavailable ); + } + break; + default: + break; + } + } + + if( nodeAtom == CheckFormat_K ) + mHandler->addCheckFormat( mCheckFormat ); + + return (nodeAtom == Handler_K) ? true : false; +} // parseElementAttrs + +void ResourceParser::parseElement( const XML_Node * xmlNode, bool isTopLevel ) +{ + bool HandlerFound = this->parseElementAttrs( xmlNode, isTopLevel ); + this->parseElementList ( xmlNode, false ); + + if(HandlerFound) + { + this->addHandler(); + } +} + +void ResourceParser::parseElementList( const XML_Node * xmlParent, bool isTopLevel ) +{ + initialize(); //Make sure XMPAtoms are initialized. + + XML_cNodePos currChild = xmlParent->content.begin(); + XML_cNodePos endChild = xmlParent->content.end(); + + for( ; currChild != endChild; ++currChild ) + { + if( (*currChild)->IsWhitespaceNode() ) continue; + this->parseElement( *currChild, isTopLevel ); + } +} + +bool ResourceParser::initialize() +{ + //Check if already populated. + if( msXMPAtoms == NULL ) + { + msXMPAtoms = new XMPAtomsMap(); + + //Create XMPAtomMap from XMPAtomVec, as we need to do a lot of searching while processing the resource file. + int count = sizeof(kXMPAtomVec)/sizeof(XMPAtomMapping); + for( int i=0; i<count; i++ ) + { + XMP_StringPtr name = kXMPAtomVec[i].name; + XMPAtom atom = kXMPAtomVec[i].atom; + (*msXMPAtoms)[name] = atom; + } + } + return true; +} + +void ResourceParser::terminate() +{ + delete msXMPAtoms; + msXMPAtoms = NULL; +} + +XMPAtom ResourceParser::getXMPAtomFromString( const std::string & stringAtom ) +{ + XMPAtomsMap::const_iterator it = msXMPAtoms->find(stringAtom); + + if( it != msXMPAtoms->end() ) + return it->second; + + return XMPAtomNull; +} + +//static +XMP_OptionBits ResourceParser::getHandlerFlag( const std::string & stringAtom ) +{ + XMPAtom atom = getXMPAtomFromString( stringAtom ); + + if( !isValidXMPAtom(atom) ) + return 0; + + switch( atom ) + { + case kXMPFiles_CanInjectXMP_K: + return kXMPFiles_CanInjectXMP; + case kXMPFiles_CanExpand_K: + return kXMPFiles_CanExpand; + case kXMPFiles_CanRewrite_K: + return kXMPFiles_CanRewrite; + case kXMPFiles_PrefersInPlace_K: + return kXMPFiles_PrefersInPlace; + case kXMPFiles_CanReconcile_K: + return kXMPFiles_CanReconcile; + case kXMPFiles_AllowsOnlyXMP_K: + return kXMPFiles_AllowsOnlyXMP; + case kXMPFiles_ReturnsRawPacket_K: + return kXMPFiles_ReturnsRawPacket; + case kXMPFiles_HandlerOwnsFile_K: + return kXMPFiles_HandlerOwnsFile; + case kXMPFiles_AllowsSafeUpdate_K: + return kXMPFiles_AllowsSafeUpdate; + case kXMPFiles_NeedsReadOnlyPacket_K: + return kXMPFiles_NeedsReadOnlyPacket; + case kXMPFiles_UsesSidecarXMP_K: + return kXMPFiles_UsesSidecarXMP; + case kXMPFiles_FolderBasedFormat_K: + return kXMPFiles_FolderBasedFormat; + default: + XMP_Throw( "Invalid PluginhandlerFlag ...", kXMPErr_Unavailable ); + return 0; + } +} + +//static +XMP_OptionBits ResourceParser::getSerializeOption( const std::string & stringAtom ) +{ + XMPAtom atom = getXMPAtomFromString( stringAtom ); + + if( !isValidXMPAtom(atom) ) + return 0; + + switch( atom ) + { + case kXMP_OmitPacketWrapper_K: + return kXMP_OmitPacketWrapper; + case kXMP_ReadOnlyPacket_K: + return kXMP_ReadOnlyPacket; + case kXMP_UseCompactFormat_K: + return kXMP_UseCompactFormat; + case kXMP_UseCanonicalFormat_K: + return kXMP_UseCanonicalFormat; + case kXMP_IncludeThumbnailPad_K: + return kXMP_IncludeThumbnailPad; + case kXMP_ExactPacketLength_K: + return kXMP_ExactPacketLength; + case kXMP_OmitAllFormatting_K: + return kXMP_OmitAllFormatting; + case kXMP_OmitXMPMetaElement_K: + return kXMP_OmitXMPMetaElement; + case kXMP_EncodingMask_K: + return kXMP_EncodingMask; + case kXMP_EncodeUTF8_K: + return kXMP_EncodeUTF8; + case kXMP_EncodeUTF16Big_K: + return kXMP_EncodeUTF16Big; + case kXMP_EncodeUTF16Little_K: + return kXMP_EncodeUTF16Little; + case kXMP_EncodeUTF32Big_K: + return kXMP_EncodeUTF32Big; + case kXMP_EncodeUTF32Little_K: + return kXMP_EncodeUTF32Little; + default: + XMP_Throw( "Invalid Serialize Option ...", kXMPErr_Unavailable ); + return 0; + } +} + +XMP_FileFormat ResourceParser::getPluginFileFormat( const std::string & fileExt, bool AddIfNotFound ) +{ + XMP_FileFormat format = kXMP_UnknownFile; + + if( msXMPAtoms ) + { + XMPAtomsMap::const_iterator iter = msXMPAtoms->find( fileExt ); + if( iter != msXMPAtoms->end() ) + { + format = iter->second; + } + else if( AddIfNotFound ) + { + std::string formatStr(fileExt); + MakeUpperCase(&formatStr); + for( size_t j=formatStr.size(); j<4; j++ ) // Convert "pdf" to "PDF " + formatStr.push_back(' '); + format = GetUns32BE( formatStr.c_str() ); //Convert "PDF " into kXMP_PDFFile + (*msXMPAtoms)[ fileExt ] = format; + } + } + + return format; +} + +} //namespace XMP_PLUGIN diff --git a/XMPFiles/source/PluginHandler/XMPAtoms.h b/XMPFiles/source/PluginHandler/XMPAtoms.h new file mode 100644 index 0000000..5004008 --- /dev/null +++ b/XMPFiles/source/PluginHandler/XMPAtoms.h @@ -0,0 +1,200 @@ +// ================================================================================================= +// ADOBE SYSTEMS INCORPORATED +// Copyright 2011 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. +// ================================================================================================= + +#ifndef _H_XMPATOMS +#define _H_XMPATOMS +#include "FileHandler.h" +#include "source/ExpatAdapter.hpp" +#include <set> + +namespace XMP_PLUGIN +{ + +/** @brief An enum required to parse the resource file of plugin. + */ +enum +{ + emptyStr_K = 0, //Empty string + + // Mandatory keys in the resource file + Handler_K, + Extensions_K, + Extension_K, + FormatIDs_K, + FormatID_K, + HandlerType_K, + OverwriteHdl_K, + HandlerFlags_K, + HandlerFlag_K, + SerializeOptions_K, + SerializeOption_K, + Version_K, + CheckFormat_K, + Name_K, + Offset_K, + Length_K, + ByteSeq_K, + + // Handler types + NormalHandler_K, + OwningHandler_K, + FolderHandler_K, + + // Handler flags + kXMPFiles_CanInjectXMP_K, + kXMPFiles_CanExpand_K, + kXMPFiles_CanRewrite_K, + kXMPFiles_PrefersInPlace_K, + kXMPFiles_CanReconcile_K, + kXMPFiles_AllowsOnlyXMP_K, + kXMPFiles_ReturnsRawPacket_K, + kXMPFiles_HandlerOwnsFile_K, + kXMPFiles_AllowsSafeUpdate_K, + kXMPFiles_NeedsReadOnlyPacket_K, + kXMPFiles_UsesSidecarXMP_K, + kXMPFiles_FolderBasedFormat_K, + + // Serialize option + kXMP_OmitPacketWrapper_K, + kXMP_ReadOnlyPacket_K, + kXMP_UseCompactFormat_K, + kXMP_UseCanonicalFormat_K, + kXMP_IncludeThumbnailPad_K, + kXMP_ExactPacketLength_K, + kXMP_OmitAllFormatting_K, + kXMP_OmitXMPMetaElement_K, + kXMP_EncodingMask_K, + kXMP_EncodeUTF8_K, + kXMP_EncodeUTF16Big_K, + kXMP_EncodeUTF16Little_K, + kXMP_EncodeUTF32Big_K, + kXMP_EncodeUTF32Little_K, + + //Last element + lastfinal_K +}; + +#define XMPAtomNull emptyStr_K + +struct StringCompare : std::binary_function<const std::string &, const std::string &, bool> +{ + bool operator() (const std::string & a, const std::string & b) const + { + return ( a.compare(b) < 0 ); + } +}; +typedef std::map<std::string, XMPAtom, StringCompare> XMPAtomsMap; + + +/** @class ResourceParser + * @brief Class to parse resource file of the plugin. + */ +class ResourceParser +{ +public: + ResourceParser(ModuleSharedPtr module) + : mModule(module), mFlags(0), mSerializeOption(0), mType(0), mVersion(0), mOverwriteHandler(false) {} + + /** + * Initialize the XMPAtoms which will be used in parsing resource files. + * @return true on success. + */ + static bool initialize(); + static void terminate(); + + /** @brief Return file format corresponding to file extension \a fileExt. + * + * It is similar to GetXMPFileFormat except that it also searches in PluginManager's + * private file formats. If the extension is not a public file format and \a AddIfNotFound is true + * then it also adds the private fileformat. The priavte 4-byte file format is created by converting + * extension to upper case and appending space '0x20' to make it 4-byte. For i.e + * "pdf" -> 'PDF ' (0x50444620) + * "tmp" -> 'TMP ' (0x54415020) + * "temp" -> 'TEMP' (0x54454150) + * + * @param fileExt Extension string of the file. For i.e "pdf" + * @param AddIfNotFound If AddIfNotFound is true and public format is not found then + * priavte format is added. + * @return File format correspoding to file extension \a fileExt. + */ + static XMP_FileFormat getPluginFileFormat( const std::string & fileExt, bool AddIfNotFound ); + + /** + * Parse the XML node's children recursively. + * @param xmlParent XMLNode which will be parsed. + * @return Void. + */ + void parseElementList( const XML_Node * xmlParent, bool isTopLevel ); + +private: + void clear(); + void addHandler(); + + /** + * Parse the XML node's attribute. + * @param xmlNode XMLNode which will be parsed. + * @return true if xmlNode's name is Handler_K. + */ + bool parseElementAttrs( const XML_Node * xmlNode, bool isTopLevel ); + + /** + * Parse the XML node. + * @param xmlNode XMLNode which will be parsed. + * @return Void. + */ + void parseElement( const XML_Node * xmlNode, bool isTopLevel ); + + /** + * Return XMPAtom corresponding to string. + * @param stringAtom std::string whose XMPAtom will be return. + * @return XMPAtom corresponding to string. + */ + static XMPAtom getXMPAtomFromString( const std::string & stringAtom ); + + /** + * Return Handler flag corresponding to XMPAtom string. + * @param stringAtom Handler flag string + * @return Handler flag. + */ + static XMP_OptionBits getHandlerFlag( const std::string & stringAtom ); + + /** + * Return Serialize option corresponding to XMPAtom string. + * @param stringAtom Handler flag string + * @return Serialize option. + */ + static XMP_OptionBits getSerializeOption( const std::string & stringAtom ); + + static inline bool isValidXMPAtom( XMPAtom atom ) + { + return ( atom > emptyStr_K && atom < lastfinal_K ); + } + + static inline bool isValidHandlerType(XMPAtom atom) + { + return ( atom >= NormalHandler_K && atom <= FolderHandler_K ); + } + + ModuleSharedPtr mModule; + std::string mUID; + FileHandlerType mType; + XMP_OptionBits mFlags; + XMP_OptionBits mSerializeOption; + XMP_Uns32 mVersion; + bool mOverwriteHandler; + CheckFormat mCheckFormat; + std::set<XMP_FileFormat> mFileExtensions; + std::set<XMP_FileFormat> mFormatIDs; + FileHandlerSharedPtr mHandler; + + static XMPAtomsMap * msXMPAtoms; +}; + +} //namespace XMP_PLUGIN +#endif // _H_XMPATOMS |