1 /*
2 % Copyright (C) 2003 - 2019 GraphicsMagick Group
3 % Copyright (C) 2002 ImageMagick Studio
4 %
5 % This program is covered by multiple licenses, which are described in
6 % Copyright.txt. You should have received a copy of Copyright.txt with this
7 % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
8 %
9 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10 %                                                                             %
11 %                                                                             %
12 %                                                                             %
13 %                                 N   N  TTTTT                                %
14 %                                 NN  N    T                                  %
15 %                                 N N N    T                                  %
16 %                                 N  NN    T                                  %
17 %                                 N   N    T                                  %
18 %                                                                             %
19 %                                                                             %
20 %                Windows NT Utility Methods for GraphicsMagick                %
21 %                                                                             %
22 %                                                                             %
23 %                               Software Design                               %
24 %                                 John Cristy                                 %
25 %                                December 1996                                %
26 %                                                                             %
27 %                                                                             %
28 %                                                                             %
29 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
30 %
31 %
32 */
33 
34 #include "magick/studio.h"
35 #if defined(MSWINDOWS)
36 /*
37   Include declarations.
38 */
39 #include <sys/types.h>
40 #include <sys/utime.h>
41 #include "magick/log.h"
42 #include "magick/magick.h"
43 #include "magick/utility.h"
44 #include "magick/version.h"
45 #if defined(HasLTDL)
46 #  include "ltdl.h"
47 #endif /* defined(HasLTDL) */
48 #include "magick/nt_base.h"
49 
50 /*
51   Static declarations.
52 */
53 #if !defined(HasLTDL)
54 static char
55   *NTslsearchpath = (char *) NULL;
56 #endif
57 #if defined(HasGS)
58 static void
59   *gs_dll_handle = (void *)NULL;
60 static GhostscriptVectors
61     gs_vectors;
62 #endif /* if defined(HasGS) */
63 
64 static MagickPassFail NTstrerror_r(LONG errnum, char *strerrbuf, size_t  buflen);
65 
66 /*
67   External declarations.
68 */
69 #if !defined(MSWINDOWS)
70 extern "C" BOOL WINAPI
71   DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved);
72 #endif
73 
74 static const struct
75   {
76     const HKEY hkey;
77     const char *name;
78   }
79 hkeys[2] =
80     {
81       { HKEY_CURRENT_USER,  "HKEY_CURRENT_USER"  },
82       { HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE" }
83     };
84 
85 
86 
87 /*
88 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
89 %                                                                             %
90 %                                                                             %
91 %                                                                             %
92 %   N T c l o s e d i r                                                       %
93 %                                                                             %
94 %                                                                             %
95 %                                                                             %
96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
97 %
98 %  Method NTclosedir closes the named directory stream and frees the DIR
99 %  structure.
100 %
101 %  The format of the NTclosedir method is:
102 %
103 %      void NTclosedir(DIR *entry)
104 %
105 %  A description of each parameter follows:
106 %
107 %    o entry: Specifies a pointer to a DIR structure.
108 %
109 %
110 */
NTclosedir(DIR * entry)111 MagickExport int NTclosedir(DIR *entry)
112 {
113   assert(entry != (DIR *) NULL);
114   FindClose(entry->hSearch);
115   MagickFreeMemory(entry);
116   return 0;
117 }
118 
119 /*
120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
121 %                                                                             %
122 %                                                                             %
123 %                                                                             %
124 %   DllMain                                                                   %
125 %                                                                             %
126 %                                                                             %
127 %                                                                             %
128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
129 %
130 %  Method DllMain is an entry point to the DLL which is called when processes
131 %  and threads are initialized and terminated, or upon calls to the
132 %  Windows LoadLibrary and FreeLibrary functions.
133 %
134 %  The function returns TRUE of it succeeds, or FALSE if initialization fails.
135 %
136 %  The format of the DllMain method is:
137 %
138 %    BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
139 %
140 %  A description of each parameter follows:
141 %
142 %    o hinstDLL: handle to the DLL module
143 %
144 %    o fdwReason: reason for calling function.
145 %
146 %          May have values:
147 %             DLL_PROCESS_ATTACH - DLL is being loaded into virtual address
148 %                                  space of current process.
149 %             DLL_THREAD_ATTACH - Indicates that the current process is
150 %                                 creating a new thread.  Called under the
151 %                                 context of the new thread.
152 %             DLL_THREAD_DETACH - Indicates that the thread is exiting.
153 %                                 Called under the context of the exiting
154 %                                 thread.
155 %             DLL_PROCESS_DETACH - Indicates that the DLL is being unloaded
156 %                                  from the virtual address space of the
157 %                                  current process.
158 %
159 %    o lpvReserved: Used for passing additional info during DLL_PROCESS_ATTACH
160 %                   and DLL_PROCESS_DETACH.
161 %
162 */
163 #if defined(_DLL) && defined( ProvideDllMain )
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)164 BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
165 {
166   switch ( fdwReason )
167     {
168     case DLL_PROCESS_ATTACH:
169       {
170 #define ENV_VAR_MAX 32767 /* environment variable max is 32,767 bytes */
171 #define DLL_PATH_MAX 1024
172 
173         char
174           dll_path[DLL_PATH_MAX],
175           current_path[ENV_VAR_MAX];
176 
177         long count;
178 
179         count = GetModuleFileName(hinstDLL,dll_path,DLL_PATH_MAX);
180         if (count) {
181           for ( ; count>0 ; --count)
182             {
183               if (dll_path[count]=='\\')
184                 {
185                   dll_path[count+1]='\0';
186                   break;
187                 }
188             }
189           InitializeMagick(dll_path);
190           count = GetEnvironmentVariable("PATH",current_path,ENV_VAR_MAX);
191           if (strstr(current_path,dll_path) == NULL)
192             {
193               if (strlen(dll_path)+count+1 < ENV_VAR_MAX-1)
194                 {
195                   char
196                     new_path[ENV_VAR_MAX];
197 
198                   FormatString(new_path,"%.*s;%.*s",DLL_PATH_MAX,dll_path,
199                                ENV_VAR_MAX-DLL_PATH_MAX-1,current_path);
200                   SetEnvironmentVariable("PATH",new_path);
201                 }
202             }
203           break;
204         }
205         /* If we get here, then GetModuleFileName must have failed */
206         return FALSE;
207         break;
208       }
209     case DLL_PROCESS_DETACH:
210       DestroyMagick();
211       break;
212     default:
213       {
214         /* Do nothing */
215       }
216     }
217   return TRUE;
218 }
219 #endif
220 
221 /*
222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
223 %                                                                             %
224 %                                                                             %
225 %                                                                             %
226 %   E x i t                                                                   %
227 %                                                                             %
228 %                                                                             %
229 %                                                                             %
230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
231 %
232 %  Method Exit calls TerminateProcess for Win95.  Should quit the program
233 %  and not return.
234 %
235 %  The format of the Exit method is:
236 %
237 %      void Exit(int status)
238 %
239 %  A description of each parameter follows:
240 %
241 %    o status: an integer value representing the status of the terminating
242 %      process.
243 %
244 %
245 */
Exit(int status)246 MagickExport void Exit(int status)
247 {
248   if (IsWindows95())
249     TerminateProcess(GetCurrentProcess(),(unsigned int) status);
250   exit(status);
251 }
252 
253 /*
254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
255 %                                                                             %
256 %                                                                             %
257 %                                                                             %
258 %   M a g i c k G e t M M U P a g e S i z e                                   %
259 %                                                                             %
260 %                                                                             %
261 %                                                                             %
262 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
263 %
264 %  MagickGetMMUPageSize() returns the VM pagesize used by the MMU. The VM
265 %  pagesize is the number of bytes retrieved due to one page fault.
266 %
267 %  The format of the MagickGetMMUPageSize method is:
268 %
269 %      long MagickGetMMUPageSize()
270 %
271 */
MagickGetMMUPageSize()272 MagickExport long MagickGetMMUPageSize()
273 {
274   return 4096;
275 }
276 
277 /*
278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
279 %                                                                             %
280 %                                                                             %
281 %                                                                             %
282 %   M a g i c k G e t F i l e A t t r i b u t e s                             %
283 %                                                                             %
284 %                                                                             %
285 %                                                                             %
286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
287 %
288 %  MagickGetFileAttributes() returns the file attributes for a specified
289 %  file in a structure of type MagickStatStruct_t.
290 %
291 %  The format of the MagickGetFileAttributes method is:
292 %
293 %      int MagickGetFileAttributes(const char *filename,
294 %                                  MagickStatStruct_t *statbuf)
295 %
296 %  A description of each parameter follows:
297 %
298 %    o filename:  Path to the file
299 %
300 %    o statbuf: A structure of type MagickStatStruct_t to populate.
301 %
302 %
303 */
MagickGetFileAttributes(const char * filename,MagickStatStruct_t * statbuf)304 MagickExport int MagickGetFileAttributes(const char *filename,
305                                          MagickStatStruct_t *statbuf)
306 {
307   if (MagickStat(filename, statbuf) != 0)
308     return -1;
309 
310   return 0;
311 }
312 
313 /*
314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
315 %                                                                             %
316 %                                                                             %
317 %                                                                             %
318 %   M a g i c k S e t F i l e A t t r i b u t e s                             %
319 %                                                                             %
320 %                                                                             %
321 %                                                                             %
322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323 %
324 %  MagickSetFileAttributes() sets the access and modification time file
325 %  attributes based on values provided via in a structure of type
326 %  MagickStatStruct_t.
327 %
328 %  The format of the MagickGetFileAttributes method is:
329 %
330 %      int MagickSetFileAttributes(const char *filename,
331 %                                  const MagickStatStruct_t *statbuf)
332 %
333 %  A description of each parameter follows:
334 %
335 %    o filename:  Path to the file
336 %
337 %    o statbuf: A structure of type MagickStatStruct_t to populate.
338 %
339 %
340 */
MagickSetFileAttributes(const char * filename,const MagickStatStruct_t * statbuf)341 MagickExport int MagickSetFileAttributes(const char *filename,
342                                          const MagickStatStruct_t *statbuf)
343 {
344   /*
345     Setting file timestamps on Windows is actually almost the same as on POSIX systems.
346     https://msdn.microsoft.com/en-us/library/4wacf567.aspx
347    */
348   struct _utimbuf
349     ut;
350 
351   ut.actime = statbuf->st_atime;
352   ut.modtime = statbuf->st_mtime;
353 
354   if (_utime(filename, &ut) == -1)
355     return -1;
356 
357   return 0;
358 }
359 
360 /*
361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362 %                                                                             %
363 %                                                                             %
364 %                                                                             %
365 %   I s W i n d o w s 9 5                                                     %
366 %                                                                             %
367 %                                                                             %
368 %                                                                             %
369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 %
371 %  Method IsWindows95 returns true if the system is Windows 95.
372 %
373 %  The format of the IsWindows95 method is:
374 %
375 %      int IsWindows95()
376 %
377 %  A description of each parameter follows:
378 %
379 %    o status: an integer value representing the status of the terminating
380 %      process.
381 %
382 %
383 */
IsWindows95()384 MagickExport MagickBool IsWindows95()
385 {
386   OSVERSIONINFO
387     version_info;
388 
389   version_info.dwOSVersionInfoSize=sizeof(version_info);
390   if (GetVersionEx(&version_info) &&
391       (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS))
392     return(MagickTrue);
393   return(MagickFalse);
394 }
395 
396 /*
397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
398 %                                                                             %
399 %                                                                             %
400 %                                                                             %
401 %   InitializeWIN32ExceptionHandlers                                          %
402 %                                                                             %
403 %                                                                             %
404 %                                                                             %
405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
406 %
407 %  Method InitializeWIN32ExceptionHandlers registers a handler for WIN32
408 %  exceptions (similar to POSIX signals but different).
409 %
410 %  The format of the InitializeWIN32ExceptionHandlers method is:
411 %
412 %      void InitializeWIN32ExceptionHandlers()
413 %
414 %
415 */
416 static LONG WINAPI
MagickUnhandledExceptionFilter(struct _EXCEPTION_POINTERS * info)417 MagickUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *info)
418 {
419   /*
420     https://msdn.microsoft.com/en-us/library/windows/desktop/ms680634%28v=vs.85%29.aspx
421 
422     http://www.codeproject.com/Articles/11132/Walking-the-callstack
423 
424     http://www.microsoft.com/msj/0197/exception/exception.aspx
425 
426     Return values:
427 
428     EXCEPTION_EXECUTE_HANDLER (0x1)
429 
430     Return from UnhandledExceptionFilter and execute the associated
431     exception handler. This usually results in process termination.
432 
433     EXCEPTION_CONTINUE_EXECUTION (0xffffffff)
434 
435     Return from UnhandledExceptionFilter and continue execution from
436     the point of the exception. Note that the filter function is
437     free to modify the continuation state by modifying the exception
438     information supplied through its LPEXCEPTION_POINTERS parameter.
439 
440     EXCEPTION_CONTINUE_SEARCH (0x0)
441 
442     Proceed with normal execution of UnhandledExceptionFilter. That
443     means obeying the SetErrorMode flags, or invoking the
444     Application Error pop-up message box.
445 
446     The EXCEPTION_POINTERS structure has the definition:
447 
448     https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082%28v=vs.85%29.aspx
449     typedef struct _EXCEPTION_RECORD {
450     DWORD                    ExceptionCode;
451     DWORD                    ExceptionFlags;
452     struct _EXCEPTION_RECORD  *ExceptionRecord;
453     PVOID                    ExceptionAddress;
454     DWORD                    NumberParameters;
455     ULONG_PTR                ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
456     } EXCEPTION_RECORD, *PEXCEPTION_RECORD;
457 
458     https://msdn.microsoft.com/en-us/library/windows/desktop/ms679284%28v=vs.85%29.aspx
459     We don't care about PCONTEXT because it is processor-specific and includes low level
460     details such as register contents.
461 
462     https://msdn.microsoft.com/en-us/library/windows/desktop/ms679331%28v=vs.85%29.aspx
463     typedef struct _EXCEPTION_POINTERS {
464     PEXCEPTION_RECORD ExceptionRecord;
465     PCONTEXT          ContextRecord;
466     } EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
467 
468   */
469   static const struct {
470     DWORD  code;
471     const char *text;
472   }
473   except_descr[] =
474     {
475       /*
476         The thread tried to read from or write to a virtual address
477         for which it does not have the appropriate access.
478       */
479 #if defined(EXCEPTION_ACCESS_VIOLATION)
480       { EXCEPTION_ACCESS_VIOLATION,  "Access violation" },
481 #endif
482       /*
483         The thread tried to access an array element that is out of
484         bounds and the underlying hardware supports bounds checking.
485       */
486 #if defined(EXCEPTION_ARRAY_BOUNDS_EXCEEDED)
487       { EXCEPTION_ARRAY_BOUNDS_EXCEEDED, "Array bounds exceeded" },
488 #endif
489       /*
490         The thread tried to read or write data that is misaligned on
491         hardware that does not provide alignment. For example,
492         16-bit values must be aligned on 2-byte boundaries; 32-bit
493         values on 4-byte boundaries, and so on.
494       */
495 #if defined(EXCEPTION_DATATYPE_MISALIGNMENT)
496       { EXCEPTION_DATATYPE_MISALIGNMENT, "Datatype misalignment" },
497 #endif
498       /*
499         One of the operands in a floating-point operation is
500         denormal. A denormal value is one that is too small to
501         represent as a standard floating-point value.
502       */
503 #if defined(EXCEPTION_FLT_DENORMAL_OPERAND)
504       { EXCEPTION_FLT_DENORMAL_OPERAND, "Float - denormal operand" },
505 #endif
506       /*
507         The thread tried to divide a floating-point value by a
508         floating-point divisor of zero.
509       */
510 #if defined(EXCEPTION_FLT_DIVIDE_BY_ZERO)
511       { EXCEPTION_FLT_DIVIDE_BY_ZERO, "Float - divide by zero" },
512 #endif
513       /*
514         This exception represents any floating-point exception not
515         included in this list.
516       */
517 #if defined(EXCEPTION_FLT_INVALID_OPERATION)
518       { EXCEPTION_FLT_INVALID_OPERATION, "Float - invalid operation" },
519 #endif
520       /*
521         The exponent of a floating-point operation is greater than the
522         magnitude allowed by the corresponding type.
523       */
524 #if defined(EXCEPTION_FLT_OVERFLOW)
525       { EXCEPTION_FLT_OVERFLOW, "Float overflow" },
526 #endif
527       /*
528         The stack overflowed or underflowed as the result of a
529         floating-point operation.
530       */
531 #if defined(EXCEPTION_FLT_STACK_CHECK)
532       { EXCEPTION_FLT_STACK_CHECK, "Float - stack under/overflow" },
533 #endif
534       /*
535         The exponent of a floating-point operation is less than the
536         magnitude allowed by the corresponding type.
537       */
538 #if defined(EXCEPTION_FLT_UNDERFLOW)
539       { EXCEPTION_FLT_UNDERFLOW, "Float - underflow" },
540 #endif
541       /*
542         The thread tried to execute an invalid instruction.
543       */
544 #if defined(EXCEPTION_ILLEGAL_INSTRUCTION)
545       { EXCEPTION_ILLEGAL_INSTRUCTION, "Illegal instruction" },
546 #endif
547       /*
548         The thread tried to access a page that was not present, and
549         the system was unable to load the page. For example, this
550         exception might occur if a network connection is lost while
551         running a program over the network.
552       */
553 #if defined(EXCEPTION_IN_PAGE_ERROR)
554       { EXCEPTION_IN_PAGE_ERROR, "MMU page-in error" },
555 #endif
556       /*
557         The thread tried to divide an integer value by an integer
558         divisor of zero.
559       */
560 #if defined(EXCEPTION_INT_DIVIDE_BY_ZERO)
561       { EXCEPTION_INT_DIVIDE_BY_ZERO, "Integer divide by zero" },
562 #endif
563       /*
564         The result of an integer operation caused a carry out of the
565         most significant bit of the result.
566       */
567 #if defined(EXCEPTION_INT_OVERFLOW)
568       { EXCEPTION_INT_OVERFLOW, "Integer overflow" },
569 #endif
570       /*
571         The thread tried to execute an instruction whose operation is
572         not allowed in the current machine mode.
573       */
574 #if defined(EXCEPTION_PRIV_INSTRUCTION)
575       { EXCEPTION_PRIV_INSTRUCTION, "Privileged instruction" },
576 #endif
577       /*
578         The thread used up its stack.
579       */
580 #if defined(EXCEPTION_STACK_OVERFLOW)
581       { EXCEPTION_STACK_OVERFLOW, "Stack overflow" }
582 #endif
583     };
584 
585   char
586     message[MaxTextExtent];
587 
588   const char
589     *text = NULL;
590 
591   size_t
592     i;
593 
594   DWORD
595     code = info->ExceptionRecord->ExceptionCode;
596 
597   /*
598     Linear search for explanation of error code.
599   */
600   for (i=0; i < sizeof(except_descr)/sizeof(except_descr[0]); i++)
601     if (except_descr[i].code == code)
602       {
603         text = except_descr[i].text;
604         break;
605       }
606 
607   /*
608     If this is an exception we handle
609   */
610   if (text != NULL)
611     {
612       /*
613         Release persistent resources
614       */
615       PanicDestroyMagick();
616 
617       /*
618         Output messages like:
619 
620         gm.exe identify: caught exception 0xC0000005 "Access violation"...
621       */
622       FormatString(message,
623                    "%s: caught exception 0x%08X \"%s\"...",
624                    GetClientName(), (unsigned int) code, text);
625       if (write(STDERR_FILENO,message,
626                 (MAGICK_POSIX_IO_SIZE_T) strlen(message)) == -1)
627         {
628           /* Exists to quench warning */
629         }
630 
631       /*
632         Return from UnhandledExceptionFilter and execute the
633         associated exception handler. This usually results in process
634         termination.
635       */
636       return EXCEPTION_EXECUTE_HANDLER;
637     }
638 
639   /*
640     Can also look at ExceptionFlags and check for EXCEPTION_NONCONTINUABLE.
641   */
642 
643   /*
644     Proceed with normal execution of UnhandledExceptionFilter. That
645     means obeying the SetErrorMode flags, or invoking the Application
646     Error pop-up message box.
647   */
648   return EXCEPTION_CONTINUE_SEARCH;
649 }
650 MagickExport void
NTInitializeExceptionHandlers()651 NTInitializeExceptionHandlers()
652 {
653 
654   (void) SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
655                       SEM_NOOPENFILEERRORBOX);
656   (void) SetUnhandledExceptionFilter(MagickUnhandledExceptionFilter);
657 }
658 
659 #if !defined(HasLTDL)
660 /*
661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662 %                                                                             %
663 %                                                                             %
664 %                                                                             %
665 %   N T d l c l o s e                                                         %
666 %                                                                             %
667 %                                                                             %
668 %                                                                             %
669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
670 %
671 %   Method NTdlclose unloads the module associated with the passed handle.
672 %   Zero is returned on success.
673 %
674 %  The format of the NTdlclose method is:
675 %
676 %      void NTdlclose(void *handle)
677 %
678 %  A description of each parameter follows:
679 %
680 %    o handle: Specifies a handle to a previously loaded dynamic module.
681 %
682 */
NTdlclose(void * handle)683 MagickExport int NTdlclose(void *handle)
684 {
685   /* FreeLibrary returns zero for failure */
686   return (!(FreeLibrary(handle)));
687 }
688 
689 /*
690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
691 %                                                                             %
692 %                                                                             %
693 %                                                                             %
694 %   N T d l e r r o r                                                         %
695 %                                                                             %
696 %                                                                             %
697 %                                                                             %
698 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
699 %
700 %   Method NTdlerror returns a pointer to a string describing the last error
701 %   associated with a NTdl* function. Note that this function is not thread
702 %   safe so it should only be used under the protection of a lock.
703 %
704 %  The format of the NTdlerror method is:
705 %
706 %      const char * NTdlerror(void)
707 %
708 %  A description of each parameter follows:
709 %
710 */
NTdlerror(void)711 MagickExport const char *NTdlerror(void)
712 {
713   static char
714     last_error[MaxTextExtent];
715 
716   char
717     *error;
718 
719   last_error[0]='\0';
720   error=NTGetLastError();
721   if (error)
722     strlcpy(last_error,error,MaxTextExtent);
723   MagickFreeMemory(error);
724   return (last_error);
725 }
726 
727 /*
728 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
729 %                                                                             %
730 %                                                                             %
731 %                                                                             %
732 %   N T d l e x i t                                                           %
733 %                                                                             %
734 %                                                                             %
735 %                                                                             %
736 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
737 %
738 %   NTdlexit() exits the dynamic module loading subsystem.
739 %
740 %  The format of the NTdlexit method is:
741 %
742 %      int NTdlexit(void)
743 %
744 */
NTdlexit(void)745 MagickExport int NTdlexit(void)
746 {
747   return(0);
748 }
749 
750 /*
751 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
752 %                                                                             %
753 %                                                                             %
754 %                                                                             %
755 %   N T d l i n i t                                                         %
756 %                                                                             %
757 %                                                                             %
758 %                                                                             %
759 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
760 %
761 %   Method NTdlinit initializes the dynamic module loading subsystem.
762 %
763 %  The format of the NTdlinit method is:
764 %
765 %      int NTdlinit(void)
766 %
767 */
NTdlinit(void)768 MagickExport int NTdlinit(void)
769 {
770   return(0);
771 }
772 
773 /*
774 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
775 %                                                                             %
776 %                                                                             %
777 %                                                                             %
778 %   N T d l o p e n                                                           %
779 %                                                                             %
780 %                                                                             %
781 %                                                                             %
782 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
783 %
784 %   Method NTdlopen loads a dynamic module into memory and returns a handle
785 %   that can be used to access the various procedures in the module.
786 %
787 %  The format of the NTdlopen method is:
788 %
789 %      void *NTdlopen(const char *filename)
790 %
791 %  A description of each parameter follows:
792 %
793 %    o path: Specifies a pointer to string representing dynamic module that
794 %            is to be loaded.
795 %
796 */
NTdlopen(const char * filename)797 MagickExport void *NTdlopen(const char *filename)
798 {
799 #define MaxPathElements  31
800 
801   char
802     buffer[MaxTextExtent];
803 
804   int
805     index;
806 
807   register char
808     *p,
809     *q;
810 
811   register int
812     i;
813 
814   void
815     *handle;
816 
817   UINT
818     errorMode;
819 
820   // Set error mode so that dialog box is not displayed on error.
821   errorMode=SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
822 
823   // Load library via name
824   handle=(void *) LoadLibrary(filename);
825 
826   // If library failed to load, but a search path is defined, then
827   // attempt to load library via search path.
828   if ((handle == (void *) NULL) && (NTslsearchpath != NULL))
829     {
830       p=NTslsearchpath;
831       index=0;
832       while (index < MaxPathElements)
833         {
834           q=strchr(p,DirectoryListSeparator);
835           if (q == (char *) NULL)
836             {
837               (void) strlcpy(buffer,p,MaxTextExtent);
838               (void) strlcat(buffer,"\\",MaxTextExtent);
839               (void) strlcat(buffer,filename,MaxTextExtent);
840               handle=(void *) LoadLibrary(buffer);
841               break;
842             }
843           i=q-p;
844           (void) strncpy(buffer,p,i);
845           buffer[i]='\0';
846           (void) strlcat(buffer,"\\",MaxTextExtent);
847           (void) strlcat(buffer,filename,MaxTextExtent);
848           handle=(void *) LoadLibrary(buffer);
849           if (handle)
850             break;
851           p=q+1;
852         }
853     }
854 
855   // Restore original error handling mode.
856   SetErrorMode(errorMode);
857 
858   return(handle);
859 }
860 
861 /*
862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
863 %                                                                             %
864 %                                                                             %
865 %                                                                             %
866 %   N T d l s e t s e a r c h p a t h                                         %
867 %                                                                             %
868 %                                                                             %
869 %                                                                             %
870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
871 %
872 %   Method NTdlsetsearchpath sets the current locations that the subsystem
873 %   should look at to find dynamically loadable modules.
874 %
875 %  The format of the NTdlsetsearchpath method is:
876 %
877 %      int NTdlsetsearchpath(char *path)
878 %
879 %  A description of each parameter follows:
880 %
881 %    o path: Specifies a pointer to string representing the search path
882 %            for DLL's that can be dynamically loaded.
883 %
884 */
NTdlsetsearchpath(const char * path)885 MagickExport int NTdlsetsearchpath(const char *path)
886 {
887   if (NTslsearchpath)
888     {
889       MagickFreeMemory(NTslsearchpath);
890       NTslsearchpath=(char *) NULL;
891     }
892   if (path != (char *) NULL)
893     NTslsearchpath=AllocateString(path);
894   return (0);
895 }
896 
897 /*
898 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
899 %                                                                             %
900 %                                                                             %
901 %                                                                             %
902 %   N T d l s y m                                                             %
903 %                                                                             %
904 %                                                                             %
905 %                                                                             %
906 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
907 %
908 %   Method NTdlsym retrieve the procedure address of the procedure specified
909 %   by the passed character string.
910 %
911 %  The format of the NTdlsym method is:
912 %
913 %      void *NTdlsym(void *handle,const char *name)
914 %
915 %  A description of each parameter follows:
916 %
917 %    o handle: Specifies a handle to the previously loaded dynamic module.
918 %
919 %    o name: Specifies the procedure entry point to be returned.
920 %
921 */
NTdlsym(void * handle,const char * name)922 MagickExport void *NTdlsym(void *handle,const char *name)
923 {
924   LPFNDLLFUNC1
925     lpfnDllFunc1;
926 
927   /* FARPROC GetProcAddress(HMODULE hModule,LPCSTR lpProcName); */
928   lpfnDllFunc1=(LPFNDLLFUNC1) GetProcAddress(handle,name);
929   if (!lpfnDllFunc1)
930     return((void *) NULL);
931   return((void *) lpfnDllFunc1);
932 }
933 #endif /* !defined(HasLTDL) */
934 
935 /*
936 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
937 %                                                                             %
938 %                                                                             %
939 %                                                                             %
940 +  N T m u n m a p                                                            %
941 %                                                                             %
942 %                                                                             %
943 %                                                                             %
944 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
945 %
946 %  Method NTmunmap emulates the POSIX munmap function.
947 %
948 %  The format of the NTmunmap method is:
949 %
950 %      int NTmunmap(void *map,size_t length)
951 %
952 %  A description of each parameter follows:
953 %
954 %    o status:  Method NTmunmap returns 0 on success; otherwise, it
955 %      returns -1 and sets errno to indicate the error.
956 %
957 %    o map: The address of the binary large object.
958 %
959 %    o length: The length of the binary large object.
960 %
961 %
962 */
NTmunmap(void * map,size_t length)963 MagickExport int NTmunmap(void *map,size_t length)
964 {
965   ARG_NOT_USED(length);
966 
967   if (!UnmapViewOfFile(map))
968     return(-1);
969   return(0);
970 }
971 
972 /*
973 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
974 %                                                                             %
975 %                                                                             %
976 %                                                                             %
977 %   N T E l a p s e d T i m e                                                 %
978 %                                                                             %
979 %                                                                             %
980 %                                                                             %
981 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
982 %
983 %  Method NTElapsedTime returns the elapsed time (in seconds) since the last
984 %  call to StartTimer().
985 %
986 %  The format of the ElapsedTime method is:
987 %
988 %      double NTElapsedTime(void)
989 %
990 %
991 */
NTElapsedTime(void)992 MagickExport double NTElapsedTime(void)
993 {
994   /*
995     See
996     https://msdn.microsoft.com/en-us/library/windows/desktop/ms644905%28v=vs.85%29.aspx
997     https://msdn.microsoft.com/en-us/library/windows/desktop/ms644904%28v=vs.85%29.aspx
998   */
999   static LARGE_INTEGER pFrequency = {0};
1000   LARGE_INTEGER CurrentTime;
1001 
1002   if (pFrequency.QuadPart == 0)
1003     if (QueryPerformanceFrequency(&pFrequency) == 0)
1004       pFrequency.QuadPart = 1;  /* Mark that the Performance counter is NOT supported. */
1005 
1006   if (pFrequency.QuadPart > 1)
1007     {
1008       QueryPerformanceCounter(&CurrentTime);
1009       return (double) CurrentTime.QuadPart / pFrequency.QuadPart;
1010     }
1011   else
1012     {
1013       union
1014       {
1015         FILETIME
1016         filetime;
1017 
1018         __int64
1019         filetime64;
1020       } elapsed_time;
1021 
1022       SYSTEMTIME
1023         system_time;
1024 
1025       GetSystemTime(&system_time);
1026       SystemTimeToFileTime(&system_time,&elapsed_time.filetime);
1027       return((double) 1.0e-7*elapsed_time.filetime64);
1028     }
1029 }
1030 
1031 /*
1032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1033 %                                                                             %
1034 %                                                                             %
1035 %                                                                             %
1036 +   N T E r r o r H a n d l e r                                               %
1037 %                                                                             %
1038 %                                                                             %
1039 %                                                                             %
1040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1041 %
1042 %  Method NTErrorHandler displays an error reason and then terminates
1043 %  the program.
1044 %
1045 %  The format of the NTErrorHandler method is:
1046 %
1047 %      void NTErrorHandler(const ExceptionType error,const char *reason,
1048 %        const char *description)
1049 %
1050 %  A description of each parameter follows:
1051 %
1052 %    o error: Specifies the numeric error category.
1053 %
1054 %    o reason: Specifies the reason to display before terminating the
1055 %      program.
1056 %
1057 %    o description: Specifies any description to the reason.
1058 %
1059 %
1060 */
NTErrorHandler(const ExceptionType error,const char * reason,const char * description)1061 MagickExport void NTErrorHandler(const ExceptionType error,const char *reason,
1062   const char *description)
1063 {
1064   char
1065     buffer[3*MaxTextExtent];
1066 
1067   ARG_NOT_USED(error);
1068 
1069   if (reason == (char *) NULL)
1070     {
1071       DestroyMagick();
1072       Exit(0);
1073     }
1074   if ((description != (char *) NULL) && errno)
1075     FormatString(buffer,"%.1024s: %.1024s (%.1024s) [%.1024s].\n",
1076       GetClientName(),reason,description,strerror(errno));
1077   else
1078     if (description != (char *) NULL)
1079       FormatString(buffer,"%.1024s: %.1024s (%.1024s).\n",
1080         GetClientName(),reason,description);
1081     else
1082       if (errno)
1083         FormatString(buffer,"%.1024s: %.1024s [%.1024s].\n",
1084           GetClientName(),reason,strerror(errno));
1085       else
1086         FormatString(buffer,"%.1024s: %.1024s.\n",GetClientName(),
1087           reason);
1088   (void) MessageBox(NULL,buffer,"GraphicsMagick Exception",MB_OK | MB_TASKMODAL |
1089     MB_SETFOREGROUND | MB_ICONEXCLAMATION);
1090   DestroyMagick();
1091   Exit(0);
1092 }
1093 
1094 /*
1095 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1096 %                                                                             %
1097 %                                                                             %
1098 %                                                                             %
1099 %   N T G e t E x e c u t i o n P a t h                                       %
1100 %                                                                             %
1101 %                                                                             %
1102 %                                                                             %
1103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1104 %
1105 %  Method NTGetExecutionPath returns the execution path of a program.
1106 %
1107 %  The format of the GetExecutionPath method is:
1108 %
1109 %      unsigned int NTGetExecutionPath(char *path)
1110 %
1111 %
1112 */
NTGetExecutionPath(char * path)1113 MagickExport MagickPassFail NTGetExecutionPath(char *path)
1114 {
1115   GetModuleFileName(0,path,MaxTextExtent);
1116   return(MagickPass);
1117 }
1118 
1119 /*
1120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1121 %                                                                             %
1122 %                                                                             %
1123 %                                                                             %
1124 %   N T G e t L a s t E r r o r                                               %
1125 %                                                                             %
1126 %                                                                             %
1127 %                                                                             %
1128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1129 %
1130 %   Method NTGetLastError returns the last error that occurred.
1131 %
1132 %  The format of the NTGetLastError method is:
1133 %
1134 %      char *NTGetLastError(void)
1135 %
1136 %  A description of each parameter follows:
1137 %
1138 */
NTGetLastError(void)1139 char *NTGetLastError(void)
1140 {
1141   char
1142     *reason;
1143 
1144   int
1145     status;
1146 
1147   LPVOID
1148     buffer;
1149 
1150   status=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1151     FORMAT_MESSAGE_FROM_SYSTEM,NULL,GetLastError(),
1152     MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR) &buffer,0,NULL);
1153   if (!status)
1154     reason=AllocateString("An unknown error occurred");
1155   else
1156     {
1157       reason=AllocateString((const char *)buffer);
1158       LocalFree(buffer);
1159     }
1160   return(reason);
1161 }
1162 
1163 /*
1164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1165 %                                                                             %
1166 %                                                                             %
1167 %                                                                             %
1168 %   N T G h o s t s c r i p t D L L                                           %
1169 %                                                                             %
1170 %                                                                             %
1171 %                                                                             %
1172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1173 %
1174 %   Method NTGhostscriptDLL obtains the path to the latest Ghostscript DLL.
1175 %   The method returns False if a value is not obtained.
1176 %
1177 %  The format of the NTGhostscriptDLL method is:
1178 %
1179 %      int NTGhostscriptDLL(char *path, int path_length)
1180 %
1181 %  A description of each parameter follows:
1182 %
1183 %    o path: Pointer to buffer in which to return result.
1184 %
1185 %    o path_length: Length of buffer
1186 %
1187 */
1188 /*
1189   Get a named registry value.
1190   Key = hkeyroot\\key, named value = name.
1191  */
1192 static int
NTGetRegistryValue(HKEY hkeyroot,const char * key,const char * name,char * ptr,int * plen)1193 NTGetRegistryValue(HKEY hkeyroot, const char *key, const char *name,
1194                    char *ptr, int *plen)
1195 {
1196   HKEY
1197     hkey;
1198 
1199   DWORD
1200     cbData,
1201     keytype;
1202 
1203   BYTE
1204     b,
1205     *bptr = (BYTE *)ptr;
1206 
1207   LONG
1208     rc;
1209 
1210   if (RegOpenKeyExA(hkeyroot, key, 0, KEY_READ, &hkey)
1211       == ERROR_SUCCESS)
1212     {
1213       keytype = REG_SZ;
1214       cbData = *plen;
1215       if (bptr == (BYTE *) NULL)
1216         bptr = &b;  /* Registry API won't return ERROR_MORE_DATA */
1217       /* if ptr is NULL */
1218       rc = RegQueryValueExA(hkey, (char *)name, 0, &keytype, bptr, &cbData);
1219       RegCloseKey(hkey);
1220       if (rc == ERROR_SUCCESS)
1221         {
1222           *plen = cbData;
1223           return 0;  /* found environment variable and copied it */
1224         }
1225       else
1226         if (rc == ERROR_MORE_DATA)
1227           {
1228             /* buffer wasn't large enough */
1229             *plen = cbData;
1230             return -1;
1231           }
1232     }
1233   return 1;  /* not found */
1234 }
1235 
1236 /*
1237   Find the latest version of Ghostscript installed on the system (if
1238   any).
1239 */
1240 static MagickPassFail
NTGhostscriptFind(const char ** gs_productfamily,int * gs_major_version,int * gs_minor_version)1241 NTGhostscriptFind(const char **gs_productfamily,
1242                   int *gs_major_version,
1243                   int *gs_minor_version)
1244 {
1245   /*
1246     These are the Ghostscript product versions we will search for.
1247   */
1248   const char *products[4] =
1249     {
1250       "GPL Ghostscript",
1251       "GNU Ghostscript",
1252       "AFPL Ghostscript",
1253       "Aladdin Ghostscript"
1254     };
1255 
1256   unsigned int
1257     product_index,
1258     whence;
1259 
1260   MagickPassFail
1261     status;
1262 
1263   status=MagickFail;
1264   *gs_productfamily=NULL;
1265 
1266   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1267                         "Searching for Ghostscript...");
1268 
1269   /* Minimum version of Ghostscript is 5.50 */
1270   *gs_major_version=5;
1271   *gs_minor_version=49;
1272   for(whence=0; whence<=1; whence++)
1273   {
1274     const HKEY hkeyroot = hkeys[whence].hkey;
1275     const char *KeyRootStr = hkeys[whence].name;
1276 
1277     for(product_index=0; product_index < sizeof(products)/sizeof(products[0]); ++product_index)
1278     {
1279       HKEY hkey;
1280       LONG winstatus;
1281 
1282       REGSAM
1283         open_key_mode;
1284 
1285       char
1286         key[MaxTextExtent],
1287         last_error_msg[MaxTextExtent];
1288 
1289       (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1290                             "  Searching for %s...",
1291                             products[product_index]);
1292       FormatString(key,"SOFTWARE\\%s",products[product_index]);
1293 
1294       /*
1295         long WINAPI RegOpenKeyEx(const HKEY hKey, const LPCTSTR
1296         lpSubKey, const DWORD ulOptions, const REGSAM samDesired,
1297         PHKEY phkResult)
1298       */
1299       open_key_mode=KEY_READ;
1300       if ((winstatus=RegOpenKeyExA(hkeyroot, key, 0, open_key_mode, &hkey))
1301           == ERROR_SUCCESS)
1302         {
1303           DWORD
1304             cbData;
1305 
1306           int
1307             n;
1308 
1309           (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1310                                 "    RegOpenKeyExA() opened "
1311                                 "\"%s\\%s\"",
1312                                 KeyRootStr, key);
1313           /* Now enumerate the keys */
1314           cbData = sizeof(key) / sizeof(char);
1315           n=0;
1316           /*
1317             LONG WINAPI RegEnumKeyEx(HKEY hKey, DWORD dwIndex, LPTSTR
1318             lpName, LPDWORD lpcName, LPDWORD lpReserved, LPTSTR
1319             lpClass, LPDWORD lpcClass, PFILETIME lpftLastWriteTime)
1320 
1321             Enumerates the subkeys of the specified open registry key.
1322 
1323             RegEnumKeyA is is provided only for compatibility with
1324             16-bit versions of Windows.
1325           */
1326           while ((winstatus=RegEnumKeyA(hkey, n, key, cbData)) == ERROR_SUCCESS)
1327             {
1328               int
1329                 major_version,
1330                 minor_version;
1331 
1332               (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1333                                     "      RegEnumKeyA enumerated \"%s\"",key);
1334               n++;
1335               major_version=0;
1336               minor_version=0;
1337               if (sscanf(key,"%d.%d",&major_version,&minor_version) != 2)
1338                 continue;
1339 
1340               (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1341                                     "      Found Ghostscript (%s) version %d.%02d",
1342                                     products[product_index],
1343                                     major_version,
1344                                     minor_version);
1345 
1346               if ((major_version > *gs_major_version) ||
1347                   ((major_version == *gs_major_version) &&
1348                    (minor_version > *gs_minor_version)))
1349                 {
1350                   *gs_productfamily=products[product_index];
1351                   *gs_major_version=major_version;
1352                   *gs_minor_version=minor_version;
1353                   status=MagickPass;
1354                 }
1355             }
1356           if (winstatus != ERROR_NO_MORE_ITEMS)
1357             {
1358               (void) NTstrerror_r(winstatus,last_error_msg,sizeof(last_error_msg));
1359               (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1360                                     "      RegEnumKeyA (%s)",
1361                                     last_error_msg);
1362             }
1363           /*
1364             LONG WINAPI RegCloseKey(HKEY hKey)
1365 
1366             Close the registry key.
1367           */
1368           winstatus=RegCloseKey(hkey);
1369         }
1370       else
1371         {
1372           /*
1373             If the function fails, the return value is a nonzero error
1374             code defined in Winerror.h. You can use the FormatMessage
1375             function with the FORMAT_MESSAGE_FROM_SYSTEM flag to get a
1376             generic description of the error.
1377            */
1378           (void) NTstrerror_r(winstatus,last_error_msg,sizeof(last_error_msg));
1379           (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1380                                 "    RegOpenKeyExA() failed to open "
1381                                 "\"%s\\%s\" (%s)", KeyRootStr,
1382                                 key,last_error_msg);
1383         }
1384     }
1385   }
1386 
1387   if (status != MagickFail)
1388     {
1389       (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1390                             "Selected Ghostscript (%s) version %d.%02d",
1391                             *gs_productfamily,*gs_major_version,
1392                             *gs_minor_version);
1393     }
1394   else
1395     {
1396       (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1397                             "Failed to find Ghostscript!");
1398       *gs_major_version=0;
1399       *gs_minor_version=0;
1400     }
1401 
1402   return status;
1403 }
1404 
1405 
1406 /*
1407   Obtain a string from the installed Ghostscript (if any).
1408 */
1409 static MagickPassFail
NTGhostscriptGetString(const char * name,char * ptr,const size_t len)1410 NTGhostscriptGetString(const char *name, char *ptr, const size_t len)
1411 {
1412   static const char
1413     *gs_productfamily=NULL;
1414 
1415   static int
1416     gs_major_version=0,
1417     gs_minor_version=0;
1418 
1419   unsigned int
1420     i;
1421 
1422   int
1423     length;
1424 
1425   char
1426     key[MaxTextExtent];
1427 
1428   ptr[0]='\0';
1429 
1430   if (NULL == gs_productfamily)
1431     (void) NTGhostscriptFind(&gs_productfamily,&gs_major_version,
1432                              &gs_minor_version);
1433 
1434   if (NULL == gs_productfamily)
1435     return MagickFail;
1436 
1437   FormatString(key,"SOFTWARE\\%s\\%d.%02d",gs_productfamily,
1438                gs_major_version, gs_minor_version);
1439 
1440   for (i=0; i < sizeof(hkeys)/sizeof(hkeys[0]); ++i)
1441     {
1442       length = (int) len;
1443       if (NTGetRegistryValue(hkeys[i].hkey, key, name, ptr, &length) == 0)
1444         {
1445           (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1446                                 "Registry: \"%s\\%s\\%s\"=\"%s\"",
1447                                 hkeys[i].name,key,name,ptr);
1448           return MagickPass;
1449         }
1450       else
1451         {
1452           (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1453                                 "Failed lookup: \"%s\\%s\\%s\"",
1454                                 hkeys[i].name,key,name);
1455         }
1456     }
1457 
1458   return MagickFail;
1459 }
1460 #if defined(HasGS)
1461 
1462 /*
1463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1464 %                                                                             %
1465 %                                                                             %
1466 %                                                                             %
1467 %   N T G h o s t s c r i p t D L L                                           %
1468 %                                                                             %
1469 %                                                                             %
1470 %                                                                             %
1471 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1472 %
1473 %   Method NTGhostscriptDLL obtains the path to the latest Ghostscript DLL.
1474 %   The method returns False if a value is not obtained.
1475 %
1476 %  The format of the NTGhostscriptDLL method is:
1477 %
1478 %      int NTGhostscriptDLL( char *path, int path_length)
1479 %
1480 %  A description of each parameter follows:
1481 %
1482 %    o path: Pointer to path buffer to update
1483 %
1484 %    o path_length: Allocation size of path buffer.
1485 %%
1486 */
NTGhostscriptDLL(char * path,int path_length)1487 MagickExport int NTGhostscriptDLL(char *path, int path_length)
1488 {
1489   static char
1490     cache[MaxTextExtent],
1491     *result=NULL;
1492 
1493   path[0]='\0';
1494 
1495   if (NULL == result)
1496     {
1497       const char
1498         *directory;
1499 
1500       directory=getenv("MAGICK_GHOSTSCRIPT_PATH");
1501       if (directory != (const char *) NULL)
1502         {
1503           FormatString(cache, "%.1024s%sgsdll%u.dll", directory,
1504             DirectorySeparator, (unsigned int) sizeof(directory)*8);
1505           if (IsAccessibleAndNotEmpty(cache))
1506             result=cache;
1507           else
1508             (void) LogMagickEvent(ConfigureEvent, GetMagickModule(),
1509               "Unable to find ghostscript library: \"%s\"", cache);
1510         }
1511       else if (NTGhostscriptGetString("GS_DLL", cache, sizeof(cache)))
1512         {
1513           result=cache;
1514         }
1515     }
1516 
1517   if (result)
1518     {
1519       (void) strlcpy(path, result, path_length);
1520       return TRUE;
1521     }
1522 
1523   return FALSE;
1524 }
1525 
1526 /*
1527 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1528 %                                                                             %
1529 %                                                                             %
1530 %                                                                             %
1531 %   N T G h o s t s c r i p t D L L V e c t o r s                             %
1532 %                                                                             %
1533 %                                                                             %
1534 %                                                                             %
1535 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1536 %
1537 %   Method NTGhostscriptDLLVectors returns a GhostscriptVectors structure
1538 %   containing function vectors to invoke Ghostscript DLL functions. A null
1539 %   pointer is returned if there is an error with loading the DLL or
1540 %   retrieving the function vectors.
1541 %
1542 %  The format of the NTGhostscriptDLLVectors method is:
1543 %
1544 %      const GhostscriptVectors *NTGhostscriptDLLVectors( void )
1545 %
1546 %%
1547 */
NTGhostscriptDLLVectors(void)1548 MagickExport const GhostscriptVectors *NTGhostscriptDLLVectors( void )
1549 {
1550   if (NTGhostscriptLoadDLL())
1551     return &gs_vectors;
1552 
1553   return (GhostscriptVectors*) NULL;
1554 }
1555 
1556 /*
1557 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1558 %                                                                             %
1559 %                                                                             %
1560 %                                                                             %
1561 %   N T G h o s t s c r i p t E X E                                           %
1562 %                                                                             %
1563 %                                                                             %
1564 %                                                                             %
1565 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1566 %
1567 %   Method NTGhostscriptEXE obtains the path to the latest Ghostscript
1568 %   executable.  The method returns TRUE if path is updated, otherwise
1569 %   FALSE.  When the full path value is not obtained, then the value
1570 %   "gswin32c.exe" or "gswin64c.exe" is used.
1571 %
1572 %  The format of the NTGhostscriptEXE method is:
1573 %
1574 %      int NTGhostscriptEXE(char *path, int path_length)
1575 %
1576 %  A description of each parameter follows:
1577 %
1578 %    o path: Pointer to buffer in which to return result.
1579 %
1580 %    o path_length: Length of buffer
1581 %
1582 */
NTGhostscriptEXE(char * path,int path_length)1583 MagickExport int NTGhostscriptEXE(char *path, int path_length)
1584 {
1585   static char
1586     cache[MaxTextExtent],
1587     *result=NULL;
1588 
1589   if (NULL == result)
1590     {
1591       char
1592         gsexe[MaxTextExtent];
1593 
1594       char
1595         *p;
1596 
1597       /* Ensure a suitable default. */
1598       (void) FormatString(gsexe,"gswin%uc.exe",(unsigned int) sizeof(p)*8);
1599       (void) strlcpy(cache,gsexe,sizeof(cache));
1600 
1601       if (NTGhostscriptDLL(cache,sizeof(cache)))
1602         {
1603           p = strrchr(cache, '\\');
1604           if (p) {
1605             p++;
1606             *p = 0;
1607             (void) strlcat(cache,gsexe,sizeof(cache));
1608           }
1609         }
1610       result=cache;
1611     }
1612 
1613   if (result)
1614     {
1615       (void) strlcpy(path,result, path_length);
1616       return TRUE;
1617     }
1618 
1619   return FALSE;
1620 }
1621 #endif /* if defined(HasGS) */
1622 
1623 /*
1624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1625 %                                                                             %
1626 %                                                                             %
1627 %                                                                             %
1628 %   N T G h o s t s c r i p t F o n t s                                       %
1629 %                                                                             %
1630 %                                                                             %
1631 %                                                                             %
1632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1633 %
1634 %   Method NTGhostscriptFonts obtains the path to the Ghostscript fonts.
1635 %   The method returns False if a value is not obtained.
1636 %
1637 %  The format of the NTGhostscriptFonts method is:
1638 %
1639 %      int NTGhostscriptFonts(char *path, int path_length)
1640 %
1641 %  A description of each parameter follows:
1642 %
1643 %    o path: Pointer to buffer in which to return result.
1644 %
1645 %    o path_length: Length of buffer
1646 %
1647 */
NTGhostscriptFonts(char * path,int path_length)1648 MagickExport int NTGhostscriptFonts(char *path, int path_length)
1649 {
1650   char
1651     gs_lib_path[MaxTextExtent];
1652 
1653   path[0]='\0';
1654 
1655   if (!NTGhostscriptGetString("GS_LIB", gs_lib_path,sizeof(gs_lib_path)))
1656     return FALSE;
1657 
1658   /*
1659     The format of the GS_LIB string is a path similar to
1660 
1661     "C:\Program Files\gs\gs9.10\bin;C:\Program Files\gs\gs9.10\lib;C:\Program Files\gs\gs9.10\fonts"
1662 
1663     Ghostscript 7.0X does not include the Resource entry.
1664 
1665     Search path used by GPL Ghostscript 9.10 (2013-08-30):
1666     C:\Program Files\gs\gs9.10\bin ; C:\Program Files\gs\gs9.10\lib ;
1667     C:\Program Files\gs\gs9.10\fonts ; %rom%Resource/Init/ ; %rom%lib/ ;
1668     c:/gs/gs9.10/Resource/Init ; c:/gs/gs9.10/lib ;
1669     c:/gs/gs9.10/Resource/Font ; c:/gs/fonts
1670 
1671   */
1672   {
1673 #define URW_FONT_HELVETICA_FILE "n019003l.pfb"
1674     const char
1675       *end = NULL,
1676       *start = gs_lib_path;
1677 
1678     end = start+strlen(start);
1679     while ( start < end )
1680       {
1681         char
1682           font_dir_file[MaxTextExtent];
1683 
1684         const char
1685           *separator;
1686 
1687         int
1688           length;
1689 
1690         separator = strchr(start,DirectoryListSeparator);
1691         if (separator)
1692           length=separator-start;
1693         else
1694           length=end-start;
1695         length = Min(length+1,MaxTextExtent);
1696 
1697         (void) strlcpy(font_dir_file,start,length);
1698         (void) strlcat(font_dir_file,DirectorySeparator,MaxTextExtent);
1699         (void) strlcat(font_dir_file,URW_FONT_HELVETICA_FILE,MaxTextExtent);
1700         if (IsAccessible(font_dir_file))
1701           {
1702             (void) strlcpy(path, start, Min(length,path_length));
1703             (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1704                                   "Ghostscript fonts in directory \"%s\"",
1705                                   path);
1706             return TRUE;
1707           }
1708         start += length;
1709       }
1710 
1711 
1712     // Second scan will try to get common fonts for all gs versions.
1713     start = gs_lib_path;
1714     end = start + strlen(start);
1715     while ( start < end )
1716       {
1717         char
1718           font_dir_file[MaxTextExtent];
1719 
1720         const char
1721           *separator, *gsdir;
1722 
1723         int
1724           length;
1725 
1726         separator = strchr(start,DirectoryListSeparator);
1727         gsdir = strstr(start,"/gs/gs");
1728         if (gsdir==NULL) gsdir = strstr(start,"\\gs\\gs");
1729         if (gsdir!=NULL && (separator==NULL || gsdir<separator))
1730           {
1731             length = Min((gsdir-start)+5,MaxTextExtent);
1732             (void) strlcpy(font_dir_file,start,length);
1733             (void) strlcat(font_dir_file,"fonts",MaxTextExtent);
1734             (void) strlcat(font_dir_file,DirectorySeparator,MaxTextExtent);
1735             (void) strlcat(font_dir_file,URW_FONT_HELVETICA_FILE,MaxTextExtent);
1736             if (IsAccessible(font_dir_file))
1737               {
1738                 (void) strlcpy(path,font_dir_file,Min(length+5,path_length));  // str size "fonts" is 5.
1739                 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1740                                       "Ghostscript common fonts in directory \"%s\"",
1741                                       path);
1742                 return TRUE;
1743               }
1744           }
1745 
1746         if (separator==NULL) break;
1747         start = separator + 1;
1748       }
1749   }
1750 
1751   {
1752     /*
1753       Check "c:/gs/fonts" since Ghostscript also looks there.  This
1754       may be a more convenient place to put fonts since it would be
1755       used by every Ghostscript installation on the system.
1756 
1757       This part of the path to check is hard-coded in the Ghostscript
1758       binary via AROOTDIR=c:/gs in base/msvclib.mak and it is highly
1759       unlikely that Windows users will use a Ghostscript built with a
1760       different GS_LIB_DEFAULT (which includes AROOTDIR) definition.
1761     */
1762 
1763     const char
1764       gs_font_dir[] = "c:\\gs\\fonts";
1765 
1766     char
1767       font_dir_file[MaxTextExtent];
1768 
1769     (void) strlcpy(font_dir_file,gs_font_dir,MaxTextExtent);
1770     (void) strlcat(font_dir_file,DirectorySeparator,MaxTextExtent);
1771     (void) strlcat(font_dir_file,URW_FONT_HELVETICA_FILE,MaxTextExtent);
1772     if (IsAccessible(font_dir_file))
1773       {
1774         (void) strlcpy(path,gs_font_dir,path_length);
1775         (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1776                               "Ghostscript fonts in directory \"%s\"",
1777                               path);
1778         return TRUE;
1779       }
1780   }
1781 
1782   return FALSE;
1783 }
1784 #if defined(HasGS)
1785 
1786 /*
1787 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1788 %                                                                             %
1789 %                                                                             %
1790 %                                                                             %
1791 %   N T G h o s t s c r i p t L o a d D L L                                   %
1792 %                                                                             %
1793 %                                                                             %
1794 %                                                                             %
1795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1796 %
1797 %   Method NTGhostscriptLoadDLL attempts to load the Ghostscript DLL
1798 %   and returns True if it succeeds.
1799 %
1800 %  The format of the NTGhostscriptLoadDLL method is:
1801 %
1802 %      int NTGhostscriptLoadDLL(void)
1803 %
1804 %%
1805 */
NTGhostscriptLoadDLL(void)1806 MagickExport int NTGhostscriptLoadDLL(void)
1807 {
1808   char
1809     dll_path[MaxTextExtent];
1810 
1811   if (gs_dll_handle != (void *) NULL)
1812     return True;
1813 
1814   if (!NTGhostscriptDLL(dll_path,sizeof(dll_path)))
1815     return False;
1816 
1817   gs_dll_handle = lt_dlopen(dll_path);
1818   if (gs_dll_handle == (void *) NULL)
1819     return False;
1820 
1821   memset((void*)&gs_vectors, 0, sizeof(GhostscriptVectors));
1822 
1823   gs_vectors.exit=(int (MagickDLLCall *)(gs_main_instance*))
1824     lt_dlsym(gs_dll_handle,"gsapi_exit");
1825   gs_vectors.init_with_args=(int (MagickDLLCall *)(gs_main_instance *, int, char **))
1826     (lt_dlsym(gs_dll_handle,"gsapi_init_with_args"));
1827   gs_vectors.new_instance=(int (MagickDLLCall *)(gs_main_instance **, void *))
1828     (lt_dlsym(gs_dll_handle,"gsapi_new_instance"));
1829   gs_vectors.run_string=(int (MagickDLLCall *)(gs_main_instance *, const char *, int, int *))
1830     (lt_dlsym(gs_dll_handle,"gsapi_run_string"));
1831   gs_vectors.delete_instance=(void (MagickDLLCall *)(gs_main_instance *))
1832     (lt_dlsym(gs_dll_handle,"gsapi_delete_instance"));
1833 
1834   if ((gs_vectors.exit==NULL) ||
1835       (gs_vectors.init_with_args==NULL) ||
1836       (gs_vectors.new_instance==NULL) ||
1837       (gs_vectors.run_string==NULL) ||
1838       (gs_vectors.delete_instance==NULL))
1839     return False;
1840 
1841   return True;
1842 }
1843 
1844 /*
1845 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1846 %                                                                             %
1847 %                                                                             %
1848 %                                                                             %
1849 %   N T G h o s t s c r i p t U n L o a d D L L                               %
1850 %                                                                             %
1851 %                                                                             %
1852 %                                                                             %
1853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1854 %
1855 %   Method NTGhostscriptUnLoadDLL unloads the Ghostscript DLL if it is loaded.
1856 %
1857 %  The format of the NTGhostscriptUnLoadDLL method is:
1858 %
1859 %      int NTGhostscriptUnLoadDLL(void)
1860 %
1861 %%
1862 */
NTGhostscriptUnLoadDLL(void)1863 MagickExport int NTGhostscriptUnLoadDLL(void)
1864 {
1865   if (gs_dll_handle != (void *) NULL)
1866     {
1867       lt_dlclose(gs_dll_handle);
1868       gs_dll_handle=(void *) NULL;
1869       memset((void*)&gs_vectors, 0, sizeof(GhostscriptVectors));
1870       return True;
1871     }
1872 
1873   return False;
1874 }
1875 #endif /* if defined(HasGS) */
1876 
1877 /*
1878 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1879 %                                                                             %
1880 %                                                                             %
1881 %                                                                             %
1882 %   N T K e r n e l A P I S u p p o r t e d                                   %
1883 %                                                                             %
1884 %                                                                             %
1885 %                                                                             %
1886 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1887 %
1888 %  Method NTKernelAPISupported tests to see if an API symbol is defined in
1889 %  kernel32.dll. If it is defined, then presumably the interface can safely
1890 %  be used without crashing.
1891 %
1892 %  The format of the NTKernelAPISupported method is:
1893 %
1894 %      MagickBool NTKernelAPISupported(const char *name)
1895 %
1896 %  A description of each parameter follows:
1897 %
1898 %    o return: MagickTrue if the symbol is defined, otherwise MagickFalse.
1899 %
1900 %    o name: Symbol name.
1901 %
1902 */
NTKernelAPISupported(const char * name)1903 MagickExport MagickBool NTKernelAPISupported(const char *name)
1904 {
1905   return (GetProcAddress(GetModuleHandle("kernel32.dll"),name) == NULL ?
1906           MagickFalse : MagickTrue);
1907 }
1908 
1909 /*
1910 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1911 %                                                                             %
1912 %                                                                             %
1913 %                                                                             %
1914 %   N T R e g i s t r y K e y L o o k u p                                     %
1915 %                                                                             %
1916 %                                                                             %
1917 %                                                                             %
1918 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1919 %
1920 %  Method NTRegistryKeyLookup returns package installation path settings
1921 %  stored in the Windows Registry. Path settings are specific to the
1922 %  installed package version so that multiple package installations may
1923 %  coexist.
1924 %
1925 %  Values are stored in the registry under a base path path similar to
1926 %  "HKEY_LOCAL_MACHINE/SOFTWARE\GraphicsMagick\1.0\Q:8". The provided subkey
1927 %  is appended to this base path to form the full key.
1928 %
1929 %  The format of the NTRegistryKeyLookup method is:
1930 %
1931 %      char *NTRegistryKeyLookup(const char *subkey)
1932 %
1933 %  A description of each parameter follows:
1934 %
1935 %    o return: Returns an allocated string containing the value of the key.
1936 %           This allocation should be freed by the user once it is no longer
1937 %           needed.
1938 %
1939 %    o key: Specifies a string that identifies the registry object.
1940 %           Currently supported sub-keys include: "BinPath", "ConfigurePath",
1941 %           "LibPath", "CoderModulesPath", "FilterModulesPath", "SharePath".
1942 %
1943 */
NTRegistryKeyLookup(const char * subkey)1944 MagickExport unsigned char *NTRegistryKeyLookup(const char *subkey)
1945 {
1946   static HKEY
1947     reg_key = (HKEY) INVALID_HANDLE_VALUE;
1948 
1949   /*
1950     Look-up base-key for first access only
1951   */
1952   if (reg_key == (HKEY) INVALID_HANDLE_VALUE)
1953     {
1954       char
1955         package_key[MaxTextExtent];
1956 
1957       LONG
1958         res;
1959 
1960       FormatString(package_key,"SOFTWARE\\%s\\%s\\Q:%d", MagickPackageName,
1961                    MagickLibVersionText,QuantumDepth);
1962 
1963       res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, package_key, 0, KEY_READ,
1964                            &reg_key);
1965 
1966       if (res != ERROR_SUCCESS)
1967         {
1968           reg_key = (HKEY) INVALID_HANDLE_VALUE;
1969           return 0;
1970         }
1971     }
1972 
1973   /*
1974     Look-up sub-key
1975   */
1976   {
1977     unsigned char
1978       *dest;
1979 
1980     DWORD
1981       size,
1982       type;
1983 
1984     LONG
1985       res;
1986 
1987     size = 32;
1988     dest = MagickAllocateMemory(unsigned char *,size);
1989 
1990     if (dest != (unsigned char *) NULL)
1991       {
1992         res = RegQueryValueExA (reg_key, subkey, 0, &type, dest, &size);
1993         if (res == ERROR_MORE_DATA && type == REG_SZ)
1994           {
1995             MagickReallocMemory(unsigned char *,dest,size);
1996             res = RegQueryValueExA (reg_key, subkey, 0, &type, dest, &size);
1997           }
1998 
1999         if (type != REG_SZ || res != ERROR_SUCCESS)
2000           {
2001             MagickFreeMemory(dest);
2002           }
2003       }
2004 
2005     return dest;
2006   }
2007 }
2008 
2009 /*
2010 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2011 %                                                                             %
2012 %                                                                             %
2013 %                                                                             %
2014 %   N T R e s o u r c e T o B l o b                                           %
2015 %                                                                             %
2016 %                                                                             %
2017 %                                                                             %
2018 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2019 %
2020 %  Method NTResourceToBlob returns a blob containing the contents of the
2021 %  resource in the current executable specified by the id parameter. This
2022 %  is currently used to retrieve MGK files tha have been embedded into
2023 %  the various command line utilities.
2024 %
2025 %  The format of the telldir method is:
2026 %
2027 %      unsigned char *NTResourceToBlob(const char *id)
2028 %
2029 %  A description of each parameter follows:
2030 %
2031 %    o id: Specifies a string that identifies the resource.
2032 %
2033 %
2034 */
NTResourceToBlob(const char * id)2035 MagickExport unsigned char *NTResourceToBlob(const char *id)
2036 {
2037   char
2038     directory[MaxTextExtent];
2039 
2040   DWORD
2041     length;
2042 
2043   HGLOBAL
2044     global;
2045 
2046   HMODULE
2047     handle;
2048 
2049   HRSRC
2050     resource;
2051 
2052   unsigned char
2053     *blob,
2054     *value;
2055 
2056   assert(id != (const char *) NULL);
2057 #ifdef MagickLibName
2058   handle=GetModuleHandle(MagickLibName);
2059 #else
2060   FormatString(directory,"%.1024s%.1024s%.1024s",GetClientPath(),
2061     DirectorySeparator,GetClientFilename());
2062   if (IsAccessible(directory))
2063     handle=GetModuleHandle(directory);
2064   else
2065     handle=GetModuleHandle(0);
2066 #endif
2067   if (!handle)
2068     return((unsigned char *) NULL);
2069   /*
2070     Locate a resource matching the specified type and name in the
2071     specified module.
2072   */
2073   resource=FindResource(handle,id,"IMAGEMAGICK");
2074   if (!resource)
2075   {
2076     (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
2077       "Tried: windows resource \"%.1024s\"",id);
2078     return((unsigned char *) NULL);
2079   }
2080   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
2081     "Found: windows resource \"%.1024s\"",id);
2082   /*
2083     Load resource into global memory (in WIN32, resources are already
2084     in memory).
2085   */
2086   global=LoadResource(handle,resource);
2087   if (!global)
2088     return((unsigned char *) NULL);
2089   /*
2090     Obtain the size (in bytes) of the specified resource.
2091   */
2092   length=SizeofResource(handle,resource);
2093   /*
2094     Lock the resource in memory (really just dereferences an object
2095     permanently in memory).
2096   */
2097   value=(unsigned char *) LockResource(global);
2098   if (!value)
2099     {
2100       return((unsigned char *) NULL);
2101     }
2102   blob=MagickAllocateMemory(unsigned char *,(size_t) length+1);
2103   if (blob != (unsigned char *) NULL)
2104     {
2105       (void) memcpy(blob,value,length);
2106       blob[length]='\0';
2107     }
2108   return(blob);
2109 }
2110 
2111 /*
2112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2113 %                                                                             %
2114 %                                                                             %
2115 %                                                                             %
2116 +   N T s t r e r r o r _ r                                                   %
2117 %                                                                             %
2118 %                                                                             %
2119 %                                                                             %
2120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2121 %
2122 %   Method NTstrerror_r formats a returned Windows error code into a
2123 %   message string in a thread-safe manner.  MagickFail is returned if a
2124 %   message could not be found corresponding to the error code, otherwise
2125 %   MagickPass is returned.
2126 %
2127 %  The format of the NTstrerror_r method is:
2128 %
2129 %      MagickPassFail NTstrerror_r(LONG errnum, char *strerrbuf, size_t  buflen)
2130 %
2131 %  A description of each parameter follows:
2132 %
2133 %    o errnum: Windows error number
2134 %
2135 %    o strerrbuf: A buffer in which to write the message.
2136 %
2137 %    o buflen: The allocation length of the buffer.
2138 %
2139 */
2140 static MagickPassFail
NTstrerror_r(LONG errnum,char * strerrbuf,size_t buflen)2141 NTstrerror_r(LONG errnum, char *strerrbuf, size_t  buflen)
2142 {
2143   MagickPassFail
2144     status;
2145 
2146   LPVOID
2147     buffer;
2148 
2149   status=MagickFail;
2150   if (buflen > 0)
2151     strerrbuf[0]='\0';
2152   if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
2153                     FORMAT_MESSAGE_FROM_SYSTEM,NULL,errnum,
2154                     MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
2155                     (LPTSTR) &buffer,0,NULL))
2156     {
2157       if (strlcpy(strerrbuf,buffer,buflen) < buflen)
2158         {
2159           size_t
2160             index;
2161 
2162           for (index=0; strerrbuf[index] != 0; index++)
2163             if (strerrbuf[index] == '\015')
2164               strerrbuf[index]='\0';
2165           status=MagickPass;
2166         }
2167       LocalFree(buffer);
2168     }
2169   return status;
2170 }
2171 
2172 /*
2173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2174 %                                                                             %
2175 %                                                                             %
2176 %                                                                             %
2177 %   N T S y s t e m C o m m a n d                                             %
2178 %                                                                             %
2179 %                                                                             %
2180 %                                                                             %
2181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2182 %
2183 %   Method NTSystemComman executes the specified command and waits until it
2184 %   terminates.  The returned value is the exit status of the command.
2185 %
2186 %  The format of the NTSystemComman method is:
2187 %
2188 %      int NTSystemComman(const char *command)
2189 %
2190 %  A description of each parameter follows:
2191 %
2192 %    o command: This string is the command to execute.
2193 %
2194 %
2195 */
NTSystemComman(const char * command)2196 MagickExport int NTSystemComman(const char *command)
2197 {
2198   char
2199     local_command[MaxTextExtent];
2200 
2201   DWORD
2202     child_status;
2203 
2204   int
2205     status;
2206 
2207   PROCESS_INFORMATION
2208     process_info;
2209 
2210   STARTUPINFO
2211     startup_info;
2212 
2213   unsigned int
2214     background_process;
2215 
2216   if (command == (char *) NULL)
2217     return(-1);
2218   GetStartupInfo(&startup_info);
2219   startup_info.dwFlags=STARTF_USESHOWWINDOW;
2220   startup_info.wShowWindow=SW_SHOWMINNOACTIVE;
2221   (void) strlcpy(local_command,command,MaxTextExtent);
2222   background_process=command[strlen(command)-1] == '&';
2223   if (background_process)
2224     local_command[strlen(command)-1]='\0';
2225   if (command[strlen(command)-1] == '|')
2226      local_command[strlen(command)-1]='\0';
2227    else
2228      startup_info.wShowWindow=SW_SHOWDEFAULT;
2229   status=CreateProcess((LPCTSTR) NULL,local_command,
2230     (LPSECURITY_ATTRIBUTES) NULL,(LPSECURITY_ATTRIBUTES) NULL,(BOOL) FALSE,
2231     (DWORD) NORMAL_PRIORITY_CLASS,(LPVOID) NULL,(LPCSTR) NULL,&startup_info,
2232     &process_info);
2233   if (status == 0)
2234     return(-1);
2235   if (background_process)
2236     return(status == 0);
2237 
2238 #if 1
2239   // This code has been used for years, but supposedly may
2240   // cause problems in GUIs.
2241   status=WaitForSingleObject(process_info.hProcess,INFINITE);
2242   if (status != WAIT_OBJECT_0)
2243     return (status);
2244 #else
2245   // Following code doesn't work correctly yet
2246   while(1)
2247   {
2248     // Wait for state change or message received
2249     DWORD result=MsgWaitForMultipleObjects(1, &process_info.hProcess, FALSE,
2250       INFINITE, QS_ALLEVENTS);
2251     // Loop if return was due to message received (which we don't care about).
2252     if (result == (WAIT_OBJECT_0+1))
2253       continue;
2254     // If return was due to handle state change, then object is available.
2255     if ((result - WAIT_OBJECT_0) == 0)
2256       break;
2257    }
2258 #endif
2259 
2260   status=GetExitCodeProcess(process_info.hProcess,&child_status);
2261   if (status == 0)
2262     return(-1);
2263   CloseHandle(process_info.hProcess);
2264   CloseHandle(process_info.hThread);
2265   return((int) child_status);
2266 }
2267 
2268 /*
2269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2270 %                                                                             %
2271 %                                                                             %
2272 %                                                                             %
2273 %   N T U s e r T i m e                                                       %
2274 %                                                                             %
2275 %                                                                             %
2276 %                                                                             %
2277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2278 %
2279 %  Method NTUserTime returns the total time the process has been scheduled (i
2280 %  seconds) since the last call to StartTimer().
2281 %
2282 %  The format of the UserTime method is:
2283 %
2284 %      double NTUserTime(void)
2285 %
2286 %
2287 */
NTUserTime(void)2288 MagickExport double NTUserTime(void)
2289 {
2290   DWORD
2291     status;
2292 
2293   FILETIME
2294     create_time,
2295     exit_time;
2296 
2297   OSVERSIONINFO
2298     OsVersionInfo;
2299 
2300   union
2301   {
2302     FILETIME
2303       filetime;
2304 
2305     __int64
2306       filetime64;
2307   } kernel_time;
2308 
2309   union
2310   {
2311     FILETIME
2312       filetime;
2313 
2314     __int64
2315       filetime64;
2316   } user_time;
2317 
2318   OsVersionInfo.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
2319   GetVersionEx(&OsVersionInfo);
2320   if (OsVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)
2321     return(NTElapsedTime());
2322   status=GetProcessTimes(GetCurrentProcess(),&create_time,&exit_time,
2323     &kernel_time.filetime,&user_time.filetime);
2324   if (status != TRUE)
2325     return(0.0);
2326   return((double) 1.0e-7*(kernel_time.filetime64+user_time.filetime64));
2327 }
2328 
2329 /*
2330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2331 %                                                                             %
2332 %                                                                             %
2333 %                                                                             %
2334 %   N T W a r n i n g H a n d l e r                                           %
2335 %                                                                             %
2336 %                                                                             %
2337 %                                                                             %
2338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2339 %
2340 %  Method NTWarningHandler displays a warning reason.
2341 %
2342 %  The format of the NTWarningHandler method is:
2343 %
2344 %      void NTWarningHandler(const ExceptionType warning,const char *reason,
2345 %        const char *description)
2346 %
2347 %  A description of each parameter follows:
2348 %
2349 %    o warning: Specifies the numeric warning category.
2350 %
2351 %    o reason: Specifies the reason to display before terminating the
2352 %      program.
2353 %
2354 %    o description: Specifies any description to the reason.
2355 %
2356 %
2357 */
NTWarningHandler(const ExceptionType warning,const char * reason,const char * description)2358 MagickExport void NTWarningHandler(const ExceptionType warning,
2359   const char *reason,const char *description)
2360 {
2361   char
2362     buffer[2*MaxTextExtent];
2363 
2364   ARG_NOT_USED(warning);
2365 
2366   if (reason == (char *) NULL)
2367     return;
2368   if (description == (char *) NULL)
2369     FormatString(buffer,"%.1024s: %.1024s.\n",
2370       GetClientName(),reason);
2371   else
2372     FormatString(buffer,"%.1024s: %.1024s (%.1024s).\n",
2373       GetClientName(),reason,description);
2374   (void) MessageBox(NULL,buffer,"GraphicsMagick Warning",MB_OK | MB_TASKMODAL |
2375     MB_SETFOREGROUND | MB_ICONINFORMATION);
2376 }
2377 
2378 /*
2379 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2380 %                                                                             %
2381 %                                                                             %
2382 %                                                                             %
2383 %   N T f t r u n c a t e                                                     %
2384 %                                                                             %
2385 %                                                                             %
2386 %                                                                             %
2387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2388 %
2389 %  Method NTftruncate truncates a file to the specified size.  If the file is
2390 %  longer than the specified size, it is shortened to the specified size. If
2391 %  the file is shorter than the specified size, it is extended to the
2392 %  specified size by filling with zeros.
2393 %  This is a POSIX compatability function.
2394 %
2395 %  The format of the NTftruncate method is:
2396 %
2397 %      int NTftruncate(int filedes, off_t length)
2398 %
2399 %  A description of each parameter follows:
2400 %
2401 %    o status: Zero is returned on successful completion. Otherwise -1
2402 %        is returned and errno is set to indicate the error.
2403 %
2404 %    o filedes: File descriptor from the _open() call.
2405 %
2406 %    o length: Desired file length.
2407 %
2408 */
NTftruncate(int filedes,off_t length)2409 MagickExport int NTftruncate(int filedes, off_t length)
2410 {
2411   int
2412     status;
2413 
2414   magick_off_t
2415     current_pos;
2416 
2417   status=0;
2418   current_pos=MagickTell(filedes);
2419 
2420   /*
2421     Truncate file to size, filling any extension with nulls.
2422     Notice that this interface is limited to 2GB due to its
2423     use of a 'long' offset. Ftruncate also has this shortcoming
2424     if off_t is a 'long'.
2425 
2426     A way to support more than 2GB is to use SetFilePointerEx()
2427     to set the file position followed by SetEndOfFile() to set
2428     the file EOF to the current file position. This approach does
2429     not ensure that bytes in the extended portion are null.
2430 
2431     The CreateFileMapping() function may also be used to extend a
2432     file's length. The filler byte values are not defined in the
2433     documentation.
2434   */
2435   status=chsize(filedes,length);
2436 
2437   /*
2438     It is not documented if _chsize preserves the seek
2439     position, so restore the seek position like ftruncate
2440     does
2441   */
2442   if (!status)
2443     status=MagickSeek(filedes,current_pos,SEEK_SET);
2444   return(status);
2445 }
2446 
2447 /*
2448 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2449 %                                                                             %
2450 %                                                                             %
2451 %                                                                             %
2452 +  N T m m a p                                                                %
2453 %                                                                             %
2454 %                                                                             %
2455 %                                                                             %
2456 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2457 %
2458 %  Method NTmmap emulates POSIX mmap. Supports PROT_READ, PROT_WRITE
2459 %  protection options, and MAP_SHARED, MAP_PRIVATE, MAP_ANON flags.
2460 %  Passing a file descriptor of -1 along with the MAP_ANON flag option returns
2461 %  a memory allocation from the system page file with the specified allocated
2462 %  length.
2463 %
2464 %  The format of the NTmmap method is:
2465 %
2466 %    MagickExport void *NTmmap(char *address, size_t length, int protection,
2467 %      int flags, int file, magick_off_t offset)
2468 %
2469 %
2470 */
NTmmap(char * address,size_t length,int protection,int flags,int file,magick_off_t offset)2471 MagickExport void *NTmmap(char *address,size_t length,int protection,int flags,
2472   int file,magick_off_t offset)
2473 {
2474   void
2475     *map;
2476 
2477   HANDLE
2478     file_handle,
2479     shmem_handle;
2480 
2481   DWORD
2482     length_low,
2483     length_high,
2484     offset_low,
2485     offset_high;
2486 
2487   DWORD
2488     access_mode=0,
2489     protection_mode=0;
2490 
2491   ARG_NOT_USED(address);
2492 
2493   map=(void *) NULL;
2494   shmem_handle=INVALID_HANDLE_VALUE;
2495   file_handle=INVALID_HANDLE_VALUE;
2496 
2497   offset_low=(DWORD) (offset & 0xFFFFFFFFUL);
2498   offset_high=(DWORD) ((offset >> 32) & 0xFFFFFFFFUL);
2499 
2500   length_low=(DWORD) (length & 0xFFFFFFFFUL);
2501   length_high=(DWORD) ((((magick_off_t) length) >> 32) & 0xFFFFFFFFUL);
2502 
2503   if (protection & PROT_WRITE)
2504     {
2505       access_mode=FILE_MAP_WRITE;
2506       if (flags & MAP_PRIVATE)
2507         {
2508           // Copy on write (updates are private)
2509           access_mode=FILE_MAP_COPY;
2510           protection_mode=PAGE_WRITECOPY;
2511         }
2512       else
2513         {
2514           // Updates are shared
2515           protection_mode=PAGE_READWRITE;
2516         }
2517     }
2518   else if (protection & PROT_READ)
2519     {
2520       access_mode=FILE_MAP_READ;
2521       protection_mode=PAGE_READONLY;
2522     }
2523 
2524   if ((file == -1) && (flags & MAP_ANON))
2525     // Similar to using mmap on /dev/zero to allocate memory from paging area.
2526     file_handle=INVALID_HANDLE_VALUE;
2527   else
2528     file_handle=(HANDLE) _get_osfhandle(file);
2529 
2530   shmem_handle=CreateFileMapping(file_handle,0,protection_mode,length_high,
2531                                  length_low,0);
2532   if (shmem_handle)
2533     {
2534       map=(void *) MapViewOfFile(shmem_handle,access_mode,offset_high,
2535                                  offset_low,length);
2536       CloseHandle(shmem_handle);
2537     }
2538 
2539   if (map == (void *) NULL)
2540     return((void *) MAP_FAILED);
2541   return((void *) ((char *) map));
2542 }
2543 
2544 /*
2545 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2546 %                                                                             %
2547 %                                                                             %
2548 %                                                                             %
2549 +  N T m s y n c                                                              %
2550 %                                                                             %
2551 %                                                                             %
2552 %                                                                             %
2553 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2554 %
2555 %  Method NTmsync emulates the Unix msync function except that the flags
2556 %  argument is ignored. Windows page sync behaves mostly like MS_SYNC
2557 %  except that if the file is accessed over a network, the updates are not
2558 %  fully synchronous unless a special flag is provided when the file is
2559 %  opened.  It is not clear if flushing a range invalidates copy pages
2560 %  like Unix msync does.
2561 %
2562 %  The format of the NTmsync method is:
2563 %
2564 %      int NTmsync(void *addr, size_t len, int flags)
2565 %
2566 %  A description of each parameter follows:
2567 %
2568 %    o status:  Method NTmsync returns 0 on success; otherwise, it
2569 %      returns -1 and sets errno to indicate the error.
2570 %
2571 %    o addr: The address of the binary large object.
2572 %
2573 %    o len: The length of the binary large object.
2574 %
2575 %    o flags: Option flags (ignored for Windows)
2576 %
2577 %
2578 */
NTmsync(void * addr,size_t len,int flags)2579 MagickExport int NTmsync(void *addr, size_t len, int flags)
2580 {
2581   ARG_NOT_USED(flags);
2582   if (!FlushViewOfFile(addr,len))
2583     return(-1);
2584   return(0);
2585 }
2586 
2587 /*
2588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2589 %                                                                             %
2590 %                                                                             %
2591 %                                                                             %
2592 %   N T o p e n d i r                                                         %
2593 %                                                                             %
2594 %                                                                             %
2595 %                                                                             %
2596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2597 %
2598 %  Method NTopendir opens the directory named by filename and associates
2599 %  a directory stream with it.
2600 %
2601 %  The format of the opendir method is:
2602 %
2603 %      DIR *NTopendir(const char *path)
2604 %
2605 %  A description of each parameter follows:
2606 %
2607 %    o entry: Specifies a pointer to a DIR structure.
2608 %
2609 %
2610 */
NTopendir(const char * path)2611 MagickExport DIR *NTopendir(const char *path)
2612 {
2613   char
2614     file_specification[MaxTextExtent];
2615 
2616   DIR
2617     *entry;
2618 
2619   assert(path != (char *) NULL);
2620   if (strlcpy(file_specification,path,MaxTextExtent) >= MaxTextExtent)
2621     return (DIR *) NULL;;
2622   if (strlcat(file_specification,DirectorySeparator,MaxTextExtent) >= MaxTextExtent)
2623     return (DIR *) NULL;;
2624   entry=MagickAllocateMemory(DIR *,sizeof(DIR));
2625   if (entry != (DIR *) NULL)
2626     {
2627       entry->firsttime=TRUE;
2628       entry->hSearch=FindFirstFile(file_specification,&entry->Win32FindData);
2629     }
2630   if (entry->hSearch == INVALID_HANDLE_VALUE)
2631     {
2632       if (strlcat(file_specification,"\\*.*",MaxTextExtent) >= MaxTextExtent)
2633         {
2634           MagickFreeMemory(entry);
2635           return (DIR *) NULL;
2636         }
2637       entry->hSearch=FindFirstFile(file_specification,&entry->Win32FindData);
2638       if (entry->hSearch == INVALID_HANDLE_VALUE)
2639         {
2640           MagickFreeMemory(entry);
2641           return (DIR *) NULL;
2642         }
2643     }
2644   return(entry);
2645 }
2646 
2647 /*
2648 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2649 %                                                                             %
2650 %                                                                             %
2651 %                                                                             %
2652 %   N T r e a d d i r                                                         %
2653 %                                                                             %
2654 %                                                                             %
2655 %                                                                             %
2656 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2657 %
2658 %  Method NTreaddir returns a pointer to a structure representing the
2659 %  directory entry at the current position in the directory stream to
2660 %  which entry refers.
2661 %
2662 %  The format of the readdir
2663 %
2664 %      NTreaddir(entry)
2665 %
2666 %  A description of each parameter follows:
2667 %
2668 %    o entry: Specifies a pointer to a DIR structure.
2669 %
2670 %
2671 */
NTreaddir(DIR * entry)2672 MagickExport struct dirent *NTreaddir(DIR *entry)
2673 {
2674   int
2675     status;
2676 
2677   if (entry == (DIR *) NULL)
2678     return ((struct dirent *) NULL);
2679   if (!entry->firsttime)
2680     {
2681       status=FindNextFile(entry->hSearch,&entry->Win32FindData);
2682       if (status == 0)
2683         return ((struct dirent *) NULL);
2684     }
2685   if (strlcpy(entry->file_info.d_name,entry->Win32FindData.cFileName,
2686               sizeof(entry->file_info.d_name)) >=
2687       sizeof(entry->file_info.d_name))
2688     return ((struct dirent *) NULL);
2689   entry->firsttime=FALSE;
2690   entry->file_info.d_namlen=(int) strlen(entry->file_info.d_name);
2691   return (&entry->file_info);
2692 }
2693 
2694 /*
2695 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2696 %                                                                             %
2697 %                                                                             %
2698 %                                                                             %
2699 %   N T s e e k d i r                                                         %
2700 %                                                                             %
2701 %                                                                             %
2702 %                                                                             %
2703 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2704 %
2705 %   Method NTseekdir sets the position of the next NTreaddir() operation
2706 %   on the directory stream.
2707 %
2708 %  The format of the NTseekdir method is:
2709 %
2710 %      void NTseekdir(DIR *entry,long position)
2711 %
2712 %  A description of each parameter follows:
2713 %
2714 %    o entry: Specifies a pointer to a DIR structure.
2715 %
2716 %    o position: specifies the position associated with the directory
2717 %      stream.
2718 %
2719 %
2720 %
2721 */
NTseekdir(DIR * entry,long position)2722 MagickExport void NTseekdir(DIR *entry,long position)
2723 {
2724   ARG_NOT_USED(position);
2725   assert(entry != (DIR *) NULL);
2726 }
2727 
2728 /*
2729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2730 %                                                                             %
2731 %                                                                             %
2732 %                                                                             %
2733 %   N T t e l l d i r                                                         %
2734 %                                                                             %
2735 %                                                                             %
2736 %                                                                             %
2737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2738 %
2739 %   Method NTtelldir returns the current location associated  with  the
2740 %   named directory stream.
2741 %
2742 %  The format of the NTtelldir method is:
2743 %
2744 %      long NTtelldir(DIR *entry)
2745 %
2746 %  A description of each parameter follows:
2747 %
2748 %    o entry: Specifies a pointer to a DIR structure.
2749 %
2750 %
2751 */
NTtelldir(DIR * entry)2752 MagickExport long NTtelldir(DIR *entry)
2753 {
2754   assert(entry != (DIR *) NULL);
2755   return(0);
2756 }
2757 #endif
2758