1 // =================================================================================================
2 // ADOBE SYSTEMS INCORPORATED
3 // Copyright 2011 Adobe Systems Incorporated
4 // All Rights Reserved
5 //
6 // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
7 // of the Adobe license agreement accompanying it.
8 // =================================================================================================
9 
10 #include "PluginManager.h"
11 #include "FileHandler.h"
12 #include <algorithm>
13 #include "XMPAtoms.h"
14 #include "XMPFiles/source/HandlerRegistry.h"
15 #include "FileHandlerInstance.h"
16 #include "HostAPI.h"
17 
18 using namespace Common;
19 using namespace std;
20 
21 // =================================================================================================
22 
23 namespace XMP_PLUGIN
24 {
25 
26 const char* kResourceName_UIDs  = "XMPPLUGINUIDS";
27 const char* kLibraryExtensions[] = { "xpi" };
28 
29 struct FileHandlerPair
30 {
31 	FileHandlerSharedPtr	mStandardHandler;
32 	FileHandlerSharedPtr	mReplacementHandler;
33 };
34 
35 // =================================================================================================
36 #if 0 // unused
37 static XMP_FileFormat GetXMPFileFormatFromFilePath( XMP_StringPtr filePath )
38 {
39 	XMP_StringPtr pathName = filePath + strlen(filePath);
40 	for ( ; pathName > filePath; --pathName ) {
41 		if ( *pathName == '.' ) break;
42 	}
43 
44 	XMP_StringPtr fileExt = pathName + 1;
45 	return HandlerRegistry::getInstance().getFileFormat ( fileExt );
46 }
47 #endif
48 // =================================================================================================
49 
Plugin_MetaHandlerCTor(FileHandlerSharedPtr handler,XMPFiles * parent)50 static XMPFileHandler* Plugin_MetaHandlerCTor ( FileHandlerSharedPtr handler, XMPFiles* parent )
51 {
52 	SessionRef object;
53 	WXMP_Error error;
54 
55 	if( (handler == 0) || (! handler->load()) )
56 	{
57 		XMP_Throw ( "Plugin not loaded", kXMPErr_InternalFailure );
58 	}
59 
60 	if( handler->getModule()->getPluginAPIs()->mInitializeSessionV2Proc )
61 		handler->getModule()->getPluginAPIs()->mInitializeSessionV2Proc ( handler->getUID().c_str(), parent->GetFilePath().c_str(), (XMP_Uns32)parent->format, (XMP_Uns32)handler->getHandlerFlags(), (XMP_Uns32)parent->openFlags, &object, &error, ErrorCallbackBox( parent->errorCallback.wrapperProc, parent->errorCallback.clientProc, parent->errorCallback.context, parent->errorCallback.limit ), parent->progressTracker->GetCallbackInfo() );
62 	else
63 		handler->getModule()->getPluginAPIs()->mInitializeSessionProc ( handler->getUID().c_str(), parent->GetFilePath().c_str(), (XMP_Uns32)parent->format, (XMP_Uns32)handler->getHandlerFlags(), (XMP_Uns32)parent->openFlags, &object, &error );
64 	CheckError ( error );
65 
66 	FileHandlerInstance* instance = new FileHandlerInstance ( object, handler, parent );
67 	return instance;
68 }
69 
Plugin_MetaHandlerCTor_Standard(XMPFiles * parent)70 static XMPFileHandler* Plugin_MetaHandlerCTor_Standard( XMPFiles * parent )
71 {
72 	FileHandlerSharedPtr handler = PluginManager::getFileHandler( parent->format, PluginManager::kStandardHandler );
73 
74 	return Plugin_MetaHandlerCTor( handler, parent );
75 }
76 
Plugin_MetaHandlerCTor_Replacement(XMPFiles * parent)77 static XMPFileHandler* Plugin_MetaHandlerCTor_Replacement( XMPFiles * parent )
78 {
79 	FileHandlerSharedPtr handler = PluginManager::getFileHandler( parent->format, PluginManager::kReplacementHandler );
80 
81 	return Plugin_MetaHandlerCTor( handler, parent );
82 }
83 
84 // =================================================================================================
85 
Plugin_CheckFileFormat(FileHandlerSharedPtr handler,XMP_StringPtr filePath,XMP_IO * fileRef,XMPFiles *)86 static bool Plugin_CheckFileFormat ( FileHandlerSharedPtr handler, XMP_StringPtr filePath, XMP_IO * fileRef, XMPFiles * /*parent*/ )
87 {
88 	if ( handler != 0 ) {
89 
90 		// call into plugin if owning handler or if manifest has no CheckFormat entry
91 		if ( fileRef == 0 || handler->getCheckFormatSize() == 0) {
92 
93 			XMP_Bool ok;
94 			WXMP_Error error;
95 			CheckSessionFileFormatProc checkProc = handler->getModule()->getPluginAPIs()->mCheckFileFormatProc;
96 			checkProc ( handler->getUID().c_str(), filePath, fileRef, &ok, &error );
97 			CheckError ( error );
98 			return ConvertXMP_BoolToBool( ok );
99 
100 		} else {
101 
102 			// all CheckFormat manifest entries must match
103 			for ( XMP_Uns32 i=0; i < handler->getCheckFormatSize(); i++ ) {
104 
105 				CheckFormat checkFormat = handler->getCheckFormat ( i );
106 
107 				if ( checkFormat.empty() ) return false;
108 
109 				XMP_Uns8 buffer[1024];
110 
111 				if ( checkFormat.mLength > 1024 ) {
112 					//Ideally check format string should not be that long.
113 					//The check is here to handle only malicious data.
114 					checkFormat.mLength = 1024;
115 				}
116 
117 				fileRef->Seek ( checkFormat.mOffset, kXMP_SeekFromStart );
118 				XMP_Uns32 len = fileRef->Read ( buffer, checkFormat.mLength );
119 
120 				if ( len != checkFormat.mLength ) {
121 
122 					// Not enough byte read from the file.
123 					return false;
124 
125 				} else {
126 
127 					// Check if byteSeq is hexadecimal byte sequence, e.g 0x03045100
128 
129 					bool isHex = ( (checkFormat.mLength > 0 ) &&
130 								   (checkFormat.mByteSeq.size() == (2 + 2*checkFormat.mLength) &&
131 								   (checkFormat.mByteSeq[0] == '0') &&
132 								   (checkFormat.mByteSeq[1] == 'x') )
133 								   );
134 
135 					if ( ! isHex ) {
136 
137 						if ( memcmp ( buffer, checkFormat.mByteSeq.c_str(), checkFormat.mLength ) != 0 ) return false;
138 
139 					} else {
140 
141 						for ( XMP_Uns32 current = 0; current < checkFormat.mLength; current++ ) {
142 
143 							char oneByteBuffer[3];
144 							oneByteBuffer[0] = checkFormat.mByteSeq [ 2 + 2*current ];
145 							oneByteBuffer[1] = checkFormat.mByteSeq [ 2 + 2*current + 1 ];
146 							oneByteBuffer[2] = '\0';
147 
148 							XMP_Uns8 oneByte = (XMP_Uns8) strtoul ( oneByteBuffer, 0, 16 );
149 							if ( oneByte != buffer[current] ) return false;
150 
151 						}
152 
153 					}
154 
155 				}
156 
157 			}
158 
159 			return true;	// The checkFormat string comparison passed.
160 
161 		}
162 
163 	}
164 
165 	return false;	// Should never get here.
166 }	// Plugin_CheckFileFormat
167 
Plugin_CheckFileFormat_Standard(XMP_FileFormat format,XMP_StringPtr filePath,XMP_IO * fileRef,XMPFiles * parent)168 static bool Plugin_CheckFileFormat_Standard( XMP_FileFormat format, XMP_StringPtr filePath, XMP_IO* fileRef, XMPFiles* parent )
169 {
170 	FileHandlerSharedPtr handler = PluginManager::getFileHandler( format, PluginManager::kStandardHandler );
171 
172 	return Plugin_CheckFileFormat( handler, filePath, fileRef, parent );
173 }
174 
Plugin_CheckFileFormat_Replacement(XMP_FileFormat format,XMP_StringPtr filePath,XMP_IO * fileRef,XMPFiles * parent)175 static bool Plugin_CheckFileFormat_Replacement( XMP_FileFormat format, XMP_StringPtr filePath, XMP_IO* fileRef, XMPFiles* parent )
176 {
177 	FileHandlerSharedPtr handler = PluginManager::getFileHandler( format, PluginManager::kReplacementHandler );
178 
179 	return Plugin_CheckFileFormat( handler, filePath, fileRef, parent );
180 }
181 
182 // =================================================================================================
183 
Plugin_CheckFolderFormat(FileHandlerSharedPtr handler,const std::string & rootPath,const std::string & gpName,const std::string & parentName,const std::string & leafName,XMPFiles *)184 static bool Plugin_CheckFolderFormat( FileHandlerSharedPtr handler,
185 									  const std::string & rootPath,
186 									  const std::string & gpName,
187 									  const std::string & parentName,
188 									  const std::string & leafName,
189 									  XMPFiles * /*parent*/ )
190 {
191 	XMP_Bool result = false;
192 
193 	if ( handler != 0 )
194 	{
195 		WXMP_Error error;
196 		CheckSessionFolderFormatProc checkProc = handler->getModule()->getPluginAPIs()->mCheckFolderFormatProc;
197 		checkProc ( handler->getUID().c_str(), rootPath.c_str(), gpName.c_str(), parentName.c_str(), leafName.c_str(), &result, &error );
198 		CheckError( error );
199 	}
200 
201 	return ConvertXMP_BoolToBool( result );
202 
203 }
204 
Plugin_CheckFolderFormat_Standard(XMP_FileFormat format,const std::string & rootPath,const std::string & gpName,const std::string & parentName,const std::string & leafName,XMPFiles * parent)205 static bool Plugin_CheckFolderFormat_Standard( XMP_FileFormat format,
206 	const std::string & rootPath,
207 	const std::string & gpName,
208 	const std::string & parentName,
209 	const std::string & leafName,
210 	XMPFiles * parent )
211 {
212 	FileHandlerSharedPtr handler = PluginManager::getFileHandler( format, PluginManager::kStandardHandler );
213 
214 	return Plugin_CheckFolderFormat( handler, rootPath, gpName, parentName, leafName, parent );
215 }
216 
Plugin_CheckFolderFormat_Replacement(XMP_FileFormat format,const std::string & rootPath,const std::string & gpName,const std::string & parentName,const std::string & leafName,XMPFiles * parent)217 static bool Plugin_CheckFolderFormat_Replacement( XMP_FileFormat format,
218 	const std::string & rootPath,
219 	const std::string & gpName,
220 	const std::string & parentName,
221 	const std::string & leafName,
222 	XMPFiles * parent )
223 {
224 	FileHandlerSharedPtr handler = PluginManager::getFileHandler( format, PluginManager::kReplacementHandler );
225 
226 	return Plugin_CheckFolderFormat( handler, rootPath, gpName, parentName, leafName, parent );
227 }
228 
229 // =================================================================================================
230 
231 PluginManager* PluginManager::msPluginManager = 0;
232 
PluginManager(const std::string & pluginDir,const std::string & plugins)233 PluginManager::PluginManager( const std::string& pluginDir, const std::string& plugins )
234 : mPluginDir ( pluginDir )
235 {
236 
237 	const std::size_t count = sizeof(kLibraryExtensions) / sizeof(kLibraryExtensions[0]);
238 
239 	for ( std::size_t i = 0; i<count; ++i ) {
240 		mExtensions.push_back ( std::string ( kLibraryExtensions[i] ) );
241 	}
242 
243 	size_t pos1 = std::string::npos;
244 
245 	#if XMP_WinBuild
246 		// convert to Win kDirChar
247 		while ( (pos1 = mPluginDir.find ('/')) != string::npos ) {
248 			mPluginDir.replace (pos1, 1, "\\");
249 		}
250 	#else
251 		while ( (pos1 = mPluginDir.find ('\\')) != string::npos ) {
252 			mPluginDir.replace (pos1, 1, "/");
253 		}
254 	#endif
255 
256 	if ( ! mPluginDir.empty() && Host_IO::Exists( mPluginDir.c_str() ) ) {
257 
258 		XMP_StringPtr strPtr = plugins.c_str();
259 		size_t pos = 0;
260 		size_t length = 0;
261 
262 		for ( ; ; ++strPtr, ++length ) {
263 
264 			if ( (*strPtr == ',') || (*strPtr == '\0') ) {
265 
266 				if ( length != 0 ) {
267 
268 					//Remove white spaces from front
269 					while ( plugins[pos] == ' ' ) {
270 						++pos;
271 						--length;
272 					}
273 
274 					std::string pluginName;
275 					pluginName.assign ( plugins, pos, length );
276 
277 					//Remove extension from the plugin name
278 					size_t found = pluginName.find ( '.' );
279 					if ( found != string::npos ) pluginName.erase ( found );
280 
281 					//Remove white spaces from the back
282 					found = pluginName.find ( ' ' );
283 					if ( found != string::npos ) pluginName.erase ( found );
284 
285 					MakeLowerCase ( &pluginName );
286 					mPluginsNeeded.push_back ( pluginName );
287 
288 					//Reset for next plugin
289 					pos = pos + length + 1;
290 					length = 0;
291 
292 				}
293 
294 				if ( *strPtr == '\0' ) break;
295 
296 			}
297 
298 		}
299 
300 	}
301 
302 }	// PluginManager::PluginManager
303 
304 // =================================================================================================
305 
~PluginManager()306 PluginManager::~PluginManager()
307 {
308 	mPluginDir.clear();
309 	mExtensions.clear();
310 	mPluginsNeeded.clear();
311 	mHandlers.clear();
312 	mSessions.clear();
313 
314 	terminateHostAPI();
315 }
316 
317 // =================================================================================================
318 
registerHandler(XMP_FileFormat format,FileHandlerSharedPtr handler)319 static bool registerHandler( XMP_FileFormat format, FileHandlerSharedPtr handler )
320 {
321 	bool ret = false;
322 
323 	HandlerRegistry& hdlrReg				= HandlerRegistry::getInstance();
324 	/*FileHandlerType type					=*/ handler->getHandlerType();
325 	CheckFileFormatProc chkFileFormat		= NULL;
326 	CheckFolderFormatProc chkFolderFormat	= NULL;
327 	XMPFileHandlerCTor hdlCtor				= NULL;
328 
329 	if ( handler->getHandlerFlags() & kXMPFiles_NeedsPreloading )
330 	{
331 		try
332 		{
333 			handler->load();
334 		}
335 		catch ( ... )
336 		{
337 			return false;
338 		}
339 	}
340 
341 	if( handler->getOverwriteHandler() )
342 	{
343 		//
344 		// ctor, checkformat function pointers for replacement handler
345 		//
346 		hdlCtor			= Plugin_MetaHandlerCTor_Replacement;
347 		chkFileFormat	= Plugin_CheckFileFormat_Replacement;
348 		chkFolderFormat	= Plugin_CheckFolderFormat_Replacement;
349 	}
350 	else
351 	{
352 		//
353 		// ctor, checkformat function pointers for standard handler
354 		//
355 		hdlCtor			= Plugin_MetaHandlerCTor_Standard;
356 		chkFileFormat	= Plugin_CheckFileFormat_Standard;
357 		chkFolderFormat	= Plugin_CheckFolderFormat_Standard;
358 	}
359 
360 	//
361 	// register handler according to its type
362 	//
363 	switch( handler->getHandlerType() )
364 	{
365 		case NormalHandler_K:
366 			ret = hdlrReg.registerNormalHandler( format, handler->getHandlerFlags(), chkFileFormat,
367 												 hdlCtor, handler->getOverwriteHandler() );
368 			break;
369 
370 		case OwningHandler_K:
371 			ret = hdlrReg.registerOwningHandler( format, handler->getHandlerFlags(), chkFileFormat,
372 												 hdlCtor, handler->getOverwriteHandler() );
373 			break;
374 
375 		case FolderHandler_K:
376 			ret = hdlrReg.registerFolderHandler( format, handler->getHandlerFlags(), chkFolderFormat,
377 												 hdlCtor, handler->getOverwriteHandler() );
378 			break;
379 
380 		default:
381 			break;
382 	}
383 
384 	return ret;
385 }
386 
initialize(const std::string & pluginDir,const std::string & plugins)387 void PluginManager::initialize( const std::string& pluginDir, const std::string& plugins )
388 {
389 	try
390 	{
391 		if( msPluginManager == 0 ) msPluginManager = new PluginManager( pluginDir, plugins );
392 		msPluginManager->initializeHostAPI();
393 
394 		msPluginManager->doScan( 2 );
395 
396 		//
397 		// Register all the found plugin based file handler
398 		//
399 		for( PluginHandlerMap::iterator it = msPluginManager->mHandlers.begin(); it != msPluginManager->mHandlers.end(); ++it )
400 		{
401 			XMP_FileFormat format = it->first;
402 			FileHandlerPair handlers = it->second;
403 
404 			if( handlers.mStandardHandler != NULL )
405 			{
406 				registerHandler( format, handlers.mStandardHandler );
407 			}
408 
409 			if( handlers.mReplacementHandler != NULL )
410 			{
411 				registerHandler( format, handlers.mReplacementHandler );
412 			}
413 		}
414 	}
415 	catch( ... )
416 	{
417 		// Absorb exceptions. This is the plugin-architecture entry point.
418 	}
419 
420 }	// PluginManager::initialize
421 
422 // =================================================================================================
423 
terminate()424 void PluginManager::terminate()
425 {
426 	delete msPluginManager;
427 	msPluginManager = 0;
428 	ResourceParser::terminate();
429 }
430 
431 // =================================================================================================
432 
addFileHandler(XMP_FileFormat format,FileHandlerSharedPtr handler)433 void PluginManager::addFileHandler( XMP_FileFormat format, FileHandlerSharedPtr handler )
434 {
435 	if ( msPluginManager != 0 )
436 	{
437 		PluginHandlerMap & handlerMap = msPluginManager->mHandlers;
438 
439 		//
440 		// Create placeholder in map for format
441 		//
442 		if ( handlerMap.find(format) == handlerMap.end() )
443 		{
444 			FileHandlerPair pair;
445 			handlerMap.insert( handlerMap.end(), std::pair<XMP_FileFormat, FileHandlerPair>( format, pair) );
446 		}
447 
448 		//
449 		//
450 		// if there is already a standard handler or a replacement handler for the file format
451 		// then use the one with the highest version. If both versions are the same the first one wins.
452 		//
453 		FileHandlerSharedPtr& existingHandler =
454 			handler->getOverwriteHandler() ? handlerMap[format].mReplacementHandler : handlerMap[format].mStandardHandler;
455 
456 		if( ! existingHandler )
457 		{
458 			existingHandler = handler;
459 		}
460 		else
461 		{
462 			if( existingHandler->getUID() == handler->getUID() )
463 			{
464 				if( existingHandler->getVersion() < handler->getVersion() )
465 				{
466 					existingHandler = handler;	// replace older handler
467 				}
468 			}
469 			else
470 			{
471 				// TODO: notify client that two plugin handlers try to handle the same file format
472 				// -> need access to the global notification handler
473 			}
474 		}
475 	}
476 }
477 
478 // =================================================================================================
479 
getFileHandler(XMP_FileFormat format,HandlerPriority priority)480 FileHandlerSharedPtr PluginManager::getFileHandler( XMP_FileFormat format, HandlerPriority priority /*= kStandardHandler*/ )
481 {
482 	if ( msPluginManager != 0 )
483 	{
484 		PluginHandlerMap::iterator it = msPluginManager->mHandlers.find( format );
485 
486 		if( it != msPluginManager->mHandlers.end() )
487 		{
488 			if( priority == kStandardHandler )
489 			{
490 				return it->second.mStandardHandler;
491 			}
492 			else if( priority == kReplacementHandler )
493 			{
494 				return it->second.mReplacementHandler;
495 			}
496 		}
497 	}
498 
499 	return FileHandlerSharedPtr();
500 }
501 
502 // =================================================================================================
503 
504 static XMP_ReadWriteLock sSessionMapPluginManagerRWLock;
505 
addHandlerInstance(SessionRef session,FileHandlerInstancePtr handler)506 void PluginManager::addHandlerInstance( SessionRef session, FileHandlerInstancePtr handler )
507 {
508 	if ( msPluginManager != 0 ) {
509 		XMP_AutoLock lock(&sSessionMapPluginManagerRWLock, kXMP_WriteLock);
510 		SessionMap & sessionMap = msPluginManager->mSessions;
511 		if ( sessionMap.find(session) == sessionMap.end() ) {
512 			sessionMap[session] = handler;
513 		}
514 	}
515 }
516 
517 // =================================================================================================
518 
removeHandlerInstance(SessionRef session)519 void PluginManager::removeHandlerInstance( SessionRef session )
520 {
521 	if ( msPluginManager != 0 ) {
522 		XMP_AutoLock lock(&sSessionMapPluginManagerRWLock, kXMP_WriteLock);
523 		SessionMap & sessionMap = msPluginManager->mSessions;
524 		sessionMap.erase ( session );
525 	}
526 }
527 
528 // =================================================================================================
529 
getHandlerInstance(SessionRef session)530 FileHandlerInstancePtr PluginManager::getHandlerInstance( SessionRef session )
531 {
532 	FileHandlerInstancePtr ret = 0;
533 	if ( msPluginManager != 0 ) {
534 		XMP_AutoLock lock(&sSessionMapPluginManagerRWLock, kXMP_ReadLock);
535 		ret = msPluginManager->mSessions[session];
536 	}
537 	return ret;
538 }
539 
540 // =================================================================================================
541 
getHandlerPriority(FileHandlerInstancePtr handler)542 PluginManager::HandlerPriority PluginManager::getHandlerPriority( FileHandlerInstancePtr handler )
543 {
544 	if( handler != NULL )
545 	{
546 		for( PluginHandlerMap::iterator it=msPluginManager->mHandlers.begin();
547 			 it != msPluginManager->mHandlers.end(); it++ )
548 		{
549 			if( it->second.mStandardHandler == handler->GetHandlerInfo() )		return kStandardHandler;
550 			if( it->second.mReplacementHandler == handler->GetHandlerInfo() )	return kReplacementHandler;
551 		}
552 	}
553 
554 	return kUnknown;
555 }
556 
557 // =================================================================================================
558 
CheckPluginArchitecture(XMLParserAdapter * xmlParser)559 static bool CheckPluginArchitecture ( XMLParserAdapter * xmlParser ) {
560 
561 	#if XMP_MacBuild
562 		bool okArchitecture = true;		// Missing Architecture attribute means load on Mac.
563 	#else
564 		bool okArchitecture = false;	// Missing Architecture attribute means do not load elsewhere.
565 	#endif
566 
567 	#if XMP_64
568 		const char * nativeArchitecture = "x64";
569 	#else
570 		const char * nativeArchitecture = "x86";
571 	#endif
572 
573 	size_t i, limit;
574 	XML_Node & xmlTree = xmlParser->tree;
575 	XML_NodePtr rootElem = 0;
576 
577 	// Find the outermost XML element and see if it is PluginResource.
578 	for ( i = 0, limit = xmlTree.content.size(); i < limit; ++i ) {
579 		if ( xmlTree.content[i]->kind == kElemNode ) {
580 			rootElem = xmlTree.content[i];
581 			break;
582 		}
583 	}
584 
585 	if ( (rootElem == 0) || (rootElem->name != "PluginResource") ) return okArchitecture;
586 
587 	// Look for the Architecture attribute and see if it matches.
588 
589 	XML_NodePtr archAttr = 0;
590 	for ( i = 0, limit = rootElem->attrs.size(); i < limit; ++i ) {
591 		if ( rootElem->attrs[i]->name == "Architecture" ) {
592 			archAttr = rootElem->attrs[i];
593 			break;
594 		}
595 	}
596 
597 	if ( archAttr != 0 ) okArchitecture = (archAttr->value == nativeArchitecture);
598 
599 	return okArchitecture;
600 
601 }	// CheckPluginArchitecture
602 
603 // =================================================================================================
604 
loadResourceFile(ModuleSharedPtr module)605 void PluginManager::loadResourceFile( ModuleSharedPtr module )
606 {
607 
608 	OS_ModuleRef moduleRef = LoadModule ( module->getPath(), true );
609 
610 	if ( moduleRef != 0 ) {
611 
612 		XMLParserAdapter* parser = 0;
613 
614 		try {
615 
616 			std::string buffer;
617 			if ( GetResourceDataFromModule ( moduleRef, kResourceName_UIDs, "txt", buffer ) ) {
618 
619 				ResourceParser::initialize(); // Initialize XMPAtoms before processing resource file.
620 
621 				parser = XMP_NewExpatAdapter ( ExpatAdapter::kUseGlobalNamespaces );
622 				parser->ParseBuffer ( (XMP_Uns8*)buffer.c_str(), buffer.size(), true );
623 
624 				if ( CheckPluginArchitecture ( parser ) ) {
625 					ResourceParser resource ( module );
626 					resource.parseElementList ( &parser->tree, true );
627 				}
628 
629 				delete parser;
630 
631 			}
632 
633 		} catch ( ... ) {
634 
635 			if ( parser != 0 ) delete parser;
636 			// Otherwise ignore errors.
637 
638 		}
639 
640 		UnloadModule ( moduleRef, true );
641 
642 	}
643 
644 }	// PluginManager::loadResourceFile
645 
646 // =================================================================================================
647 
scanRecursive(const std::string & tempPath,std::vector<std::string> & ioFoundLibs,XMP_Int32 inLevel,XMP_Int32 inMaxNestingLevel)648 void PluginManager::scanRecursive( const std::string & tempPath, std::vector<std::string>& ioFoundLibs, XMP_Int32 inLevel, XMP_Int32 inMaxNestingLevel )
649 {
650 	++inLevel;
651 	Host_IO::AutoFolder aFolder;
652 	if ( Host_IO::GetFileMode( tempPath.c_str() ) != Host_IO::kFMode_IsFolder ) return;
653 
654 	aFolder.folder = Host_IO::OpenFolder( tempPath.c_str() );
655 	std::string childPath, childName;
656 
657 	while ( Host_IO::GetNextChild ( aFolder.folder, &childName ) ) {
658 
659 		// Make sure the children of CONTENTS are legit.
660 		childPath = tempPath;
661 		childPath += kDirChar;
662 		childPath += childName;
663 		Host_IO::FileMode clientMode = Host_IO::GetFileMode ( childPath.c_str() );
664 
665 		bool okFolder = (clientMode == Host_IO::kFMode_IsFolder);
666 		#if XMP_MacBuild
667 			if ( okFolder ) okFolder = ( ! IsValidLibrary ( childPath ) );
668 		#endif
669 
670 		// only step into non-packages (neither bundle nor framework) on Mac
671 		if ( okFolder ) {
672 
673 			if ( inLevel < inMaxNestingLevel ) {
674 				scanRecursive ( childPath + kDirChar, ioFoundLibs, inLevel, inMaxNestingLevel );
675 			}
676 
677 		} else {
678 
679 			if ( childName[0] == '~' ) continue; // ignore plug-ins like "~PDFL.xpi"
680 
681 			std::string fileExt;
682 			XMP_StringPtr extPos = childName.c_str() + childName.size();
683 			for ( ; (extPos != childName.c_str()) && (*extPos != '.'); --extPos ) {}
684 			if ( *extPos == '.' ) {
685 				fileExt.assign ( extPos+1 );
686 				MakeLowerCase ( &fileExt );
687 			}
688 
689 			StringVec::const_iterator iterFound =
690 				std::find_if ( mExtensions.begin(), mExtensions.end(),
691 					       [&fileExt](const std::string& file_ext){ return file_ext == fileExt; });
692 
693 			if ( iterFound != mExtensions.end() ) {
694 
695 				//Check if the found plugin is present in the user's demanding plugin list.
696 				childName.erase ( extPos - childName.c_str() );
697 				MakeLowerCase ( &childName );
698 
699 				StringVec::const_iterator pluginNeeded =
700 					std::find_if ( mPluginsNeeded.begin(), mPluginsNeeded.end(),
701 						       [&childName](const std::string& child_name){ return child_name == childName; });
702 
703 				if ( (pluginNeeded != mPluginsNeeded.end()) || mPluginsNeeded.empty() ) {
704 					ioFoundLibs.push_back ( childPath );
705 				}
706 
707 			}
708 
709 		}
710 
711 	}
712 
713 	aFolder.Close();
714 
715 }	// PluginManager::scanRecursive
716 
717 // =================================================================================================
718 
doScan(const XMP_Int32 inMaxNumOfNestedFolder)719 void PluginManager::doScan( const XMP_Int32 inMaxNumOfNestedFolder )
720 {
721 	XMP_Assert(inMaxNumOfNestedFolder > 0);
722 	if ( inMaxNumOfNestedFolder < 1 ) return; // noop, wrong parameter
723 
724 	// scan directory
725 	std::vector<std::string> foundLibs;
726 	XMP_Int32 iteration = 0;
727 	scanRecursive ( mPluginDir, foundLibs, iteration, inMaxNumOfNestedFolder );
728 
729 	// add found modules
730 	std::vector<std::string>::const_iterator iter = foundLibs.begin();
731 	std::vector<std::string>::const_iterator iterEnd = foundLibs.end();
732 	for ( ; iter != iterEnd; ++iter ) {
733 		std::string path ( *iter );
734 		ModuleSharedPtr module ( new Module ( path ) );
735 		loadResourceFile ( module );
736 	}
737 
738 }	// PluginManager::doScan
739 
740 // =================================================================================================
741 
getHostAPI(XMP_Uns32 version)742 HostAPIRef PluginManager::getHostAPI( XMP_Uns32 version )
743 {
744 	HostAPIRef hostAPI = NULL;
745 
746 	if( msPluginManager == NULL )	return NULL;
747 	if(  version < 1 )				return NULL;
748 
749 	HostAPIMap::iterator iter = msPluginManager->mHostAPIs.find( version );
750 
751 	if( iter != msPluginManager->mHostAPIs.end() )
752 	{
753 		hostAPI = iter->second;
754 	}
755 
756 	return hostAPI;
757 }
758 
759 // =================================================================================================
760 
terminateHostAPI()761 void PluginManager::terminateHostAPI()
762 {
763 	for( HostAPIMap::iterator it = msPluginManager->mHostAPIs.begin(); it != msPluginManager->mHostAPIs.end(); ++it )
764 	{
765 		XMP_Uns32 version = it->first;
766 		HostAPIRef hostAPI = it->second;
767 
768 		switch( version )
769 		{
770 		case 1:
771 		case 2:
772 		case 3:
773 		case 4:
774 			{
775 				delete hostAPI->mFileIOAPI;
776 				delete hostAPI->mStrAPI;
777 				delete hostAPI->mAbortAPI;
778 				delete hostAPI->mStandardHandlerAPI;
779 				delete hostAPI;
780 			}
781 			break;
782 
783 		default:
784 			{
785 				delete hostAPI;
786 			}
787 		}
788 	}
789 }
790 
initializeHostAPI()791 void PluginManager::initializeHostAPI()
792 {
793 	HostAPIRef hostAPI = NULL;
794 
795 
796 	for ( int i = 0; i < XMP_HOST_API_VERSION_4; i++ )
797 	{
798 		hostAPI				= new HostAPI();
799 		hostAPI->mSize		= sizeof( HostAPI );
800 		hostAPI->mVersion	= i + 1;
801 
802 		switch( hostAPI->mVersion )
803 		{
804 		case 1:
805 			SetupHostAPI_V1( hostAPI );
806 			break;
807 
808 		case 2:
809 			SetupHostAPI_V2( hostAPI );
810 			break;
811 
812 		case 3:
813 			SetupHostAPI_V3( hostAPI );
814 			break;
815 
816 		default:
817 		case 4:
818 			SetupHostAPI_V4( hostAPI );
819 			break;
820 		}
821 
822 		msPluginManager->mHostAPIs[ hostAPI->mVersion ] = hostAPI;
823 	}
824 }
825 
826 }	// namespace XMP_PLUGIN
827