1 // =====================================================================
2 // FreeImage Plugin Interface
3 //
4 // Design and implementation by
5 // - Floris van den Berg (floris@geekhq.nl)
6 // - Rui Lopes (ruiglopes@yahoo.com)
7 // - Detlev Vendt (detlev.vendt@brillit.de)
8 // - Petr Pytelka (pyta@lightcomp.com)
9 //
10 // This file is part of FreeImage 3
11 //
12 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
13 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
14 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
15 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
16 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
17 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
18 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
19 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
20 // THIS DISCLAIMER.
21 //
22 // Use at your own risk!
23 // =====================================================================
24 
25 #ifdef _MSC_VER
26 #pragma warning (disable : 4786) // identifier was truncated to 'number' characters
27 #endif
28 
29 #ifdef _WIN32
30 #include <windows.h>
31 #include <io.h>
32 #else
33 #include <ctype.h>
34 #endif // _WIN32
35 
36 #include "FreeImage.h"
37 #include "Utilities.h"
38 #include "FreeImageIO.h"
39 #include "Plugin.h"
40 
41 #include "../Metadata/FreeImageTag.h"
42 
43 // =====================================================================
44 
45 using namespace std;
46 
47 // =====================================================================
48 // Plugin search list
49 // =====================================================================
50 
51 const char *
52 s_search_list[] = {
53 	"",
54 	"plugins\\",
55 };
56 
57 static int s_search_list_size = sizeof(s_search_list) / sizeof(char *);
58 static PluginList *s_plugins = NULL;
59 static int s_plugin_reference_count = 0;
60 
61 
62 // =====================================================================
63 // Reimplementation of stricmp (it is not supported on some systems)
64 // =====================================================================
65 
66 int
FreeImage_stricmp(const char * s1,const char * s2)67 FreeImage_stricmp(const char *s1, const char *s2) {
68 	int c1, c2;
69 
70 	do {
71 		c1 = tolower(*s1++);
72 		c2 = tolower(*s2++);
73 	} while (c1 && c1 == c2);
74 
75 	return c1 - c2;
76 }
77 
78 // =====================================================================
79 //  Implementation of PluginList
80 // =====================================================================
81 
PluginList()82 PluginList::PluginList() :
83 m_plugin_map(),
84 m_node_count(0) {
85 }
86 
87 FREE_IMAGE_FORMAT
AddNode(FI_InitProc init_proc,void * instance,const char * format,const char * description,const char * extension,const char * regexpr)88 PluginList::AddNode(FI_InitProc init_proc, void *instance, const char *format, const char *description, const char *extension, const char *regexpr) {
89 	if (init_proc != NULL) {
90 		PluginNode *node = new(std::nothrow) PluginNode;
91 		Plugin *plugin = new(std::nothrow) Plugin;
92 		if(!node || !plugin) {
93 			if(node) delete node;
94 			if(plugin) delete plugin;
95 			FreeImage_OutputMessageProc(FIF_UNKNOWN, FI_MSG_ERROR_MEMORY);
96 			return FIF_UNKNOWN;
97 		}
98 
99 		memset(plugin, 0, sizeof(Plugin));
100 
101 		// fill-in the plugin structure
102 		// note we have memset to 0, so all unset pointers should be NULL)
103 
104 		init_proc(plugin, (int)m_plugin_map.size());
105 
106 		// get the format string (two possible ways)
107 
108 		const char *the_format = NULL;
109 
110 		if (format != NULL) {
111 			the_format = format;
112 		} else if (plugin->format_proc != NULL) {
113 			the_format = plugin->format_proc();
114 		}
115 
116 		// add the node if it wasn't there already
117 
118 		if (the_format != NULL) {
119 			node->m_id = (int)m_plugin_map.size();
120 			node->m_instance = instance;
121 			node->m_plugin = plugin;
122 			node->m_format = format;
123 			node->m_description = description;
124 			node->m_extension = extension;
125 			node->m_regexpr = regexpr;
126 			node->m_enabled = TRUE;
127 
128 			m_plugin_map[(const int)m_plugin_map.size()] = node;
129 
130 			return (FREE_IMAGE_FORMAT)node->m_id;
131 		}
132 
133 		// something went wrong while allocating the plugin... cleanup
134 
135 		delete plugin;
136 		delete node;
137 	}
138 
139 	return FIF_UNKNOWN;
140 }
141 
142 PluginNode *
FindNodeFromFormat(const char * format)143 PluginList::FindNodeFromFormat(const char *format) {
144 	for (map<int, PluginNode *>::iterator i = m_plugin_map.begin(); i != m_plugin_map.end(); ++i) {
145 		const char *the_format = ((*i).second->m_format != NULL) ? (*i).second->m_format : (*i).second->m_plugin->format_proc();
146 
147 		if ((*i).second->m_enabled) {
148 			if (FreeImage_stricmp(the_format, format) == 0) {
149 				return (*i).second;
150 			}
151 		}
152 	}
153 
154 	return NULL;
155 }
156 
157 PluginNode *
FindNodeFromMime(const char * mime)158 PluginList::FindNodeFromMime(const char *mime) {
159 	for (map<int, PluginNode *>::iterator i = m_plugin_map.begin(); i != m_plugin_map.end(); ++i) {
160 		const char *the_mime = ((*i).second->m_plugin->mime_proc != NULL) ? (*i).second->m_plugin->mime_proc() : "";
161 
162 		if ((*i).second->m_enabled) {
163 			if ((the_mime != NULL) && (strcmp(the_mime, mime) == 0)) {
164 				return (*i).second;
165 			}
166 		}
167 	}
168 
169 	return NULL;
170 }
171 
172 PluginNode *
FindNodeFromFIF(int node_id)173 PluginList::FindNodeFromFIF(int node_id) {
174 	map<int, PluginNode *>::iterator i = m_plugin_map.find(node_id);
175 
176 	if (i != m_plugin_map.end()) {
177 		return (*i).second;
178 	}
179 
180 	return NULL;
181 }
182 
183 int
Size() const184 PluginList::Size() const {
185 	return (int)m_plugin_map.size();
186 }
187 
188 BOOL
IsEmpty() const189 PluginList::IsEmpty() const {
190 	return m_plugin_map.empty();
191 }
192 
~PluginList()193 PluginList::~PluginList() {
194 	for (map<int, PluginNode *>::iterator i = m_plugin_map.begin(); i != m_plugin_map.end(); ++i) {
195 #ifdef _WIN32
196 		if ((*i).second->m_instance != NULL) {
197 			FreeLibrary((HINSTANCE)(*i).second->m_instance);
198 		}
199 #endif
200 		delete (*i).second->m_plugin;
201 		delete ((*i).second);
202 	}
203 }
204 
205 // =====================================================================
206 // Retrieve a pointer to the plugin list container
207 // =====================================================================
208 
209 PluginList * DLL_CALLCONV
FreeImage_GetPluginList()210 FreeImage_GetPluginList() {
211 	return s_plugins;
212 }
213 
214 // =====================================================================
215 // Plugin System Initialization
216 // =====================================================================
217 
218 void DLL_CALLCONV
FreeImage_Initialise(BOOL load_local_plugins_only)219 FreeImage_Initialise(BOOL load_local_plugins_only) {
220 	if (s_plugin_reference_count++ == 0) {
221 
222 		/*
223 		Note: initialize all singletons here
224 		in order to avoid race conditions with multi-threading
225 		*/
226 
227 		// initialise the TagLib singleton
228 		TagLib& s = TagLib::instance();
229 
230 		// internal plugin initialization
231 
232 		s_plugins = new(std::nothrow) PluginList;
233 
234 		if (s_plugins) {
235 			/* NOTE :
236 			The order used to initialize internal plugins below MUST BE the same order
237 			as the one used to define the FREE_IMAGE_FORMAT enum.
238 			*/
239 			s_plugins->AddNode(InitBMP);
240 			s_plugins->AddNode(InitICO);
241 			s_plugins->AddNode(InitJPEG);
242 			s_plugins->AddNode(InitJNG);
243 			s_plugins->AddNode(InitKOALA);
244 			s_plugins->AddNode(InitIFF);
245 			s_plugins->AddNode(InitMNG);
246 			s_plugins->AddNode(InitPNM, NULL, "PBM", "Portable Bitmap (ASCII)", "pbm", "^P1");
247 			s_plugins->AddNode(InitPNM, NULL, "PBMRAW", "Portable Bitmap (RAW)", "pbm", "^P4");
248 			s_plugins->AddNode(InitPCD);
249 			s_plugins->AddNode(InitPCX);
250 			s_plugins->AddNode(InitPNM, NULL, "PGM", "Portable Greymap (ASCII)", "pgm", "^P2");
251 			s_plugins->AddNode(InitPNM, NULL, "PGMRAW", "Portable Greymap (RAW)", "pgm", "^P5");
252 			s_plugins->AddNode(InitPNG);
253 			s_plugins->AddNode(InitPNM, NULL, "PPM", "Portable Pixelmap (ASCII)", "ppm", "^P3");
254 			s_plugins->AddNode(InitPNM, NULL, "PPMRAW", "Portable Pixelmap (RAW)", "ppm", "^P6");
255 			s_plugins->AddNode(InitRAS);
256 			s_plugins->AddNode(InitTARGA);
257 			s_plugins->AddNode(InitTIFF);
258 			s_plugins->AddNode(InitWBMP);
259 			s_plugins->AddNode(InitPSD);
260 			s_plugins->AddNode(InitCUT);
261 			s_plugins->AddNode(InitXBM);
262 			s_plugins->AddNode(InitXPM);
263 			s_plugins->AddNode(InitDDS);
264 	        s_plugins->AddNode(InitGIF);
265 	        s_plugins->AddNode(InitHDR);
266 			s_plugins->AddNode(InitG3);
267 			s_plugins->AddNode(InitSGI);
268 			s_plugins->AddNode(InitEXR);
269 			s_plugins->AddNode(InitJ2K);
270 			s_plugins->AddNode(InitJP2);
271 			s_plugins->AddNode(InitPFM);
272 			s_plugins->AddNode(InitPICT);
273 			s_plugins->AddNode(InitRAW);
274 			s_plugins->AddNode(InitWEBP);
275 #if !(defined(_MSC_VER) && (_MSC_VER <= 1310))
276 			s_plugins->AddNode(InitJXR);
277 #endif // unsupported by MS Visual Studio 2003 !!!
278 
279 			// external plugin initialization
280 
281 #ifdef _WIN32
282 			if (!load_local_plugins_only) {
283 				int count = 0;
284 				char buffer[MAX_PATH + 200];
285 				wchar_t current_dir[2 * _MAX_PATH], module[2 * _MAX_PATH];
286 				BOOL bOk = FALSE;
287 
288 				// store the current directory. then set the directory to the application location
289 
290 				if (GetCurrentDirectoryW(2 * _MAX_PATH, current_dir) != 0) {
291 					if (GetModuleFileNameW(NULL, module, 2 * _MAX_PATH) != 0) {
292 						wchar_t *last_point = wcsrchr(module, L'\\');
293 
294 						if (last_point) {
295 							*last_point = L'\0';
296 
297 							bOk = SetCurrentDirectoryW(module);
298 						}
299 					}
300 				}
301 
302 				// search for plugins
303 
304 				while (count < s_search_list_size) {
305 					_finddata_t find_data;
306 					long find_handle;
307 
308 					strcpy(buffer, s_search_list[count]);
309 					strcat(buffer, "*.fip");
310 
311 					if ((find_handle = (long)_findfirst(buffer, &find_data)) != -1L) {
312 						do {
313 							strcpy(buffer, s_search_list[count]);
314 							strncat(buffer, find_data.name, MAX_PATH + 200);
315 
316 							HINSTANCE instance = LoadLibrary(buffer);
317 
318 							if (instance != NULL) {
319 								FARPROC proc_address = GetProcAddress(instance, "_Init@8");
320 
321 								if (proc_address != NULL) {
322 									s_plugins->AddNode((FI_InitProc)proc_address, (void *)instance);
323 								} else {
324 									FreeLibrary(instance);
325 								}
326 							}
327 						} while (_findnext(find_handle, &find_data) != -1L);
328 
329 						_findclose(find_handle);
330 					}
331 
332 					count++;
333 				}
334 
335 				// restore the current directory
336 
337 				if (bOk) {
338 					SetCurrentDirectoryW(current_dir);
339 				}
340 			}
341 #endif // _WIN32
342 		}
343 	}
344 }
345 
346 void DLL_CALLCONV
FreeImage_DeInitialise()347 FreeImage_DeInitialise() {
348 	--s_plugin_reference_count;
349 
350 	if (s_plugin_reference_count == 0) {
351 		delete s_plugins;
352 	}
353 }
354 
355 // =====================================================================
356 // Open and close a bitmap
357 // =====================================================================
358 
359 void * DLL_CALLCONV
FreeImage_Open(PluginNode * node,FreeImageIO * io,fi_handle handle,BOOL open_for_reading)360 FreeImage_Open(PluginNode *node, FreeImageIO *io, fi_handle handle, BOOL open_for_reading) {
361 	if (node->m_plugin->open_proc != NULL) {
362        return node->m_plugin->open_proc(io, handle, open_for_reading);
363 	}
364 
365 	return NULL;
366 }
367 
368 void DLL_CALLCONV
FreeImage_Close(PluginNode * node,FreeImageIO * io,fi_handle handle,void * data)369 FreeImage_Close(PluginNode *node, FreeImageIO *io, fi_handle handle, void *data) {
370 	if (node->m_plugin->close_proc != NULL) {
371 		node->m_plugin->close_proc(io, handle, data);
372 	}
373 }
374 
375 // =====================================================================
376 // Plugin System Load/Save Functions
377 // =====================================================================
378 
379 FIBITMAP * DLL_CALLCONV
FreeImage_LoadFromHandle(FREE_IMAGE_FORMAT fif,FreeImageIO * io,fi_handle handle,int flags)380 FreeImage_LoadFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle, int flags) {
381 	if ((fif >= 0) && (fif < FreeImage_GetFIFCount())) {
382 		PluginNode *node = s_plugins->FindNodeFromFIF(fif);
383 
384 		if (node != NULL) {
385 			if(node->m_plugin->load_proc != NULL) {
386 				void *data = FreeImage_Open(node, io, handle, TRUE);
387 
388 				FIBITMAP *bitmap = node->m_plugin->load_proc(io, handle, -1, flags, data);
389 
390 				FreeImage_Close(node, io, handle, data);
391 
392 				return bitmap;
393 			}
394 		}
395 	}
396 
397 	return NULL;
398 }
399 
400 FIBITMAP * DLL_CALLCONV
FreeImage_Load(FREE_IMAGE_FORMAT fif,const char * filename,int flags)401 FreeImage_Load(FREE_IMAGE_FORMAT fif, const char *filename, int flags) {
402 	FreeImageIO io;
403 	SetDefaultIO(&io);
404 
405 	FILE *handle = fopen(filename, "rb");
406 
407 	if (handle) {
408 		FIBITMAP *bitmap = FreeImage_LoadFromHandle(fif, &io, (fi_handle)handle, flags);
409 
410 		fclose(handle);
411 
412 		return bitmap;
413 	} else {
414 		FreeImage_OutputMessageProc((int)fif, "FreeImage_Load: failed to open file %s", filename);
415 	}
416 
417 	return NULL;
418 }
419 
420 FIBITMAP * DLL_CALLCONV
FreeImage_LoadU(FREE_IMAGE_FORMAT fif,const wchar_t * filename,int flags)421 FreeImage_LoadU(FREE_IMAGE_FORMAT fif, const wchar_t *filename, int flags) {
422 	FreeImageIO io;
423 	SetDefaultIO(&io);
424 #ifdef _WIN32
425 	FILE *handle = _wfopen(filename, L"rb");
426 
427 	if (handle) {
428 		FIBITMAP *bitmap = FreeImage_LoadFromHandle(fif, &io, (fi_handle)handle, flags);
429 
430 		fclose(handle);
431 
432 		return bitmap;
433 	} else {
434 		FreeImage_OutputMessageProc((int)fif, "FreeImage_LoadU: failed to open input file");
435 	}
436 #endif
437 	return NULL;
438 }
439 
440 BOOL DLL_CALLCONV
FreeImage_SaveToHandle(FREE_IMAGE_FORMAT fif,FIBITMAP * dib,FreeImageIO * io,fi_handle handle,int flags)441 FreeImage_SaveToHandle(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags) {
442 	// cannot save "header only" formats
443 	if(FreeImage_HasPixels(dib) == FALSE) {
444 		FreeImage_OutputMessageProc((int)fif, "FreeImage_SaveToHandle: cannot save \"header only\" formats");
445 		return FALSE;
446 	}
447 
448 	if ((fif >= 0) && (fif < FreeImage_GetFIFCount())) {
449 		PluginNode *node = s_plugins->FindNodeFromFIF(fif);
450 
451 		if (node) {
452 			if(node->m_plugin->save_proc != NULL) {
453 				void *data = FreeImage_Open(node, io, handle, FALSE);
454 
455 				BOOL result = node->m_plugin->save_proc(io, dib, handle, -1, flags, data);
456 
457 				FreeImage_Close(node, io, handle, data);
458 
459 				return result;
460 			}
461 		}
462 	}
463 
464 	return FALSE;
465 }
466 
467 
468 BOOL DLL_CALLCONV
FreeImage_Save(FREE_IMAGE_FORMAT fif,FIBITMAP * dib,const char * filename,int flags)469 FreeImage_Save(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const char *filename, int flags) {
470 	FreeImageIO io;
471 	SetDefaultIO(&io);
472 
473 	FILE *handle = fopen(filename, "w+b");
474 
475 	if (handle) {
476 		BOOL success = FreeImage_SaveToHandle(fif, dib, &io, (fi_handle)handle, flags);
477 
478 		fclose(handle);
479 
480 		return success;
481 	} else {
482 		FreeImage_OutputMessageProc((int)fif, "FreeImage_Save: failed to open file %s", filename);
483 	}
484 
485 	return FALSE;
486 }
487 
488 BOOL DLL_CALLCONV
FreeImage_SaveU(FREE_IMAGE_FORMAT fif,FIBITMAP * dib,const wchar_t * filename,int flags)489 FreeImage_SaveU(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const wchar_t *filename, int flags) {
490 	FreeImageIO io;
491 	SetDefaultIO(&io);
492 #ifdef _WIN32
493 	FILE *handle = _wfopen(filename, L"w+b");
494 
495 	if (handle) {
496 		BOOL success = FreeImage_SaveToHandle(fif, dib, &io, (fi_handle)handle, flags);
497 
498 		fclose(handle);
499 
500 		return success;
501 	} else {
502 		FreeImage_OutputMessageProc((int)fif, "FreeImage_SaveU: failed to open output file");
503 	}
504 #endif
505 	return FALSE;
506 }
507 
508 // =====================================================================
509 // Plugin construction + enable/disable functions
510 // =====================================================================
511 
512 FREE_IMAGE_FORMAT DLL_CALLCONV
FreeImage_RegisterLocalPlugin(FI_InitProc proc_address,const char * format,const char * description,const char * extension,const char * regexpr)513 FreeImage_RegisterLocalPlugin(FI_InitProc proc_address, const char *format, const char *description, const char *extension, const char *regexpr) {
514 	return s_plugins->AddNode(proc_address, NULL, format, description, extension, regexpr);
515 }
516 
517 #ifdef _WIN32
518 FREE_IMAGE_FORMAT DLL_CALLCONV
FreeImage_RegisterExternalPlugin(const char * path,const char * format,const char * description,const char * extension,const char * regexpr)519 FreeImage_RegisterExternalPlugin(const char *path, const char *format, const char *description, const char *extension, const char *regexpr) {
520 	if (path != NULL) {
521 		HINSTANCE instance = LoadLibrary(path);
522 
523 		if (instance != NULL) {
524 			FARPROC proc_address = GetProcAddress(instance, "_Init@8");
525 
526 			FREE_IMAGE_FORMAT result = s_plugins->AddNode((FI_InitProc)proc_address, (void *)instance, format, description, extension, regexpr);
527 
528 			if (result == FIF_UNKNOWN)
529 				FreeLibrary(instance);
530 
531 			return result;
532 		}
533 	}
534 
535 	return FIF_UNKNOWN;
536 }
537 #endif // _WIN32
538 
539 int DLL_CALLCONV
FreeImage_SetPluginEnabled(FREE_IMAGE_FORMAT fif,BOOL enable)540 FreeImage_SetPluginEnabled(FREE_IMAGE_FORMAT fif, BOOL enable) {
541 	if (s_plugins != NULL) {
542 		PluginNode *node = s_plugins->FindNodeFromFIF(fif);
543 
544 		if (node != NULL) {
545 			BOOL previous_state = node->m_enabled;
546 
547 			node->m_enabled = enable;
548 
549 			return previous_state;
550 		}
551 	}
552 
553 	return -1;
554 }
555 
556 int DLL_CALLCONV
FreeImage_IsPluginEnabled(FREE_IMAGE_FORMAT fif)557 FreeImage_IsPluginEnabled(FREE_IMAGE_FORMAT fif) {
558 	if (s_plugins != NULL) {
559 		PluginNode *node = s_plugins->FindNodeFromFIF(fif);
560 
561 		return (node != NULL) ? node->m_enabled : FALSE;
562 	}
563 
564 	return -1;
565 }
566 
567 // =====================================================================
568 // Plugin Access Functions
569 // =====================================================================
570 
571 int DLL_CALLCONV
FreeImage_GetFIFCount()572 FreeImage_GetFIFCount() {
573 	return (s_plugins != NULL) ? s_plugins->Size() : 0;
574 }
575 
576 FREE_IMAGE_FORMAT DLL_CALLCONV
FreeImage_GetFIFFromFormat(const char * format)577 FreeImage_GetFIFFromFormat(const char *format) {
578 	if (s_plugins != NULL) {
579 		PluginNode *node = s_plugins->FindNodeFromFormat(format);
580 
581 		return (node != NULL) ? (FREE_IMAGE_FORMAT)node->m_id : FIF_UNKNOWN;
582 	}
583 
584 	return FIF_UNKNOWN;
585 }
586 
587 FREE_IMAGE_FORMAT DLL_CALLCONV
FreeImage_GetFIFFromMime(const char * mime)588 FreeImage_GetFIFFromMime(const char *mime) {
589 	if (s_plugins != NULL) {
590 		PluginNode *node = s_plugins->FindNodeFromMime(mime);
591 
592 		return (node != NULL) ? (FREE_IMAGE_FORMAT)node->m_id : FIF_UNKNOWN;
593 	}
594 
595 	return FIF_UNKNOWN;
596 }
597 
598 const char * DLL_CALLCONV
FreeImage_GetFormatFromFIF(FREE_IMAGE_FORMAT fif)599 FreeImage_GetFormatFromFIF(FREE_IMAGE_FORMAT fif) {
600 	if (s_plugins != NULL) {
601 		PluginNode *node = s_plugins->FindNodeFromFIF(fif);
602 
603 		return (node != NULL) ? (node->m_format != NULL) ? node->m_format : node->m_plugin->format_proc() : NULL;
604 	}
605 
606 	return NULL;
607 }
608 
609 const char * DLL_CALLCONV
FreeImage_GetFIFMimeType(FREE_IMAGE_FORMAT fif)610 FreeImage_GetFIFMimeType(FREE_IMAGE_FORMAT fif) {
611 	if (s_plugins != NULL) {
612 		PluginNode *node = s_plugins->FindNodeFromFIF(fif);
613 
614 		return (node != NULL) ? (node->m_plugin != NULL) ? ( node->m_plugin->mime_proc != NULL )? node->m_plugin->mime_proc() : NULL : NULL : NULL;
615 	}
616 
617 	return NULL;
618 }
619 
620 const char * DLL_CALLCONV
FreeImage_GetFIFExtensionList(FREE_IMAGE_FORMAT fif)621 FreeImage_GetFIFExtensionList(FREE_IMAGE_FORMAT fif) {
622 	if (s_plugins != NULL) {
623 		PluginNode *node = s_plugins->FindNodeFromFIF(fif);
624 
625 		return (node != NULL) ? (node->m_extension != NULL) ? node->m_extension : (node->m_plugin->extension_proc != NULL) ? node->m_plugin->extension_proc() : NULL : NULL;
626 	}
627 
628 	return NULL;
629 }
630 
631 const char * DLL_CALLCONV
FreeImage_GetFIFDescription(FREE_IMAGE_FORMAT fif)632 FreeImage_GetFIFDescription(FREE_IMAGE_FORMAT fif) {
633 	if (s_plugins != NULL) {
634 		PluginNode *node = s_plugins->FindNodeFromFIF(fif);
635 
636 		return (node != NULL) ? (node->m_description != NULL) ? node->m_description : (node->m_plugin->description_proc != NULL) ? node->m_plugin->description_proc() : NULL : NULL;
637 	}
638 
639 	return NULL;
640 }
641 
642 const char * DLL_CALLCONV
FreeImage_GetFIFRegExpr(FREE_IMAGE_FORMAT fif)643 FreeImage_GetFIFRegExpr(FREE_IMAGE_FORMAT fif) {
644 	if (s_plugins != NULL) {
645 		PluginNode *node = s_plugins->FindNodeFromFIF(fif);
646 
647 		return (node != NULL) ? (node->m_regexpr != NULL) ? node->m_regexpr : (node->m_plugin->regexpr_proc != NULL) ? node->m_plugin->regexpr_proc() : NULL : NULL;
648 	}
649 
650 	return NULL;
651 }
652 
653 BOOL DLL_CALLCONV
FreeImage_FIFSupportsReading(FREE_IMAGE_FORMAT fif)654 FreeImage_FIFSupportsReading(FREE_IMAGE_FORMAT fif) {
655 	if (s_plugins != NULL) {
656 		PluginNode *node = s_plugins->FindNodeFromFIF(fif);
657 
658 		return (node != NULL) ? node->m_plugin->load_proc != NULL : FALSE;
659 	}
660 
661 	return FALSE;
662 }
663 
664 BOOL DLL_CALLCONV
FreeImage_FIFSupportsWriting(FREE_IMAGE_FORMAT fif)665 FreeImage_FIFSupportsWriting(FREE_IMAGE_FORMAT fif) {
666 	if (s_plugins != NULL) {
667 		PluginNode *node = s_plugins->FindNodeFromFIF(fif);
668 
669 		return (node != NULL) ? node->m_plugin->save_proc != NULL : FALSE ;
670 	}
671 
672 	return FALSE;
673 }
674 
675 BOOL DLL_CALLCONV
FreeImage_FIFSupportsExportBPP(FREE_IMAGE_FORMAT fif,int depth)676 FreeImage_FIFSupportsExportBPP(FREE_IMAGE_FORMAT fif, int depth) {
677 	if (s_plugins != NULL) {
678 		PluginNode *node = s_plugins->FindNodeFromFIF(fif);
679 
680 		return (node != NULL) ?
681 			(node->m_plugin->supports_export_bpp_proc != NULL) ?
682 				node->m_plugin->supports_export_bpp_proc(depth) : FALSE : FALSE;
683 	}
684 
685 	return FALSE;
686 }
687 
688 BOOL DLL_CALLCONV
FreeImage_FIFSupportsExportType(FREE_IMAGE_FORMAT fif,FREE_IMAGE_TYPE type)689 FreeImage_FIFSupportsExportType(FREE_IMAGE_FORMAT fif, FREE_IMAGE_TYPE type) {
690 	if (s_plugins != NULL) {
691 		PluginNode *node = s_plugins->FindNodeFromFIF(fif);
692 
693 		return (node != NULL) ?
694 			(node->m_plugin->supports_export_type_proc != NULL) ?
695 				node->m_plugin->supports_export_type_proc(type) : FALSE : FALSE;
696 	}
697 
698 	return FALSE;
699 }
700 
701 BOOL DLL_CALLCONV
FreeImage_FIFSupportsICCProfiles(FREE_IMAGE_FORMAT fif)702 FreeImage_FIFSupportsICCProfiles(FREE_IMAGE_FORMAT fif) {
703 	if (s_plugins != NULL) {
704 		PluginNode *node = s_plugins->FindNodeFromFIF(fif);
705 
706 		return (node != NULL) ?
707 			(node->m_plugin->supports_icc_profiles_proc != NULL) ?
708 				node->m_plugin->supports_icc_profiles_proc() : FALSE : FALSE;
709 	}
710 
711 	return FALSE;
712 }
713 
714 BOOL DLL_CALLCONV
FreeImage_FIFSupportsNoPixels(FREE_IMAGE_FORMAT fif)715 FreeImage_FIFSupportsNoPixels(FREE_IMAGE_FORMAT fif) {
716 	if (s_plugins != NULL) {
717 		PluginNode *node = s_plugins->FindNodeFromFIF(fif);
718 
719 		return (node != NULL) ?
720 			(node->m_plugin->supports_no_pixels_proc != NULL) ?
721 				node->m_plugin->supports_no_pixels_proc() : FALSE : FALSE;
722 	}
723 
724 	return FALSE;
725 }
726 
727 FREE_IMAGE_FORMAT DLL_CALLCONV
FreeImage_GetFIFFromFilename(const char * filename)728 FreeImage_GetFIFFromFilename(const char *filename) {
729 	if (filename != NULL) {
730 		const char *extension;
731 
732 		// get the proper extension if we received a filename
733 
734 		char *place = strrchr((char *)filename, '.');
735 		extension = (place != NULL) ? ++place : filename;
736 
737 		// look for the extension in the plugin table
738 
739 		for (int i = 0; i < FreeImage_GetFIFCount(); ++i) {
740 
741 			if (s_plugins->FindNodeFromFIF(i)->m_enabled) {
742 
743 				// compare the format id with the extension
744 
745 				if (FreeImage_stricmp(FreeImage_GetFormatFromFIF((FREE_IMAGE_FORMAT)i), extension) == 0) {
746 					return (FREE_IMAGE_FORMAT)i;
747 				} else {
748 					// make a copy of the extension list and split it
749 
750 					char *copy = (char *)malloc(strlen(FreeImage_GetFIFExtensionList((FREE_IMAGE_FORMAT)i)) + 1);
751 					memset(copy, 0, strlen(FreeImage_GetFIFExtensionList((FREE_IMAGE_FORMAT)i)) + 1);
752 					memcpy(copy, FreeImage_GetFIFExtensionList((FREE_IMAGE_FORMAT)i), strlen(FreeImage_GetFIFExtensionList((FREE_IMAGE_FORMAT)i)));
753 
754 					// get the first token
755 
756 					char *token = strtok(copy, ",");
757 
758 					while (token != NULL) {
759 						if (FreeImage_stricmp(token, extension) == 0) {
760 							free(copy);
761 
762 								return (FREE_IMAGE_FORMAT)i;
763 						}
764 
765 						token = strtok(NULL, ",");
766 					}
767 
768 					// free the copy of the extension list
769 
770 					free(copy);
771 				}
772 			}
773 		}
774 	}
775 
776 	return FIF_UNKNOWN;
777 }
778 
779 FREE_IMAGE_FORMAT DLL_CALLCONV
FreeImage_GetFIFFromFilenameU(const wchar_t * filename)780 FreeImage_GetFIFFromFilenameU(const wchar_t *filename) {
781 #ifdef _WIN32
782 	if (filename == NULL) return FIF_UNKNOWN;
783 
784 	// get the proper extension if we received a filename
785 	wchar_t *place = wcsrchr((wchar_t *)filename, '.');
786 	if (place == NULL) return FIF_UNKNOWN;
787 	// convert to single character - no national chars in extensions
788 	char *extension = (char *)malloc(wcslen(place)+1);
789 	unsigned int i=0;
790 	for(; i < wcslen(place); i++) // convert 16-bit to 8-bit
791 		extension[i] = (char)(place[i] & 0x00FF);
792 	// set terminating 0
793 	extension[i]=0;
794 	FREE_IMAGE_FORMAT fRet = FreeImage_GetFIFFromFilename(extension);
795 	free(extension);
796 
797 	return fRet;
798 #else
799 	return FIF_UNKNOWN;
800 #endif // _WIN32
801 }
802 
803 BOOL DLL_CALLCONV
FreeImage_ValidateFIF(FREE_IMAGE_FORMAT fif,FreeImageIO * io,fi_handle handle)804 FreeImage_ValidateFIF(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle) {
805 	if (s_plugins != NULL) {
806 		BOOL validated = FALSE;
807 
808 		PluginNode *node = s_plugins->FindNodeFromFIF(fif);
809 
810 		if (node) {
811 			long tell = io->tell_proc(handle);
812 
813 			validated = (node != NULL) ? (node->m_enabled) ? (node->m_plugin->validate_proc != NULL) ? node->m_plugin->validate_proc(io, handle) : FALSE : FALSE : FALSE;
814 
815 			io->seek_proc(handle, tell, SEEK_SET);
816 		}
817 
818 		return validated;
819 	}
820 
821 	return FALSE;
822 }
823