summaryrefslogtreecommitdiff
path: root/gs/base/gp_macio.c
diff options
context:
space:
mode:
Diffstat (limited to 'gs/base/gp_macio.c')
-rw-r--r--gs/base/gp_macio.c1051
1 files changed, 1051 insertions, 0 deletions
diff --git a/gs/base/gp_macio.c b/gs/base/gp_macio.c
new file mode 100644
index 000000000..cbd3c5059
--- /dev/null
+++ b/gs/base/gp_macio.c
@@ -0,0 +1,1051 @@
+/* Copyright (C) 2001-2006 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied, modified
+ or distributed except as expressly authorized under the terms of that
+ license. Refer to licensing information at http://www.artifex.com/
+ or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
+ San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
+*/
+
+/* $Id$ */
+
+#ifndef __CARBON__
+//#include "MacHeaders"
+#include <Palettes.h>
+#include <Aliases.h>
+#include <Quickdraw.h>
+#include <QDOffscreen.h>
+#include <AppleEvents.h>
+#include <Fonts.h>
+#include <Controls.h>
+#include <Script.h>
+#include <Timer.h>
+#include <Folders.h>
+#include <Resources.h>
+#include <Sound.h>
+#include <ToolUtils.h>
+#include <Menus.h>
+#include <LowMem.h>
+#include <Devices.h>
+#include <Scrap.h>
+#include <StringCompare.h>
+#include <Gestalt.h>
+#include <Folders.h>
+#include <Files.h>
+#include <Fonts.h>
+#include <FixMath.h>
+#include <Resources.h>
+#else
+#include <Carbon.h>
+#include <CoreServices.h>
+#endif /* __CARBON__ */
+
+#include "stdio_.h"
+#include "math_.h"
+#include "string_.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <console.h>
+
+#include "gx.h"
+#include "gp.h"
+#include "gpmisc.h"
+#include "gxdevice.h"
+
+#include "gp_mac.h"
+
+#include "stream.h"
+#include "gxiodev.h" /* must come after stream.h */
+//#include "gp_macAE.h"
+#include "gsdll.h"
+
+//HWND hwndtext;
+
+
+extern void
+convertSpecToPath(FSSpec * s, char * p, int pLen)
+{
+ OSStatus err = noErr;
+ CInfoPBRec params;
+ Str255 dirName;
+ int totLen = 0, dirLen = 0;
+
+ memcpy(p, s->name + 1, s->name[0]);
+ totLen += s->name[0];
+
+ params.dirInfo.ioNamePtr = dirName;
+ params.dirInfo.ioVRefNum = s->vRefNum;
+ params.dirInfo.ioDrParID = s->parID;
+ params.dirInfo.ioFDirIndex = -1;
+
+ do {
+ params.dirInfo.ioDrDirID = params.dirInfo.ioDrParID;
+ err = PBGetCatInfoSync(&params);
+
+ if ((err != noErr) || (totLen + dirName[0] + 2 > pLen)) {
+ p[0] = 0;
+ return;
+ }
+
+ dirName[++dirName[0]] = ':';
+ memmove(p + dirName[0], p, totLen);
+ memcpy(p, dirName + 1, dirName[0]);
+ totLen += dirName[0];
+ } while (params.dirInfo.ioDrParID != fsRtParID);
+
+ p[totLen] = 0;
+
+ return;
+}
+
+OSErr
+convertPathToSpec(const char *path, const int pathlength, FSSpec * spec)
+{
+ Str255 filename;
+
+ /* path must be shorter than 255 bytes */
+ if (pathlength > 254) return bdNamErr;
+
+ *filename = pathlength;
+ memcpy(filename + 1, path, pathlength);
+
+ return FSMakeFSSpec(0, 0, filename, spec);
+}
+
+/* ------ File name syntax ------ */
+
+/* Define the character used for separating file names in a list. */
+const char gp_file_name_list_separator = ',';
+
+/* Define the default scratch file name prefix. */
+const char gp_scratch_file_name_prefix[] = "tempgs_";
+
+/* Define the name of the null output file. */
+const char gp_null_file_name[] = "????";
+
+/* Define the name that designates the current directory. */
+extern const char gp_current_directory_name[] = ":";
+
+int fake_stdin = 0;
+
+
+/* Do platform-dependent initialization */
+
+void
+setenv(const char * env, char *p) {
+// if ( strcmp(env,"outfile") == 0) {
+// sprintf((char *)&g_fcout[0],"%s",p);
+// }
+}
+
+char *
+getenv(const char * env) {
+
+ char *p;
+ FSSpec pFile;
+ OSErr err = 0;
+ char fpath[256]="";
+
+ if ( strcmp(env,"GS_LIB") == 0) {
+
+ pFile.name[0] = 0;
+ err = FindFolder(kOnSystemDisk, kApplicationSupportFolderType, kDontCreateFolder,
+ &pFile.vRefNum, &pFile.parID);
+
+ if (err != noErr) goto failed;
+
+// FSMakeFSSpec(pFile.vRefNum, pFile.parID,thepfname, &pfile);
+ convertSpecToPath(&pFile, fpath, 256);
+// sprintf(fpath,"%s",fpath);
+ p = (char*)malloc((size_t) ( 4*strlen(fpath) + 40));
+ sprintf(p,"%s,%sGhostscript:lib,%sGhostscript:fonts",
+ (char *)&fpath[0],(char *)&fpath[0],
+ (char *)&fpath[0] );
+
+ return p;
+failed:
+
+ return NULL;
+ } else
+ return NULL;
+
+}
+
+/* ====== Substitute for stdio ====== */
+
+/* Forward references */
+static void mac_std_init(void);
+static stream_proc_process(mac_stdin_read_process);
+static stream_proc_process(mac_stdout_write_process);
+static stream_proc_process(mac_stderr_write_process);
+static stream_proc_available(mac_std_available);
+
+/* Use a pseudo IODevice to get mac_stdio_init called at the right time. */
+/* This is bad architecture; we'll fix it later. */
+static iodev_proc_init(mac_stdio_init);
+const gx_io_device gs_iodev_macstdio =
+{
+ "macstdio", "Special",
+ {mac_stdio_init, iodev_no_open_device,
+ iodev_no_open_file, iodev_no_fopen, iodev_no_fclose,
+ iodev_no_delete_file, iodev_no_rename_file,
+ iodev_no_file_status, iodev_no_enumerate_files
+ }
+};
+
+/* Do one-time initialization */
+static int
+mac_stdio_init(gx_io_device * iodev, gs_memory_t * mem)
+{
+ mac_std_init(); /* redefine stdin/out/err to our window routines */
+ return 0;
+}
+
+/* Define alternate 'open' routines for our stdin/out/err streams. */
+
+extern const gx_io_device gs_iodev_stdin;
+static int
+mac_stdin_open(gx_io_device * iodev, const char *access, stream ** ps,
+ gs_memory_t * mem)
+{
+ int code = gs_iodev_stdin.procs.open_device(iodev, access, ps, mem);
+ stream *s = *ps;
+
+ if (code != 1)
+ return code;
+ s->procs.process = mac_stdin_read_process;
+ s->procs.available = mac_std_available;
+ s->file = NULL;
+ return 0;
+}
+
+extern const gx_io_device gs_iodev_stdout;
+static int
+mac_stdout_open(gx_io_device * iodev, const char *access, stream ** ps,
+ gs_memory_t * mem)
+{
+ int code = gs_iodev_stdout.procs.open_device(iodev, access, ps, mem);
+ stream *s = *ps;
+
+ if (code != 1)
+ return code;
+ s->procs.process = mac_stdout_write_process;
+ s->procs.available = mac_std_available;
+ s->file = NULL;
+ return 0;
+}
+
+extern const gx_io_device gs_iodev_stderr;
+static int
+mac_stderr_open(gx_io_device * iodev, const char *access, stream ** ps,
+ gs_memory_t * mem)
+{
+ int code = gs_iodev_stderr.procs.open_device(iodev, access, ps, mem);
+ stream *s = *ps;
+
+ if (code != 1)
+ return code;
+ s->procs.process = mac_stderr_write_process;
+ s->procs.available = mac_std_available;
+ s->file = NULL;
+ return 0;
+}
+
+/* Patch stdin/out/err to use our windows. */
+static void
+mac_std_init(void)
+{
+ /* If stdxxx is the console, replace the 'open' routines, */
+ /* which haven't gotten called yet. */
+
+// if (gp_file_is_console(gs_stdin))
+ gs_findiodevice((const byte *)"%stdin", 6)->procs.open_device =
+ mac_stdin_open;
+
+// if (gp_file_is_console(gs_stdout))
+ gs_findiodevice((const byte *)"%stdout", 7)->procs.open_device =
+ mac_stdout_open;
+
+// if (gp_file_is_console(gs_stderr))
+ gs_findiodevice((const byte *)"%stderr", 7)->procs.open_device =
+ mac_stderr_open;
+}
+
+
+static int
+mac_stdin_read_process(stream_state *st, stream_cursor_read *ignore_pr,
+ stream_cursor_write *pw, bool last)
+{
+ uint count = pw->limit - pw->ptr;
+ /* callback to get more input */
+ if (pgsdll_callback == NULL) return EOFC;
+ count = (*pgsdll_callback) (GSDLL_STDIN, (char*)pw->ptr + 1, count);
+ pw->ptr += count;
+ return 1;
+}
+
+
+static int
+mac_stdout_write_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *ignore_pw, bool last)
+{ uint count = pr->limit - pr->ptr;
+
+ if (pgsdll_callback == NULL) return EOFC;
+ (*pgsdll_callback) (GSDLL_STDOUT, (char *)(pr->ptr + 1), count);
+ pr->ptr = pr->limit;
+ return 0;
+}
+
+static int
+mac_stderr_write_process(stream_state *st, stream_cursor_read *pr,
+ stream_cursor_write *ignore_pw, bool last)
+{ uint count = pr->limit - pr->ptr;
+
+ if (pgsdll_callback == NULL) return EOFC;
+ (*pgsdll_callback) (GSDLL_STDOUT, (char *)(pr->ptr + 1), count);
+ pr->ptr = pr->limit;
+ return 0;
+}
+
+static int
+mac_std_available(register stream * s, long *pl)
+{
+ *pl = -1; // EOF, since we can't do it
+ return 0; // OK
+}
+
+/* ------ Printer accessing ------ */
+
+/* These should NEVER be called. */
+
+/* Open a connection to a printer. A null file name means use the */
+/* standard printer connected to the machine, if any. */
+/* "|command" opens an output pipe. */
+/* Return NULL if the connection could not be opened. */
+
+FILE *
+gp_open_printer (char *fname, int binary_mode)
+{
+ if (strlen(fname) == 0)
+ return gp_open_scratch_file(gp_scratch_file_name_prefix, fname, binary_mode ? "wb" : "w");
+ else
+ return gp_fopen(fname, binary_mode ? "wb" : "b");
+}
+
+/* Close the connection to the printer. */
+
+void
+gp_close_printer (FILE *pfile, const char *fname)
+{
+ fclose(pfile);
+}
+
+
+/* Define whether case is insignificant in file names. */
+/* OBSOLETE
+const int gp_file_names_ignore_case = 1;
+*/
+
+/* Define the string to be concatenated with the file mode */
+/* for opening files without end-of-line conversion. */
+const char gp_fmode_binary_suffix[] = "b";
+
+/* Define the file modes for binary reading or writing. */
+const char gp_fmode_rb[] = "rb";
+const char gp_fmode_wb[] = "wb";
+
+
+/* Set a file into binary or text mode. */
+int
+gp_setmode_binary(FILE *pfile, bool binary)
+{ return 0; /* Noop under VMS */
+}
+
+
+/* Create and open a scratch file with a given name prefix. */
+/* Write the actual file name at fname. */
+
+FILE *
+gp_open_scratch_file (const char *prefix, char fname[gp_file_name_sizeof], const char *mode)
+{
+ char thefname[256];
+ Str255 thepfname;
+ OSErr myErr;
+ short foundVRefNum;
+ long foundDirID;
+ FSSpec fSpec;
+ FILE *f;
+ int prefix_length = strlen(prefix);
+
+ if (prefix_length > gp_file_name_sizeof) return NULL;
+ strcpy (fname, (char *) prefix);
+ {
+ char newName[50];
+
+ tmpnam (newName);
+ if ( prefix_length + strlen(newName) > gp_file_name_sizeof ) return NULL;
+ strcat (fname, newName);
+ }
+
+ if ( strlen(fname) > 255 ) return NULL;
+ if ( strrchr(fname,':') == NULL ) {
+ memmove((char*)&thepfname[1],(char *)&fname[0],strlen(fname));
+ thepfname[0]=strlen(fname);
+ myErr = FindFolder(kOnSystemDisk,kTemporaryFolderType,kCreateFolder,
+ &foundVRefNum, &foundDirID);
+ if ( myErr != noErr ) {
+ eprintf("Can't find temp folder.\n");
+ return (NULL);
+ }
+ FSMakeFSSpec(foundVRefNum, foundDirID,thepfname, &fSpec);
+ convertSpecToPath(&fSpec, thefname, sizeof(thefname) - 1);
+ sprintf(fname,"%s",thefname);
+ } else {
+ sprintf((char*)&thefname[0],"%s\0",fname);
+ memmove((char*)&thepfname[1],(char *)&thefname[0],strlen(thefname));
+ thepfname[0]=strlen(thefname);
+ }
+
+ f = gp_fopen (thefname, mode);
+ if (f == NULL)
+ eprintf1("**** Could not open temporary file %s\n", fname);
+ return f;
+}
+
+/* read a resource and copy the data into a buffer */
+/* we don't have access to an allocator, nor any context for local */
+/* storage, so we implement the following idiom: we return the size */
+/* of the requested resource and copy the data into buf iff it's */
+/* non-NULL. Thus, the caller can pass NULL for buf the first time, */
+/* allocate the appropriate sized buffer, and then call us a second */
+/* time to actually transfer the data. */
+int
+gp_read_macresource(byte *buf, const char *fname, const uint type, const ushort id)
+{
+ Handle resource = NULL;
+ SInt32 size = 0;
+ FSSpec spec;
+ SInt16 fileref;
+ OSErr result;
+
+ /* open file */
+ result = convertPathToSpec(fname, strlen(fname), &spec);
+ if (result != noErr) goto fin;
+ fileref = FSpOpenResFile(&spec, fsRdPerm);
+ if (fileref == -1) goto fin;
+
+ if_debug1('s', "[s] loading resource from fileref %d\n", fileref);
+
+ /* load resource */
+ resource = Get1Resource((ResType)type, (SInt16)id);
+ if (resource == NULL) goto fin;
+
+ /* allocate res */
+ /* GetResourceSize() is probably good enough */
+ //size = GetResourceSizeOnDisk(resource);
+ size = GetMaxResourceSize(resource);
+
+ if_debug1('s', "[s] resource size on disk is %d bytes\n", size);
+
+ /* if we don't have a buffer to fill, just return */
+ if (buf == NULL) goto fin;
+
+ /* otherwise, copy resource into res from handle */
+ HLock(resource);
+ memcpy(buf, *resource, size);
+ HUnlock(resource);
+
+fin:
+ /* free resource, if necessary */
+ ReleaseResource(resource);
+ CloseResFile(fileref);
+
+ return (size);
+}
+
+/* return a list of font names and corresponding paths from
+ * the native system locations
+ */
+int gp_native_fontmap(char *names[], char *paths[], int *count)
+{
+ return 0;
+}
+
+/* ------ File enumeration ------ */
+
+/****** THIS IS NOT SUPPORTED ON MACINTOSH SYSTEMS. ******/
+
+struct file_enum_s {
+ char *pattern;
+ int first_time;
+ gs_memory_t *memory;
+};
+
+/* Initialize an enumeration. NEEDS WORK ON HANDLING * ? \. */
+
+file_enum *
+gp_enumerate_files_init (const char *pat, uint patlen, gs_memory_t *memory)
+
+{ file_enum *pfen =
+ (file_enum *)gs_alloc_bytes(memory, sizeof(file_enum), "gp_enumerate_files");
+ char *pattern;
+ if ( pfen == 0 ) return 0;
+ pattern =
+ (char *)gs_alloc_bytes(memory, patlen + 1, "gp_enumerate_files(pattern)");
+ if ( pattern == 0 ) return 0;
+ memcpy(pattern, pat, patlen);
+ pattern[patlen] = 0;
+ pfen->pattern = pattern;
+ pfen->memory = memory;
+ pfen->first_time = 1;
+ return pfen;
+}
+
+/* Enumerate the next file. */
+
+uint
+gp_enumerate_files_next (file_enum *pfen, char *ptr, uint maxlen)
+
+{ if ( pfen->first_time )
+ { pfen->first_time = 0;
+ }
+ return -1;
+}
+
+/* Clean up the file enumeration. */
+
+void
+gp_enumerate_files_close (file_enum *pfen)
+
+{
+ gs_free_object(pfen->memory, pfen->pattern, "gp_enumerate_files_close(pattern)");
+ gs_free_object(pfen->memory, (char *)pfen, "gp_enumerate_files_close");
+}
+
+FILE *
+gp_fopen (const char * fname, const char * mode) {
+
+ char thefname[256];
+ FILE *fid;
+
+//sprintf((char*)&thefname[0],"\n%s\n",fname);
+//(*pgsdll_callback) (GSDLL_STDOUT, thefname, strlen(fname));
+ if ( strrchr(fname,':') == NULL )
+// sprintf((char *)&thefname[0],"%s%s\0",g_homeDir,fname);
+ sprintf((char *)&thefname[0],"%s%s\0","",fname);
+ else
+ sprintf((char*)&thefname[0],"%s\0",fname);
+
+ fid = fopen(thefname,mode);
+
+ return fid;
+
+}
+
+FILE *
+popen (const char * fname, const char * mode ) {
+ return gp_fopen (fname, mode);
+}
+
+int
+pclose (FILE * pipe ) {
+ return fclose (pipe);
+}
+
+/* -------------- Helpers for gp_file_name_combine_generic ------------- */
+
+#ifdef __CARBON__
+
+/* compare an HFSUnitStr255 with a C string */
+static int compare_UniStr(HFSUniStr255 u, const char *c, uint len)
+{
+ int i,searchlen,unichar;
+ searchlen = min(len,u.length);
+ for (i = 0; i < searchlen; i++) {
+ unichar = u.unicode[i];
+ /* punt on wide characters. we should really convert */
+ if (unichar & !0xFF) return -1;
+ /* otherwise return the the index of the first non-matching character */
+ if (unichar != c[i]) break;
+ }
+ /* return the offset iff we matched the whole volume name */
+ return (i == u.length) ? i : 0;
+}
+
+uint gp_file_name_root(const char *fname, uint len)
+{
+ OSErr err = noErr;
+ HFSUniStr255 volumeName;
+ FSRef rootDirectory;
+ int index, match;
+
+ if (len > 0 && fname[0] == ':')
+ return 0; /* A relative path, no root. */
+
+ /* iterate over mounted volumes and compare our path */
+ index = 1;
+ while (err == noErr) {
+ err = FSGetVolumeInfo (kFSInvalidVolumeRefNum, index,
+ NULL, kFSVolInfoNone, NULL, /* not interested in these fields */
+ &volumeName, &rootDirectory);
+ if (err == nsvErr) return 0; /* no more volumes */
+ if (err == noErr) {
+ match = compare_UniStr(volumeName, fname, len);
+ if (match > 0) {
+ /* include the separator if it's present */
+ if (fname[match] == ':') return match + 1;
+ return match;
+ }
+ }
+ index++;
+ }
+
+ /* nothing matched */
+ return 0;
+}
+
+#else /* Classic MacOS */
+
+/* FSGetVolumeInfo requires carbonlib or macos >= 9
+ we essentially leave this unimplemented on Classic */
+uint gp_file_name_root(const char *fname, uint len)
+{
+ return 0;
+}
+
+#endif /* __CARBON__ */
+
+
+uint gs_file_name_check_separator(const char *fname, int len, const char *item)
+{ if (len > 0) {
+ if (fname[0] == ':') {
+ if (fname == item + 1 && item[0] == ':')
+ return 1; /* It is a separator after parent. */
+ if (len > 1 && fname[1] == ':')
+ return 0; /* It is parent, not a separator. */
+ return 1;
+ }
+ } else if (len < 0) {
+ if (fname[-1] == ':')
+ return 1;
+ }
+ return 0;
+}
+
+bool gp_file_name_is_parent(const char *fname, uint len)
+{ return len == 1 && fname[0] == ':';
+}
+
+bool gp_file_name_is_current(const char *fname, uint len)
+{ return (len == 0) || (len == 1 && fname[0] == ':');
+}
+
+const char *gp_file_name_separator(void)
+{ return ":";
+}
+
+const char *gp_file_name_directory_separator(void)
+{ return ":";
+}
+
+const char *gp_file_name_parent(void)
+{ return "::";
+}
+
+const char *gp_file_name_current(void)
+{ return ":";
+}
+
+bool gp_file_name_is_partent_allowed(void)
+{ return true;
+}
+
+bool gp_file_name_is_empty_item_meanful(void)
+{ return true;
+}
+
+gp_file_name_combine_result
+gp_file_name_combine(const char *prefix, uint plen, const char *fname, uint flen,
+ bool no_sibling, char *buffer, uint *blen)
+{
+ return gp_file_name_combine_generic(prefix, plen,
+ fname, flen, no_sibling, buffer, blen);
+}
+
+// FIXME: there must be a system util for this!
+static char *MacStr2c(char *pstring)
+{
+ char *cstring;
+ int len = (pstring[0] < 256) ? pstring[0] : 255;
+
+ if (len == 0) return NULL;
+
+ cstring = malloc(len + 1);
+ if (cstring != NULL) {
+ memcpy(cstring, &(pstring[1]), len);
+ cstring[len] = '\0';
+ }
+
+ return(cstring);
+}
+
+/* ------ Font enumeration ------ */
+
+ /* This is used to query the native os for a list of font names and
+ * corresponding paths. The general idea is to save the hassle of
+ * building a custom fontmap file
+ */
+
+typedef struct {
+ int size, style, id;
+} fond_entry;
+
+typedef struct {
+ int entries;
+ fond_entry *refs;
+} fond_table;
+
+static fond_table *fond_table_new(int entries)
+{
+ fond_table *table = malloc(sizeof(fond_table));
+ if (table != NULL) {
+ table->entries = entries;
+ table->refs = malloc(entries * sizeof(fond_entry));
+ if (table->refs == NULL) { free(table); table = NULL; }
+ }
+ return table;
+}
+
+static void fond_table_free(fond_table *table)
+{
+ if (table != NULL) {
+ if (table->refs) free(table->refs);
+ free(table);
+ }
+}
+
+static fond_table *fond_table_grow(fond_table *table, int entries)
+{
+ if (table == NULL) {
+ table = fond_table_new(entries);
+ } else {
+ table->entries += entries;
+ table->refs = realloc(table->refs, table->entries * sizeof(fond_entry));
+ }
+ return table;
+}
+
+static int get_int16(unsigned char *p) {
+ return (p[0]&0xFF)<<8 | (p[1]&0xFF);
+}
+
+static int get_int32(unsigned char *p) {
+ return (p[0]&0xFF)<<24 | (p[1]&0xFF)<<16 | (p[2]&0xFF)<<8 | (p[3]&0xFF);
+}
+
+/* parse and summarize FOND resource information */
+static fond_table * parse_fond(FSSpec *spec)
+{
+ OSErr result = noErr;
+ FSRef specref;
+ SInt16 ref;
+ Handle fond = NULL;
+ unsigned char *res;
+ fond_table *table = NULL;
+ int i,j, count, n, start;
+
+ /* FSpOpenResFile will fail for data fork resource (.dfont) files.
+ FSOpenResourceFile can open either, but cannot handle broken resource
+ maps, as often occurs in font files (the suitcase version of Arial,
+ for example) Thus, we try one, and then the other. */
+
+ result = FSpMakeFSRef(spec,&specref);
+#ifdef __CARBON__
+ if (result == noErr)
+ result = FSOpenResourceFile(&specref, 0, NULL, fsRdPerm, &ref);
+#else
+ result = bdNamErr; /* simulate failure of the carbon routine above */
+#endif
+ if (result != noErr) {
+ ref = FSpOpenResFile(spec, fsRdPerm);
+ result = ResError();
+ }
+ if (result != noErr || ref <= 0) {
+ char path[256];
+ convertSpecToPath(spec, path, 256);
+ dlprintf2("unable to open resource file '%s' for font enumeration (error %d)\n",
+ path, result);
+ goto fin;
+ }
+
+ /* we've opened the font file, now loop over the FOND resource(s)
+ and construct a table of the font references */
+
+ start = 0; /* number of entries so far */
+ UseResFile(ref);
+ count = Count1Resources('FOND');
+ for (i = 0; i < count; i++) {
+ fond = Get1IndResource('FOND', i+1);
+ if (fond == NULL) {
+ result = ResError();
+ goto fin;
+ }
+
+ /* The FOND resource structure corresponds to the FamRec and AsscEntry
+ data structures documented in the FontManager reference. However,
+ access to these types is deprecated in Carbon. We therefore access the
+ data by direct offset in the hope that the resource format will not change
+ even if api access to the in-memory versions goes away. */
+ HLock(fond);
+ res = *fond + 52; /* offset to association table */
+ n = get_int16(res) + 1; res += 2;
+ table = fond_table_grow(table, n);
+ for (j = start; j < start + n; j++ ) {
+ table->refs[j].size = get_int16(res); res += 2;
+ table->refs[j].style = get_int16(res); res += 2;
+ table->refs[j].id = get_int16(res); res += 2;
+ }
+ start += n;
+ HUnlock(fond);
+ }
+fin:
+ CloseResFile(ref);
+ return table;
+}
+
+/* FIXME: should check for uppercase as well */
+static int is_ttf_file(const char *path)
+{
+ int len = strlen(path);
+ return !memcmp(path+len-4,".ttf",4);
+}
+static int is_otf_file(const char *path)
+{
+ int len = strlen(path);
+ return !memcmp(path+len-4,".otf",4);
+}
+
+static void strip_char(char *string, int len, const int c)
+{
+ char *bit;
+ len += 1;
+ while(bit = strchr(string,' ')) {
+ memmove(bit, bit + 1, string + len - bit - 1);
+ }
+}
+
+/* get the macos name for the font instance and mangle it into a PS
+ fontname */
+static char *makePSFontName(FMFontFamily Family, FMFontStyle Style)
+{
+ Str255 Name;
+ OSStatus result;
+ int length;
+ char *stylename, *fontname;
+ char *psname;
+
+ result = FMGetFontFamilyName(Family, Name);
+ if (result != noErr) return NULL;
+ fontname = MacStr2c(Name);
+ if (fontname == NULL) return NULL;
+ strip_char(fontname, strlen(fontname), ' ');
+
+ switch (Style) {
+ case 0: stylename=""; break;;
+ case 1: stylename="Bold"; break;;
+ case 2: stylename="Italic"; break;;
+ case 3: stylename="BoldItalic"; break;;
+ default: stylename="Unknown"; break;;
+ }
+
+ length = strlen(fontname) + strlen(stylename) + 2;
+ psname = malloc(length);
+ if (Style != 0)
+ snprintf(psname, length, "%s-%s", fontname, stylename);
+ else
+ snprintf(psname, length, "%s", fontname);
+
+ free(fontname);
+
+ return psname;
+}
+
+typedef struct {
+ int count;
+ FMFontIterator Iterator;
+ char *name;
+ char *path;
+ FSSpec last_container;
+ char *last_container_path;
+ fond_table *last_table;
+} fontenum_t;
+
+void *gp_enumerate_fonts_init(gs_memory_t *mem)
+{
+ fontenum_t *state = gs_alloc_bytes(mem, sizeof(fontenum_t),
+ "macos font enumerator state");
+ FMFontIterator *Iterator = &state->Iterator;
+ OSStatus result;
+
+ if (state != NULL) {
+ state->count = 0;
+ state->name = NULL;
+ state->path = NULL;
+ result = FMCreateFontIterator(NULL, NULL,
+ kFMLocalIterationScope, Iterator);
+ if (result != noErr) return NULL;
+ memset(&state->last_container, 0, sizeof(FSSpec));
+ state->last_container_path = NULL;
+ state->last_table = NULL;
+ }
+
+ return (void *)state;
+}
+
+void gp_enumerate_fonts_free(void *enum_state)
+{
+ fontenum_t *state = (fontenum_t *)enum_state;
+ FMFontIterator *Iterator = &state->Iterator;
+
+ FMDisposeFontIterator(Iterator);
+
+ /* free any malloc'd stuff here */
+ if (state->name) free(state->name);
+ if (state->path) free(state->path);
+ if (state->last_container_path) free(state->last_container_path);
+ if (state->last_table) fond_table_free(state->last_table);
+ /* the garbage collector will take care of the struct itself */
+
+}
+
+int gp_enumerate_fonts_next(void *enum_state, char **fontname, char **path)
+{
+ fontenum_t *state = (fontenum_t *)enum_state;
+ FMFontIterator *Iterator = &state->Iterator;
+ FMFont Font;
+ FourCharCode Format;
+ FMFontFamily FontFamily;
+ FMFontStyle Style;
+ FSSpec FontContainer;
+ char type[5];
+ char fontpath[256];
+ char *psname;
+ fond_table *table = NULL;
+ OSStatus result;
+
+ result = FMGetNextFont(Iterator, &Font);
+ if (result != noErr) return 0; /* no more fonts */
+
+ result = FMGetFontFormat(Font, &Format);
+ type[0] = ((char*)&Format)[0];
+ type[1] = ((char*)&Format)[1];
+ type[2] = ((char*)&Format)[2];
+ type[3] = ((char*)&Format)[3];
+ type[4] = '\0';
+
+ FMGetFontFamilyInstanceFromFont(Font, &FontFamily, &Style);
+ if (state->name) free (state->name);
+
+ psname = makePSFontName(FontFamily, Style);
+ if (psname == NULL) {
+ state->name = strdup("GSPlaceHolder");
+ } else {
+ state->name = psname;
+ }
+
+ result = FMGetFontContainer(Font, &FontContainer);
+ if (!memcmp(&FontContainer, &state->last_container, sizeof(FSSpec))) {
+ /* we have cached data on this file */
+ strncpy(fontpath, state->last_container_path, 256);
+ table = state->last_table;
+ } else {
+ convertSpecToPath(&FontContainer, fontpath, 256);
+ if (!is_ttf_file(fontpath) && !is_otf_file(fontpath))
+ table = parse_fond(&FontContainer);
+ /* cache data on the new font file */
+ memcpy(&state->last_container, &FontContainer, sizeof(FSSpec));
+ if (state->last_container_path) free (state->last_container_path);
+ state->last_container_path = strdup(fontpath);
+ if (state->last_table) fond_table_free(state->last_table);
+ state->last_table = table;
+ }
+
+ if (state->path) {
+ free(state->path);
+ state->path = NULL;
+ }
+ if (table != NULL) {
+ int i;
+ for (i = 0; i < table->entries; i++) {
+ if (table->refs[i].size == 0) { /* ignore non-scalable fonts */
+ if (table->refs[i].style == Style) {
+ int len = strlen(fontpath) + strlen("%macresource%#sfnt+") + 6;
+ state->path = malloc(len);
+ snprintf(state->path, len, "%%macresource%%%s#sfnt+%d",
+ fontpath, table->refs[i].id);
+ break;
+ }
+ }
+ }
+ } else {
+ /* regular font file */
+ state->path = strdup(fontpath);
+ }
+ if (state->path == NULL) {
+ /* no matching font was found in the FOND resource table. this usually */
+ /* means an LWFN file, which we don't handle yet. */
+ /* we still specify these with a %macresource% path, but no res id */
+ /* TODO: check file type */
+ int len = strlen(fontpath) + strlen("%macresource%#POST") + 1;
+ state->path = malloc(len);
+ snprintf(state->path, len, "%%macresource%%%s#POST", fontpath);
+ }
+#ifdef DEBUG
+ dlprintf2("fontenum: returning '%s' in '%s'\n", state->name, state->path);
+#endif
+ *fontname = state->name;
+ *path = state->path;
+
+ state->count += 1;
+ return 1;
+}
+
+/* --------- 64 bit file access ----------- */
+/* fixme: Not implemented yet.
+ * Currently we stub it with 32 bits access.
+ */
+
+FILE *gp_fopen_64(const char *filename, const char *mode)
+{
+ return fopen(filename, mode);
+}
+
+FILE *gp_open_scratch_file_64(const char *prefix,
+ char fname[gp_file_name_sizeof],
+ const char *mode)
+{
+ return gp_open_scratch_file(prefix, fname, mode);
+}
+
+FILE *gp_open_printer_64(char fname[gp_file_name_sizeof], int binary_mode)
+{
+ return gp_open_printer(fname, binary_mode);
+}
+
+int64_t gp_ftell_64(FILE *strm)
+{
+ return ftell(strm);
+}
+
+int gp_fseek_64(FILE *strm, int64_t offset, int origin)
+{
+ long offset1 = (long)offset;
+
+ if (offset != offset1)
+ return -1;
+ return fseek(strm, offset1, origin);
+}