MagickCore 7.1.1-43
Convert, Edit, Or Compose Bitmap Images
Loading...
Searching...
No Matches
utility-private.h
1/*
2 Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization
3 dedicated to making software imaging solutions freely available.
4
5 You may not use this file except in compliance with the License. You may
6 obtain a copy of the License at
7
8 https://imagemagick.org/script/license.php
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15
16 MagickCore private utility methods.
17*/
18#ifndef MAGICKCORE_UTILITY_PRIVATE_H
19#define MAGICKCORE_UTILITY_PRIVATE_H
20
21#include "MagickCore/memory_.h"
22#include "MagickCore/nt-base.h"
23#include "MagickCore/nt-base-private.h"
24#if defined(MAGICKCORE_HAVE_UTIME_H)
25#include <utime.h>
26#endif
27
28#if defined(__cplusplus) || defined(c_plusplus)
29extern "C" {
30#endif
31
32#define MagickPathTemplate "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" /* min 6 X's */
33
34extern MagickPrivate char
35 **GetPathComponents(const char *,size_t *),
36 **ListFiles(const char *,const char *,size_t *);
37
38extern MagickPrivate MagickBooleanType
39 GetExecutionPath(char *,const size_t),
40 ShredFile(const char *);
41
42extern MagickPrivate ssize_t
43 GetMagickPageSize(void);
44
45extern MagickPrivate void
46 ChopPathComponents(char *,const size_t),
47 ExpandFilename(char *);
48
49static inline MagickBooleanType GetPathSignature(int file,char signature[33])
50{
51 char
52 *p = signature;
53
54 ssize_t
55 i;
56
57 static const char
58 hex[] = "0123456789abcdef";
59
60 uint64_t
61 file_identity[2];
62
63#if defined(MAGICKCORE_WINDOWS_SUPPORT)
64 BY_HANDLE_FILE_INFORMATION file_info;
65 HANDLE handle = (HANDLE) _get_osfhandle(file);
66 if (handle == INVALID_HANDLE_VALUE)
67 return(MagickFalse);
68 if (GetFileInformationByHandle(handle,&file_info) == 0)
69 return(MagickFalse);
70 file_identity[0]=(uint64_t) file_info.dwVolumeSerialNumber;
71 file_identity[1]=((uint64_t) file_info.nFileIndexHigh << 32) |
72 (uint64_t) file_info.nFileIndexLow;
73#else
74 struct stat file_attributes;
75 if (fstat(file, &file_attributes) != 0)
76 return(MagickFalse);
77 file_identity[0]=(uint64_t) file_attributes.st_dev;
78 file_identity[1]=(uint64_t) file_attributes.st_ino;
79#endif
80 for (i=0; i < 2; i++)
81 {
82 ssize_t
83 shift;
84
85 for (shift=60; shift >= 0; shift-=4)
86 *p++=hex[(file_identity[i] >> shift) & 0xF];
87 }
88 *p='\0';
89 return(MagickTrue);
90}
91
92static inline int MagickReadDirectory(DIR *directory,struct dirent *entry,
93 struct dirent **result)
94{
95 (void) entry;
96 errno=0;
97 *result=readdir(directory);
98 return(errno);
99}
100
101/*
102 Windows UTF8 compatibility methods.
103*/
104
105#if defined(MAGICKCORE_WINDOWS_SUPPORT)
106static inline wchar_t *create_wchar_path(const char *utf8)
107{
108 int
109 count;
110
111 wchar_t
112 *wide;
113
114 count=MultiByteToWideChar(CP_UTF8,0,utf8,-1,NULL,0);
115 if ((count > MAX_PATH) && (strncmp(utf8,"\\\\?\\",4) != 0) &&
116 (NTLongPathsEnabled() == MagickFalse))
117 {
118 char
119 buffer[MagickPathExtent];
120
121 wchar_t
122 shortPath[MAX_PATH],
123 *longPath;
124
125 (void) FormatLocaleString(buffer,MagickPathExtent,"\\\\?\\%s",utf8);
126 count+=4;
127 longPath=(wchar_t *) NTAcquireQuantumMemory((size_t) count,
128 sizeof(*longPath));
129 if (longPath == (wchar_t *) NULL)
130 return((wchar_t *) NULL);
131 count=MultiByteToWideChar(CP_UTF8,0,buffer,-1,longPath,count);
132 if (count != 0)
133 count=(int) GetShortPathNameW(longPath,shortPath,MAX_PATH);
134 longPath=(wchar_t *) RelinquishMagickMemory(longPath);
135 if ((count < 5) || (count >= MAX_PATH))
136 return((wchar_t *) NULL);
137 wide=(wchar_t *) NTAcquireQuantumMemory((size_t) count-3,sizeof(*wide));
138 wcscpy(wide,shortPath+4);
139 return(wide);
140 }
141 wide=(wchar_t *) NTAcquireQuantumMemory((size_t) count,sizeof(*wide));
142 if ((wide != (wchar_t *) NULL) &&
143 (MultiByteToWideChar(CP_UTF8,0,utf8,-1,wide,count) == 0))
144 wide=(wchar_t *) RelinquishMagickMemory(wide);
145 return(wide);
146}
147
148static inline wchar_t *create_wchar_mode(const char *mode)
149{
150 int
151 count;
152
153 wchar_t
154 *wide;
155
156 count=MultiByteToWideChar(CP_UTF8,0,mode,-1,NULL,0);
157 wide=(wchar_t *) AcquireQuantumMemory((size_t) count+1,
158 sizeof(*wide));
159 if (wide == (wchar_t *) NULL)
160 return((wchar_t *) NULL);
161 if (MultiByteToWideChar(CP_UTF8,0,mode,-1,wide,count) == 0)
162 {
163 wide=(wchar_t *) RelinquishMagickMemory(wide);
164 return((wchar_t *) NULL);
165 }
166 /* Specifies that the file is not inherited by child processes */
167 wide[count] = L'\0';
168 wide[count-1] = L'N';
169 return(wide);
170}
171#endif
172
173static inline int access_utf8(const char *path,int mode)
174{
175 if (path == (const char *) NULL)
176 return(-1);
177#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
178 return(access(path,mode));
179#else
180 int
181 status;
182
183 wchar_t
184 *path_wide;
185
186 path_wide=create_wchar_path(path);
187 if (path_wide == (wchar_t *) NULL)
188 return(-1);
189 status=_waccess(path_wide,mode);
190 path_wide=(wchar_t *) RelinquishMagickMemory(path_wide);
191 return(status);
192#endif
193}
194
195#if defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__CYGWIN__) && !defined(__MINGW32__)
196#define close_utf8 _close
197#else
198#define close_utf8 close
199#endif
200
201static inline FILE *fopen_utf8(const char *path,const char *mode)
202{
203#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
204 return(fopen(path,mode));
205#else
206 FILE
207 *file;
208
209 wchar_t
210 *mode_wide,
211 *path_wide;
212
213 path_wide=create_wchar_path(path);
214 if (path_wide == (wchar_t *) NULL)
215 return((FILE *) NULL);
216 mode_wide=create_wchar_mode(mode);
217 if (mode_wide == (wchar_t *) NULL)
218 {
219 path_wide=(wchar_t *) RelinquishMagickMemory(path_wide);
220 return((FILE *) NULL);
221 }
222 file=_wfopen(path_wide,mode_wide);
223 mode_wide=(wchar_t *) RelinquishMagickMemory(mode_wide);
224 path_wide=(wchar_t *) RelinquishMagickMemory(path_wide);
225 return(file);
226#endif
227}
228
229static inline MagickBooleanType is_symlink_utf8(const char *path)
230{
231#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
232#if defined(MAGICKCORE_POSIX_SUPPORT)
233 struct stat
234 status;
235
236 if (lstat(path,&status) == -1)
237 return(MagickFalse);
238 return(S_ISLNK(status.st_mode) != 0 ? MagickTrue : MagickFalse);
239#else
240 return(MagickFalse);
241#endif
242#else
243 return(NTIsSymlinkWide(path));
244#endif
245}
246
247static inline void getcwd_utf8(char *path,size_t extent)
248{
249#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
250 char
251 *directory;
252
253 directory=getcwd(path,extent);
254 (void) directory;
255#else
256 wchar_t
257 wide_path[MagickPathExtent];
258
259 (void) _wgetcwd(wide_path,MagickPathExtent-1);
260 (void) WideCharToMultiByte(CP_UTF8,0,wide_path,-1,path,(int) extent,NULL,NULL);
261#endif
262}
263
264#if defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__CYGWIN__) && !defined(__MINGW32__)
265typedef int
266 mode_t;
267#endif
268
269static inline int open_utf8(const char *path,int flags,mode_t mode)
270{
271#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
272 return(open(path,flags,mode));
273#else
274 int
275 status;
276
277 wchar_t
278 *path_wide;
279
280 path_wide=create_wchar_path(path);
281 if (path_wide == (wchar_t *) NULL)
282 return(-1);
283 /* O_NOINHERIT specifies that the file is not inherited by child processes */
284 status=_wopen(path_wide,flags | O_NOINHERIT,mode);
285 path_wide=(wchar_t *) RelinquishMagickMemory(path_wide);
286 return(status);
287#endif
288}
289
290static inline FILE *popen_utf8(const char *command,const char *type)
291{
292#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
293 return(popen(command,type));
294#else
295 FILE
296 *file;
297
298 int
299 length;
300
301 wchar_t
302 *command_wide,
303 type_wide[5];
304
305 file=(FILE *) NULL;
306 length=MultiByteToWideChar(CP_UTF8,0,type,-1,type_wide,5);
307 if (length == 0)
308 return(file);
309 length=MultiByteToWideChar(CP_UTF8,0,command,-1,NULL,0);
310 if (length == 0)
311 return(file);
312 command_wide=(wchar_t *) AcquireQuantumMemory((size_t) length,
313 sizeof(*command_wide));
314 if (command_wide == (wchar_t *) NULL)
315 return(file);
316 length=MultiByteToWideChar(CP_UTF8,0,command,-1,command_wide,length);
317 if (length != 0)
318 file=_wpopen(command_wide,type_wide);
319 command_wide=(wchar_t *) RelinquishMagickMemory(command_wide);
320 return(file);
321#endif
322}
323
324static inline char *realpath_utf8(const char *path)
325{
326#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
327#if defined(MAGICKCORE_HAVE_REALPATH)
328 return(realpath(path,(char *) NULL));
329#else
330 return(AcquireString(path));
331#endif
332#else
333 char
334 *real_path;
335
336 DWORD
337 final_path_length,
338 full_path_length;
339
340 HANDLE
341 file_handle;
342
343 int
344 length,
345 utf8_length;
346
347 wchar_t
348 *clean_path,
349 *full_path,
350 *wide_path;
351
352 /*
353 Convert UTF-8 to UTF-16.
354 */
355 if (path == (const char *) NULL)
356 return((char *) NULL);
357 length=MultiByteToWideChar(CP_UTF8,0,path,-1,NULL,0);
358 if (length <= 0)
359 return((char *) NULL);
360 wide_path=(wchar_t *) AcquireQuantumMemory(length,sizeof(wchar_t));
361 if (wide_path == (wchar_t *) NULL)
362 return((char *) NULL);
363 MultiByteToWideChar(CP_UTF8,0,path,-1,wide_path,length);
364 /*
365 Normalize syntactically.
366 */
367 full_path_length=GetFullPathNameW(wide_path,0,NULL,NULL);
368 if (full_path_length == 0)
369 {
370 wide_path=(wchar_t *) RelinquishMagickMemory(wide_path);
371 return((char *) NULL);
372 }
373 full_path=(wchar_t *) AcquireQuantumMemory(full_path_length,sizeof(wchar_t));
374 if (full_path == (wchar_t *) NULL)
375 {
376 wide_path=(wchar_t *) RelinquishMagickMemory(wide_path);
377 return((char *) NULL);
378 }
379 GetFullPathNameW(wide_path,full_path_length,full_path,NULL);
380 wide_path=(wchar_t *) RelinquishMagickMemory(wide_path);
381 /*
382 Open the file/directory to resolve symlinks.
383 */
384 file_handle=CreateFileW(full_path,GENERIC_READ,FILE_SHARE_READ |
385 FILE_SHARE_WRITE | FILE_SHARE_DELETE,NULL,OPEN_EXISTING,
386 FILE_FLAG_BACKUP_SEMANTICS,NULL);
387 if (file_handle != INVALID_HANDLE_VALUE)
388 {
389 /*
390 Resolve final canonical path.
391 */
392 final_path_length=GetFinalPathNameByHandleW(file_handle,NULL,0,
393 FILE_NAME_NORMALIZED);
394 if (final_path_length == 0)
395 {
396 CloseHandle(file_handle);
397 full_path=(wchar_t *) RelinquishMagickMemory(full_path);
398 return((char *) NULL);
399 }
400 full_path=(wchar_t *) RelinquishMagickMemory(full_path);
401 full_path=(wchar_t *) AcquireQuantumMemory(final_path_length,
402 sizeof(wchar_t));
403 if (full_path == (wchar_t *) NULL)
404 {
405 CloseHandle(file_handle);
406 return((char *) NULL);
407 }
408 GetFinalPathNameByHandleW(file_handle,full_path,final_path_length,
409 FILE_NAME_NORMALIZED);
410 CloseHandle(file_handle);
411 }
412 /*
413 Remove \\?\ prefix for POSIX-like behavior.
414 */
415 clean_path=full_path;
416 if (wcsncmp(full_path,L"\\\\?\\",4) == 0)
417 clean_path=full_path+4;
418 /*
419 Convert UTF-16 to UTF-8.
420 */
421 utf8_length=WideCharToMultiByte(CP_UTF8,0,clean_path,-1,NULL,0,NULL,NULL);
422 if (utf8_length <= 0)
423 {
424 full_path=(wchar_t *) RelinquishMagickMemory(full_path);
425 return NULL;
426 }
427 real_path=(char *) AcquireQuantumMemory(utf8_length,sizeof(char));
428 if (real_path == (char *) NULL)
429 {
430 full_path=(wchar_t *) RelinquishMagickMemory(full_path);
431 return NULL;
432 }
433 WideCharToMultiByte(CP_UTF8,0,clean_path,-1,real_path,utf8_length,NULL,NULL);
434 full_path=(wchar_t *) RelinquishMagickMemory(full_path);
435 return(real_path);
436#endif
437}
438
439static inline int remove_utf8(const char *path)
440{
441#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
442 return(unlink(path));
443#else
444 int
445 status;
446
447 wchar_t
448 *path_wide;
449
450 path_wide=create_wchar_path(path);
451 if (path_wide == (wchar_t *) NULL)
452 return(-1);
453 status=_wremove(path_wide);
454 path_wide=(wchar_t *) RelinquishMagickMemory(path_wide);
455 return(status);
456#endif
457}
458
459static inline int rename_utf8(const char *source,const char *destination)
460{
461#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
462 return(rename(source,destination));
463#else
464 int
465 status;
466
467 wchar_t
468 *destination_wide,
469 *source_wide;
470
471 source_wide=create_wchar_path(source);
472 if (source_wide == (wchar_t *) NULL)
473 return(-1);
474 destination_wide=create_wchar_path(destination);
475 if (destination_wide == (wchar_t *) NULL)
476 {
477 source_wide=(wchar_t *) RelinquishMagickMemory(source_wide);
478 return(-1);
479 }
480 status=_wrename(source_wide,destination_wide);
481 destination_wide=(wchar_t *) RelinquishMagickMemory(destination_wide);
482 source_wide=(wchar_t *) RelinquishMagickMemory(source_wide);
483 return(status);
484#endif
485}
486
487static inline int set_file_timestamp(const char *path,struct stat *attributes)
488{
489 int
490 status;
491
492#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
493#if defined(MAGICKCORE_HAVE_UTIMENSAT)
494#if defined(__APPLE__) || defined(__NetBSD__)
495#define st_atim st_atimespec
496#define st_ctim st_ctimespec
497#define st_mtim st_mtimespec
498#endif
499
500 struct timespec
501 timestamp[2];
502
503 timestamp[0].tv_sec=attributes->st_atim.tv_sec;
504 timestamp[0].tv_nsec=attributes->st_atim.tv_nsec;
505 timestamp[1].tv_sec=attributes->st_mtim.tv_sec;
506 timestamp[1].tv_nsec=attributes->st_mtim.tv_nsec;
507 status=utimensat(AT_FDCWD,path,timestamp,0);
508#else
509 struct utimbuf
510 timestamp;
511
512 timestamp.actime=attributes->st_atime;
513 timestamp.modtime=attributes->st_mtime;
514 status=utime(path,&timestamp);
515#endif
516#else
517 HANDLE
518 handle;
519
520 wchar_t
521 *path_wide;
522
523 status=(-1);
524 path_wide=create_wchar_path(path);
525 if (path_wide == (WCHAR *) NULL)
526 return(status);
527 handle=CreateFileW(path_wide,FILE_WRITE_ATTRIBUTES,FILE_SHARE_WRITE |
528 FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
529 if (handle != (HANDLE) NULL)
530 {
531 FILETIME
532 creation_time,
533 last_access_time,
534 last_write_time;
535
536 ULARGE_INTEGER
537 date_time;
538
539 date_time.QuadPart=(ULONGLONG) (attributes->st_ctime*10000000LL)+
540 116444736000000000LL;
541 creation_time.dwLowDateTime=date_time.LowPart;
542 creation_time.dwHighDateTime=date_time.HighPart;
543 date_time.QuadPart=(ULONGLONG) (attributes->st_atime*10000000LL)+
544 116444736000000000LL;
545 last_access_time.dwLowDateTime=date_time.LowPart;
546 last_access_time.dwHighDateTime=date_time.HighPart;
547 date_time.QuadPart=(ULONGLONG) (attributes->st_mtime*10000000LL)+
548 116444736000000000LL;
549 last_write_time.dwLowDateTime=date_time.LowPart;
550 last_write_time.dwHighDateTime=date_time.HighPart;
551 status=SetFileTime(handle,&creation_time,&last_access_time,&last_write_time);
552 CloseHandle(handle);
553 status=0;
554 }
555 path_wide=(WCHAR *) RelinquishMagickMemory(path_wide);
556#endif
557 return(status);
558}
559
560static inline int stat_utf8(const char *path,struct stat *attributes)
561{
562#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
563 return(stat(path,attributes));
564#else
565 int
566 status;
567
568 wchar_t
569 *path_wide;
570
571 path_wide=create_wchar_path(path);
572 if (path_wide == (WCHAR *) NULL)
573 return(-1);
574 status=_wstati64(path_wide,attributes);
575 path_wide=(WCHAR *) RelinquishMagickMemory(path_wide);
576 return(status);
577#endif
578}
579
580#if defined(__cplusplus) || defined(c_plusplus)
581}
582#endif
583
584#endif