1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: gp_mswin.c 8250 2007-09-25 13:31:24Z giles $ */
15 /*
16  * Microsoft Windows platform support for Ghostscript.
17  *
18  * Original version by Russell Lang and Maurice Castro with help from
19  * Programming Windows, 2nd Ed., Charles Petzold, Microsoft Press;
20  * initially created from gp_dosfb.c and gp_itbc.c 5th June 1992.
21  */
22 
23 /* Modified for Win32 & Microsoft C/C++ 8.0 32-Bit, 26.Okt.1994 */
24 /* by Friedrich Nowak                                           */
25 
26 /* Original EXE and GSview specific code removed */
27 /* DLL version must now be used under MS-Windows */
28 /* Russell Lang 16 March 1996 */
29 
30 #include "stdio_.h"
31 #include "string_.h"
32 #include "memory_.h"
33 #include "pipe_.h"
34 #include <stdlib.h>
35 #include <stdarg.h>
36 #include "ctype_.h"
37 #include <io.h>
38 #include "malloc_.h"
39 #include <fcntl.h>
40 #include <signal.h>
41 #include "gx.h"
42 #include "gp.h"
43 #include "gpcheck.h"
44 #include "gpmisc.h"
45 #include "gserrors.h"
46 #include "gsexit.h"
47 
48 #include "windows_.h"
49 #include <stdarg.h>
50 #include <shellapi.h>
51 #include <winspool.h>
52 #include "gp_mswin.h"
53 
54 /* Library routines not declared in a standard header */
55 extern char *getenv(const char *);
56 
57 /* limits */
58 #define MAXSTR 255
59 
60 /* GLOBAL VARIABLE that needs to be removed */
61 char win_prntmp[MAXSTR];	/* filename of PRN temporary file */
62 
63 /* GLOBAL VARIABLES - initialised at DLL load time */
64 HINSTANCE phInstance;
65 BOOL is_win32s = FALSE;
66 
67 const LPSTR szAppName = "Ghostscript";
68 static int is_printer(const char *name);
69 
70 
71 /* ====== Generic platform procedures ====== */
72 
73 /* ------ Initialization/termination (from gp_itbc.c) ------ */
74 
75 /* Do platform-dependent initialization. */
76 void
gp_init(void)77 gp_init(void)
78 {
79 }
80 
81 /* Do platform-dependent cleanup. */
82 void
gp_exit(int exit_status,int code)83 gp_exit(int exit_status, int code)
84 {
85 }
86 
87 /* Exit the program. */
88 void
gp_do_exit(int exit_status)89 gp_do_exit(int exit_status)
90 {
91     exit(exit_status);
92 }
93 
94 /* ------ Persistent data cache ------*/
95 
96 /* insert a buffer under a (type, key) pair */
gp_cache_insert(int type,byte * key,int keylen,void * buffer,int buflen)97 int gp_cache_insert(int type, byte *key, int keylen, void *buffer, int buflen)
98 {
99     /* not yet implemented */
100     return 0;
101 }
102 
103 /* look up a (type, key) in the cache */
gp_cache_query(int type,byte * key,int keylen,void ** buffer,gp_cache_alloc alloc,void * userdata)104 int gp_cache_query(int type, byte* key, int keylen, void **buffer,
105     gp_cache_alloc alloc, void *userdata)
106 {
107     /* not yet implemented */
108     return -1;
109 }
110 
111 /* ------ Printer accessing ------ */
112 
113 /* Forward references */
114 static int gp_printfile(const char *, const char *);
115 
116 /* Open a connection to a printer.  A null file name means use the */
117 /* standard printer connected to the machine, if any. */
118 /* Return NULL if the connection could not be opened. */
119 FILE *
gp_open_printer(char fname[gp_file_name_sizeof],int binary_mode)120 gp_open_printer(char fname[gp_file_name_sizeof], int binary_mode)
121 {
122     if (is_printer(fname)) {
123 	FILE *pfile;
124 
125 	/* Open a scratch file, which we will send to the */
126 	/* actual printer in gp_close_printer. */
127 	pfile = gp_open_scratch_file(gp_scratch_file_name_prefix,
128 				     win_prntmp, "wb");
129 	return pfile;
130     } else if (fname[0] == '|') 	/* pipe */
131 	return popen(fname + 1, (binary_mode ? "wb" : "w"));
132     else if (strcmp(fname, "LPT1:") == 0)
133 	return NULL;	/* not supported, use %printer%name instead  */
134     else
135 	return fopen(fname, (binary_mode ? "wb" : "w"));
136 }
137 
138 /* Close the connection to the printer. */
139 void
gp_close_printer(FILE * pfile,const char * fname)140 gp_close_printer(FILE * pfile, const char *fname)
141 {
142     fclose(pfile);
143     if (!is_printer(fname))
144 	return;			/* a file, not a printer */
145 
146     gp_printfile(win_prntmp, fname);
147     unlink(win_prntmp);
148 }
149 
150 
151 /* Dialog box to select printer port */
152 DLGRETURN CALLBACK
SpoolDlgProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)153 SpoolDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
154 {
155     LPSTR entry;
156 
157     switch (message) {
158 	case WM_INITDIALOG:
159 	    entry = (LPSTR) lParam;
160 	    while (*entry) {
161 		SendDlgItemMessage(hDlg, SPOOL_PORT, LB_ADDSTRING, 0, (LPARAM) entry);
162 		entry += lstrlen(entry) + 1;
163 	    }
164 	    SendDlgItemMessage(hDlg, SPOOL_PORT, LB_SETCURSEL, 0, (LPARAM) 0);
165 	    return TRUE;
166 	case WM_COMMAND:
167 	    switch (LOWORD(wParam)) {
168 		case SPOOL_PORT:
169 		    if (HIWORD(wParam) == LBN_DBLCLK)
170 			PostMessage(hDlg, WM_COMMAND, IDOK, 0L);
171 		    return FALSE;
172 		case IDOK:
173 		    EndDialog(hDlg, 1 + (int)SendDlgItemMessage(hDlg, SPOOL_PORT, LB_GETCURSEL, 0, 0L));
174 		    return TRUE;
175 		case IDCANCEL:
176 		    EndDialog(hDlg, 0);
177 		    return TRUE;
178 	    }
179     }
180     return FALSE;
181 }
182 
183 /* return TRUE if queue looks like a valid printer name */
184 int
is_spool(const char * queue)185 is_spool(const char *queue)
186 {
187     char *prefix = "\\\\spool";	/* 7 characters long */
188     int i;
189 
190     for (i = 0; i < 7; i++) {
191 	if (prefix[i] == '\\') {
192 	    if ((*queue != '\\') && (*queue != '/'))
193 		return FALSE;
194 	} else if (tolower(*queue) != prefix[i])
195 	    return FALSE;
196 	queue++;
197     }
198     if (*queue && (*queue != '\\') && (*queue != '/'))
199 	return FALSE;
200     return TRUE;
201 }
202 
203 
204 static int
is_printer(const char * name)205 is_printer(const char *name)
206 {
207     /* is printer if no name given */
208     if (strlen(name) == 0)
209 	return TRUE;
210 
211     /* is printer if name prefixed by \\spool\ */
212     if (is_spool(name))
213 	return TRUE;
214 
215     return FALSE;
216 }
217 
218 
219 /******************************************************************/
220 /* Print File to port or queue */
221 /* port==NULL means prompt for port or queue with dialog box */
222 
223 /* This is messy because of past support for old version of Windows. */
224 
225 /* Win95, WinNT: Use OpenPrinter, WritePrinter etc. */
226 static int gp_printfile_win32(const char *filename, char *port);
227 
228 /*
229  * Valid values for pmport are:
230  *   ""
231  *      action: Use default queue
232  *   "\\spool\printer name"
233  *      action: send to printer using WritePrinter.
234  *              Using "%printer%printer name" is preferred
235  *   "\\spool"
236  *      action: prompt for queue name then send to printer using WritePrinter.
237  *              THIS IS CURRENTLY BROKEN
238  */
239 /* Print File */
240 static int
gp_printfile(const char * filename,const char * pmport)241 gp_printfile(const char *filename, const char *pmport)
242 {
243     if (strlen(pmport) == 0) {	/* get default printer */
244 	char buf[256];
245 	char *p;
246 
247 	/* WinNT stores default printer in registry and win.ini */
248 	/* Win95 stores default printer in win.ini */
249 	GetProfileString("windows", "device", "", buf, sizeof(buf));
250 	if ((p = strchr(buf, ',')) != NULL)
251 	    *p = '\0';
252 	return gp_printfile_win32(filename, buf);
253     } else if (is_spool(pmport)) {
254 	if (strlen(pmport) >= 8)
255 	    return gp_printfile_win32(filename, (char *)pmport + 8);
256 	else
257 	    return gp_printfile_win32(filename, (char *)NULL);
258     } else
259 	return gs_error_undefinedfilename;
260 }
261 
262 #define PRINT_BUF_SIZE 16384u
263 #define PORT_BUF_SIZE 4096
264 
265 char *
get_queues(void)266 get_queues(void)
267 {
268     int i;
269     DWORD count, needed;
270     PRINTER_INFO_1 *prinfo;
271     char *enumbuffer;
272     char *buffer;
273     char *p;
274 
275     /* enumerate all available printers */
276     EnumPrinters(PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL, NULL, 1, NULL, 0, &needed, &count);
277     if (needed == 0) {
278 	/* no printers */
279 	enumbuffer = malloc(4);
280 	if (enumbuffer == (char *)NULL)
281 	    return NULL;
282 	memset(enumbuffer, 0, 4);
283 	return enumbuffer;
284     }
285     enumbuffer = malloc(needed);
286     if (enumbuffer == (char *)NULL)
287 	return NULL;
288     if (!EnumPrinters(PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL, NULL, 1, (LPBYTE) enumbuffer, needed, &needed, &count)) {
289 	char buf[256];
290 
291 	free(enumbuffer);
292 	sprintf(buf, "EnumPrinters() failed, error code = %d", GetLastError());
293 	MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
294 	return NULL;
295     }
296     prinfo = (PRINTER_INFO_1 *) enumbuffer;
297     if ((buffer = malloc(PORT_BUF_SIZE)) == (char *)NULL) {
298 	free(enumbuffer);
299 	return NULL;
300     }
301     /* copy printer names to single buffer */
302     p = buffer;
303     for (i = 0; i < count; i++) {
304 	if (strlen(prinfo[i].pName) + 1 < (PORT_BUF_SIZE - (p - buffer))) {
305 	    strcpy(p, prinfo[i].pName);
306 	    p += strlen(p) + 1;
307 	}
308     }
309     *p = '\0';			/* double null at end */
310     free(enumbuffer);
311     return buffer;
312 }
313 
314 /* return TRUE if queuename available */
315 /* return FALSE if cancelled or error */
316 /* if queue non-NULL, use as suggested queue */
317 BOOL
get_queuename(char * portname,const char * queue)318 get_queuename(char *portname, const char *queue)
319 {
320     char *buffer;
321     char *p;
322     int i, iport;
323 
324     buffer = get_queues();
325     if (buffer == NULL)
326 	return FALSE;
327     if ((queue == (char *)NULL) || (strlen(queue) == 0)) {
328         /* PROMPTING FOR A QUEUE IS CURRENTLY BROKEN */
329 	/* select a queue */
330 	iport = DialogBoxParam(phInstance, "QueueDlgBox", (HWND) NULL, SpoolDlgProc, (LPARAM) buffer);
331 	if (!iport) {
332 	    free(buffer);
333 	    return FALSE;
334 	}
335 	p = buffer;
336 	for (i = 1; i < iport && strlen(p) != 0; i++)
337 	    p += lstrlen(p) + 1;
338 	/* prepend \\spool\ which is used by Ghostscript to distinguish */
339 	/* real files from queues */
340 	strcpy(portname, "\\\\spool\\");
341 	strcat(portname, p);
342     } else {
343 	strcpy(portname, "\\\\spool\\");
344 	strcat(portname, queue);
345     }
346 
347     free(buffer);
348     return TRUE;
349 }
350 
351 /* True Win32 method, using OpenPrinter, WritePrinter etc. */
352 static int
gp_printfile_win32(const char * filename,char * port)353 gp_printfile_win32(const char *filename, char *port)
354 {
355     DWORD count;
356     char *buffer;
357     char portname[MAXSTR];
358     FILE *f;
359     HANDLE printer;
360     DOC_INFO_1 di;
361     DWORD written;
362 
363     if (!get_queuename(portname, port))
364 	return FALSE;
365     port = portname + 8;	/* skip over \\spool\ */
366 
367     if ((buffer = malloc(PRINT_BUF_SIZE)) == (char *)NULL)
368 	return FALSE;
369 
370     if ((f = fopen(filename, "rb")) == (FILE *) NULL) {
371 	free(buffer);
372 	return FALSE;
373     }
374     /* open a printer */
375     if (!OpenPrinter(port, &printer, NULL)) {
376 	char buf[256];
377 
378 	sprintf(buf, "OpenPrinter() failed for \042%s\042, error code = %d", port, GetLastError());
379 	MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
380 	free(buffer);
381 	return FALSE;
382     }
383     /* from here until ClosePrinter, should AbortPrinter on error */
384 
385     di.pDocName = szAppName;
386     di.pOutputFile = NULL;
387     di.pDatatype = "RAW";	/* for available types see EnumPrintProcessorDatatypes */
388     if (!StartDocPrinter(printer, 1, (LPBYTE) & di)) {
389 	char buf[256];
390 
391 	sprintf(buf, "StartDocPrinter() failed, error code = %d", GetLastError());
392 	MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
393 	AbortPrinter(printer);
394 	free(buffer);
395 	return FALSE;
396     }
397     /* copy file to printer */
398     while ((count = fread(buffer, 1, PRINT_BUF_SIZE, f)) != 0) {
399 	if (!WritePrinter(printer, (LPVOID) buffer, count, &written)) {
400 	    free(buffer);
401 	    fclose(f);
402 	    AbortPrinter(printer);
403 	    return FALSE;
404 	}
405     }
406     fclose(f);
407     free(buffer);
408 
409     if (!EndDocPrinter(printer)) {
410 	char buf[256];
411 
412 	sprintf(buf, "EndDocPrinter() failed, error code = %d", GetLastError());
413 	MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
414 	AbortPrinter(printer);
415 	return FALSE;
416     }
417     if (!ClosePrinter(printer)) {
418 	char buf[256];
419 
420 	sprintf(buf, "ClosePrinter() failed, error code = %d", GetLastError());
421 	MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
422 	return FALSE;
423     }
424     return TRUE;
425 }
426 
427 
428 
429 
430 /******************************************************************/
431 /* MS Windows has popen and pclose in stdio.h, but under different names.
432  * Unfortunately MSVC5 and 6 have a broken implementation of _popen,
433  * so we use own.  Our implementation only supports mode "wb".
434  */
mswin_popen(const char * cmd,const char * mode)435 FILE *mswin_popen(const char *cmd, const char *mode)
436 {
437     SECURITY_ATTRIBUTES saAttr;
438     STARTUPINFO siStartInfo;
439     PROCESS_INFORMATION piProcInfo;
440     HANDLE hPipeTemp = INVALID_HANDLE_VALUE;
441     HANDLE hChildStdinRd = INVALID_HANDLE_VALUE;
442     HANDLE hChildStdinWr = INVALID_HANDLE_VALUE;
443     HANDLE hChildStdoutWr = INVALID_HANDLE_VALUE;
444     HANDLE hChildStderrWr = INVALID_HANDLE_VALUE;
445     HANDLE hProcess = GetCurrentProcess();
446     int handle = 0;
447     char *command = NULL;
448     FILE *pipe = NULL;
449 
450     if (strcmp(mode, "wb") != 0)
451 	return NULL;
452 
453     /* Set the bInheritHandle flag so pipe handles are inherited. */
454     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
455     saAttr.bInheritHandle = TRUE;
456     saAttr.lpSecurityDescriptor = NULL;
457 
458     /* Create anonymous inheritable pipes for STDIN for child.
459      * First create a noninheritable duplicate handle of our end of
460      * the pipe, then close the inheritable handle.
461      */
462     if (handle == 0)
463         if (!CreatePipe(&hChildStdinRd, &hPipeTemp, &saAttr, 0))
464 	    handle = -1;
465     if (handle == 0) {
466 	if (!DuplicateHandle(hProcess, hPipeTemp,
467 	    hProcess, &hChildStdinWr, 0, FALSE /* not inherited */,
468 	    DUPLICATE_SAME_ACCESS))
469 	    handle = -1;
470         CloseHandle(hPipeTemp);
471     }
472     /* Create inheritable duplicate handles for our stdout/err */
473     if (handle == 0)
474 	if (!DuplicateHandle(hProcess, GetStdHandle(STD_OUTPUT_HANDLE),
475 	    hProcess, &hChildStdoutWr, 0, TRUE /* inherited */,
476 	    DUPLICATE_SAME_ACCESS))
477 	    handle = -1;
478     if (handle == 0)
479         if (!DuplicateHandle(hProcess, GetStdHandle(STD_ERROR_HANDLE),
480             hProcess, &hChildStderrWr, 0, TRUE /* inherited */,
481 	    DUPLICATE_SAME_ACCESS))
482 	    handle = -1;
483 
484     /* Set up members of STARTUPINFO structure. */
485     memset(&siStartInfo, 0, sizeof(STARTUPINFO));
486     siStartInfo.cb = sizeof(STARTUPINFO);
487     siStartInfo.dwFlags = STARTF_USESTDHANDLES;
488     siStartInfo.hStdInput = hChildStdinRd;
489     siStartInfo.hStdOutput = hChildStdoutWr;
490     siStartInfo.hStdError = hChildStderrWr;
491 
492     if (handle == 0) {
493 	command = (char *)malloc(strlen(cmd)+1);
494 	if (command)
495 	    strcpy(command, cmd);
496 	else
497 	    handle = -1;
498     }
499 
500     if (handle == 0)
501 	if (!CreateProcess(NULL,
502 	    command,  	   /* command line                       */
503 	    NULL,          /* process security attributes        */
504 	    NULL,          /* primary thread security attributes */
505 	    TRUE,          /* handles are inherited              */
506 	    0,             /* creation flags                     */
507 	    NULL,          /* environment                        */
508 	    NULL,          /* use parent's current directory     */
509 	    &siStartInfo,  /* STARTUPINFO pointer                */
510 	    &piProcInfo))  /* receives PROCESS_INFORMATION  */
511 	{
512 	    handle = -1;
513 	}
514 	else {
515 	    CloseHandle(piProcInfo.hProcess);
516 	    CloseHandle(piProcInfo.hThread);
517 	    handle = _open_osfhandle((long)hChildStdinWr, 0);
518 	}
519 
520     if (hChildStdinRd != INVALID_HANDLE_VALUE)
521 	CloseHandle(hChildStdinRd);	/* close our copy */
522     if (hChildStdoutWr != INVALID_HANDLE_VALUE)
523 	CloseHandle(hChildStdoutWr);	/* close our copy */
524     if (hChildStderrWr != INVALID_HANDLE_VALUE)
525 	CloseHandle(hChildStderrWr);	/* close our copy */
526     if (command)
527 	free(command);
528 
529     if (handle < 0) {
530 	if (hChildStdinWr != INVALID_HANDLE_VALUE)
531 	    CloseHandle(hChildStdinWr);
532     }
533     else {
534 	pipe = _fdopen(handle, "wb");
535 	if (pipe == NULL)
536 	    _close(handle);
537     }
538     return pipe;
539 }
540 
541 
542 /* ------ File naming and accessing ------ */
543 
544 /* Create and open a scratch file with a given name prefix. */
545 /* Write the actual file name at fname. */
546 FILE *
gp_open_scratch_file(const char * prefix,char * fname,const char * mode)547 gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
548 {
549     UINT n;
550     DWORD l;
551     HANDLE hfile = INVALID_HANDLE_VALUE;
552     int fd = -1;
553     FILE *f = NULL;
554     char sTempDir[_MAX_PATH];
555     char sTempFileName[_MAX_PATH];
556 
557     memset(fname, 0, gp_file_name_sizeof);
558     if (!gp_file_name_is_absolute(prefix, strlen(prefix))) {
559 	int plen = sizeof(sTempDir);
560 
561 	if (gp_gettmpdir(sTempDir, &plen) != 0)
562 	    l = GetTempPath(sizeof(sTempDir), sTempDir);
563 	else
564 	    l = strlen(sTempDir);
565     } else {
566 	strncpy(sTempDir, prefix, sizeof(sTempDir));
567 	prefix = "";
568 	l = strlen(sTempDir);
569     }
570     /* Fix the trailing terminator so GetTempFileName doesn't get confused */
571     if (sTempDir[l-1] == '/')
572 	sTempDir[l-1] = '\\';		/* What Windoze prefers */
573 
574     if (l <= sizeof(sTempDir)) {
575 	n = GetTempFileName(sTempDir, prefix, 0, sTempFileName);
576 	if (n == 0) {
577 	    /* If 'prefix' is not a directory, it is a path prefix. */
578 	    int l = strlen(sTempDir), i;
579 
580 	    for (i = l - 1; i > 0; i--) {
581 		uint slen = gs_file_name_check_separator(sTempDir + i, l, sTempDir + l);
582 
583 		if (slen > 0) {
584 		    sTempDir[i] = 0;
585 		    i += slen;
586 		    break;
587 		}
588 	    }
589 	    if (i > 0)
590 		n = GetTempFileName(sTempDir, sTempDir + i, 0, sTempFileName);
591 	}
592 	if (n != 0) {
593 	    hfile = CreateFile(sTempFileName,
594 		GENERIC_READ | GENERIC_WRITE | DELETE,
595 		FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
596 		FILE_ATTRIBUTE_NORMAL /* | FILE_FLAG_DELETE_ON_CLOSE */,
597 		NULL);
598 	    /*
599 	     * Can't apply FILE_FLAG_DELETE_ON_CLOSE due to
600 	     * the logics of clist_fclose. Also note that
601 	     * gdev_prn_render_pages requires multiple temporary files
602 	     * to exist simultaneousely, so that keeping all them opened
603 	     * may exceed available CRTL file handles.
604 	     */
605 	}
606     }
607     if (hfile != INVALID_HANDLE_VALUE) {
608 	/* Associate a C file handle with an OS file handle. */
609 	fd = _open_osfhandle((long)hfile, 0);
610 	if (fd == -1)
611 	    CloseHandle(hfile);
612 	else {
613 	    /* Associate a C file stream with C file handle. */
614 	    f = fdopen(fd, mode);
615 	    if (f == NULL)
616 		_close(fd);
617 	}
618     }
619     if (f != NULL) {
620 	if ((strlen(sTempFileName) < gp_file_name_sizeof))
621 	    strncpy(fname, sTempFileName, gp_file_name_sizeof - 1);
622 	else {
623 	    /* The file name is too long. */
624 	    fclose(f);
625 	    f = NULL;
626 	}
627     }
628     if (f == NULL)
629 	eprintf1("**** Could not open temporary file '%s'\n", fname);
630     return f;
631 }
632 
633 /* Open a file with the given name, as a stream of uninterpreted bytes. */
634 FILE *
gp_fopen(const char * fname,const char * mode)635 gp_fopen(const char *fname, const char *mode)
636 {
637     return fopen(fname, mode);
638 }
639 
640 /* ------ Font enumeration ------ */
641 
642  /* This is used to query the native os for a list of font names and
643   * corresponding paths. The general idea is to save the hassle of
644   * building a custom fontmap file.
645   */
646 
gp_enumerate_fonts_init(gs_memory_t * mem)647 void *gp_enumerate_fonts_init(gs_memory_t *mem)
648 {
649     return NULL;
650 }
651 
gp_enumerate_fonts_next(void * enum_state,char ** fontname,char ** path)652 int gp_enumerate_fonts_next(void *enum_state, char **fontname, char **path)
653 {
654     return 0;
655 }
656 
gp_enumerate_fonts_free(void * enum_state)657 void gp_enumerate_fonts_free(void *enum_state)
658 {
659 }
660 
661 /* --------- 64 bit file access ----------- */
662 /* MSVC versions before 8 doen't provide big files.
663    MSVC 8 doesn't distinguish big and small files,
664    but provide special positioning functions
665    to access data behind 4GB.
666    Currently we support 64 bits file access with MSVC only.
667  */
668 
gp_fopen_64(const char * filename,const char * mode)669 FILE *gp_fopen_64(const char *filename, const char *mode)
670 {
671     return fopen(filename, mode);
672 }
673 
gp_open_scratch_file_64(const char * prefix,char fname[gp_file_name_sizeof],const char * mode)674 FILE *gp_open_scratch_file_64(const char *prefix,
675 			   char fname[gp_file_name_sizeof],
676 			   const char *mode)
677 {
678     return gp_open_scratch_file(prefix, fname, mode);
679 }
680 
gp_open_printer_64(char fname[gp_file_name_sizeof],int binary_mode)681 FILE *gp_open_printer_64(char fname[gp_file_name_sizeof], int binary_mode)
682 {
683     /* Assuming gp_open_scratch_file_64 is same as gp_open_scratch_file -
684        see the body of gp_open_printer. */
685     return gp_open_printer(fname, binary_mode);
686 }
687 
688 #if defined(_MSC_VER) && _MSC_VER < 1400
689     int64_t _ftelli64( FILE *);
690     int _fseeki64( FILE *, int64_t, int);
691 #endif
692 
gp_ftell_64(FILE * strm)693 int64_t gp_ftell_64(FILE *strm)
694 {
695 #if !defined(_MSC_VER)
696     return ftell(strm);
697 #elif _MSC_VER < 1200
698     return ftell(strm);
699 #else
700     return (int64_t)_ftelli64(strm);
701 #endif
702 }
703 
gp_fseek_64(FILE * strm,int64_t offset,int origin)704 int gp_fseek_64(FILE *strm, int64_t offset, int origin)
705 {
706 #if !defined(_MSC_VER)
707     return fseek(strm, offset, origin);
708 #elif _MSC_VER < 1200
709     long offset1 = (long)offset;
710 
711     if (offset != offset1)
712 	return -1;
713     return fseek(strm, offset1, origin);
714 #else
715     return _fseeki64(strm, offset, origin);
716 #endif
717 }
718 
719 /* -------------------------  _snprintf -----------------------------*/
720 
721 /* Microsoft Visual C++ 2005  doesn't properly define snprintf,
722    which is defined in the C standard ISO/IEC 9899:1999 (E) */
723 
snprintf(char * buffer,size_t count,const char * format,...)724 int snprintf(char *buffer, size_t count, const char *format, ...)
725 {
726     if (count > 0) {
727 	va_list args;
728 	int n;
729 
730 	va_start(args, format);
731 	n = _vsnprintf(buffer, count, format, args);
732 	buffer[count - 1] = 0;
733 	va_end(args);
734 	return n;
735     } else
736 	return 0;
737 }
738