1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                  M   M   OOO   DDDD   U   U  L      EEEEE                   %
7%                  MM MM  O   O  D   D  U   U  L      E                       %
8%                  M M M  O   O  D   D  U   U  L      EEE                     %
9%                  M   M  O   O  D   D  U   U  L      E                       %
10%                  M   M   OOO   DDDD    UUU   LLLLL  EEEEE                   %
11%                                                                             %
12%                                                                             %
13%                          MagickCore Module Methods                          %
14%                                                                             %
15%                              Software Design                                %
16%                              Bob Friesenhahn                                %
17%                                March 2000                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.imagemagick.org/script/license.php                            %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41  Include declarations.
42*/
43#include "MagickCore/studio.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/coder.h"
46#include "MagickCore/client.h"
47#include "MagickCore/configure.h"
48#include "MagickCore/exception.h"
49#include "MagickCore/exception-private.h"
50#include "MagickCore/log.h"
51#include "MagickCore/linked-list.h"
52#include "MagickCore/magic.h"
53#include "MagickCore/magick.h"
54#include "MagickCore/memory_.h"
55#include "MagickCore/module.h"
56#include "MagickCore/module-private.h"
57#include "MagickCore/nt-base-private.h"
58#include "MagickCore/policy.h"
59#include "MagickCore/semaphore.h"
60#include "MagickCore/splay-tree.h"
61#include "MagickCore/static.h"
62#include "MagickCore/string_.h"
63#include "MagickCore/string-private.h"
64#include "MagickCore/token.h"
65#include "MagickCore/utility.h"
66#include "MagickCore/utility-private.h"
67#if defined(MAGICKCORE_MODULES_SUPPORT)
68#if defined(MAGICKCORE_LTDL_DELEGATE)
69#include "ltdl.h"
70typedef lt_dlhandle ModuleHandle;
71#else
72typedef void *ModuleHandle;
73#endif
74
75/*
76  Define declarations.
77*/
78#if defined(MAGICKCORE_LTDL_DELEGATE)
79#  define ModuleGlobExpression "*.la"
80#else
81#  if defined(_DEBUG)
82#    define ModuleGlobExpression "IM_MOD_DB_*.dll"
83#  else
84#    define ModuleGlobExpression "IM_MOD_RL_*.dll"
85#  endif
86#endif
87
88/*
89  Global declarations.
90*/
91static SemaphoreInfo
92  *module_semaphore = (SemaphoreInfo *) NULL;
93
94static SplayTreeInfo
95  *module_list = (SplayTreeInfo *) NULL;
96
97/*
98  Forward declarations.
99*/
100static const ModuleInfo
101  *RegisterModule(const ModuleInfo *,ExceptionInfo *);
102
103static MagickBooleanType
104  GetMagickModulePath(const char *,MagickModuleType,char *,ExceptionInfo *),
105  IsModuleTreeInstantiated(),
106  UnregisterModule(const ModuleInfo *,ExceptionInfo *);
107
108static void
109  TagToCoderModuleName(const char *,char *),
110  TagToFilterModuleName(const char *,char *),
111  TagToModuleName(const char *,const char *,char *);
112
113/*
114%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
115%                                                                             %
116%                                                                             %
117%                                                                             %
118%   A c q u i r e M o d u l e I n f o                                         %
119%                                                                             %
120%                                                                             %
121%                                                                             %
122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
123%
124%  AcquireModuleInfo() allocates the ModuleInfo structure.
125%
126%  The format of the AcquireModuleInfo method is:
127%
128%      ModuleInfo *AcquireModuleInfo(const char *path,const char *tag)
129%
130%  A description of each parameter follows:
131%
132%    o path: the path associated with the tag.
133%
134%    o tag: a character string that represents the image format we are
135%      looking for.
136%
137*/
138MagickExport ModuleInfo *AcquireModuleInfo(const char *path,const char *tag)
139{
140  ModuleInfo
141    *module_info;
142
143  module_info=(ModuleInfo *) AcquireMagickMemory(sizeof(*module_info));
144  if (module_info == (ModuleInfo *) NULL)
145    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
146  (void) ResetMagickMemory(module_info,0,sizeof(*module_info));
147  if (path != (const char *) NULL)
148    module_info->path=ConstantString(path);
149  if (tag != (const char *) NULL)
150    module_info->tag=ConstantString(tag);
151  module_info->timestamp=time(0);
152  module_info->signature=MagickCoreSignature;
153  return(module_info);
154}
155
156/*
157%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
158%                                                                             %
159%                                                                             %
160%                                                                             %
161%   D e s t r o y M o d u l e L i s t                                         %
162%                                                                             %
163%                                                                             %
164%                                                                             %
165%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
166%
167%  DestroyModuleList() unregisters any previously loaded modules and exits
168%  the module loaded environment.
169%
170%  The format of the DestroyModuleList module is:
171%
172%      void DestroyModuleList(void)
173%
174*/
175MagickExport void DestroyModuleList(void)
176{
177  /*
178    Destroy magick modules.
179  */
180  LockSemaphoreInfo(module_semaphore);
181#if defined(MAGICKCORE_MODULES_SUPPORT)
182  if (module_list != (SplayTreeInfo *) NULL)
183    module_list=DestroySplayTree(module_list);
184#endif
185  UnlockSemaphoreInfo(module_semaphore);
186}
187
188/*
189%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
190%                                                                             %
191%                                                                             %
192%                                                                             %
193%   G e t M o d u l e I n f o                                                 %
194%                                                                             %
195%                                                                             %
196%                                                                             %
197%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
198%
199%  GetModuleInfo() returns a pointer to a ModuleInfo structure that matches the
200%  specified tag.  If tag is NULL, the head of the module list is returned. If
201%  no modules are loaded, or the requested module is not found, NULL is
202%  returned.
203%
204%  The format of the GetModuleInfo module is:
205%
206%      ModuleInfo *GetModuleInfo(const char *tag,ExceptionInfo *exception)
207%
208%  A description of each parameter follows:
209%
210%    o tag: a character string that represents the image format we are
211%      looking for.
212%
213%    o exception: return any errors or warnings in this structure.
214%
215*/
216MagickExport ModuleInfo *GetModuleInfo(const char *tag,ExceptionInfo *exception)
217{
218  ModuleInfo
219    *module_info;
220
221  if (IsModuleTreeInstantiated() == MagickFalse)
222    return((ModuleInfo *) NULL);
223  LockSemaphoreInfo(module_semaphore);
224  ResetSplayTreeIterator(module_list);
225  if ((tag == (const char *) NULL) || (LocaleCompare(tag,"*") == 0))
226    {
227#if defined(MAGICKCORE_MODULES_SUPPORT)
228      if (LocaleCompare(tag,"*") == 0)
229        (void) OpenModules(exception);
230#endif
231      module_info=(ModuleInfo *) GetNextValueInSplayTree(module_list);
232      UnlockSemaphoreInfo(module_semaphore);
233      return(module_info);
234    }
235  module_info=(ModuleInfo *) GetValueFromSplayTree(module_list,tag);
236  UnlockSemaphoreInfo(module_semaphore);
237  return(module_info);
238}
239
240/*
241%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242%                                                                             %
243%                                                                             %
244%                                                                             %
245%   G e t M o d u l e I n f o L i s t                                         %
246%                                                                             %
247%                                                                             %
248%                                                                             %
249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250%
251%  GetModuleInfoList() returns any modules that match the specified pattern.
252%
253%  The format of the GetModuleInfoList function is:
254%
255%      const ModuleInfo **GetModuleInfoList(const char *pattern,
256%        size_t *number_modules,ExceptionInfo *exception)
257%
258%  A description of each parameter follows:
259%
260%    o pattern: Specifies a pointer to a text string containing a pattern.
261%
262%    o number_modules:  This integer returns the number of modules in the list.
263%
264%    o exception: return any errors or warnings in this structure.
265%
266*/
267
268#if defined(__cplusplus) || defined(c_plusplus)
269extern "C" {
270#endif
271
272static int ModuleInfoCompare(const void *x,const void *y)
273{
274  const ModuleInfo
275    **p,
276    **q;
277
278  p=(const ModuleInfo **) x,
279  q=(const ModuleInfo **) y;
280  if (LocaleCompare((*p)->path,(*q)->path) == 0)
281    return(LocaleCompare((*p)->tag,(*q)->tag));
282  return(LocaleCompare((*p)->path,(*q)->path));
283}
284
285#if defined(__cplusplus) || defined(c_plusplus)
286}
287#endif
288
289MagickExport const ModuleInfo **GetModuleInfoList(const char *pattern,
290  size_t *number_modules,ExceptionInfo *exception)
291{
292  const ModuleInfo
293    **modules;
294
295  register const ModuleInfo
296    *p;
297
298  register ssize_t
299    i;
300
301  /*
302    Allocate module list.
303  */
304  assert(pattern != (char *) NULL);
305  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
306  assert(number_modules != (size_t *) NULL);
307  *number_modules=0;
308  p=GetModuleInfo("*",exception);
309  if (p == (const ModuleInfo *) NULL)
310    return((const ModuleInfo **) NULL);
311  modules=(const ModuleInfo **) AcquireQuantumMemory((size_t)
312    GetNumberOfNodesInSplayTree(module_list)+1UL,sizeof(*modules));
313  if (modules == (const ModuleInfo **) NULL)
314    return((const ModuleInfo **) NULL);
315  /*
316    Generate module list.
317  */
318  LockSemaphoreInfo(module_semaphore);
319  ResetSplayTreeIterator(module_list);
320  p=(const ModuleInfo *) GetNextValueInSplayTree(module_list);
321  for (i=0; p != (const ModuleInfo *) NULL; )
322  {
323    if ((p->stealth == MagickFalse) &&
324        (GlobExpression(p->tag,pattern,MagickFalse) != MagickFalse))
325      modules[i++]=p;
326    p=(const ModuleInfo *) GetNextValueInSplayTree(module_list);
327  }
328  UnlockSemaphoreInfo(module_semaphore);
329  qsort((void *) modules,(size_t) i,sizeof(*modules),ModuleInfoCompare);
330  modules[i]=(ModuleInfo *) NULL;
331  *number_modules=(size_t) i;
332  return(modules);
333}
334
335/*
336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
337%                                                                             %
338%                                                                             %
339%                                                                             %
340%   G e t M o d u l e L i s t                                                 %
341%                                                                             %
342%                                                                             %
343%                                                                             %
344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
345%
346%  GetModuleList() returns any image format modules that match the specified
347%  pattern.
348%
349%  The format of the GetModuleList function is:
350%
351%      char **GetModuleList(const char *pattern,const MagickModuleType type,
352%        size_t *number_modules,ExceptionInfo *exception)
353%
354%  A description of each parameter follows:
355%
356%    o pattern: Specifies a pointer to a text string containing a pattern.
357%
358%    o type: choose from MagickImageCoderModule or MagickImageFilterModule.
359%
360%    o number_modules:  This integer returns the number of modules in the
361%      list.
362%
363%    o exception: return any errors or warnings in this structure.
364%
365*/
366
367#if defined(__cplusplus) || defined(c_plusplus)
368extern "C" {
369#endif
370
371static int ModuleCompare(const void *x,const void *y)
372{
373  register const char
374    **p,
375    **q;
376
377   p=(const char **) x;
378  q=(const char **) y;
379  return(LocaleCompare(*p,*q));
380}
381
382#if defined(__cplusplus) || defined(c_plusplus)
383}
384#endif
385
386static inline int MagickReadDirectory(DIR *directory,struct dirent *entry,
387  struct dirent **result)
388{
389#if defined(MAGICKCORE_HAVE_READDIR_R)
390  return(readdir_r(directory,entry,result));
391#else
392  (void) entry;
393  errno=0;
394  *result=readdir(directory);
395  return(errno);
396#endif
397}
398
399MagickExport char **GetModuleList(const char *pattern,
400  const MagickModuleType type,size_t *number_modules,ExceptionInfo *exception)
401{
402#define MaxModules  511
403
404  char
405    **modules,
406    filename[MagickPathExtent],
407    module_path[MagickPathExtent],
408    path[MagickPathExtent];
409
410  DIR
411    *directory;
412
413  MagickBooleanType
414    status;
415
416  register ssize_t
417    i;
418
419  size_t
420    max_entries;
421
422  struct dirent
423    *buffer,
424    *entry;
425
426  /*
427    Locate all modules in the image coder or filter path.
428  */
429  switch (type)
430  {
431    case MagickImageCoderModule:
432    default:
433    {
434      TagToCoderModuleName("magick",filename);
435      status=GetMagickModulePath(filename,MagickImageCoderModule,module_path,
436        exception);
437      break;
438    }
439    case MagickImageFilterModule:
440    {
441      TagToFilterModuleName("analyze",filename);
442      status=GetMagickModulePath(filename,MagickImageFilterModule,module_path,
443        exception);
444      break;
445    }
446  }
447  if (status == MagickFalse)
448    return((char **) NULL);
449  GetPathComponent(module_path,HeadPath,path);
450  max_entries=MaxModules;
451  modules=(char **) AcquireQuantumMemory((size_t) max_entries+1UL,
452    sizeof(*modules));
453  if (modules == (char **) NULL)
454    return((char **) NULL);
455  *modules=(char *) NULL;
456  directory=opendir(path);
457  if (directory == (DIR *) NULL)
458    {
459      modules=(char **) RelinquishMagickMemory(modules);
460      return((char **) NULL);
461    }
462  buffer=(struct dirent *) AcquireMagickMemory(sizeof(*buffer)+FILENAME_MAX+1);
463  if (buffer == (struct dirent *) NULL)
464    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
465  i=0;
466  while ((MagickReadDirectory(directory,buffer,&entry) == 0) &&
467         (entry != (struct dirent *) NULL))
468  {
469    status=GlobExpression(entry->d_name,ModuleGlobExpression,MagickFalse);
470    if (status == MagickFalse)
471      continue;
472    if (GlobExpression(entry->d_name,pattern,MagickFalse) == MagickFalse)
473      continue;
474    if (i >= (ssize_t) max_entries)
475      {
476        modules=(char **) NULL;
477        if (~max_entries > max_entries)
478          modules=(char **) ResizeQuantumMemory(modules,(size_t)
479            (max_entries << 1),sizeof(*modules));
480        max_entries<<=1;
481        if (modules == (char **) NULL)
482          break;
483      }
484    /*
485      Add new module name to list.
486    */
487    modules[i]=AcquireString((char *) NULL);
488    GetPathComponent(entry->d_name,BasePath,modules[i]);
489    if (LocaleNCompare("IM_MOD_",modules[i],7) == 0)
490      {
491        (void) CopyMagickString(modules[i],modules[i]+10,MagickPathExtent);
492        modules[i][strlen(modules[i])-1]='\0';
493      }
494    i++;
495  }
496  buffer=(struct dirent *) RelinquishMagickMemory(buffer);
497  (void) closedir(directory);
498  if (modules == (char **) NULL)
499    {
500      (void) ThrowMagickException(exception,GetMagickModule(),ConfigureError,
501        "MemoryAllocationFailed","`%s'",pattern);
502      return((char **) NULL);
503    }
504  qsort((void *) modules,(size_t) i,sizeof(*modules),ModuleCompare);
505  modules[i]=(char *) NULL;
506  *number_modules=(size_t) i;
507  return(modules);
508}
509
510/*
511%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
512%                                                                             %
513%                                                                             %
514%                                                                             %
515%  G e t M a g i c k M o d u l e P a t h                                      %
516%                                                                             %
517%                                                                             %
518%                                                                             %
519%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
520%
521%  GetMagickModulePath() finds a module with the specified module type and
522%  filename.
523%
524%  The format of the GetMagickModulePath module is:
525%
526%      MagickBooleanType GetMagickModulePath(const char *filename,
527%        MagickModuleType module_type,char *path,ExceptionInfo *exception)
528%
529%  A description of each parameter follows:
530%
531%    o filename: the module file name.
532%
533%    o module_type: the module type: MagickImageCoderModule or
534%      MagickImageFilterModule.
535%
536%    o path: the path associated with the filename.
537%
538%    o exception: return any errors or warnings in this structure.
539%
540*/
541static MagickBooleanType GetMagickModulePath(const char *filename,
542  MagickModuleType module_type,char *path,ExceptionInfo *exception)
543{
544  char
545    *module_path;
546
547  assert(filename != (const char *) NULL);
548  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
549  assert(path != (char *) NULL);
550  assert(exception != (ExceptionInfo *) NULL);
551  if (strchr(filename,'/') != (char *) NULL)
552    return(MagickFalse);
553  (void) CopyMagickString(path,filename,MagickPathExtent);
554  module_path=(char *) NULL;
555  switch (module_type)
556  {
557    case MagickImageCoderModule:
558    default:
559    {
560      (void) LogMagickEvent(ModuleEvent,GetMagickModule(),
561        "Searching for coder module file \"%s\" ...",filename);
562      module_path=GetEnvironmentValue("MAGICK_CODER_MODULE_PATH");
563#if defined(MAGICKCORE_CODER_PATH)
564      if (module_path == (char *) NULL)
565        module_path=AcquireString(MAGICKCORE_CODER_PATH);
566#endif
567      break;
568    }
569    case MagickImageFilterModule:
570    {
571      (void) LogMagickEvent(ModuleEvent,GetMagickModule(),
572        "Searching for filter module file \"%s\" ...",filename);
573      module_path=GetEnvironmentValue("MAGICK_CODER_FILTER_PATH");
574#if defined(MAGICKCORE_FILTER_PATH)
575      if (module_path == (char *) NULL)
576        module_path=AcquireString(MAGICKCORE_FILTER_PATH);
577#endif
578      break;
579    }
580  }
581  if (module_path != (char *) NULL)
582    {
583      register char
584        *p,
585        *q;
586
587      for (p=module_path-1; p != (char *) NULL; )
588      {
589        (void) CopyMagickString(path,p+1,MagickPathExtent);
590        q=strchr(path,DirectoryListSeparator);
591        if (q != (char *) NULL)
592          *q='\0';
593        q=path+strlen(path)-1;
594        if ((q >= path) && (*q != *DirectorySeparator))
595          (void) ConcatenateMagickString(path,DirectorySeparator,
596            MagickPathExtent);
597        (void) ConcatenateMagickString(path,filename,MagickPathExtent);
598        if (IsPathAccessible(path) != MagickFalse)
599          {
600            module_path=DestroyString(module_path);
601            return(MagickTrue);
602          }
603        p=strchr(p+1,DirectoryListSeparator);
604      }
605      module_path=DestroyString(module_path);
606    }
607#if defined(MAGICKCORE_INSTALLED_SUPPORT)
608  else
609#if defined(MAGICKCORE_CODER_PATH)
610    {
611      const char
612        *directory;
613
614      /*
615        Search hard coded paths.
616      */
617      switch (module_type)
618      {
619        case MagickImageCoderModule:
620        default:
621        {
622          directory=MAGICKCORE_CODER_PATH;
623          break;
624        }
625        case MagickImageFilterModule:
626        {
627          directory=MAGICKCORE_FILTER_PATH;
628          break;
629        }
630      }
631      (void) FormatLocaleString(path,MagickPathExtent,"%s%s",directory,
632        filename);
633      if (IsPathAccessible(path) == MagickFalse)
634        {
635          ThrowFileException(exception,ConfigureWarning,
636            "UnableToOpenModuleFile",path);
637          return(MagickFalse);
638        }
639      return(MagickTrue);
640    }
641#else
642#if defined(MAGICKCORE_WINDOWS_SUPPORT)
643    {
644      const char
645        *registery_key;
646
647      unsigned char
648        *key_value;
649
650      /*
651        Locate path via registry key.
652      */
653      switch (module_type)
654      {
655        case MagickImageCoderModule:
656        default:
657        {
658          registery_key="CoderModulesPath";
659          break;
660        }
661        case MagickImageFilterModule:
662        {
663          registery_key="FilterModulesPath";
664          break;
665        }
666      }
667      key_value=NTRegistryKeyLookup(registery_key);
668      if (key_value == (unsigned char *) NULL)
669        {
670          ThrowMagickException(exception,GetMagickModule(),ConfigureError,
671            "RegistryKeyLookupFailed","`%s'",registery_key);
672          return(MagickFalse);
673        }
674      (void) FormatLocaleString(path,MagickPathExtent,"%s%s%s",(char *)
675        key_value,DirectorySeparator,filename);
676      key_value=(unsigned char *) RelinquishMagickMemory(key_value);
677      if (IsPathAccessible(path) == MagickFalse)
678        {
679          ThrowFileException(exception,ConfigureWarning,
680            "UnableToOpenModuleFile",path);
681          return(MagickFalse);
682        }
683      return(MagickTrue);
684    }
685#endif
686#endif
687#if !defined(MAGICKCORE_CODER_PATH) && !defined(MAGICKCORE_WINDOWS_SUPPORT)
688# error MAGICKCORE_CODER_PATH or MAGICKCORE_WINDOWS_SUPPORT must be defined when MAGICKCORE_INSTALLED_SUPPORT is defined
689#endif
690#else
691  {
692    char
693      *home;
694
695    home=GetEnvironmentValue("MAGICK_HOME");
696    if (home != (char *) NULL)
697      {
698        /*
699          Search MAGICK_HOME.
700        */
701#if !defined(MAGICKCORE_POSIX_SUPPORT)
702        (void) FormatLocaleString(path,MagickPathExtent,"%s%s%s",home,
703          DirectorySeparator,filename);
704#else
705        const char
706          *directory;
707
708        switch (module_type)
709        {
710          case MagickImageCoderModule:
711          default:
712          {
713            directory=MAGICKCORE_CODER_RELATIVE_PATH;
714            break;
715          }
716          case MagickImageFilterModule:
717          {
718            directory=MAGICKCORE_FILTER_RELATIVE_PATH;
719            break;
720          }
721        }
722        (void) FormatLocaleString(path,MagickPathExtent,"%s/lib/%s/%s",home,
723          directory,filename);
724#endif
725        home=DestroyString(home);
726        if (IsPathAccessible(path) != MagickFalse)
727          return(MagickTrue);
728      }
729  }
730  if (*GetClientPath() != '\0')
731    {
732      /*
733        Search based on executable directory.
734      */
735#if !defined(MAGICKCORE_POSIX_SUPPORT)
736      (void) FormatLocaleString(path,MagickPathExtent,"%s%s%s",GetClientPath(),
737        DirectorySeparator,filename);
738#else
739      char
740        prefix[MagickPathExtent];
741
742      const char
743        *directory;
744
745      switch (module_type)
746      {
747        case MagickImageCoderModule:
748        default:
749        {
750          directory="coders";
751          break;
752        }
753        case MagickImageFilterModule:
754        {
755          directory="filters";
756          break;
757        }
758      }
759      (void) CopyMagickString(prefix,GetClientPath(),MagickPathExtent);
760      ChopPathComponents(prefix,1);
761      (void) FormatLocaleString(path,MagickPathExtent,"%s/lib/%s/%s/%s",prefix,
762        MAGICKCORE_MODULES_RELATIVE_PATH,directory,filename);
763#endif
764      if (IsPathAccessible(path) != MagickFalse)
765        return(MagickTrue);
766    }
767#if defined(MAGICKCORE_WINDOWS_SUPPORT)
768  {
769    /*
770      Search module path.
771    */
772    if ((NTGetModulePath("CORE_RL_MagickCore_.dll",path) != MagickFalse) ||
773        (NTGetModulePath("CORE_DB_MagickCore_.dll",path) != MagickFalse))
774      {
775        (void) ConcatenateMagickString(path,DirectorySeparator,
776          MagickPathExtent);
777        (void) ConcatenateMagickString(path,filename,MagickPathExtent);
778        if (IsPathAccessible(path) != MagickFalse)
779          return(MagickTrue);
780      }
781  }
782#endif
783  {
784    char
785      *home;
786
787    home=GetEnvironmentValue("XDG_CONFIG_HOME");
788    if (home == (char *) NULL)
789      home=GetEnvironmentValue("LOCALAPPDATA");
790    if (home == (char *) NULL)
791      home=GetEnvironmentValue("APPDATA");
792    if (home == (char *) NULL)
793      home=GetEnvironmentValue("USERPROFILE");
794    if (home != (char *) NULL)
795      {
796        /*
797          Search $XDG_CONFIG_HOME/ImageMagick.
798        */
799        (void) FormatLocaleString(path,MagickPathExtent,"%s%sImageMagick%s%s",
800          home,DirectorySeparator,DirectorySeparator,filename);
801        home=DestroyString(home);
802        if (IsPathAccessible(path) != MagickFalse)
803          return(MagickTrue);
804      }
805    home=GetEnvironmentValue("HOME");
806    if (home != (char *) NULL)
807      {
808        /*
809          Search $HOME/.config/ImageMagick.
810        */
811        (void) FormatLocaleString(path,MagickPathExtent,
812          "%s%s.config%sImageMagick%s%s",home,DirectorySeparator,
813          DirectorySeparator,DirectorySeparator,filename);
814        home=DestroyString(home);
815        if (IsPathAccessible(path) != MagickFalse)
816          return(MagickTrue);
817      }
818  }
819  /*
820    Search current directory.
821  */
822  if (IsPathAccessible(path) != MagickFalse)
823    return(MagickTrue);
824  if (exception->severity < ConfigureError)
825    ThrowFileException(exception,ConfigureWarning,"UnableToOpenModuleFile",
826      path);
827#endif
828  return(MagickFalse);
829}
830
831/*
832%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
833%                                                                             %
834%                                                                             %
835%                                                                             %
836%   I s M o d u l e T r e e I n s t a n t i a t e d                           %
837%                                                                             %
838%                                                                             %
839%                                                                             %
840%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
841%
842%  IsModuleTreeInstantiated() determines if the module tree is instantiated.
843%  If not, it instantiates the tree and returns it.
844%
845%  The format of the IsModuleTreeInstantiated() method is:
846%
847%      IsModuleTreeInstantiated()
848%
849*/
850
851static void *DestroyModuleNode(void *module_info)
852{
853  ExceptionInfo
854    *exception;
855
856  register ModuleInfo
857    *p;
858
859  exception=AcquireExceptionInfo();
860  p=(ModuleInfo *) module_info;
861  if (UnregisterModule(p,exception) == MagickFalse)
862    CatchException(exception);
863  if (p->tag != (char *) NULL)
864    p->tag=DestroyString(p->tag);
865  if (p->path != (char *) NULL)
866    p->path=DestroyString(p->path);
867  exception=DestroyExceptionInfo(exception);
868  return(RelinquishMagickMemory(p));
869}
870
871static MagickBooleanType IsModuleTreeInstantiated()
872{
873  if (module_list == (SplayTreeInfo *) NULL)
874    {
875      if (module_semaphore == (SemaphoreInfo *) NULL)
876        ActivateSemaphoreInfo(&module_semaphore);
877      LockSemaphoreInfo(module_semaphore);
878      if (module_list == (SplayTreeInfo *) NULL)
879        {
880          MagickBooleanType
881            status;
882
883          ModuleInfo
884            *module_info;
885
886          module_list=NewSplayTree(CompareSplayTreeString,
887            (void *(*)(void *)) NULL,DestroyModuleNode);
888          if (module_list == (SplayTreeInfo *) NULL)
889            ThrowFatalException(ResourceLimitFatalError,
890              "MemoryAllocationFailed");
891          module_info=AcquireModuleInfo((const char *) NULL,"[boot-strap]");
892          module_info->stealth=MagickTrue;
893          status=AddValueToSplayTree(module_list,module_info->tag,module_info);
894          if (status == MagickFalse)
895            ThrowFatalException(ResourceLimitFatalError,
896              "MemoryAllocationFailed");
897          if (lt_dlinit() != 0)
898            ThrowFatalException(ModuleFatalError,
899              "UnableToInitializeModuleLoader");
900        }
901      UnlockSemaphoreInfo(module_semaphore);
902    }
903  return(module_list != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
904}
905
906/*
907%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
908%                                                                             %
909%                                                                             %
910%                                                                             %
911%   I n v o k e D y n a m i c I m a g e F i l t e r                           %
912%                                                                             %
913%                                                                             %
914%                                                                             %
915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
916%
917%  InvokeDynamicImageFilter() invokes a dynamic image filter.
918%
919%  The format of the InvokeDynamicImageFilter module is:
920%
921%      MagickBooleanType InvokeDynamicImageFilter(const char *tag,Image **image,
922%        const int argc,const char **argv,ExceptionInfo *exception)
923%
924%  A description of each parameter follows:
925%
926%    o tag: a character string that represents the name of the particular
927%      module.
928%
929%    o image: the image.
930%
931%    o argc: a pointer to an integer describing the number of elements in the
932%      argument vector.
933%
934%    o argv: a pointer to a text array containing the command line arguments.
935%
936%    o exception: return any errors or warnings in this structure.
937%
938*/
939MagickExport MagickBooleanType InvokeDynamicImageFilter(const char *tag,
940  Image **images,const int argc,const char **argv,ExceptionInfo *exception)
941{
942  char
943    name[MagickPathExtent],
944    path[MagickPathExtent];
945
946  ImageFilterHandler
947    *image_filter;
948
949  MagickBooleanType
950    status;
951
952  ModuleHandle
953    handle;
954
955  PolicyRights
956    rights;
957
958  /*
959    Find the module.
960  */
961  assert(images != (Image **) NULL);
962  assert((*images)->signature == MagickCoreSignature);
963  if ((*images)->debug != MagickFalse)
964    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
965      (*images)->filename);
966#if !defined(MAGICKCORE_BUILD_MODULES)
967  {
968    MagickBooleanType
969      status;
970
971    status=InvokeStaticImageFilter(tag,images,argc,argv,exception);
972    if (status != MagickFalse)
973      return(status);
974  }
975#endif
976  rights=ReadPolicyRights;
977  if (IsRightsAuthorized(FilterPolicyDomain,rights,tag) == MagickFalse)
978    {
979      errno=EPERM;
980      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
981        "NotAuthorized","`%s'",tag);
982      return(MagickFalse);
983    }
984  TagToFilterModuleName(tag,name);
985  status=GetMagickModulePath(name,MagickImageFilterModule,path,exception);
986  if (status == MagickFalse)
987    {
988      (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
989        "UnableToLoadModule","'%s': %s",name,path);
990      return(MagickFalse);
991    }
992  /*
993    Open the module.
994  */
995  handle=(ModuleHandle) lt_dlopen(path);
996  if (handle == (ModuleHandle) NULL)
997    {
998      (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
999        "UnableToLoadModule","'%s': %s",name,lt_dlerror());
1000      return(MagickFalse);
1001    }
1002  /*
1003    Locate the module.
1004  */
1005#if !defined(MAGICKCORE_NAMESPACE_PREFIX)
1006  (void) FormatLocaleString(name,MagickPathExtent,"%sImage",tag);
1007#else
1008  (void) FormatLocaleString(name,MagickPathExtent,"%s%sImage",
1009    MAGICKCORE_NAMESPACE_PREFIX,tag);
1010#endif
1011  /*
1012    Execute the module.
1013  */
1014  ClearMagickException(exception);
1015  image_filter=(ImageFilterHandler *) lt_dlsym(handle,name);
1016  if (image_filter == (ImageFilterHandler *) NULL)
1017    (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
1018      "UnableToLoadModule","'%s': %s",name,lt_dlerror());
1019  else
1020    {
1021      size_t
1022        signature;
1023
1024      if ((*images)->debug != MagickFalse)
1025        (void) LogMagickEvent(ModuleEvent,GetMagickModule(),
1026          "Invoking \"%s\" dynamic image filter",tag);
1027      signature=image_filter(images,argc,argv,exception);
1028      if ((*images)->debug != MagickFalse)
1029        (void) LogMagickEvent(ModuleEvent,GetMagickModule(),"\"%s\" completes",
1030          tag);
1031      if (signature != MagickImageFilterSignature)
1032        (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
1033          "ImageFilterSignatureMismatch","'%s': %8lx != %8lx",tag,
1034          (unsigned long) signature,(unsigned long) MagickImageFilterSignature);
1035    }
1036  /*
1037    Close the module.
1038  */
1039  if (lt_dlclose(handle) != 0)
1040    (void) ThrowMagickException(exception,GetMagickModule(),ModuleWarning,
1041      "UnableToCloseModule","'%s': %s",name,lt_dlerror());
1042  return(exception->severity < ErrorException ? MagickTrue : MagickFalse);
1043}
1044
1045/*
1046%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1047%                                                                             %
1048%                                                                             %
1049%                                                                             %
1050%  L i s t M o d u l e I n f o                                                %
1051%                                                                             %
1052%                                                                             %
1053%                                                                             %
1054%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1055%
1056%  ListModuleInfo() lists the module info to a file.
1057%
1058%  The format of the ListModuleInfo module is:
1059%
1060%      MagickBooleanType ListModuleInfo(FILE *file,ExceptionInfo *exception)
1061%
1062%  A description of each parameter follows.
1063%
1064%    o file:  An pointer to a FILE.
1065%
1066%    o exception: return any errors or warnings in this structure.
1067%
1068*/
1069MagickExport MagickBooleanType ListModuleInfo(FILE *file,
1070  ExceptionInfo *exception)
1071{
1072  char
1073    filename[MagickPathExtent],
1074    module_path[MagickPathExtent],
1075    **modules,
1076    path[MagickPathExtent];
1077
1078  register ssize_t
1079    i;
1080
1081  size_t
1082    number_modules;
1083
1084  if (file == (const FILE *) NULL)
1085    file=stdout;
1086  /*
1087    List image coders.
1088  */
1089  modules=GetModuleList("*",MagickImageCoderModule,&number_modules,exception);
1090  if (modules == (char **) NULL)
1091    return(MagickFalse);
1092  TagToCoderModuleName("magick",filename);
1093  (void) GetMagickModulePath(filename,MagickImageCoderModule,module_path,
1094    exception);
1095  GetPathComponent(module_path,HeadPath,path);
1096  (void) FormatLocaleFile(file,"\nPath: %s\n\n",path);
1097  (void) FormatLocaleFile(file,"Image Coder\n");
1098  (void) FormatLocaleFile(file,
1099    "-------------------------------------------------"
1100    "------------------------------\n");
1101  for (i=0; i < (ssize_t) number_modules; i++)
1102  {
1103    (void) FormatLocaleFile(file,"%s",modules[i]);
1104    (void) FormatLocaleFile(file,"\n");
1105  }
1106  (void) fflush(file);
1107  /*
1108    Relinquish resources.
1109  */
1110  for (i=0; i < (ssize_t) number_modules; i++)
1111    modules[i]=DestroyString(modules[i]);
1112  modules=(char **) RelinquishMagickMemory(modules);
1113  /*
1114    List image filters.
1115  */
1116  modules=GetModuleList("*",MagickImageFilterModule,&number_modules,exception);
1117  if (modules == (char **) NULL)
1118    return(MagickFalse);
1119  TagToFilterModuleName("analyze",filename);
1120  (void) GetMagickModulePath(filename,MagickImageFilterModule,module_path,
1121    exception);
1122  GetPathComponent(module_path,HeadPath,path);
1123  (void) FormatLocaleFile(file,"\nPath: %s\n\n",path);
1124  (void) FormatLocaleFile(file,"Image Filter\n");
1125  (void) FormatLocaleFile(file,
1126    "-------------------------------------------------"
1127    "------------------------------\n");
1128  for (i=0; i < (ssize_t) number_modules; i++)
1129  {
1130    (void) FormatLocaleFile(file,"%s",modules[i]);
1131    (void) FormatLocaleFile(file,"\n");
1132  }
1133  (void) fflush(file);
1134  /*
1135    Relinquish resources.
1136  */
1137  for (i=0; i < (ssize_t) number_modules; i++)
1138    modules[i]=DestroyString(modules[i]);
1139  modules=(char **) RelinquishMagickMemory(modules);
1140  return(MagickTrue);
1141}
1142
1143/*
1144%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1145%                                                                             %
1146%                                                                             %
1147%                                                                             %
1148+   M o d u l e C o m p o n e n t G e n e s i s                               %
1149%                                                                             %
1150%                                                                             %
1151%                                                                             %
1152%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1153%
1154%  ModuleComponentGenesis() instantiates the module component.
1155%
1156%  The format of the ModuleComponentGenesis method is:
1157%
1158%      MagickBooleanType ModuleComponentGenesis(void)
1159%
1160*/
1161MagickPrivate MagickBooleanType ModuleComponentGenesis(void)
1162{
1163  MagickBooleanType
1164    status;
1165
1166  if (module_semaphore == (SemaphoreInfo *) NULL)
1167    module_semaphore=AcquireSemaphoreInfo();
1168  status=IsModuleTreeInstantiated();
1169  return(status);
1170}
1171
1172/*
1173%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1174%                                                                             %
1175%                                                                             %
1176%                                                                             %
1177+   M o d u l e C o m p o n e n t T e r m i n u s                             %
1178%                                                                             %
1179%                                                                             %
1180%                                                                             %
1181%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1182%
1183%  ModuleComponentTerminus() destroys the module component.
1184%
1185%  The format of the ModuleComponentTerminus method is:
1186%
1187%      ModuleComponentTerminus(void)
1188%
1189*/
1190MagickPrivate void ModuleComponentTerminus(void)
1191{
1192  if (module_semaphore == (SemaphoreInfo *) NULL)
1193    ActivateSemaphoreInfo(&module_semaphore);
1194  DestroyModuleList();
1195  RelinquishSemaphoreInfo(&module_semaphore);
1196}
1197
1198/*
1199%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1200%                                                                             %
1201%                                                                             %
1202%                                                                             %
1203%   O p e n M o d u l e                                                       %
1204%                                                                             %
1205%                                                                             %
1206%                                                                             %
1207%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1208%
1209%  OpenModule() loads a module, and invokes its registration module.  It
1210%  returns MagickTrue on success, and MagickFalse if there is an error.
1211%
1212%  The format of the OpenModule module is:
1213%
1214%      MagickBooleanType OpenModule(const char *module,ExceptionInfo *exception)
1215%
1216%  A description of each parameter follows:
1217%
1218%    o module: a character string that indicates the module to load.
1219%
1220%    o exception: return any errors or warnings in this structure.
1221%
1222*/
1223MagickPrivate MagickBooleanType OpenModule(const char *module,
1224  ExceptionInfo *exception)
1225{
1226  char
1227    filename[MagickPathExtent],
1228    module_name[MagickPathExtent],
1229    name[MagickPathExtent],
1230    path[MagickPathExtent];
1231
1232  MagickBooleanType
1233    status;
1234
1235  ModuleHandle
1236    handle;
1237
1238  ModuleInfo
1239    *module_info;
1240
1241  register const CoderInfo
1242    *p;
1243
1244  size_t
1245    signature;
1246
1247  /*
1248    Assign module name from alias.
1249  */
1250  assert(module != (const char *) NULL);
1251  module_info=(ModuleInfo *) GetModuleInfo(module,exception);
1252  if (module_info != (ModuleInfo *) NULL)
1253    return(MagickTrue);
1254  (void) CopyMagickString(module_name,module,MagickPathExtent);
1255  p=GetCoderInfo(module,exception);
1256  if (p != (CoderInfo *) NULL)
1257    (void) CopyMagickString(module_name,p->name,MagickPathExtent);
1258  if (GetValueFromSplayTree(module_list,module_name) != (void *) NULL)
1259    return(MagickTrue);  /* module already opened, return */
1260  /*
1261    Locate module.
1262  */
1263  handle=(ModuleHandle) NULL;
1264  TagToCoderModuleName(module_name,filename);
1265  (void) LogMagickEvent(ModuleEvent,GetMagickModule(),
1266    "Searching for module \"%s\" using filename \"%s\"",module_name,filename);
1267  *path='\0';
1268  status=GetMagickModulePath(filename,MagickImageCoderModule,path,exception);
1269  if (status == MagickFalse)
1270    return(MagickFalse);
1271  /*
1272    Load module
1273  */
1274  (void) LogMagickEvent(ModuleEvent,GetMagickModule(),
1275    "Opening module at path \"%s\"",path);
1276  handle=(ModuleHandle) lt_dlopen(path);
1277  if (handle == (ModuleHandle) NULL)
1278    {
1279      (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
1280        "UnableToLoadModule","'%s': %s",path,lt_dlerror());
1281      return(MagickFalse);
1282    }
1283  /*
1284    Register module.
1285  */
1286  module_info=AcquireModuleInfo(path,module_name);
1287  module_info->handle=handle;
1288  if (RegisterModule(module_info,exception) == (ModuleInfo *) NULL)
1289    return(MagickFalse);
1290  /*
1291    Define RegisterFORMATImage method.
1292  */
1293  TagToModuleName(module_name,"Register%sImage",name);
1294  module_info->register_module=(size_t (*)(void)) lt_dlsym(handle,name);
1295  if (module_info->register_module == (size_t (*)(void)) NULL)
1296    {
1297      (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
1298        "UnableToRegisterImageFormat","'%s': %s",module_name,lt_dlerror());
1299      return(MagickFalse);
1300    }
1301  (void) LogMagickEvent(ModuleEvent,GetMagickModule(),
1302    "Method \"%s\" in module \"%s\" at address %p",name,module_name,
1303    (void *) module_info->register_module);
1304  /*
1305    Define UnregisterFORMATImage method.
1306  */
1307  TagToModuleName(module_name,"Unregister%sImage",name);
1308  module_info->unregister_module=(void (*)(void)) lt_dlsym(handle,name);
1309  if (module_info->unregister_module == (void (*)(void)) NULL)
1310    {
1311      (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
1312        "UnableToRegisterImageFormat","'%s': %s",module_name,lt_dlerror());
1313      return(MagickFalse);
1314    }
1315  (void) LogMagickEvent(ModuleEvent,GetMagickModule(),
1316    "Method \"%s\" in module \"%s\" at address %p",name,module_name,
1317    (void *) module_info->unregister_module);
1318  signature=module_info->register_module();
1319  if (signature != MagickImageCoderSignature)
1320    {
1321      (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
1322        "ImageCoderSignatureMismatch","'%s': %8lx != %8lx",module_name,
1323        (unsigned long) signature,(unsigned long) MagickImageCoderSignature);
1324      return(MagickFalse);
1325    }
1326  return(MagickTrue);
1327}
1328
1329/*
1330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1331%                                                                             %
1332%                                                                             %
1333%                                                                             %
1334%   O p e n M o d u l e s                                                     %
1335%                                                                             %
1336%                                                                             %
1337%                                                                             %
1338%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1339%
1340%  OpenModules() loads all available modules.
1341%
1342%  The format of the OpenModules module is:
1343%
1344%      MagickBooleanType OpenModules(ExceptionInfo *exception)
1345%
1346%  A description of each parameter follows:
1347%
1348%    o exception: return any errors or warnings in this structure.
1349%
1350*/
1351MagickPrivate MagickBooleanType OpenModules(ExceptionInfo *exception)
1352{
1353  char
1354    **modules;
1355
1356  register ssize_t
1357    i;
1358
1359  size_t
1360    number_modules;
1361
1362  /*
1363    Load all modules.
1364  */
1365  (void) GetMagickInfo((char *) NULL,exception);
1366  number_modules=0;
1367  modules=GetModuleList("*",MagickImageCoderModule,&number_modules,exception);
1368  if ((modules == (char **) NULL) || (*modules == (char *) NULL))
1369    {
1370      if (modules != (char **) NULL)
1371        modules=(char **) RelinquishMagickMemory(modules);
1372      return(MagickFalse);
1373    }
1374  for (i=0; i < (ssize_t) number_modules; i++)
1375    (void) OpenModule(modules[i],exception);
1376  /*
1377    Relinquish resources.
1378  */
1379  for (i=0; i < (ssize_t) number_modules; i++)
1380    modules[i]=DestroyString(modules[i]);
1381  modules=(char **) RelinquishMagickMemory(modules);
1382  return(MagickTrue);
1383}
1384
1385/*
1386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1387%                                                                             %
1388%                                                                             %
1389%                                                                             %
1390%   R e g i s t e r M o d u l e                                               %
1391%                                                                             %
1392%                                                                             %
1393%                                                                             %
1394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1395%
1396%  RegisterModule() adds an entry to the module list.  It returns a pointer to
1397%  the registered entry on success.
1398%
1399%  The format of the RegisterModule module is:
1400%
1401%      ModuleInfo *RegisterModule(const ModuleInfo *module_info,
1402%        ExceptionInfo *exception)
1403%
1404%  A description of each parameter follows:
1405%
1406%    o info: a pointer to the registered entry is returned.
1407%
1408%    o module_info: a pointer to the ModuleInfo structure to register.
1409%
1410%    o exception: return any errors or warnings in this structure.
1411%
1412*/
1413static const ModuleInfo *RegisterModule(const ModuleInfo *module_info,
1414  ExceptionInfo *exception)
1415{
1416  MagickBooleanType
1417    status;
1418
1419  assert(module_info != (ModuleInfo *) NULL);
1420  assert(module_info->signature == MagickCoreSignature);
1421  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",module_info->tag);
1422  if (module_list == (SplayTreeInfo *) NULL)
1423    return((const ModuleInfo *) NULL);
1424  status=AddValueToSplayTree(module_list,module_info->tag,module_info);
1425  if (status == MagickFalse)
1426    (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
1427      "MemoryAllocationFailed","`%s'",module_info->tag);
1428  return(module_info);
1429}
1430
1431/*
1432%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1433%                                                                             %
1434%                                                                             %
1435%                                                                             %
1436%  T a g T o C o d e r M o d u l e N a m e                                    %
1437%                                                                             %
1438%                                                                             %
1439%                                                                             %
1440%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1441%
1442%  TagToCoderModuleName() munges a module tag and obtains the filename of the
1443%  corresponding module.
1444%
1445%  The format of the TagToCoderModuleName module is:
1446%
1447%      char *TagToCoderModuleName(const char *tag,char *name)
1448%
1449%  A description of each parameter follows:
1450%
1451%    o tag: a character string representing the module tag.
1452%
1453%    o name: return the module name here.
1454%
1455*/
1456static void TagToCoderModuleName(const char *tag,char *name)
1457{
1458  assert(tag != (char *) NULL);
1459  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",tag);
1460  assert(name != (char *) NULL);
1461#if defined(MAGICKCORE_LTDL_DELEGATE)
1462  (void) FormatLocaleString(name,MagickPathExtent,"%s.la",tag);
1463  (void) LocaleLower(name);
1464#else
1465#if defined(MAGICKCORE_WINDOWS_SUPPORT)
1466  if (LocaleNCompare("IM_MOD_",tag,7) == 0)
1467    (void) CopyMagickString(name,tag,MagickPathExtent);
1468  else
1469    {
1470#if defined(_DEBUG)
1471      (void) FormatLocaleString(name,MagickPathExtent,"IM_MOD_DB_%s_.dll",tag);
1472#else
1473      (void) FormatLocaleString(name,MagickPathExtent,"IM_MOD_RL_%s_.dll",tag);
1474#endif
1475    }
1476#endif
1477#endif
1478}
1479
1480/*
1481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1482%                                                                             %
1483%                                                                             %
1484%                                                                             %
1485%  T a g T o F i l t e r M o d u l e N a m e                                  %
1486%                                                                             %
1487%                                                                             %
1488%                                                                             %
1489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1490%
1491%  TagToFilterModuleName() munges a module tag and returns the filename of the
1492%  corresponding filter module.
1493%
1494%  The format of the TagToFilterModuleName module is:
1495%
1496%      void TagToFilterModuleName(const char *tag,char name)
1497%
1498%  A description of each parameter follows:
1499%
1500%    o tag: a character string representing the module tag.
1501%
1502%    o name: return the filter name here.
1503%
1504*/
1505static void TagToFilterModuleName(const char *tag,char *name)
1506{
1507  assert(tag != (char *) NULL);
1508  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",tag);
1509  assert(name != (char *) NULL);
1510#if defined(MAGICKCORE_WINDOWS_SUPPORT)
1511  (void) FormatLocaleString(name,MagickPathExtent,"FILTER_%s_.dll",tag);
1512#elif !defined(MAGICKCORE_LTDL_DELEGATE)
1513  (void) FormatLocaleString(name,MagickPathExtent,"%s.dll",tag);
1514#else
1515  (void) FormatLocaleString(name,MagickPathExtent,"%s.la",tag);
1516#endif
1517}
1518
1519/*
1520%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1521%                                                                             %
1522%                                                                             %
1523%                                                                             %
1524%   T a g T o M o d u l e N a m e                                             %
1525%                                                                             %
1526%                                                                             %
1527%                                                                             %
1528%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1529%
1530%  TagToModuleName() munges the module tag name and returns an upper-case tag
1531%  name as the input string, and a user-provided format.
1532%
1533%  The format of the TagToModuleName module is:
1534%
1535%      TagToModuleName(const char *tag,const char *format,char *module)
1536%
1537%  A description of each parameter follows:
1538%
1539%    o tag: the module tag.
1540%
1541%    o format: a sprintf-compatible format string containing %s where the
1542%      upper-case tag name is to be inserted.
1543%
1544%    o module: pointer to a destination buffer for the formatted result.
1545%
1546*/
1547static void TagToModuleName(const char *tag,const char *format,char *module)
1548{
1549  char
1550    name[MagickPathExtent];
1551
1552  assert(tag != (const char *) NULL);
1553  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",tag);
1554  assert(format != (const char *) NULL);
1555  assert(module != (char *) NULL);
1556  (void) CopyMagickString(name,tag,MagickPathExtent);
1557  LocaleUpper(name);
1558#if !defined(MAGICKCORE_NAMESPACE_PREFIX)
1559  (void) FormatLocaleString(module,MagickPathExtent,format,name);
1560#else
1561  {
1562    char
1563      prefix_format[MagickPathExtent];
1564
1565    (void) FormatLocaleString(prefix_format,MagickPathExtent,"%s%s",
1566      MAGICKCORE_NAMESPACE_PREFIX,format);
1567    (void) FormatLocaleString(module,MagickPathExtent,prefix_format,name);
1568  }
1569#endif
1570}
1571
1572/*
1573%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1574%                                                                             %
1575%                                                                             %
1576%                                                                             %
1577%   U n r e g i s t e r M o d u l e                                           %
1578%                                                                             %
1579%                                                                             %
1580%                                                                             %
1581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1582%
1583%  UnregisterModule() unloads a module, and invokes its de-registration module.
1584%  Returns MagickTrue on success, and MagickFalse if there is an error.
1585%
1586%  The format of the UnregisterModule module is:
1587%
1588%      MagickBooleanType UnregisterModule(const ModuleInfo *module_info,
1589%        ExceptionInfo *exception)
1590%
1591%  A description of each parameter follows:
1592%
1593%    o module_info: the module info.
1594%
1595%    o exception: return any errors or warnings in this structure.
1596%
1597*/
1598static MagickBooleanType UnregisterModule(const ModuleInfo *module_info,
1599  ExceptionInfo *exception)
1600{
1601  /*
1602    Locate and execute UnregisterFORMATImage module.
1603  */
1604  assert(module_info != (const ModuleInfo *) NULL);
1605  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",module_info->tag);
1606  assert(exception != (ExceptionInfo *) NULL);
1607  if (module_info->unregister_module == NULL)
1608    return(MagickTrue);
1609  module_info->unregister_module();
1610  if (lt_dlclose((ModuleHandle) module_info->handle) != 0)
1611    {
1612      (void) ThrowMagickException(exception,GetMagickModule(),ModuleWarning,
1613        "UnableToCloseModule","'%s': %s",module_info->tag,lt_dlerror());
1614      return(MagickFalse);
1615    }
1616  return(MagickTrue);
1617}
1618#else
1619
1620#if !defined(MAGICKCORE_BUILD_MODULES)
1621extern size_t
1622  analyzeImage(Image **,const int,const char **,ExceptionInfo *);
1623#endif
1624
1625MagickExport MagickBooleanType ListModuleInfo(FILE *magick_unused(file),
1626  ExceptionInfo *magick_unused(exception))
1627{
1628  return(MagickTrue);
1629}
1630
1631MagickExport MagickBooleanType InvokeDynamicImageFilter(const char *tag,
1632  Image **image,const int argc,const char **argv,ExceptionInfo *exception)
1633{
1634  PolicyRights
1635    rights;
1636
1637  assert(image != (Image **) NULL);
1638  assert((*image)->signature == MagickCoreSignature);
1639  if ((*image)->debug != MagickFalse)
1640    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
1641  rights=ReadPolicyRights;
1642  if (IsRightsAuthorized(FilterPolicyDomain,rights,tag) == MagickFalse)
1643    {
1644      errno=EPERM;
1645      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
1646        "NotAuthorized","`%s'",tag);
1647      return(MagickFalse);
1648    }
1649#if defined(MAGICKCORE_BUILD_MODULES)
1650  (void) tag;
1651  (void) argc;
1652  (void) argv;
1653  (void) exception;
1654#else
1655  {
1656    ImageFilterHandler
1657      *image_filter;
1658
1659    image_filter=(ImageFilterHandler *) NULL;
1660    if (LocaleCompare("analyze",tag) == 0)
1661      image_filter=(ImageFilterHandler *) analyzeImage;
1662    if (image_filter == (ImageFilterHandler *) NULL)
1663      (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
1664        "UnableToLoadModule","`%s'",tag);
1665    else
1666      {
1667        size_t
1668          signature;
1669
1670        if ((*image)->debug != MagickFalse)
1671          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1672            "Invoking \"%s\" static image filter",tag);
1673        signature=image_filter(image,argc,argv,exception);
1674        if ((*image)->debug != MagickFalse)
1675          (void) LogMagickEvent(CoderEvent,GetMagickModule(),"\"%s\" completes",
1676            tag);
1677        if (signature != MagickImageFilterSignature)
1678          {
1679            (void) ThrowMagickException(exception,GetMagickModule(),ModuleError,
1680              "ImageFilterSignatureMismatch","'%s': %8lx != %8lx",tag,
1681              (unsigned long) signature,(unsigned long)
1682              MagickImageFilterSignature);
1683            return(MagickFalse);
1684          }
1685      }
1686  }
1687#endif
1688  return(MagickTrue);
1689}
1690#endif
1691