summaryrefslogtreecommitdiff
path: root/XMPFiles/source/PluginHandler
diff options
context:
space:
mode:
authorHubert Figuière <hub@figuiere.net>2013-05-14 18:21:26 -0400
committerHubert Figuière <hub@figuiere.net>2013-05-14 18:21:26 -0400
commit81a4c6bcb1879cb321246590faca595e9746f8e5 (patch)
treecf92c416eb3e41708149905abd0030680aebadf5 /XMPFiles/source/PluginHandler
parent42dbac60f15e038270d6e0c7285caba8256e86f1 (diff)
Update to XMP SDK CS6
Diffstat (limited to 'XMPFiles/source/PluginHandler')
-rw-r--r--XMPFiles/source/PluginHandler/FileHandler.h101
-rw-r--r--XMPFiles/source/PluginHandler/FileHandlerInstance.cpp106
-rw-r--r--XMPFiles/source/PluginHandler/FileHandlerInstance.h47
-rw-r--r--XMPFiles/source/PluginHandler/HostAPIImpl.cpp637
-rw-r--r--XMPFiles/source/PluginHandler/Module.cpp169
-rw-r--r--XMPFiles/source/PluginHandler/Module.h65
-rw-r--r--XMPFiles/source/PluginHandler/ModuleUtils.h77
-rw-r--r--XMPFiles/source/PluginHandler/OS_Utils_Linux.cpp230
-rw-r--r--XMPFiles/source/PluginHandler/OS_Utils_Mac.cpp366
-rw-r--r--XMPFiles/source/PluginHandler/OS_Utils_WIN.cpp66
-rw-r--r--XMPFiles/source/PluginHandler/PluginManager.cpp779
-rw-r--r--XMPFiles/source/PluginHandler/PluginManager.h190
-rw-r--r--XMPFiles/source/PluginHandler/XMPAtoms.cpp408
-rw-r--r--XMPFiles/source/PluginHandler/XMPAtoms.h200
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