MagickCore  7.1.2-29
Convert, Edit, Or Compose Bitmap Images
nt-base.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % N N TTTTT %
7 % NN N T %
8 % N N N T %
9 % N NN T %
10 % N N T %
11 % %
12 % %
13 % Windows NT Utility Methods for MagickCore %
14 % %
15 % Software Design %
16 % Cristy %
17 % December 1996 %
18 % %
19 % %
20 % Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/license/ %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 /*
39  Include declarations.
40 */
41 #include "MagickCore/studio.h"
42 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
43 #include "MagickCore/client.h"
44 #include "MagickCore/distribute-cache-private.h"
45 #include "MagickCore/exception-private.h"
46 #include "MagickCore/image-private.h"
47 #include "MagickCore/locale_.h"
48 #include "MagickCore/log.h"
49 #include "MagickCore/magick.h"
50 #include "MagickCore/memory_.h"
51 #include "MagickCore/memory-private.h"
52 #include "MagickCore/nt-base.h"
53 #include "MagickCore/nt-base-private.h"
54 #include "MagickCore/resource_.h"
55 #include "MagickCore/resource-private.h"
56 #include "MagickCore/timer.h"
57 #include "MagickCore/string_.h"
58 #include "MagickCore/string-private.h"
59 #include "MagickCore/utility.h"
60 #include "MagickCore/utility-private.h"
61 #include "MagickCore/version.h"
62 #if defined(MAGICKCORE_LTDL_DELEGATE)
63 # include "ltdl.h"
64 #endif
65 #if defined(MAGICKCORE_CIPHER_SUPPORT)
66 #include <ntsecapi.h>
67 #include <wincrypt.h>
68 #endif
69 ␌
70 /*
71  Define declarations.
72 */
73 #if !defined(MAP_FAILED)
74 #define MAP_FAILED ((void *)(LONG_PTR)-1)
75 #endif
76 #define MaxWideByteExtent 100
77 ␌
78 /*
79  Typedef declarations.
80 */
81 
82 /*
83  We need to make sure only one instance is created for each process and that
84  is why we wrap the new/delete instance methods.
85 
86  From: http://www.ghostscript.com/doc/current/API.htm
87  "The Win32 DLL gsdll32.dll can be used by multiple programs simultaneously,
88  but only once within each process"
89 */
90 typedef struct _NTGhostInfo
91 {
92  void
93  (MagickDLLCall *delete_instance)(gs_main_instance *);
94 
95  int
96  (MagickDLLCall *new_instance)(gs_main_instance **,void *);
97 
98  MagickBooleanType
99  has_instance;
100 } NTGhostInfo;
101 ␌
102 /*
103  Static declarations.
104 */
105 static NTGhostInfo
106  nt_ghost_info;
107 
108 static GhostInfo
109  ghost_info;
110 
111 static void
112  *ghost_handle = (void *) NULL;
113 
114 static SemaphoreInfo
115  *ghost_semaphore = (SemaphoreInfo *) NULL;
116 ␌
117 struct
118 {
119  const HKEY
120  hkey;
121 
122  const char
123  *name;
124 }
125 const registry_roots[2] =
126 {
127  { HKEY_CURRENT_USER, "HKEY_CURRENT_USER" },
128  { HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE" }
129 };
130 
131 /*
132  External declarations.
133 */
134 static void MagickDLLCall NTGhostscriptDeleteInstance(
135  gs_main_instance *instance)
136 {
137  LockSemaphoreInfo(ghost_semaphore);
138  nt_ghost_info.delete_instance(instance);
139  nt_ghost_info.has_instance=MagickFalse;
140  UnlockSemaphoreInfo(ghost_semaphore);
141 }
142 
143 static int MagickDLLCall NTGhostscriptNewInstance(gs_main_instance **pinstance,
144  void *caller_handle)
145 {
146  int
147  status;
148 
149  LockSemaphoreInfo(ghost_semaphore);
150  status=-1;
151  if (nt_ghost_info.has_instance == MagickFalse)
152  {
153  status=nt_ghost_info.new_instance(pinstance,caller_handle);
154  if (status >= 0)
155  nt_ghost_info.has_instance=MagickTrue;
156  }
157  UnlockSemaphoreInfo(ghost_semaphore);
158  return(status);
159 }
160 
161 static inline char *create_utf8_string(const wchar_t *wide)
162 {
163  char
164  *utf8;
165 
166  int
167  count;
168 
169  count=WideCharToMultiByte(CP_UTF8,0,wide,-1,NULL,0,NULL,NULL);
170  if (count == 0)
171  return((char *) NULL);
172  utf8=(char *) NTAcquireQuantumMemory(count+1,sizeof(*utf8));
173  if (utf8 == (char *) NULL)
174  return((char *) NULL);
175  count=WideCharToMultiByte(CP_UTF8,0,wide,-1,utf8,count,NULL,NULL);
176  if (count == 0)
177  {
178  utf8=(char *) RelinquishMagickMemory(utf8);
179  return((char *) NULL);
180  }
181  utf8[count]=0;
182  return(utf8);
183 }
184 
185 static unsigned char *NTGetRegistryValue(HKEY root,const char *key,DWORD flags,
186  const char *name)
187 {
188  unsigned char
189  *value;
190 
191  HKEY
192  registry_key;
193 
194  DWORD
195  size,
196  type;
197 
198  LSTATUS
199  status;
200 
201  wchar_t
202  wide_name[MaxWideByteExtent];
203 
204  value=(unsigned char *) NULL;
205  status=RegOpenKeyExA(root,key,0,(KEY_READ | flags),&registry_key);
206  if (status != ERROR_SUCCESS)
207  return(value);
208  if (MultiByteToWideChar(CP_UTF8,0,name,-1,wide_name,MaxWideByteExtent) == 0)
209  {
210  RegCloseKey(registry_key);
211  return(value);
212  }
213  status=RegQueryValueExW(registry_key,wide_name,0,&type,0,&size);
214  if ((status == ERROR_SUCCESS) && (type == REG_SZ))
215  {
216  LPBYTE
217  wide;
218 
219  wide=(LPBYTE) NTAcquireQuantumMemory((const size_t) size,sizeof(*wide));
220  if (wide != (LPBYTE) NULL)
221  {
222  status=RegQueryValueExW(registry_key,wide_name,0,&type,wide,&size);
223  if ((status == ERROR_SUCCESS) && (type == REG_SZ))
224  value=(unsigned char *) create_utf8_string((const wchar_t *) wide);
225  wide=(LPBYTE) RelinquishMagickMemory(wide);
226  }
227  }
228  RegCloseKey(registry_key);
229  return(value);
230 }
231 ␌
232 /*
233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
234 % %
235 % %
236 % %
237 % D l l M a i n %
238 % %
239 % %
240 % %
241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242 %
243 % DllMain() is an entry point to the DLL which is called when processes and
244 % threads are initialized and terminated, or upon calls to the Windows
245 % LoadLibrary and FreeLibrary functions.
246 %
247 % The function returns TRUE of it succeeds, or FALSE if initialization fails.
248 %
249 % The format of the DllMain method is:
250 %
251 % BOOL WINAPI DllMain(HINSTANCE handle,DWORD reason,LPVOID lpvReserved)
252 %
253 % A description of each parameter follows:
254 %
255 % o handle: handle to the DLL module
256 %
257 % o reason: reason for calling function:
258 %
259 % DLL_PROCESS_ATTACH - DLL is being loaded into virtual address
260 % space of current process.
261 % DLL_THREAD_ATTACH - Indicates that the current process is
262 % creating a new thread. Called under the
263 % context of the new thread.
264 % DLL_THREAD_DETACH - Indicates that the thread is exiting.
265 % Called under the context of the exiting
266 % thread.
267 % DLL_PROCESS_DETACH - Indicates that the DLL is being unloaded
268 % from the virtual address space of the
269 % current process.
270 %
271 % o lpvReserved: Used for passing additional info during DLL_PROCESS_ATTACH
272 % and DLL_PROCESS_DETACH.
273 %
274 */
275 #if defined(_DLL) && defined(ProvideDllMain)
276 BOOL WINAPI DllMain(HINSTANCE handle,DWORD reason,LPVOID lpvReserved)
277 {
278  switch (reason)
279  {
280  case DLL_PROCESS_ATTACH:
281  {
282  char
283  *module_path;
284 
285  ssize_t
286  count;
287 
288  wchar_t
289  *wide_path;
290 
291  MagickCoreGenesis((const char *) NULL,MagickFalse);
292  wide_path=(wchar_t *) NTAcquireQuantumMemory(MagickPathExtent,
293  sizeof(*wide_path));
294  if (wide_path == (wchar_t *) NULL)
295  return(FALSE);
296  count=(ssize_t) GetModuleFileNameW(handle,wide_path,MagickPathExtent);
297  if (count != 0)
298  {
299  char
300  *path;
301 
302  module_path=create_utf8_string(wide_path);
303  for ( ; count > 0; count--)
304  if (module_path[count] == '\\')
305  {
306  module_path[count+1]='\0';
307  break;
308  }
309  path=(char *) NTAcquireQuantumMemory(MagickPathExtent,
310  16*sizeof(*path));
311  if (path == (char *) NULL)
312  {
313  module_path=DestroyString(module_path);
314  wide_path=(wchar_t *) RelinquishMagickMemory(wide_path);
315  return(FALSE);
316  }
317  count=(ssize_t) GetEnvironmentVariable("PATH",path,16*
318  MagickPathExtent);
319  if ((count != 0) && (strstr(path,module_path) == (char *) NULL))
320  {
321  if ((strlen(module_path)+count+1) < (16*MagickPathExtent-1))
322  {
323  char
324  *variable;
325 
326  variable=(char *) NTAcquireQuantumMemory(MagickPathExtent,
327  16*sizeof(*variable));
328  if (variable == (char *) NULL)
329  {
330  path=DestroyString(path);
331  module_path=DestroyString(module_path);
332  wide_path=(wchar_t *) RelinquishMagickMemory(wide_path);
333  return(FALSE);
334  }
335  (void) FormatLocaleString(variable,16*MagickPathExtent,
336  "%s;%s",module_path,path);
337  SetEnvironmentVariable("PATH",variable);
338  variable=DestroyString(variable);
339  }
340  }
341  path=DestroyString(path);
342  module_path=DestroyString(module_path);
343  }
344  wide_path=(wchar_t *) RelinquishMagickMemory(wide_path);
345  break;
346  }
347  case DLL_PROCESS_DETACH:
348  {
349  MagickCoreTerminus();
350  break;
351  }
352  default:
353  break;
354  }
355  return(TRUE);
356 }
357 #endif
358 ␌
359 #if !defined(__MINGW32__)
360 /*
361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362 % %
363 % %
364 % %
365 % g e t t i m e o f d a y %
366 % %
367 % %
368 % %
369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 %
371 % The gettimeofday() method get the time of day.
372 %
373 % The format of the gettimeofday method is:
374 %
375 % int gettimeofday(struct timeval *time_value,struct timezone *time_zone)
376 %
377 % A description of each parameter follows:
378 %
379 % o time_value: the time value.
380 %
381 % o time_zone: the time zone.
382 %
383 */
384 MagickPrivate int gettimeofday (struct timeval *time_value,
385  struct timezone *time_zone)
386 {
387 #define EpochFiletime MagickLLConstant(116444736000000000)
388 
389  static int
390  is_tz_set;
391 
392  if (time_value != (struct timeval *) NULL)
393  {
394  FILETIME
395  file_time;
396 
397  __int64
398  time;
399 
400  LARGE_INTEGER
401  date_time;
402 
403  GetSystemTimeAsFileTime(&file_time);
404  date_time.LowPart=file_time.dwLowDateTime;
405  date_time.HighPart=file_time.dwHighDateTime;
406  time=date_time.QuadPart;
407  time-=EpochFiletime;
408  time/=10;
409  time_value->tv_sec=(long) (time / 1000000);
410  time_value->tv_usec=(long) (time % 1000000);
411  }
412  if (time_zone != (struct timezone *) NULL)
413  {
414  int
415  daylight;
416 
417  long
418  timezone=0;
419 
420  if (is_tz_set == 0)
421  {
422  _tzset();
423  is_tz_set++;
424  }
425  _get_timezone(&timezone);
426  time_zone->tz_minuteswest=timezone/60;
427  _get_daylight(&daylight);
428  time_zone->tz_dsttime=daylight;
429  }
430  return(0);
431 }
432 #endif
433 ␌
434 /*
435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
436 % %
437 % %
438 % %
439 % N T A c c e s s W i d e %
440 % %
441 % %
442 % %
443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
444 %
445 % NTAccessWide() checks the file accessibility of a file path.
446 #
447 # The format of the NTAccessWide method is:
448 %
449 % int NTAccessWide(const char *path, int mode)
450 %
451 % A description of each parameter follows:
452 %
453 % o path: the file path.
454 %
455 % o mode: the accessibility mode.
456 %
457 */
458 MagickExport int NTAccessWide(const char *path, int mode)
459 {
460  int
461  status;
462 
463  wchar_t
464  *path_wide;
465 
466  path_wide=NTCreateWidePath(path);
467  if (path_wide == (wchar_t *) NULL)
468  return(-1);
469  status=_waccess(path_wide,mode);
470  path_wide=(wchar_t *) RelinquishMagickMemory(path_wide);
471  return(status);
472 }
473 ␌
474 /*
475 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
476 % %
477 % %
478 % %
479 % N T A r g v T o U T F 8 %
480 % %
481 % %
482 % %
483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484 %
485 % NTArgvToUTF8() converts the wide command line arguments to UTF-8 to ensure
486 % compatibility with Linux.
487 %
488 % The format of the NTArgvToUTF8 method is:
489 %
490 % char **NTArgvToUTF8(const int argc,wchar_t **argv)
491 %
492 % A description of each parameter follows:
493 %
494 % o argc: the number of command line arguments.
495 %
496 % o argv: the wide-character command line arguments.
497 %
498 */
499 MagickPrivate char **NTArgvToUTF8(const int argc,wchar_t **argv)
500 {
501  char
502  **utf8;
503 
504  ssize_t
505  i;
506 
507  utf8=(char **) NTAcquireQuantumMemory(argc,sizeof(*utf8));
508  if (utf8 == (char **) NULL)
509  ThrowFatalException(ResourceLimitFatalError,"UnableToConvertStringToARGV");
510  for (i=0; i < (ssize_t) argc; i++)
511  {
512  utf8[i]=create_utf8_string(argv[i]);
513  if (utf8[i] == (char *) NULL)
514  {
515  for (i--; i >= 0; i--)
516  utf8[i]=DestroyString(utf8[i]);
517  ThrowFatalException(ResourceLimitFatalError,
518  "UnableToConvertStringToARGV");
519  }
520  }
521  return(utf8);
522 }
523 ␌
524 /*
525 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
526 % %
527 % %
528 % %
529 % N T C l o s e D i r e c t o r y %
530 % %
531 % %
532 % %
533 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
534 %
535 % NTCloseDirectory() closes the named directory stream and frees the DIR
536 % structure.
537 %
538 % The format of the NTCloseDirectory method is:
539 %
540 % int NTCloseDirectory(DIR *entry)
541 %
542 % A description of each parameter follows:
543 %
544 % o entry: Specifies a pointer to a DIR structure.
545 %
546 */
547 MagickPrivate int NTCloseDirectory(DIR *entry)
548 {
549  assert(entry != (DIR *) NULL);
550  if (IsEventLogging() != MagickFalse)
551  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
552  FindClose(entry->hSearch);
553  entry=(DIR *) RelinquishMagickMemory(entry);
554  return(0);
555 }
556 /*
557 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
558 % %
559 % %
560 % %
561 % N T C l o s e L i b r a r y %
562 % %
563 % %
564 % %
565 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
566 %
567 % NTCloseLibrary() unloads the module associated with the passed handle.
568 %
569 % The format of the NTCloseLibrary method is:
570 %
571 % void NTCloseLibrary(void *handle)
572 %
573 % A description of each parameter follows:
574 %
575 % o handle: Specifies a handle to a previously loaded dynamic module.
576 %
577 */
578 MagickPrivate int NTCloseLibrary(void *handle)
579 {
580  return(FreeLibrary((HINSTANCE) handle) ? 0 : 1);
581 }
582 ␌
583 /*
584 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
585 % %
586 % %
587 % %
588 % N T C r e a t e W i d e P a t h %
589 % %
590 % %
591 % %
592 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
593 %
594 % NTCreateWidePath() returns the wide-character version of the specified
595 % UTF-8 path.
596 %
597 % The format of the NTCreateWidePath method is:
598 %
599 % void NTCreateWidePath(void *handle)
600 %
601 % A description of each parameter follows:
602 %
603 % o utf8: Specifies a handle to a previously loaded dynamic module.
604 %
605 */
606 MagickExport wchar_t* NTCreateWidePath(const char *utf8)
607 {
608  int
609  count;
610 
611  wchar_t
612  *wide;
613 
614  count=MultiByteToWideChar(CP_UTF8,0,utf8,-1,NULL,0);
615  if ((count > MAX_PATH) && (strncmp(utf8,"\\\\?\\",4) != 0) &&
616  (NTLongPathsEnabled() == MagickFalse))
617  {
618  char
619  buffer[MagickPathExtent];
620 
621  wchar_t
622  shortPath[MAX_PATH],
623  *longPath;
624 
625  size_t
626  length;
627 
628  (void) FormatLocaleString(buffer,MagickPathExtent,"\\\\?\\%s",utf8);
629  count+=4;
630  longPath=(wchar_t *) NTAcquireQuantumMemory((size_t) count,
631  sizeof(*longPath));
632  if (longPath == (wchar_t *) NULL)
633  return((wchar_t *) NULL);
634  count=MultiByteToWideChar(CP_UTF8,0,buffer,-1,longPath,count);
635  if (count != 0)
636  count=(int) GetShortPathNameW(longPath,shortPath,MAX_PATH);
637  longPath=(wchar_t *) RelinquishMagickMemory(longPath);
638  if ((count < 5) || (count >= MAX_PATH))
639  return((wchar_t *) NULL);
640  length=(size_t) count-3;
641  wide=(wchar_t *) NTAcquireQuantumMemory(length,sizeof(*wide));
642  wcscpy_s(wide,length,shortPath+4);
643  return(wide);
644  }
645  wide=(wchar_t *) NTAcquireQuantumMemory((size_t) count,sizeof(*wide));
646  if ((wide != (wchar_t *) NULL) &&
647  (MultiByteToWideChar(CP_UTF8,0,utf8,-1,wide,count) == 0))
648  wide=(wchar_t *) RelinquishMagickMemory(wide);
649  return(wide);
650 }
651 ␌
652 /*
653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
654 % %
655 % %
656 % %
657 % N T E l a p s e d T i m e %
658 % %
659 % %
660 % %
661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662 %
663 % NTElapsedTime() returns the elapsed time (in seconds) since the last call to
664 % StartTimer().
665 %
666 % The format of the ElapsedTime method is:
667 %
668 % double NTElapsedTime(void)
669 %
670 */
671 MagickPrivate double NTElapsedTime(void)
672 {
673  union
674  {
675  FILETIME
676  filetime;
677 
678  __int64
679  filetime64;
680  } elapsed_time;
681 
682  LARGE_INTEGER
683  performance_count;
684 
685  static LARGE_INTEGER
686  frequency = { 0 };
687 
688  SYSTEMTIME
689  system_time;
690 
691  if (frequency.QuadPart == 0)
692  {
693  if (QueryPerformanceFrequency(&frequency) == 0)
694  frequency.QuadPart=1;
695  }
696  if (frequency.QuadPart > 1)
697  {
698  QueryPerformanceCounter(&performance_count);
699  return((double) performance_count.QuadPart/frequency.QuadPart);
700  }
701  GetSystemTime(&system_time);
702  SystemTimeToFileTime(&system_time,&elapsed_time.filetime);
703  return((double) 1.0e-7*elapsed_time.filetime64);
704 }
705 
706 /*
707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
708 % %
709 % %
710 % %
711 % N T E r f %
712 % %
713 % %
714 % %
715 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
716 %
717 % NTErf() computes the error function of x.
718 %
719 % The format of the NTErf method is:
720 %
721 % double NTErf(double x)
722 %
723 % A description of each parameter follows:
724 %
725 % o x: The value to compute the error function for.
726 %
727 */
728 MagickPrivate double NTErf(double x)
729 {
730  double
731  a1,
732  a2,
733  a3,
734  a4,
735  a5,
736  p,
737  t,
738  y;
739 
740  int
741  sign;
742 
743  a1=0.254829592;
744  a2=-0.284496736;
745  a3=1.421413741;
746  a4=-1.453152027;
747  a5=1.061405429;
748  p=0.3275911;
749  sign=x < 0 ? -1 : 1;
750  x=fabs(x);
751  t=1.0/(1.0+p*x);
752  y=1.0-(((((a5*t+a4)*t)+a3)*t+a2)*t+a1)*t*exp(-x*x);
753  return(sign*y);
754 }
755 ␌
756 /*
757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
758 % %
759 % %
760 % %
761 + N T E r r o r H a n d l e r %
762 % %
763 % %
764 % %
765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
766 %
767 % NTErrorHandler() displays an error reason and then terminates the program.
768 %
769 % The format of the NTErrorHandler method is:
770 %
771 % void NTErrorHandler(const ExceptionType severity,const char *reason,
772 % const char *description)
773 %
774 % A description of each parameter follows:
775 %
776 % o severity: Specifies the numeric error category.
777 %
778 % o reason: Specifies the reason to display before terminating the
779 % program.
780 %
781 % o description: Specifies any description to the reason.
782 %
783 */
784 MagickPrivate void NTErrorHandler(const ExceptionType severity,
785  const char *reason,const char *description)
786 {
787  char
788  buffer[3*MagickPathExtent],
789  *message;
790 
791  (void) severity;
792  if (reason == (char *) NULL)
793  {
794  MagickCoreTerminus();
795  exit(0);
796  }
797  message=GetExceptionMessage(errno);
798  if ((description != (char *) NULL) && errno)
799  (void) FormatLocaleString(buffer,MagickPathExtent,"%s: %s (%s) [%s].\n",
800  GetClientName(),reason,description,message);
801  else
802  if (description != (char *) NULL)
803  (void) FormatLocaleString(buffer,MagickPathExtent,"%s: %s (%s).\n",
804  GetClientName(),reason,description);
805  else
806  if (errno != 0)
807  (void) FormatLocaleString(buffer,MagickPathExtent,"%s: %s [%s].\n",
808  GetClientName(),reason,message);
809  else
810  (void) FormatLocaleString(buffer,MagickPathExtent,"%s: %s.\n",
811  GetClientName(),reason);
812  message=DestroyString(message);
813  (void) MessageBox(NULL,buffer,"ImageMagick Exception",MB_OK | MB_TASKMODAL |
814  MB_SETFOREGROUND | MB_ICONEXCLAMATION);
815  MagickCoreTerminus();
816  exit(0);
817 }
818 ␌
819 /*
820 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
821 % %
822 % %
823 % %
824 % N T G a t h e r R a n d o m D a t a %
825 % %
826 % %
827 % %
828 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
829 %
830 % NTGatherRandomData() gathers random data and returns it.
831 %
832 % The format of the GatherRandomData method is:
833 %
834 % MagickBooleanType NTGatherRandomData(const size_t length,
835 % unsigned char *random)
836 %
837 % A description of each parameter follows:
838 %
839 % length: the length of random data buffer
840 %
841 % random: the random data is returned here.
842 %
843 */
844 MagickPrivate MagickBooleanType NTGatherRandomData(const size_t length,
845  unsigned char *random)
846 {
847 #if defined(MAGICKCORE_CIPHER_SUPPORT) && defined(_MSC_VER)
848  HCRYPTPROV
849  handle;
850 
851  int
852  status;
853 
854  handle=(HCRYPTPROV) NULL;
855  status=CryptAcquireContext(&handle,NULL,MS_DEF_PROV,PROV_RSA_FULL,
856  (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET));
857  if (status == 0)
858  status=CryptAcquireContext(&handle,NULL,MS_DEF_PROV,PROV_RSA_FULL,
859  (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET));
860  if (status == 0)
861  return(MagickFalse);
862  status=CryptGenRandom(handle,(DWORD) length,random);
863  if (status == 0)
864  {
865  status=CryptReleaseContext(handle,0);
866  return(MagickFalse);
867  }
868  status=CryptReleaseContext(handle,0);
869  if (status == 0)
870  return(MagickFalse);
871 #else
872  (void) random;
873  (void) length;
874 #endif
875  return(MagickTrue);
876 }
877 ␌
878 /*
879 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
880 % %
881 % %
882 % %
883 % N T G e t E n v i r o n m e n t V a l u e %
884 % %
885 % %
886 % %
887 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
888 %
889 % NTGetEnvironmentValue() returns the environment string that matches the
890 % specified name.
891 %
892 % The format of the NTGetEnvironmentValue method is:
893 %
894 % char *GetEnvironmentValue(const char *name)
895 %
896 % A description of each parameter follows:
897 %
898 % o name: the environment name.
899 %
900 */
901 extern MagickPrivate char *NTGetEnvironmentValue(const char *name)
902 {
903  char
904  *environment = (char *) NULL;
905 
906  DWORD
907  size;
908 
909  LPWSTR
910  wide;
911 
912  wchar_t
913  wide_name[MaxWideByteExtent];
914 
915  if (MultiByteToWideChar(CP_UTF8,0,name,-1,wide_name,MaxWideByteExtent) == 0)
916  return(environment);
917  size=GetEnvironmentVariableW(wide_name,(LPWSTR) NULL,0);
918  if (size == 0)
919  return(environment);
920  wide=(LPWSTR) NTAcquireQuantumMemory((const size_t) size,sizeof(*wide));
921  if (wide == (LPWSTR) NULL)
922  return(environment);
923  if (GetEnvironmentVariableW(wide_name,wide,size) != 0)
924  environment=create_utf8_string(wide);
925  wide=(LPWSTR) RelinquishMagickMemory(wide);
926  return(environment);
927 }
928 ␌
929 /*
930 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
931 % %
932 % %
933 % %
934 % N T G e t E x e c u t i o n P a t h %
935 % %
936 % %
937 % %
938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
939 %
940 % NTGetExecutionPath() returns the execution path of a program.
941 %
942 % The format of the GetExecutionPath method is:
943 %
944 % MagickBooleanType NTGetExecutionPath(char *path,const size_t extent)
945 %
946 % A description of each parameter follows:
947 %
948 % o path: the pathname of the executable that started the process.
949 %
950 % o extent: the maximum extent of the path.
951 %
952 */
953 MagickPrivate MagickBooleanType NTGetExecutionPath(char *path,
954  const size_t extent)
955 {
956  wchar_t
957  wide_path[MagickPathExtent];
958 
959  (void) GetModuleFileNameW((HMODULE) NULL,wide_path,(DWORD) extent);
960  (void) WideCharToMultiByte(CP_UTF8,0,wide_path,-1,path,(int) extent,NULL,
961  NULL);
962  return(MagickTrue);
963 }
964 ␌
965 /*
966 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
967 % %
968 % %
969 % %
970 % N T G e t L a s t E r r o r M e s s a g e %
971 % %
972 % %
973 % %
974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
975 %
976 % NTGetLastErrorMessage() returns the last error that occurred.
977 %
978 % The format of the NTGetLastErrorMessage method is:
979 %
980 % char *NTGetLastErrorMessage(DWORD last_error)
981 %
982 % A description of each parameter follows:
983 %
984 % o last_error: The value of GetLastError.
985 %
986 */
987 static char *NTGetLastErrorMessage(DWORD last_error)
988 {
989  char
990  *reason;
991 
992  int
993  status;
994 
995  LPVOID
996  buffer = (LPVOID) NULL;
997 
998  status=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
999  FORMAT_MESSAGE_FROM_SYSTEM,NULL,last_error,
1000  MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR) &buffer,0,NULL);
1001  if (!status)
1002  reason=AcquireString("An unknown error occurred");
1003  else
1004  {
1005  reason=AcquireString((const char *) buffer);
1006  LocalFree(buffer);
1007  }
1008  return(reason);
1009 }
1010 ␌
1011 /*
1012 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1013 % %
1014 % %
1015 % %
1016 % N T G e t L i b r a r y E r r o r %
1017 % %
1018 % %
1019 % %
1020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1021 %
1022 % Lt_dlerror() returns a pointer to a string describing the last error
1023 % associated with a lt_dl method. Note that this function is not thread
1024 % safe so it should only be used under the protection of a lock.
1025 %
1026 % The format of the NTGetLibraryError method is:
1027 %
1028 % const char *NTGetLibraryError(void)
1029 %
1030 */
1031 MagickPrivate const char *NTGetLibraryError(void)
1032 {
1033  static char
1034  last_error[MagickPathExtent];
1035 
1036  char
1037  *error;
1038 
1039  *last_error='\0';
1040  error=NTGetLastErrorMessage(GetLastError());
1041  if (error)
1042  (void) CopyMagickString(last_error,error,MagickPathExtent);
1043  error=DestroyString(error);
1044  return(last_error);
1045 }
1046 ␌
1047 /*
1048 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1049 % %
1050 % %
1051 % %
1052 % N T G e t L i b r a r y S y m b o l %
1053 % %
1054 % %
1055 % %
1056 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1057 %
1058 % NTGetLibrarySymbol() retrieve the procedure address of the method
1059 % specified by the passed character string.
1060 %
1061 % The format of the NTGetLibrarySymbol method is:
1062 %
1063 % void *NTGetLibrarySymbol(void *handle,const char *name)
1064 %
1065 % A description of each parameter follows:
1066 %
1067 % o handle: Specifies a handle to the previously loaded dynamic module.
1068 %
1069 % o name: Specifies the procedure entry point to be returned.
1070 %
1071 */
1072 void *NTGetLibrarySymbol(void *handle,const char *name)
1073 {
1074  FARPROC
1075  proc_address;
1076 
1077  proc_address=GetProcAddress((HMODULE) handle,(LPCSTR) name);
1078  if (proc_address == (FARPROC) NULL)
1079  return((void *) NULL);
1080  return((void *) proc_address);
1081 }
1082 ␌
1083 /*
1084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1085 % %
1086 % %
1087 % %
1088 % N T G e t M o d u l e P a t h %
1089 % %
1090 % %
1091 % %
1092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1093 %
1094 % NTGetModulePath() returns the path of the specified module.
1095 %
1096 % The format of the GetModulePath method is:
1097 %
1098 % MagickBooleanType NTGetModulePath(const char *module,char *path)
1099 %
1100 % A description of each parameter follows:
1101 %
1102 % modith: the module name.
1103 %
1104 % path: the module path is returned here.
1105 %
1106 */
1107 MagickPrivate MagickBooleanType NTGetModulePath(const char *module,char *path)
1108 {
1109  char
1110  module_path[MagickPathExtent];
1111 
1112  HMODULE
1113  handle;
1114 
1115  ssize_t
1116  length;
1117 
1118  *path='\0';
1119  handle=GetModuleHandle(module);
1120  if (handle == (HMODULE) NULL)
1121  return(MagickFalse);
1122  length=GetModuleFileName(handle,module_path,MagickPathExtent);
1123  if (length != 0)
1124  GetPathComponent(module_path,HeadPath,path);
1125  return(MagickTrue);
1126 }
1127 ␌
1128 /*
1129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1130 % %
1131 % %
1132 % %
1133 % N T G h o s t s c r i p t D L L V e c t o r s %
1134 % %
1135 % %
1136 % %
1137 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1138 %
1139 % NTGhostscriptDLLVectors() returns a GhostInfo structure that includes
1140 % function vectors to invoke Ghostscript DLL functions. A null pointer is
1141 % returned if there is an error when loading the DLL or retrieving the
1142 % function vectors.
1143 %
1144 % The format of the NTGhostscriptDLLVectors method is:
1145 %
1146 % const GhostInfo *NTGhostscriptDLLVectors(void)
1147 %
1148 */
1149 static int NTLocateGhostscript(DWORD flags,int *root_index,
1150  const char **product_family,int *major_version,int *minor_version,
1151  int *patch_version)
1152 {
1153  int
1154  i;
1155 
1156  MagickBooleanType
1157  status;
1158 
1159  static const char
1160  *products[2] =
1161  {
1162  "Artifex Ghostscript",
1163  "GPL Ghostscript"
1164  };
1165 
1166  /*
1167  Find the most recent version of Ghostscript.
1168  */
1169  status=MagickFalse;
1170  *root_index=0;
1171  *product_family=NULL;
1172  *major_version=5;
1173  *minor_version=49; /* min version of Ghostscript is 5.50 */
1174  for (i=0; i < (ssize_t) (sizeof(products)/sizeof(products[0])); i++)
1175  {
1176  char
1177  key[MagickPathExtent];
1178 
1179  HKEY
1180  hkey;
1181 
1182  int
1183  j;
1184 
1185  REGSAM
1186  mode;
1187 
1188  (void) FormatLocaleString(key,MagickPathExtent,"SOFTWARE\\%s",products[i]);
1189  for (j=0; j < (ssize_t) (sizeof(registry_roots)/sizeof(registry_roots[0]));
1190  j++)
1191  {
1192  mode=KEY_READ | flags;
1193  if (RegOpenKeyExA(registry_roots[j].hkey,key,0,mode,&hkey) ==
1194  ERROR_SUCCESS)
1195  {
1196  DWORD
1197  extent;
1198 
1199  int
1200  k;
1201 
1202  /*
1203  Now enumerate the keys.
1204  */
1205  extent=sizeof(key)/sizeof(char);
1206  for (k=0; RegEnumKeyA(hkey,k,key,extent) == ERROR_SUCCESS; k++)
1207  {
1208  int
1209  major,
1210  minor,
1211  patch;
1212 
1213  major=0;
1214  minor=0;
1215  patch=0;
1216  if (MagickSscanf(key,"%d.%d.%d",&major,&minor,&patch) != 3)
1217  if (MagickSscanf(key,"%d.%d",&major,&minor) != 2)
1218  continue;
1219  if ((major > *major_version) ||
1220  ((major == *major_version) && (minor > *minor_version)) ||
1221  ((minor == *minor_version) && (patch > *patch_version)))
1222  {
1223  *root_index=j;
1224  *product_family=products[i];
1225  *major_version=major;
1226  *minor_version=minor;
1227  *patch_version=patch;
1228  status=MagickTrue;
1229  }
1230  }
1231  (void) RegCloseKey(hkey);
1232  }
1233  }
1234  }
1235  if (status == MagickFalse)
1236  {
1237  *major_version=0;
1238  *minor_version=0;
1239  *patch_version=0;
1240  }
1241  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),"Ghostscript (%s) "
1242  "version %d.%d.%d",*product_family,*major_version,*minor_version,*patch_version);
1243  return(status);
1244 }
1245 
1246 static MagickBooleanType NTGhostscriptGetString(const char *name,
1247  BOOL *is_64_bit,char *value,const size_t length)
1248 {
1249  char
1250  buffer[MagickPathExtent],
1251  *directory;
1252 
1253  static const char
1254  *product_family = (const char *) NULL;
1255 
1256  static BOOL
1257  is_64_bit_version = FALSE;
1258 
1259  static int
1260  flags = 0,
1261  major_version = 0,
1262  minor_version = 0,
1263  patch_version = 0,
1264  root_index = 0;
1265 
1266  unsigned char
1267  *registry_value;
1268 
1269  /*
1270  Get a string from the installed Ghostscript.
1271  */
1272  *value='\0';
1273  directory=(char *) NULL;
1274  if (LocaleCompare(name,"GS_DLL") == 0)
1275  {
1276  directory=GetEnvironmentValue("MAGICK_GHOSTSCRIPT_PATH");
1277  if (directory != (char *) NULL)
1278  {
1279  (void) FormatLocaleString(buffer,MagickPathExtent,"%s%sgsdll64.dll",
1280  directory,DirectorySeparator);
1281  if (IsPathAccessible(buffer) != MagickFalse)
1282  {
1283  directory=DestroyString(directory);
1284  (void) CopyMagickString(value,buffer,length);
1285  if (is_64_bit != NULL)
1286  *is_64_bit=TRUE;
1287  return(MagickTrue);
1288  }
1289  (void) FormatLocaleString(buffer,MagickPathExtent,"%s%sgsdll32.dll",
1290  directory,DirectorySeparator);
1291  if (IsPathAccessible(buffer) != MagickFalse)
1292  {
1293  directory=DestroyString(directory);
1294  (void) CopyMagickString(value,buffer,length);
1295  if (is_64_bit != NULL)
1296  *is_64_bit=FALSE;
1297  return(MagickTrue);
1298  }
1299  return(MagickFalse);
1300  }
1301  }
1302  if (product_family == (const char *) NULL)
1303  {
1304  flags=0;
1305 #if defined(KEY_WOW64_32KEY)
1306 #if defined(_WIN64)
1307  flags=KEY_WOW64_64KEY;
1308 #else
1309  flags=KEY_WOW64_32KEY;
1310 #endif
1311  (void) NTLocateGhostscript(flags,&root_index,&product_family,
1312  &major_version,&minor_version,&patch_version);
1313  if (product_family == (const char *) NULL)
1314 #if defined(_WIN64)
1315  flags=KEY_WOW64_32KEY;
1316  else
1317  is_64_bit_version=TRUE;
1318 #else
1319  flags=KEY_WOW64_64KEY;
1320 #endif
1321 #endif
1322  }
1323  if (product_family == (const char *) NULL)
1324  {
1325  (void) NTLocateGhostscript(flags,&root_index,&product_family,
1326  &major_version,&minor_version,&patch_version);
1327 #if !defined(_WIN64)
1328  is_64_bit_version=TRUE;
1329 #endif
1330  }
1331  if (product_family == (const char *) NULL)
1332  return(MagickFalse);
1333  if (is_64_bit != NULL)
1334  *is_64_bit=is_64_bit_version;
1335  (void) FormatLocaleString(buffer,MagickPathExtent,"SOFTWARE\\%s\\%d.%.2d.%d",
1336  product_family,major_version,minor_version,patch_version);
1337  registry_value=NTGetRegistryValue(registry_roots[root_index].hkey,buffer,
1338  flags,name);
1339  if (registry_value == (unsigned char *) NULL)
1340  {
1341  (void) FormatLocaleString(buffer,MagickPathExtent,"SOFTWARE\\%s\\%d.%02d",
1342  product_family,major_version,minor_version);
1343  registry_value=NTGetRegistryValue(registry_roots[root_index].hkey,buffer,
1344  flags,name);
1345  }
1346  if (registry_value == (unsigned char *) NULL)
1347  return(MagickFalse);
1348  (void) CopyMagickString(value,(const char *) registry_value,length);
1349  registry_value=(unsigned char *) RelinquishMagickMemory(registry_value);
1350  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1351  "registry: \"%s\\%s\\%s\"=\"%s\"",registry_roots[root_index].name,
1352  buffer,name,value);
1353  return(MagickTrue);
1354 }
1355 
1356 static MagickBooleanType NTGhostscriptDLL(char *path,int length)
1357 {
1358  static char
1359  dll[MagickPathExtent] = { "" };
1360 
1361  static BOOL
1362  is_64_bit;
1363 
1364  *path='\0';
1365  if ((*dll == '\0') &&
1366  (NTGhostscriptGetString("GS_DLL",&is_64_bit,dll,sizeof(dll)) != MagickTrue))
1367  return(MagickFalse);
1368 #if defined(_WIN64)
1369  if (!is_64_bit)
1370  return(MagickFalse);
1371 #else
1372  if (is_64_bit)
1373  return(MagickFalse);
1374 #endif
1375  (void) CopyMagickString(path,dll,length);
1376  return(MagickTrue);
1377 }
1378 
1379 static inline MagickBooleanType NTGhostscriptHasValidHandle()
1380 {
1381  if ((nt_ghost_info.delete_instance == NULL) || (ghost_info.exit == NULL) ||
1382  (nt_ghost_info.new_instance == NULL) || (ghost_info.set_stdio == NULL) ||
1383  (ghost_info.init_with_args == NULL) || (ghost_info.revision == NULL))
1384  return(MagickFalse);
1385  return(MagickTrue);
1386 }
1387 
1388 MagickPrivate const GhostInfo *NTGhostscriptDLLVectors(void)
1389 {
1390  char
1391  path[MagickPathExtent];
1392 
1393  if (ghost_semaphore == (SemaphoreInfo *) NULL)
1394  ActivateSemaphoreInfo(&ghost_semaphore);
1395  LockSemaphoreInfo(ghost_semaphore);
1396  if (ghost_handle != (void *) NULL)
1397  {
1398  UnlockSemaphoreInfo(ghost_semaphore);
1399  if (NTGhostscriptHasValidHandle() == MagickTrue)
1400  return(&ghost_info);
1401  return((GhostInfo *) NULL);
1402  }
1403  if (NTGhostscriptDLL(path,sizeof(path)) != MagickTrue)
1404  {
1405  UnlockSemaphoreInfo(ghost_semaphore);
1406  return((GhostInfo *) NULL);
1407  }
1408  ghost_handle=lt_dlopen(path);
1409  if (ghost_handle == (void *) NULL)
1410  {
1411  UnlockSemaphoreInfo(ghost_semaphore);
1412  return((GhostInfo *) NULL);
1413  }
1414  (void) memset((void *) &nt_ghost_info,0,sizeof(NTGhostInfo));
1415  nt_ghost_info.delete_instance=(void (MagickDLLCall *)(gs_main_instance *)) (
1416  lt_dlsym(ghost_handle,"gsapi_delete_instance"));
1417  nt_ghost_info.new_instance=(int (MagickDLLCall *)(gs_main_instance **,
1418  void *)) (lt_dlsym(ghost_handle,"gsapi_new_instance"));
1419  nt_ghost_info.has_instance=MagickFalse;
1420  (void) memset((void *) &ghost_info,0,sizeof(GhostInfo));
1421  ghost_info.delete_instance=NTGhostscriptDeleteInstance;
1422  ghost_info.exit=(int (MagickDLLCall *)(gs_main_instance*))
1423  lt_dlsym(ghost_handle,"gsapi_exit");
1424  ghost_info.init_with_args=(int (MagickDLLCall *)(gs_main_instance *,int,
1425  char **)) (lt_dlsym(ghost_handle,"gsapi_init_with_args"));
1426  ghost_info.new_instance=NTGhostscriptNewInstance;
1427  ghost_info.run_string=(int (MagickDLLCall *)(gs_main_instance *,const char *,
1428  int,int *)) (lt_dlsym(ghost_handle,"gsapi_run_string"));
1429  ghost_info.set_arg_encoding=(int (MagickDLLCall*)(gs_main_instance*, int)) (
1430  lt_dlsym(ghost_handle, "gsapi_set_arg_encoding"));
1431  ghost_info.set_stdio=(int (MagickDLLCall *)(gs_main_instance *,int(
1432  MagickDLLCall *)(void *,char *,int),int(MagickDLLCall *)(void *,
1433  const char *,int),int(MagickDLLCall *)(void *,const char *,int)))
1434  (lt_dlsym(ghost_handle,"gsapi_set_stdio"));
1435  ghost_info.revision=(int (MagickDLLCall *)(gsapi_revision_t *,int)) (
1436  lt_dlsym(ghost_handle,"gsapi_revision"));
1437  UnlockSemaphoreInfo(ghost_semaphore);
1438  if (NTGhostscriptHasValidHandle() == MagickTrue)
1439  return(&ghost_info);
1440  return((GhostInfo *) NULL);
1441 }
1442 ␌
1443 /*
1444 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1445 % %
1446 % %
1447 % %
1448 % N T G h o s t s c r i p t E X E %
1449 % %
1450 % %
1451 % %
1452 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1453 %
1454 % NTGhostscriptEXE() obtains the path to the latest Ghostscript executable.
1455 % The method returns FALSE if a full path value is not obtained and returns
1456 % a default path of gswin32c.exe.
1457 %
1458 % The format of the NTGhostscriptEXE method is:
1459 %
1460 % void NTGhostscriptEXE(char *path,int length)
1461 %
1462 % A description of each parameter follows:
1463 %
1464 % o path: return the Ghostscript executable path here.
1465 %
1466 % o length: length of buffer.
1467 %
1468 */
1469 MagickPrivate void NTGhostscriptEXE(char *path,int length)
1470 {
1471  char
1472  *p;
1473 
1474  static char
1475  program[MagickPathExtent] = { "" };
1476 
1477  static BOOL
1478  is_64_bit_version = FALSE;
1479 
1480  if (*program == '\0')
1481  {
1482  if (ghost_semaphore == (SemaphoreInfo *) NULL)
1483  ActivateSemaphoreInfo(&ghost_semaphore);
1484  LockSemaphoreInfo(ghost_semaphore);
1485  if (*program == '\0')
1486  {
1487  if (NTGhostscriptGetString("GS_DLL",&is_64_bit_version,program,
1488  sizeof(program)) == MagickFalse)
1489  {
1490  UnlockSemaphoreInfo(ghost_semaphore);
1491 #if defined(_WIN64)
1492  (void) CopyMagickString(program,"gswin64c.exe",sizeof(program));
1493 #else
1494  (void) CopyMagickString(program,"gswin32c.exe",sizeof(program));
1495 #endif
1496  (void) CopyMagickString(path,program,length);
1497  return;
1498  }
1499  p=strrchr(program,'\\');
1500  if (p != (char *) NULL)
1501  {
1502  p++;
1503  *p='\0';
1504  (void) ConcatenateMagickString(program,is_64_bit_version ?
1505  "gswin64c.exe" : "gswin32c.exe",sizeof(program));
1506  }
1507  }
1508  UnlockSemaphoreInfo(ghost_semaphore);
1509  }
1510  (void) CopyMagickString(path,program,length);
1511 }
1512 ␌
1513 /*
1514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1515 % %
1516 % %
1517 % %
1518 % N T G h o s t s c r i p t F o n t s %
1519 % %
1520 % %
1521 % %
1522 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1523 %
1524 % NTGhostscriptFonts() obtains the path to the Ghostscript fonts. The method
1525 % returns false if it cannot determine the font path.
1526 %
1527 % The format of the NTGhostscriptFonts method is:
1528 %
1529 % MagickBooleanType NTGhostscriptFonts(char *path,int length)
1530 %
1531 % A description of each parameter follows:
1532 %
1533 % o path: return the font path here.
1534 %
1535 % o length: length of the path buffer.
1536 %
1537 */
1538 MagickPrivate MagickBooleanType NTGhostscriptFonts(char *path,int length)
1539 {
1540  char
1541  buffer[MagickPathExtent],
1542  *directory,
1543  filename[MagickPathExtent];
1544 
1545  char
1546  *p,
1547  *q;
1548 
1549  *path='\0';
1550  directory=GetEnvironmentValue("MAGICK_GHOSTSCRIPT_FONT_PATH");
1551  if (directory != (char *) NULL)
1552  {
1553  (void) CopyMagickString(buffer,directory,MagickPathExtent);
1554  directory=DestroyString(directory);
1555  }
1556  else
1557  {
1558  if (NTGhostscriptGetString("GS_LIB",NULL,buffer,
1559  MagickPathExtent) == MagickFalse)
1560  return(MagickFalse);
1561  }
1562  for (p=buffer-1; p != (char *) NULL; p=strchr(p+1,DirectoryListSeparator))
1563  {
1564  (void) CopyMagickString(path,p+1,length+1);
1565  q=strchr(path,DirectoryListSeparator);
1566  if (q != (char *) NULL)
1567  *q='\0';
1568  (void) FormatLocaleString(filename,MagickPathExtent,"%s%sfonts.dir",path,
1569  DirectorySeparator);
1570  if (IsPathAccessible(filename) != MagickFalse)
1571  return(MagickTrue);
1572  (void) FormatLocaleString(filename,MagickPathExtent,"%s%sn019003l.pfb",path,
1573  DirectorySeparator);
1574  if (IsPathAccessible(filename) != MagickFalse)
1575  return(MagickTrue);
1576  }
1577  *path='\0';
1578  return(MagickFalse);
1579 }
1580 ␌
1581 /*
1582 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1583 % %
1584 % %
1585 % %
1586 % N T G h o s t s c r i p t U n L o a d D L L %
1587 % %
1588 % %
1589 % %
1590 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1591 %
1592 % NTGhostscriptUnLoadDLL() unloads the Ghostscript DLL and returns TRUE if
1593 % it succeeds.
1594 %
1595 % The format of the NTGhostscriptUnLoadDLL method is:
1596 %
1597 % int NTGhostscriptUnLoadDLL(void)
1598 %
1599 */
1600 MagickPrivate void NTGhostscriptUnLoadDLL(void)
1601 {
1602  if (ghost_semaphore == (SemaphoreInfo *) NULL)
1603  ActivateSemaphoreInfo(&ghost_semaphore);
1604  LockSemaphoreInfo(ghost_semaphore);
1605  if (ghost_handle != (void *) NULL)
1606  {
1607  (void) lt_dlclose(ghost_handle);
1608  ghost_handle=(void *) NULL;
1609  (void) memset((void *) &ghost_info,0,sizeof(GhostInfo));
1610  }
1611  UnlockSemaphoreInfo(ghost_semaphore);
1612  RelinquishSemaphoreInfo(&ghost_semaphore);
1613 }
1614 ␌
1615 /*
1616 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1617 % %
1618 % %
1619 % %
1620 % N T I s L i n k W i d e %
1621 % %
1622 % %
1623 % %
1624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1625 %
1626 % NTIsSymlinkWide() returns a boolean value indicating whether the specified path
1627 % is a a link.
1628 %
1629 % The format of the NTIsSymlinkWide method is:
1630 %
1631 % MagickBooleanType NTIsSymlinkWide(const char *path)
1632 %
1633 % A description of each parameter follows:
1634 %
1635 % o path: the file path.
1636 %
1637 */
1638 MagickExport MagickBooleanType NTIsSymlinkWide(const char *path)
1639 {
1640  DWORD
1641  attributes;
1642 
1643  wchar_t
1644  *path_wide;
1645 
1646  path_wide=NTCreateWidePath(path);
1647  attributes=GetFileAttributesW(path_wide);
1648  if (attributes == INVALID_FILE_ATTRIBUTES)
1649  return(MagickFalse);
1650  return(((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) ? MagickTrue :
1651  MagickFalse);
1652 }
1653 ␌
1654 /*
1655 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1656 % %
1657 % %
1658 % %
1659 % N T L o n g P a t h s E n a b l e d %
1660 % %
1661 % %
1662 % %
1663 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1664 %
1665 % NTLongPathsEnabled() returns a boolean indicating whether long paths are
1666 $ enabled.
1667 %
1668 % The format of the NTLongPathsEnabled method is:
1669 %
1670 % MagickBooleanType NTLongPathsEnabled()
1671 %
1672 */
1673 MagickExport MagickBooleanType NTLongPathsEnabled()
1674 {
1675  static size_t
1676  long_paths_enabled = 2;
1677 
1678  if (long_paths_enabled == 2)
1679  {
1680  DWORD
1681  size,
1682  type,
1683  value;
1684 
1685  HKEY
1686  registry_key;
1687 
1688  LONG
1689  status;
1690 
1691  registry_key=(HKEY) INVALID_HANDLE_VALUE;
1692  status=RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1693  "SYSTEM\\CurrentControlSet\\Control\\FileSystem",0,KEY_READ,
1694  &registry_key);
1695  if (status != ERROR_SUCCESS)
1696  {
1697  RegCloseKey(registry_key);
1698  long_paths_enabled=0;
1699  return(MagickFalse);
1700  }
1701  value=0;
1702  status=RegQueryValueExA(registry_key,"LongPathsEnabled",0,&type,NULL,
1703  NULL);
1704  if ((status != ERROR_SUCCESS) || (type != REG_DWORD))
1705  {
1706  RegCloseKey(registry_key);
1707  long_paths_enabled=0;
1708  return(MagickFalse);
1709  }
1710  size=0;
1711  status=RegQueryValueExA(registry_key,"LongPathsEnabled",0,&type,
1712  (LPBYTE) &value,&size);
1713  RegCloseKey(registry_key);
1714  if (status != ERROR_SUCCESS)
1715  {
1716  long_paths_enabled=0;
1717  return(MagickFalse);
1718  }
1719  long_paths_enabled=(size_t) value;
1720  }
1721  return(long_paths_enabled == 1 ? MagickTrue : MagickFalse);
1722 }
1723 ␌
1724 /*
1725 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1726 % %
1727 % %
1728 % %
1729 + N T M a p M e m o r y %
1730 % %
1731 % %
1732 % %
1733 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1734 %
1735 % Mmap() emulates the Unix method of the same name.
1736 %
1737 % The format of the NTMapMemory method is:
1738 %
1739 % MagickPrivate void *NTMapMemory(char *address,size_t length,int protection,
1740 % int access,int file,MagickOffsetType offset)
1741 %
1742 */
1743 MagickPrivate void *NTMapMemory(char *address,size_t length,int protection,
1744  int flags,int file,MagickOffsetType offset)
1745 {
1746  DWORD
1747  access_mode,
1748  high_length,
1749  high_offset,
1750  low_length,
1751  low_offset,
1752  protection_mode;
1753 
1754  HANDLE
1755  file_handle,
1756  map_handle;
1757 
1758  void
1759  *map;
1760 
1761  (void) address;
1762  access_mode=0;
1763  file_handle=INVALID_HANDLE_VALUE;
1764  low_length=(DWORD) (length & 0xFFFFFFFFUL);
1765  high_length=(DWORD) ((((MagickOffsetType) length) >> 32) & 0xFFFFFFFFUL);
1766  map_handle=INVALID_HANDLE_VALUE;
1767  map=(void *) NULL;
1768  low_offset=(DWORD) (offset & 0xFFFFFFFFUL);
1769  high_offset=(DWORD) ((offset >> 32) & 0xFFFFFFFFUL);
1770  protection_mode=0;
1771  if (protection & PROT_WRITE)
1772  {
1773  access_mode=FILE_MAP_WRITE;
1774  if (!(flags & MAP_PRIVATE))
1775  protection_mode=PAGE_READWRITE;
1776  else
1777  {
1778  access_mode=FILE_MAP_COPY;
1779  protection_mode=PAGE_WRITECOPY;
1780  }
1781  }
1782  else
1783  if (protection & PROT_READ)
1784  {
1785  access_mode=FILE_MAP_READ;
1786  protection_mode=PAGE_READONLY;
1787  }
1788  if ((file == -1) && (flags & MAP_ANONYMOUS))
1789  file_handle=INVALID_HANDLE_VALUE;
1790  else
1791  file_handle=(HANDLE) _get_osfhandle(file);
1792  map_handle=CreateFileMapping(file_handle,0,protection_mode,high_length,
1793  low_length,0);
1794  if (map_handle)
1795  {
1796  map=(void *) MapViewOfFile(map_handle,access_mode,high_offset,low_offset,
1797  length);
1798  CloseHandle(map_handle);
1799  }
1800  if (map == (void *) NULL)
1801  return((void *) ((char *) MAP_FAILED));
1802  return((void *) ((char *) map));
1803 }
1804 ␌
1805 /*
1806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1807 % %
1808 % %
1809 % %
1810 % N T O p e n D i r e c t o r y %
1811 % %
1812 % %
1813 % %
1814 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1815 %
1816 % NTOpenDirectory() opens the directory named by filename and associates a
1817 % directory stream with it.
1818 %
1819 % The format of the NTOpenDirectory method is:
1820 %
1821 % DIR *NTOpenDirectory(const char *path)
1822 %
1823 % A description of each parameter follows:
1824 %
1825 % o entry: Specifies a pointer to a DIR structure.
1826 %
1827 */
1828 MagickPrivate DIR *NTOpenDirectory(const char *path)
1829 {
1830  DIR
1831  *entry;
1832 
1833  size_t
1834  length;
1835 
1836  wchar_t
1837  file_specification[MagickPathExtent];
1838 
1839  assert(path != (const char *) NULL);
1840  length=MultiByteToWideChar(CP_UTF8,0,path,-1,file_specification,
1841  MagickPathExtent);
1842  if (length == 0)
1843  return((DIR *) NULL);
1844  if (wcsncat_s(file_specification,MagickPathExtent,L"\\*.*",MagickPathExtent-
1845  wcslen(file_specification)-1) != 0)
1846  return((DIR *) NULL);
1847  entry=(DIR *) AcquireCriticalMemory(sizeof(DIR));
1848  entry->firsttime=TRUE;
1849  entry->hSearch=FindFirstFileW(file_specification,&entry->Win32FindData);
1850  if (entry->hSearch == INVALID_HANDLE_VALUE)
1851  {
1852  entry=(DIR *) RelinquishMagickMemory(entry);
1853  return((DIR *) NULL);
1854  }
1855  return(entry);
1856 }
1857 ␌
1858 /*
1859 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1860 % %
1861 % %
1862 % %
1863 % N T O p e n L i b r a r y %
1864 % %
1865 % %
1866 % %
1867 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1868 %
1869 % NTOpenLibrary() loads a dynamic module into memory and returns a handle that
1870 % can be used to access the various procedures in the module.
1871 %
1872 % The format of the NTOpenLibrary method is:
1873 %
1874 % void *NTOpenLibrary(const char *filename)
1875 %
1876 % A description of each parameter follows:
1877 %
1878 % o path: Specifies a pointer to string representing dynamic module that
1879 % is to be loaded.
1880 %
1881 */
1882 static UINT ChangeErrorMode(void)
1883 {
1884  typedef UINT
1885  (CALLBACK *GETERRORMODE)(void);
1886 
1887  GETERRORMODE
1888  getErrorMode;
1889 
1890  HMODULE
1891  handle;
1892 
1893  UINT
1894  mode;
1895 
1896  mode=SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX;
1897 
1898  handle=GetModuleHandle("kernel32.dll");
1899  if (handle == (HMODULE) NULL)
1900  return SetErrorMode(mode);
1901 
1902  getErrorMode=(GETERRORMODE) NTGetLibrarySymbol(handle,"GetErrorMode");
1903  if (getErrorMode != (GETERRORMODE) NULL)
1904  mode=getErrorMode() | SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX;
1905 
1906  return SetErrorMode(mode);
1907 }
1908 
1909 static inline void *NTLoadLibrary(const char *filename)
1910 {
1911  void
1912  *library;
1913 
1914  wchar_t
1915  *path;
1916 
1917  library=(void *) NULL;
1918  path=NTCreateWidePath(filename);
1919  if (path != (wchar_t *) NULL)
1920  {
1921  library=LoadLibraryExW(path,NULL,LOAD_WITH_ALTERED_SEARCH_PATH);
1922  path=(wchar_t *) RelinquishMagickMemory(path);
1923  }
1924  return(library);
1925 }
1926 
1927 MagickPrivate void *NTOpenLibrary(const char *filename)
1928 {
1929  UINT
1930  mode;
1931 
1932  void
1933  *handle;
1934 
1935  mode=ChangeErrorMode();
1936  handle=NTLoadLibrary(filename);
1937 #if defined(MAGICKCORE_LTDL_DELEGATE)
1938  if (handle == (void *) NULL)
1939  {
1940  char
1941  path[MagickPathExtent];
1942 
1943  const char
1944  *p,
1945  *q;
1946 
1947  p=lt_dlgetsearchpath();
1948  while (p != (const char*) NULL)
1949  {
1950  q=strchr(p,DirectoryListSeparator);
1951  if (q != (const char*) NULL)
1952  (void) CopyMagickString(path,p,q-p+1);
1953  else
1954  (void) CopyMagickString(path,p,MagickPathExtent);
1955  (void) ConcatenateMagickString(path,DirectorySeparator,MagickPathExtent);
1956  (void) ConcatenateMagickString(path,filename,MagickPathExtent);
1957  handle=NTLoadLibrary(path);
1958  if (handle != (void *) NULL || q == (const char*) NULL)
1959  break;
1960  p=q+1;
1961  }
1962  }
1963 #endif
1964  SetErrorMode(mode);
1965  return(handle);
1966 }
1967 ␌
1968 /*
1969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1970 % %
1971 % %
1972 % %
1973 % N T O p e n F i l e W i d e %
1974 % %
1975 % %
1976 % %
1977 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1978 %
1979 % NTOpenFileWide() opens a file and returns a file pointer.
1980 %
1981 % The format of the NTOpenFileWide method is:
1982 %
1983 % FILE *NTOpenFileWide(const char* path, const char* mode)
1984 %
1985 % A description of each parameter follows:
1986 %
1987 % o path: the file path.
1988 %
1989 % o mode: the file open mode.
1990 %
1991 */
1992 static inline wchar_t *create_wchar_mode(const char *mode)
1993 {
1994  int
1995  count;
1996 
1997  wchar_t
1998  *wide;
1999 
2000  count=MultiByteToWideChar(CP_UTF8,0,mode,-1,NULL,0);
2001  wide=(wchar_t *) AcquireQuantumMemory((size_t) count+1,
2002  sizeof(*wide));
2003  if (wide == (wchar_t *) NULL)
2004  return((wchar_t *) NULL);
2005  if (MultiByteToWideChar(CP_UTF8,0,mode,-1,wide,count) == 0)
2006  {
2007  wide=(wchar_t *) RelinquishMagickMemory(wide);
2008  return((wchar_t *) NULL);
2009  }
2010  /* Specifies that the file is not inherited by child processes */
2011  wide[count] = L'\0';
2012  wide[count-1] = L'N';
2013  return(wide);
2014 }
2015 
2016 MagickExport FILE *NTOpenFileWide(const char* path, const char* mode)
2017 {
2018  FILE
2019  *file;
2020 
2021  wchar_t
2022  *mode_wide,
2023  *path_wide;
2024 
2025  path_wide=NTCreateWidePath(path);
2026  if (path_wide == (wchar_t *) NULL)
2027  return((FILE *) NULL);
2028  mode_wide=create_wchar_mode(mode);
2029  if (mode_wide == (wchar_t *) NULL)
2030  {
2031  path_wide=(wchar_t *) RelinquishMagickMemory(path_wide);
2032  return((FILE *) NULL);
2033  }
2034  if (_wfopen_s(&file,path_wide,mode_wide) != 0)
2035  file=(FILE *) NULL;
2036  mode_wide=(wchar_t *) RelinquishMagickMemory(mode_wide);
2037  path_wide=(wchar_t *) RelinquishMagickMemory(path_wide);
2038  return(file);
2039 }
2040 ␌
2041 /*
2042 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2043 % %
2044 % %
2045 % %
2046 % N T O p e n P i p e W i d e %
2047 % %
2048 % %
2049 % %
2050 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2051 %
2052 % NTOpenPipeWide() opens a pipe and returns a file pointer.
2053 %
2054 % The format of the NTOpenPipeWide method is:
2055 %
2056 % FILE *NTOpenPipeWide(const char* command, const char* type)
2057 %
2058 % A description of each parameter follows:
2059 %
2060 % o command: the command to execute.
2061 %
2062 % o type: the file open mode.
2063 %
2064 */
2065 MagickExport FILE *NTOpenPipeWide(const char *command,const char *type)
2066 {
2067  FILE
2068  *file;
2069 
2070  int
2071  length;
2072 
2073  wchar_t
2074  *command_wide,
2075  type_wide[5];
2076 
2077  file=(FILE *) NULL;
2078  length=MultiByteToWideChar(CP_UTF8,0,type,-1,type_wide,5);
2079  if (length == 0)
2080  return(file);
2081  length=MultiByteToWideChar(CP_UTF8,0,command,-1,NULL,0);
2082  if (length == 0)
2083  return(file);
2084  command_wide=(wchar_t *) AcquireQuantumMemory((size_t) length,
2085  sizeof(*command_wide));
2086  if (command_wide == (wchar_t *) NULL)
2087  return(file);
2088  length=MultiByteToWideChar(CP_UTF8,0,command,-1,command_wide,length);
2089  if (length != 0)
2090  file=_wpopen(command_wide,type_wide);
2091  command_wide=(wchar_t *) RelinquishMagickMemory(command_wide);
2092  return(file);
2093 }
2094 ␌
2095 /*
2096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2097 % %
2098 % %
2099 % %
2100 % N T O p e n W i d e %
2101 % %
2102 % %
2103 % %
2104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2105 %
2106 % NTOpenWide() opens the file specified by path and mode.
2107 %
2108 % The format of the NTOpenWide method is:
2109 %
2110 % FILE *NTOpenWide(const char* path, const char* mode)
2111 %
2112 % A description of each parameter follows:
2113 %
2114 % o path: the file path.
2115 %
2116 % o flags: the file open flags.
2117 %
2118 % o mode: the file open mode.
2119 %
2120 */
2121 MagickExport int NTOpenWide(const char* path,int flags,mode_t mode)
2122 {
2123  int
2124  file_handle,
2125  status;
2126 
2127  wchar_t
2128  *path_wide;
2129 
2130  path_wide=NTCreateWidePath(path);
2131  if (path_wide == (wchar_t *) NULL)
2132  return(-1);
2133  /* O_NOINHERIT specifies that the file is not inherited by child processes */
2134  status=_wsopen_s(&file_handle,path_wide,flags | O_NOINHERIT,_SH_DENYNO,mode);
2135  path_wide=(wchar_t *) RelinquishMagickMemory(path_wide);
2136  return(status == 0 ? file_handle : -1);
2137 }
2138 ␌
2139 /*
2140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2141 % %
2142 % %
2143 % %
2144 % N T R e a d D i r e c t o r y %
2145 % %
2146 % %
2147 % %
2148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2149 %
2150 % NTReadDirectory() returns a pointer to a structure representing the
2151 % directory entry at the current position in the directory stream to which
2152 % entry refers.
2153 %
2154 % The format of the NTReadDirectory
2155 %
2156 % NTReadDirectory(entry)
2157 %
2158 % A description of each parameter follows:
2159 %
2160 % o entry: Specifies a pointer to a DIR structure.
2161 %
2162 */
2163 MagickPrivate struct dirent *NTReadDirectory(DIR *entry)
2164 {
2165  int
2166  status;
2167 
2168  size_t
2169  length;
2170 
2171  if (entry == (DIR *) NULL)
2172  return((struct dirent *) NULL);
2173  if (!entry->firsttime)
2174  {
2175  status=FindNextFileW(entry->hSearch,&entry->Win32FindData);
2176  if (status == 0)
2177  return((struct dirent *) NULL);
2178  }
2179  length=WideCharToMultiByte(CP_UTF8,0,entry->Win32FindData.cFileName,-1,
2180  entry->file_info.d_name,sizeof(entry->file_info.d_name),NULL,NULL);
2181  if (length == 0)
2182  return((struct dirent *) NULL);
2183  entry->firsttime=FALSE;
2184  entry->file_info.d_namlen=(int) strlen(entry->file_info.d_name);
2185  return(&entry->file_info);
2186 }
2187 ␌
2188 /*
2189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2190 % %
2191 % %
2192 % %
2193 % N T R e a l P a t h W i d e %
2194 % %
2195 % %
2196 % %
2197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2198 %
2199 % NTRealPathWide returns the absolute path of the specified path.
2200 %
2201 % The format of the NTRealPathWide method is:
2202 %
2203 % char *NTRealPathWide(const char *path)
2204 %
2205 % A description of each parameter follows:
2206 %
2207 % o path: the file path.
2208 %
2209 */
2210 static inline wchar_t* resolve_symlink(const wchar_t* path)
2211 {
2212  DWORD
2213  link_length;
2214 
2215  HANDLE
2216  file_handle;
2217 
2218  wchar_t
2219  *link;
2220 
2221  file_handle=CreateFileW(path,GENERIC_READ,FILE_SHARE_READ |FILE_SHARE_WRITE |
2222  FILE_SHARE_DELETE,NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
2223  if (file_handle == INVALID_HANDLE_VALUE)
2224  return((wchar_t *) NULL);
2225  link_length=GetFinalPathNameByHandleW(file_handle,NULL,0,
2226  FILE_NAME_NORMALIZED);
2227  link=(wchar_t *) AcquireQuantumMemory(link_length,sizeof(wchar_t));
2228  if (link == (wchar_t *) NULL)
2229  {
2230  CloseHandle(file_handle);
2231  return((wchar_t *) NULL);
2232  }
2233  GetFinalPathNameByHandleW(file_handle,link,link_length,FILE_NAME_NORMALIZED);
2234  CloseHandle(file_handle);
2235  return(link);
2236 }
2237 
2238 MagickExport char *NTRealPathWide(const char *path)
2239 {
2240  char
2241  *real_path;
2242 
2243  wchar_t
2244  *wide_real_path,
2245  *wide_path;
2246 
2247  wide_path=NTCreateWidePath(path);
2248  wide_real_path=resolve_symlink(wide_path);
2249  if (wide_real_path == (wchar_t*) NULL)
2250  {
2251  DWORD
2252  full_path_length;
2253 
2254  full_path_length=GetFullPathNameW(wide_path,0,NULL,NULL);
2255  wide_real_path=(wchar_t *) AcquireQuantumMemory(full_path_length,
2256  sizeof(wchar_t));
2257  if (wide_real_path == (wchar_t*) NULL)
2258  {
2259  wide_path=(wchar_t *) RelinquishMagickMemory(wide_path);
2260  return((char*) NULL);
2261  }
2262  GetFullPathNameW(wide_path,full_path_length,wide_real_path,NULL);
2263  }
2264  wide_path=(wchar_t *) RelinquishMagickMemory(wide_path);
2265  /*
2266  Remove \\?\ prefix for POSIX-like behavior.
2267  */
2268  if (wcsncmp(wide_real_path,L"\\\\?\\",4) == 0)
2269  real_path=create_utf8_string(wide_real_path+4);
2270  else
2271  real_path=create_utf8_string(wide_real_path);
2272  wide_real_path=(wchar_t *) RelinquishMagickMemory(wide_real_path);
2273  return(real_path);
2274 }
2275 ␌
2276 /*
2277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2278 % %
2279 % %
2280 % %
2281 % N T R e g i s t r y K e y L o o k u p %
2282 % %
2283 % %
2284 % %
2285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2286 %
2287 % NTRegistryKeyLookup() returns ImageMagick installation path settings
2288 % stored in the Windows Registry. Path settings are specific to the
2289 % installed ImageMagick version so that multiple Image Magick installations
2290 % may coexist.
2291 %
2292 % Values are stored in the registry under a base path similar to
2293 % "HKEY_LOCAL_MACHINE/SOFTWARE\ImageMagick\6.7.4\Q:16" or
2294 % "HKEY_CURRENT_USER/SOFTWARE\ImageMagick\6.7.4\Q:16". The provided subkey
2295 % is appended to this base path to form the full key.
2296 %
2297 % The format of the NTRegistryKeyLookup method is:
2298 %
2299 % unsigned char *NTRegistryKeyLookup(const char *subkey)
2300 %
2301 % A description of each parameter follows:
2302 %
2303 % o subkey: Specifies a string that identifies the registry object.
2304 % Currently supported sub-keys include: "BinPath", "ConfigurePath",
2305 % "LibPath", "CoderModulesPath", "FilterModulesPath", "SharePath".
2306 %
2307 */
2308 MagickPrivate unsigned char *NTRegistryKeyLookup(const char *subkey)
2309 {
2310  char
2311  package_key[MagickPathExtent] = "";
2312 
2313  unsigned char
2314  *value;
2315 
2316  (void) FormatLocaleString(package_key,MagickPathExtent,
2317  "SOFTWARE\\%s\\%s\\Q:%d",MagickPackageName,MagickLibVersionText,
2318  MAGICKCORE_QUANTUM_DEPTH);
2319  value=NTGetRegistryValue(HKEY_LOCAL_MACHINE,package_key,0,subkey);
2320  if (value == (unsigned char *) NULL)
2321  value=NTGetRegistryValue(HKEY_CURRENT_USER,package_key,0,subkey);
2322  return(value);
2323 }
2324 ␌
2325 /*
2326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2327 % %
2328 % %
2329 % %
2330 % N T R e m o v e W i d e %
2331 % %
2332 % %
2333 % %
2334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2335 %
2336 % NTRemoveWide() removes the specified file.
2337 %
2338 % The format of the NTRemoveWide method is:
2339 %
2340 % int NTRemoveWide(const char *path)
2341 %
2342 % A description of each parameter follows:
2343 %
2344 % o path: the file path.
2345 %
2346 */
2347 MagickExport int NTRemoveWide(const char *path)
2348 {
2349  int
2350  status;
2351 
2352  wchar_t
2353  *path_wide;
2354 
2355  path_wide=NTCreateWidePath(path);
2356  if (path_wide == (wchar_t *) NULL)
2357  return(-1);
2358  status=_wremove(path_wide);
2359  path_wide=(wchar_t *) RelinquishMagickMemory(path_wide);
2360  return(status);
2361 }
2362 ␌
2363 /*
2364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2365 % %
2366 % %
2367 % %
2368 % N T R e n a m e W i d e %
2369 % %
2370 % %
2371 % %
2372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2373 %
2374 % NTRenameWide() renames a file.
2375 %
2376 % The format of the NTRenameWide method is:
2377 %
2378 % int NTRenameWide(const char *source, const char *destination)
2379 %
2380 % A description of each parameter follows:
2381 %
2382 % o source: the source file path.
2383 %
2384 % o destination: the destination file path.
2385 %
2386 */
2387 MagickExport int NTRenameWide(const char* source, const char* destination)
2388 {
2389  int
2390  status;
2391 
2392  wchar_t
2393  *destination_wide,
2394  *source_wide;
2395 
2396  source_wide=NTCreateWidePath(source);
2397  if (source_wide == (wchar_t *) NULL)
2398  return(-1);
2399  destination_wide=NTCreateWidePath(destination);
2400  if (destination_wide == (wchar_t *) NULL)
2401  {
2402  source_wide=(wchar_t *) RelinquishMagickMemory(source_wide);
2403  return(-1);
2404  }
2405  status=_wrename(source_wide,destination_wide);
2406  destination_wide=(wchar_t *) RelinquishMagickMemory(destination_wide);
2407  source_wide=(wchar_t *) RelinquishMagickMemory(source_wide);
2408  return(status);
2409 }
2410 ␌
2411 /*
2412 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2413 % %
2414 % %
2415 % %
2416 % N T R e p o r t E v e n t %
2417 % %
2418 % %
2419 % %
2420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2421 %
2422 % NTReportEvent() reports an event.
2423 %
2424 % The format of the NTReportEvent method is:
2425 %
2426 % MagickBooleanType NTReportEvent(const char *event,
2427 % const MagickBooleanType error)
2428 %
2429 % A description of each parameter follows:
2430 %
2431 % o event: the event.
2432 %
2433 % o error: MagickTrue the event is an error.
2434 %
2435 */
2436 MagickPrivate MagickBooleanType NTReportEvent(const char *event,
2437  const MagickBooleanType error)
2438 {
2439  const char
2440  *events[1];
2441 
2442  HANDLE
2443  handle;
2444 
2445  WORD
2446  type;
2447 
2448  handle=RegisterEventSource(NULL,MAGICKCORE_PACKAGE_NAME);
2449  if (handle == NULL)
2450  return(MagickFalse);
2451  events[0]=event;
2452  type=error ? EVENTLOG_ERROR_TYPE : EVENTLOG_WARNING_TYPE;
2453  ReportEvent(handle,type,0,0,NULL,1,0,events,NULL);
2454  DeregisterEventSource(handle);
2455  return(MagickTrue);
2456 }
2457 ␌
2458 /*
2459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2460 % %
2461 % %
2462 % %
2463 % N T R e s o u r c e T o B l o b %
2464 % %
2465 % %
2466 % %
2467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2468 %
2469 % NTResourceToBlob() returns a blob containing the contents of the resource
2470 % in the current executable specified by the id parameter. This currently
2471 % used to retrieve MGK files tha have been embedded into the various command
2472 % line utilities.
2473 %
2474 % The format of the NTResourceToBlob method is:
2475 %
2476 % unsigned char *NTResourceToBlob(const char *id)
2477 %
2478 % A description of each parameter follows:
2479 %
2480 % o id: Specifies a string that identifies the resource.
2481 %
2482 */
2483 MagickPrivate unsigned char *NTResourceToBlob(const char *id)
2484 {
2485 #ifndef MAGICKCORE_LIBRARY_NAME
2486  char
2487  path[MagickPathExtent];
2488 #endif
2489 
2490  DWORD
2491  length;
2492 
2493  HGLOBAL
2494  global;
2495 
2496  HMODULE
2497  handle;
2498 
2499  HRSRC
2500  resource;
2501 
2502  unsigned char
2503  *blob,
2504  *value;
2505 
2506  assert(id != (const char *) NULL);
2507  if (IsEventLogging() != MagickFalse)
2508  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",id);
2509 #ifdef MAGICKCORE_LIBRARY_NAME
2510  handle=GetModuleHandle(MAGICKCORE_LIBRARY_NAME);
2511 #else
2512  (void) FormatLocaleString(path,MagickPathExtent,"%s%s%s",GetClientPath(),
2513  DirectorySeparator,GetClientName());
2514  if (IsPathAccessible(path) != MagickFalse)
2515  handle=GetModuleHandle(path);
2516  else
2517  handle=GetModuleHandle(0);
2518 #endif
2519  if (!handle)
2520  return((unsigned char *) NULL);
2521  resource=FindResource(handle,id,"IMAGEMAGICK");
2522  if (!resource)
2523  return((unsigned char *) NULL);
2524  global=LoadResource(handle,resource);
2525  if (!global)
2526  return((unsigned char *) NULL);
2527  length=SizeofResource(handle,resource);
2528  value=(unsigned char *) LockResource(global);
2529  if (!value)
2530  {
2531  FreeResource(global);
2532  return((unsigned char *) NULL);
2533  }
2534  blob=(unsigned char *) AcquireQuantumMemory(length+MagickPathExtent,
2535  sizeof(*blob));
2536  if (blob != (unsigned char *) NULL)
2537  {
2538  (void) memcpy(blob,value,length);
2539  blob[length]='\0';
2540  }
2541  UnlockResource(global);
2542  FreeResource(global);
2543  return(blob);
2544 }
2545 ␌
2546 /*
2547 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2548 % %
2549 % %
2550 % %
2551 % NT S e t F i l e T i m e s t a m p %
2552 % %
2553 % %
2554 % %
2555 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2556 %
2557 % NTSetFileTimestamp() sets the file timestamps for a specified file.
2558 %
2559 % The format of the NTSetFileTimestamp method is:
2560 %
2561 % int NTSetFileTimestamp(const char *path, struct stat *attributes)
2562 %
2563 % A description of each parameter follows:
2564 %
2565 % o path: the file path.
2566 %
2567 % o attributes: the file attributes.
2568 %
2569 */
2570 MagickExport int NTSetFileTimestamp(const char *path, struct stat *attributes)
2571 {
2572  HANDLE
2573  handle;
2574 
2575  int
2576  status;
2577 
2578  wchar_t
2579  *path_wide;
2580 
2581  status=(-1);
2582  path_wide=NTCreateWidePath(path);
2583  if (path_wide == (WCHAR *) NULL)
2584  return(status);
2585  handle=CreateFileW(path_wide,FILE_WRITE_ATTRIBUTES,FILE_SHARE_WRITE |
2586  FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
2587  if (handle != (HANDLE) NULL)
2588  {
2589  FILETIME
2590  creation_time,
2591  last_access_time,
2592  last_write_time;
2593 
2594  ULARGE_INTEGER
2595  date_time;
2596 
2597  date_time.QuadPart=(ULONGLONG) (attributes->st_ctime*10000000LL)+
2598  116444736000000000LL;
2599  creation_time.dwLowDateTime=date_time.LowPart;
2600  creation_time.dwHighDateTime=date_time.HighPart;
2601  date_time.QuadPart=(ULONGLONG) (attributes->st_atime*10000000LL)+
2602  116444736000000000LL;
2603  last_access_time.dwLowDateTime=date_time.LowPart;
2604  last_access_time.dwHighDateTime=date_time.HighPart;
2605  date_time.QuadPart=(ULONGLONG) (attributes->st_mtime*10000000LL)+
2606  116444736000000000LL;
2607  last_write_time.dwLowDateTime=date_time.LowPart;
2608  last_write_time.dwHighDateTime=date_time.HighPart;
2609  status=SetFileTime(handle,&creation_time,&last_access_time,&last_write_time);
2610  CloseHandle(handle);
2611  status=0;
2612  }
2613  path_wide=(WCHAR *) RelinquishMagickMemory(path_wide);
2614  return(status);
2615 }
2616 ␌
2617 /*
2618 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2619 % %
2620 % %
2621 % %
2622 % N T S t a t W i d e %
2623 % %
2624 % %
2625 % %
2626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2627 %
2628 % NTStatWide() gets the file attributes for a specified file.
2629 %
2630 % The format of the NTStatWide method is:
2631 %
2632 % int NTStatWide(const char *path,struct stat *attributes)
2633 %
2634 % A description of each parameter follows:
2635 %
2636 % o path: the file path.
2637 %
2638 % o attributes: the file attributes.
2639 %
2640 */
2641 
2642 static inline _ino_t MapFileIndexToIno(uint64_t fileIndex)
2643 {
2644  fileIndex^=fileIndex >> 33;
2645  fileIndex*=0xff51afd7ed558ccdULL;
2646  fileIndex^=fileIndex >> 33;
2647  fileIndex*=0xc4ceb9fe1a85ec53ULL;
2648  fileIndex^=fileIndex >> 33;
2649  return((_ino_t) fileIndex);
2650 }
2651 
2652 MagickExport int NTStatWide(const char *path,struct stat *attributes)
2653 {
2654 #ifndef S_IFDIR
2655  #define S_IFDIR 0040000 /* directory */
2656 #endif
2657 #ifndef S_IFREG
2658  #define S_IFREG 0100000 /* regular file */
2659 #endif
2660 #ifndef S_IRUSR
2661  #define S_IRUSR 0000400 /* owner has read permission */
2662 #endif
2663 #ifndef S_IWUSR
2664  #define S_IWUSR 0000200 /* owner has write permission */
2665 #endif
2666 #ifndef S_IXUSR
2667  #define S_IXUSR 0000100 /* owner has execute/search permission */
2668 #endif
2669 
2670  int
2671  status;
2672 
2673  wchar_t
2674  *path_wide;
2675 
2676  path_wide=NTCreateWidePath(path);
2677  if (path_wide == (WCHAR *) NULL)
2678  return(-1);
2679  status=wstat(path_wide,attributes);
2680  if (status == 0)
2681  {
2682  HANDLE handle = CreateFileW(path_wide,FILE_READ_ATTRIBUTES,
2683  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,NULL,
2684  OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
2685  if (handle != INVALID_HANDLE_VALUE)
2686  {
2687  BY_HANDLE_FILE_INFORMATION
2688  file_info;
2689 
2690  /*
2691  POSIX emulation of Windows file attributes.
2692  */
2693  if (GetFileInformationByHandle(handle,&file_info) != 0)
2694  {
2695  attributes->st_dev=(dev_t) file_info.dwVolumeSerialNumber;
2696  attributes->st_ino=MapFileIndexToIno((((uint64_t)
2697  file_info.nFileIndexHigh) << 32) | (uint64_t)
2698  file_info.nFileIndexLow);
2699  attributes->st_mode=0;
2700  if ((file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
2701  attributes->st_mode|=S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR;
2702  else
2703  attributes->st_mode|=S_IFREG | S_IRUSR | S_IWUSR;
2704  if ((file_info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0)
2705  attributes->st_mode&=~S_IWUSR;
2706  }
2707  CloseHandle(handle);
2708  }
2709  }
2710  path_wide=(WCHAR *) RelinquishMagickMemory(path_wide);
2711  return(status);
2712 }
2713 ␌
2714 /*
2715 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2716 % %
2717 % %
2718 % %
2719 % N T S y s t e m C o m m a n d %
2720 % %
2721 % %
2722 % %
2723 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2724 %
2725 % NTSystemCommand() executes the specified command and waits until it
2726 % terminates. The returned value is the exit status of the command.
2727 %
2728 % The format of the NTSystemCommand method is:
2729 %
2730 % int NTSystemCommand(MagickFalse,const char *command)
2731 %
2732 % A description of each parameter follows:
2733 %
2734 % o command: This string is the command to execute.
2735 %
2736 % o output: an optional buffer to store the output from stderr/stdout.
2737 %
2738 */
2739 MagickPrivate int NTSystemCommand(const char *command,char *output)
2740 {
2741 #define CleanupOutputHandles \
2742  if (read_output != (HANDLE) NULL) \
2743  { \
2744  CloseHandle(read_output); \
2745  read_output=(HANDLE) NULL; \
2746  CloseHandle(write_output); \
2747  write_output=(HANDLE) NULL; \
2748  }
2749 
2750 #define CopyLastError \
2751  last_error=GetLastError(); \
2752  if (output != (char *) NULL) \
2753  { \
2754  error=NTGetLastErrorMessage(last_error); \
2755  if (error != (char *) NULL) \
2756  { \
2757  (void) CopyMagickString(output,error,MagickPathExtent); \
2758  error=DestroyString(error); \
2759  } \
2760  }
2761 
2762  char
2763  *error,
2764  local_command[MagickPathExtent];
2765 
2766  DWORD
2767  child_status,
2768  last_error;
2769 
2770  int
2771  status;
2772 
2773  MagickBooleanType
2774  asynchronous;
2775 
2776  HANDLE
2777  read_output,
2778  write_output;
2779 
2780  PROCESS_INFORMATION
2781  process_info;
2782 
2783  size_t
2784  output_offset;
2785 
2786  STARTUPINFO
2787  startup_info;
2788 
2789  if (command == (char *) NULL)
2790  return(-1);
2791  read_output=(HANDLE) NULL;
2792  write_output=(HANDLE) NULL;
2793  GetStartupInfo(&startup_info);
2794  startup_info.dwFlags=STARTF_USESHOWWINDOW;
2795  startup_info.wShowWindow=SW_SHOWMINNOACTIVE;
2796  (void) CopyMagickString(local_command,command,MagickPathExtent);
2797  asynchronous=command[strlen(command)-1] == '&' ? MagickTrue : MagickFalse;
2798  if (asynchronous != MagickFalse)
2799  {
2800  local_command[strlen(command)-1]='\0';
2801  startup_info.wShowWindow=SW_SHOWDEFAULT;
2802  }
2803  else
2804  {
2805  if (command[strlen(command)-1] == '|')
2806  local_command[strlen(command)-1]='\0';
2807  else
2808  startup_info.wShowWindow=SW_HIDE;
2809  read_output=(HANDLE) NULL;
2810  if (output != (char *) NULL)
2811  {
2812  if (CreatePipe(&read_output,&write_output,NULL,0))
2813  {
2814  if (SetHandleInformation(write_output,HANDLE_FLAG_INHERIT,
2815  HANDLE_FLAG_INHERIT))
2816  {
2817  startup_info.dwFlags|=STARTF_USESTDHANDLES;
2818  startup_info.hStdOutput=write_output;
2819  startup_info.hStdError=write_output;
2820  }
2821  else
2822  CleanupOutputHandles;
2823  }
2824  else
2825  read_output=(HANDLE) NULL;
2826  }
2827  }
2828  status=CreateProcess((LPCTSTR) NULL,local_command,(LPSECURITY_ATTRIBUTES)
2829  NULL,(LPSECURITY_ATTRIBUTES) NULL,(BOOL) TRUE,(DWORD)
2830  NORMAL_PRIORITY_CLASS,(LPVOID) NULL,(LPCSTR) NULL,&startup_info,
2831  &process_info);
2832  if (status == 0)
2833  {
2834  CopyLastError;
2835  CleanupOutputHandles;
2836  return(last_error == ERROR_FILE_NOT_FOUND ? 127 : -1);
2837  }
2838  if (output != (char *) NULL)
2839  *output='\0';
2840  if (asynchronous != MagickFalse)
2841  return(status == 0);
2842  output_offset=0;
2843  status=STATUS_TIMEOUT;
2844  while (status == STATUS_TIMEOUT)
2845  {
2846  DWORD
2847  size;
2848 
2849  status=WaitForSingleObject(process_info.hProcess,1000);
2850  size=0;
2851  if (read_output != (HANDLE) NULL)
2852  if (!PeekNamedPipe(read_output,NULL,0,NULL,&size,NULL))
2853  break;
2854  while (size > 0)
2855  {
2856  char
2857  buffer[MagickPathExtent];
2858 
2859  DWORD
2860  bytes_read;
2861 
2862  if (ReadFile(read_output,buffer,MagickPathExtent-1,&bytes_read,NULL))
2863  {
2864  size_t
2865  count;
2866 
2867  count=MagickMin(MagickPathExtent-output_offset,
2868  (size_t) bytes_read+1);
2869  if (count > 0)
2870  {
2871  (void) CopyMagickString(output+output_offset,buffer,count);
2872  output_offset+=count-1;
2873  }
2874  }
2875  if (!PeekNamedPipe(read_output,NULL,0,NULL,&size,NULL))
2876  break;
2877  }
2878  }
2879  if (status != WAIT_OBJECT_0)
2880  {
2881  CopyLastError;
2882  CleanupOutputHandles;
2883  return(status);
2884  }
2885  status=GetExitCodeProcess(process_info.hProcess,&child_status);
2886  if (status == 0)
2887  {
2888  CopyLastError;
2889  CleanupOutputHandles;
2890  return(-1);
2891  }
2892  CloseHandle(process_info.hProcess);
2893  CloseHandle(process_info.hThread);
2894  CleanupOutputHandles;
2895  return((int) child_status);
2896 }
2897 ␌
2898 /*
2899 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2900 % %
2901 % %
2902 % %
2903 % N T S y s t e m C o n i f i g u r a t i o n %
2904 % %
2905 % %
2906 % %
2907 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2908 %
2909 % NTSystemConfiguration() provides a way for the application to determine
2910 % values for system limits or options at runtime.
2911 %
2912 % The format of the exit method is:
2913 %
2914 % ssize_t NTSystemConfiguration(int name)
2915 %
2916 % A description of each parameter follows:
2917 %
2918 % o name: _SC_PAGE_SIZE or _SC_PHYS_PAGES.
2919 %
2920 */
2921 MagickPrivate ssize_t NTSystemConfiguration(int name)
2922 {
2923  switch (name)
2924  {
2925  case _SC_PAGE_SIZE:
2926  {
2927  SYSTEM_INFO
2928  system_info;
2929 
2930  GetSystemInfo(&system_info);
2931  return(system_info.dwPageSize);
2932  }
2933  case _SC_PHYS_PAGES:
2934  {
2935  MEMORYSTATUSEX
2936  status;
2937 
2938  SYSTEM_INFO
2939  system_info;
2940 
2941  status.dwLength=sizeof(status);
2942  if (GlobalMemoryStatusEx(&status) == 0)
2943  return(0L);
2944  GetSystemInfo(&system_info);
2945  return((ssize_t) status.ullTotalPhys/system_info.dwPageSize);
2946  }
2947  case _SC_OPEN_MAX:
2948  return(2048);
2949  default:
2950  break;
2951  }
2952  return(-1);
2953 }
2954 ␌
2955 /*
2956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2957 % %
2958 % %
2959 % %
2960 % N T T r u n c a t e F i l e %
2961 % %
2962 % %
2963 % %
2964 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2965 %
2966 % NTTruncateFile() truncates a file to a specified length.
2967 %
2968 % The format of the NTTruncateFile method is:
2969 %
2970 % int NTTruncateFile(int file,off_t length)
2971 %
2972 % A description of each parameter follows:
2973 %
2974 % o file: the file.
2975 %
2976 % o length: the file length.
2977 %
2978 */
2979 MagickPrivate int NTTruncateFile(int file,off_t length)
2980 {
2981  DWORD
2982  file_pointer;
2983 
2984  HANDLE
2985  file_handle;
2986 
2987  long
2988  high,
2989  low;
2990 
2991  file_handle=(HANDLE) _get_osfhandle(file);
2992  if (file_handle == INVALID_HANDLE_VALUE)
2993  return(-1);
2994  low=(long) (length & 0xffffffffUL);
2995  high=(long) ((((MagickOffsetType) length) >> 32) & 0xffffffffUL);
2996  file_pointer=SetFilePointer(file_handle,low,&high,FILE_BEGIN);
2997  if ((file_pointer == 0xFFFFFFFF) && (GetLastError() != NO_ERROR))
2998  return(-1);
2999  if (SetEndOfFile(file_handle) == 0)
3000  return(-1);
3001  return(0);
3002 }
3003 ␌
3004 /*
3005 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3006 % %
3007 % %
3008 % %
3009 + N T U n m a p M e m o r y %
3010 % %
3011 % %
3012 % %
3013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3014 %
3015 % NTUnmapMemory() emulates the Unix munmap method.
3016 %
3017 % The format of the NTUnmapMemory method is:
3018 %
3019 % int NTUnmapMemory(void *map,size_t length)
3020 %
3021 % A description of each parameter follows:
3022 %
3023 % o map: the address of the binary large object.
3024 %
3025 % o length: the length of the binary large object.
3026 %
3027 */
3028 MagickPrivate int NTUnmapMemory(void *map,size_t length)
3029 {
3030  (void) length;
3031  if (UnmapViewOfFile(map) == 0)
3032  return(-1);
3033  return(0);
3034 }
3035 ␌
3036 /*
3037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3038 % %
3039 % %
3040 % %
3041 % N T W a r n i n g H a n d l e r %
3042 % %
3043 % %
3044 % %
3045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3046 %
3047 % NTWarningHandler() displays a warning reason.
3048 %
3049 % The format of the NTWarningHandler method is:
3050 %
3051 % void NTWarningHandler(const ExceptionType severity,const char *reason,
3052 % const char *description)
3053 %
3054 % A description of each parameter follows:
3055 %
3056 % o severity: Specifies the numeric warning category.
3057 %
3058 % o reason: Specifies the reason to display before terminating the
3059 % program.
3060 %
3061 % o description: Specifies any description to the reason.
3062 %
3063 */
3064 MagickPrivate void NTWarningHandler(const ExceptionType severity,
3065  const char *reason,const char *description)
3066 {
3067  char
3068  buffer[2*MagickPathExtent];
3069 
3070  (void) severity;
3071  if (reason == (char *) NULL)
3072  return;
3073  if (description == (char *) NULL)
3074  (void) FormatLocaleString(buffer,MagickPathExtent,"%s: %s.\n",GetClientName(),
3075  reason);
3076  else
3077  (void) FormatLocaleString(buffer,MagickPathExtent,"%s: %s (%s).\n",
3078  GetClientName(),reason,description);
3079  (void) MessageBox(NULL,buffer,"ImageMagick Warning",MB_OK | MB_TASKMODAL |
3080  MB_SETFOREGROUND | MB_ICONINFORMATION);
3081 }
3082 ␌
3083 /*
3084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3085 % %
3086 % %
3087 % %
3088 % N T W i n d o w s G e n e s i s %
3089 % %
3090 % %
3091 % %
3092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3093 %
3094 % NTWindowsGenesis() initializes the MagickCore Windows environment.
3095 %
3096 % The format of the NTWindowsGenesis method is:
3097 %
3098 % void NTWindowsGenesis(void)
3099 %
3100 */
3101 MagickPrivate void NTWindowsGenesis(void)
3102 {
3103  char
3104  *mode;
3105 
3106  mode=GetEnvironmentValue("MAGICK_ERRORMODE");
3107  if (mode != (char *) NULL)
3108  {
3109  (void) SetErrorMode(StringToInteger(mode));
3110  mode=DestroyString(mode);
3111  }
3112 #if defined(_DEBUG) && !defined(__MINGW32__)
3113  if (IsEventLogging() != MagickFalse)
3114  {
3115  int
3116  debug;
3117 
3118  debug=_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
3119  //debug |= _CRTDBG_CHECK_ALWAYS_DF;
3120  debug |= _CRTDBG_DELAY_FREE_MEM_DF;
3121  debug |= _CRTDBG_LEAK_CHECK_DF;
3122  (void) _CrtSetDbgFlag(debug);
3123 
3124  //_ASSERTE(_CrtCheckMemory());
3125 
3126  //_CrtSetBreakAlloc(42);
3127  }
3128 #endif
3129 #if defined(MAGICKCORE_INSTALLED_SUPPORT)
3130  {
3131  unsigned char
3132  *path;
3133 
3134  path=NTRegistryKeyLookup("LibPath");
3135  if (path != (unsigned char *) NULL)
3136  {
3137  wchar_t
3138  *lib_path;
3139 
3140  lib_path=NTCreateWidePath((const char *) path);
3141  if (lib_path != (wchar_t *) NULL)
3142  {
3143  SetDllDirectoryW(lib_path);
3144  lib_path=(wchar_t *) RelinquishMagickMemory(lib_path);
3145  }
3146  path=(unsigned char *) RelinquishMagickMemory(path);
3147  }
3148  }
3149 #endif
3150 }
3151 ␌
3152 /*
3153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3154 % %
3155 % %
3156 % %
3157 % N T W i n d o w s T e r m i n u s %
3158 % %
3159 % %
3160 % %
3161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3162 %
3163 % NTWindowsTerminus() terminates the MagickCore Windows environment.
3164 %
3165 % The format of the NTWindowsTerminus method is:
3166 %
3167 % void NTWindowsTerminus(void)
3168 %
3169 */
3170 MagickPrivate void NTWindowsTerminus(void)
3171 {
3172  NTGhostscriptUnLoadDLL();
3173  DistributeCacheTerminus();
3174 }
3175 #endif