1*593dc095SDavid du Colombier /* Copyright (C) 2002 artofcode LLC All rights reserved.
2*593dc095SDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
5*593dc095SDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
9*593dc095SDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15*593dc095SDavid du Colombier */
16*593dc095SDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: gsiomacres.c,v 1.5 2003/09/03 03:22:59 giles Exp $ */
18*593dc095SDavid du Colombier /* %macresource% IODevice implementation for loading MacOS fonts */
19*593dc095SDavid du Colombier
20*593dc095SDavid du Colombier /*
21*593dc095SDavid du Colombier * MacOS often stores fonts in 'resource forks' an extended attribute
22*593dc095SDavid du Colombier * of the HFS filesystem that allows storing chunks of data indexed by
23*593dc095SDavid du Colombier * a resource 'type' and 'id'. MacOS X introduced the '.dfont' format
24*593dc095SDavid du Colombier * for compatibility with non-HFS filesystems; it consists of the
25*593dc095SDavid du Colombier * resource data for a font stored on the data fork (normal file).
26*593dc095SDavid du Colombier *
27*593dc095SDavid du Colombier * We provide here a special %macresource% IODevice so that Ghostscript
28*593dc095SDavid du Colombier * can open these native fonts on MacOS. It opens the requested file and
29*593dc095SDavid du Colombier * returns a stream containing the indicated resource data, whether from
30*593dc095SDavid du Colombier * the resource fork or, if that fails, from the datafork assuming a
31*593dc095SDavid du Colombier * .dfont file.
32*593dc095SDavid du Colombier *
33*593dc095SDavid du Colombier * Since the only use at this point is font loading, we don't implement
34*593dc095SDavid du Colombier * the usual complement of delete, rename and so on.
35*593dc095SDavid du Colombier */
36*593dc095SDavid du Colombier
37*593dc095SDavid du Colombier #include "std.h"
38*593dc095SDavid du Colombier #include "stdio_.h"
39*593dc095SDavid du Colombier #include "string_.h"
40*593dc095SDavid du Colombier #include "malloc_.h"
41*593dc095SDavid du Colombier #include "ierrors.h"
42*593dc095SDavid du Colombier #include "gserror.h"
43*593dc095SDavid du Colombier #include "gstypes.h"
44*593dc095SDavid du Colombier #include "gsmemory.h"
45*593dc095SDavid du Colombier #include "stream.h"
46*593dc095SDavid du Colombier #include "gdebug.h"
47*593dc095SDavid du Colombier #include "gxiodev.h"
48*593dc095SDavid du Colombier #include "gp.h"
49*593dc095SDavid du Colombier
50*593dc095SDavid du Colombier /* dfont loading code */
51*593dc095SDavid du Colombier
52*593dc095SDavid du Colombier /* 4-byte resource types as uint32s */
53*593dc095SDavid du Colombier #define TYPE_sfnt 0x73666e74
54*593dc095SDavid du Colombier #define TYPE_FOND 0x464f4e44
55*593dc095SDavid du Colombier #define TYPE_NFNT 0x4e464e54
56*593dc095SDavid du Colombier #define TYPE_ftag 0x66746167
57*593dc095SDavid du Colombier #define TYPE_vers 0x76657273
58*593dc095SDavid du Colombier
59*593dc095SDavid du Colombier typedef struct {
60*593dc095SDavid du Colombier unsigned int data_offset;
61*593dc095SDavid du Colombier unsigned int map_offset;
62*593dc095SDavid du Colombier unsigned int data_length;
63*593dc095SDavid du Colombier unsigned int map_length;
64*593dc095SDavid du Colombier } resource_header;
65*593dc095SDavid du Colombier
66*593dc095SDavid du Colombier typedef struct {
67*593dc095SDavid du Colombier unsigned int type;
68*593dc095SDavid du Colombier unsigned int offset;
69*593dc095SDavid du Colombier unsigned int length;
70*593dc095SDavid du Colombier byte *data;
71*593dc095SDavid du Colombier char *name;
72*593dc095SDavid du Colombier unsigned short id;
73*593dc095SDavid du Colombier byte flags;
74*593dc095SDavid du Colombier } resource;
75*593dc095SDavid du Colombier
76*593dc095SDavid du Colombier typedef struct {
77*593dc095SDavid du Colombier resource *resources;
78*593dc095SDavid du Colombier int n_resources;
79*593dc095SDavid du Colombier } resource_list;
80*593dc095SDavid du Colombier
81*593dc095SDavid du Colombier private
get_int32(byte * p)82*593dc095SDavid du Colombier int get_int32(byte *p) {
83*593dc095SDavid du Colombier return (p[0]&0xFF)<<24 | (p[1]&0xFF)<<16 | (p[2]&0xFF)<<8 | (p[3]&0xFF);
84*593dc095SDavid du Colombier }
85*593dc095SDavid du Colombier
86*593dc095SDavid du Colombier private
get_int24(byte * p)87*593dc095SDavid du Colombier int get_int24(byte *p) {
88*593dc095SDavid du Colombier return (p[0]&0xFF)<<16 | (p[1]&0xFF)<<8 | (p[2]&0xFF);
89*593dc095SDavid du Colombier }
90*593dc095SDavid du Colombier
91*593dc095SDavid du Colombier private
get_int16(byte * p)92*593dc095SDavid du Colombier int get_int16(byte *p) {
93*593dc095SDavid du Colombier return (p[0]&0xFF)<<8 | (p[1]&0xFF);
94*593dc095SDavid du Colombier }
95*593dc095SDavid du Colombier
96*593dc095SDavid du Colombier private
read_int32(FILE * in,void * p)97*593dc095SDavid du Colombier int read_int32(FILE *in, void *p)
98*593dc095SDavid du Colombier {
99*593dc095SDavid du Colombier byte w[4], err;
100*593dc095SDavid du Colombier
101*593dc095SDavid du Colombier err = fread(w, 1, 4, in);
102*593dc095SDavid du Colombier if (err != 4) return -1;
103*593dc095SDavid du Colombier
104*593dc095SDavid du Colombier *(unsigned int*)p = get_int32(w);
105*593dc095SDavid du Colombier return 0;
106*593dc095SDavid du Colombier }
107*593dc095SDavid du Colombier
108*593dc095SDavid du Colombier private
read_int24(FILE * in,void * p)109*593dc095SDavid du Colombier int read_int24(FILE *in, void *p)
110*593dc095SDavid du Colombier {
111*593dc095SDavid du Colombier byte w[3], err;
112*593dc095SDavid du Colombier
113*593dc095SDavid du Colombier err = fread(w, 1, 3, in);
114*593dc095SDavid du Colombier if (err != 3) return -1;
115*593dc095SDavid du Colombier
116*593dc095SDavid du Colombier *(unsigned int*)p = get_int24(w);
117*593dc095SDavid du Colombier return 0;
118*593dc095SDavid du Colombier }
119*593dc095SDavid du Colombier
120*593dc095SDavid du Colombier private
read_int16(FILE * in,void * p)121*593dc095SDavid du Colombier int read_int16(FILE *in, void *p)
122*593dc095SDavid du Colombier {
123*593dc095SDavid du Colombier byte w[2], err;
124*593dc095SDavid du Colombier
125*593dc095SDavid du Colombier err = fread(w, 1, 2, in);
126*593dc095SDavid du Colombier if (err != 2) return -1;
127*593dc095SDavid du Colombier
128*593dc095SDavid du Colombier *(unsigned short*)p = get_int16(w);
129*593dc095SDavid du Colombier return 0;
130*593dc095SDavid du Colombier }
131*593dc095SDavid du Colombier
132*593dc095SDavid du Colombier private
read_int8(FILE * in,void * p)133*593dc095SDavid du Colombier int read_int8(FILE *in, void *p)
134*593dc095SDavid du Colombier {
135*593dc095SDavid du Colombier byte c = fgetc(in);
136*593dc095SDavid du Colombier if (c < 0) return -1;
137*593dc095SDavid du Colombier
138*593dc095SDavid du Colombier *(byte*)p = (c&0xFF);
139*593dc095SDavid du Colombier return 0;
140*593dc095SDavid du Colombier }
141*593dc095SDavid du Colombier
142*593dc095SDavid du Colombier /* convert a 4-character typecode from C string to uint32 representation */
res_string2type(const char * type_string)143*593dc095SDavid du Colombier private unsigned int res_string2type(const char *type_string)
144*593dc095SDavid du Colombier {
145*593dc095SDavid du Colombier unsigned int type = type_string[0] << 24 |
146*593dc095SDavid du Colombier type_string[1] << 16 |
147*593dc095SDavid du Colombier type_string[2] << 8 |
148*593dc095SDavid du Colombier type_string[3];
149*593dc095SDavid du Colombier return (type);
150*593dc095SDavid du Colombier }
151*593dc095SDavid du Colombier /* convert a 4-character typecode from unsigned int to C string representation */
res_type2string(const unsigned int type,char * type_string)152*593dc095SDavid du Colombier private char * res_type2string(const unsigned int type, char *type_string)
153*593dc095SDavid du Colombier {
154*593dc095SDavid du Colombier if (type_string == NULL) return NULL;
155*593dc095SDavid du Colombier
156*593dc095SDavid du Colombier type_string[0] = (type >> 24) & 0xFF;
157*593dc095SDavid du Colombier type_string[1] = (type >> 16) & 0xFF;
158*593dc095SDavid du Colombier type_string[2] = (type >> 8) & 0xFF;
159*593dc095SDavid du Colombier type_string[3] = (type) & 0xFF;
160*593dc095SDavid du Colombier type_string[4] = '\0';
161*593dc095SDavid du Colombier
162*593dc095SDavid du Colombier return (type_string);
163*593dc095SDavid du Colombier }
164*593dc095SDavid du Colombier
165*593dc095SDavid du Colombier private
read_resource_header(FILE * in,int offset)166*593dc095SDavid du Colombier resource_header *read_resource_header(FILE *in, int offset)
167*593dc095SDavid du Colombier {
168*593dc095SDavid du Colombier resource_header *header = malloc(sizeof(*header));
169*593dc095SDavid du Colombier
170*593dc095SDavid du Colombier fseek(in, offset, SEEK_SET);
171*593dc095SDavid du Colombier
172*593dc095SDavid du Colombier read_int32(in, &(header->data_offset));
173*593dc095SDavid du Colombier read_int32(in, &(header->map_offset));
174*593dc095SDavid du Colombier read_int32(in, &(header->data_length));
175*593dc095SDavid du Colombier read_int32(in, &(header->map_length));
176*593dc095SDavid du Colombier
177*593dc095SDavid du Colombier if (feof(in)) {
178*593dc095SDavid du Colombier free (header);
179*593dc095SDavid du Colombier header = NULL;
180*593dc095SDavid du Colombier }
181*593dc095SDavid du Colombier
182*593dc095SDavid du Colombier return header;
183*593dc095SDavid du Colombier }
184*593dc095SDavid du Colombier
185*593dc095SDavid du Colombier private
read_resource_map(FILE * in,resource_header * header)186*593dc095SDavid du Colombier resource_list *read_resource_map(FILE *in, resource_header *header)
187*593dc095SDavid du Colombier {
188*593dc095SDavid du Colombier resource_list *list;
189*593dc095SDavid du Colombier int n_resources;
190*593dc095SDavid du Colombier int type_offset, name_offset, this_name_offset;
191*593dc095SDavid du Colombier unsigned int *types;
192*593dc095SDavid du Colombier int *number, *ref_offsets;
193*593dc095SDavid du Colombier int n_types;
194*593dc095SDavid du Colombier char type_string[5];
195*593dc095SDavid du Colombier byte *buf, *p;
196*593dc095SDavid du Colombier int i,j,k;
197*593dc095SDavid du Colombier
198*593dc095SDavid du Colombier buf = malloc(sizeof(*buf)*header->map_length);
199*593dc095SDavid du Colombier if (buf == NULL) {
200*593dc095SDavid du Colombier if_debug1('s', "error: could not allocate %d bytes for resource map\n", header->map_length);
201*593dc095SDavid du Colombier return NULL;
202*593dc095SDavid du Colombier }
203*593dc095SDavid du Colombier
204*593dc095SDavid du Colombier /* read in the whole resource map */
205*593dc095SDavid du Colombier fseek(in, header->map_offset, SEEK_SET);
206*593dc095SDavid du Colombier fread(buf, 1, header->map_length, in);
207*593dc095SDavid du Colombier
208*593dc095SDavid du Colombier type_offset = get_int16(buf + 24);
209*593dc095SDavid du Colombier name_offset = get_int16(buf + 26);
210*593dc095SDavid du Colombier n_types = get_int16(buf + 28); n_types++;
211*593dc095SDavid du Colombier
212*593dc095SDavid du Colombier if (type_offset != 30)
213*593dc095SDavid du Colombier if_debug1('s', "[s] warning! resource type list offset is %d, not 30!\n", type_offset);
214*593dc095SDavid du Colombier
215*593dc095SDavid du Colombier /* determine the total number of resources */
216*593dc095SDavid du Colombier types = malloc(sizeof(*types)*n_types);
217*593dc095SDavid du Colombier number = malloc(sizeof(*number)*n_types);
218*593dc095SDavid du Colombier ref_offsets = malloc(sizeof(*ref_offsets)*n_types);
219*593dc095SDavid du Colombier n_resources = 0;
220*593dc095SDavid du Colombier p = buf + type_offset; /* this seems to be off by two in files!? */
221*593dc095SDavid du Colombier p = buf + 30;
222*593dc095SDavid du Colombier for (i = 0; i < n_types; i++) {
223*593dc095SDavid du Colombier types[i] = get_int32(p);
224*593dc095SDavid du Colombier number[i] = get_int16(p + 4) + 1;
225*593dc095SDavid du Colombier ref_offsets[i] = get_int16(p + 6);
226*593dc095SDavid du Colombier p += 8;
227*593dc095SDavid du Colombier n_resources += number[i];
228*593dc095SDavid du Colombier }
229*593dc095SDavid du Colombier
230*593dc095SDavid du Colombier /* parse the individual resources */
231*593dc095SDavid du Colombier list = malloc(sizeof(resource_list));
232*593dc095SDavid du Colombier list->resources = malloc(sizeof(resource)*n_resources);
233*593dc095SDavid du Colombier list->n_resources = n_resources;
234*593dc095SDavid du Colombier k = 0;
235*593dc095SDavid du Colombier for (i = 0; i < n_types; i++) {
236*593dc095SDavid du Colombier res_type2string(types[i], type_string);
237*593dc095SDavid du Colombier if_debug2('s', "[s] %d resources of type '%s':\n", number[i], type_string);
238*593dc095SDavid du Colombier p = buf + type_offset + ref_offsets[i]; /* FIXME: also off? */
239*593dc095SDavid du Colombier /* p = buf + 32 + ref_offsets[i]; */
240*593dc095SDavid du Colombier for (j = 0; j < number[i]; j++) {
241*593dc095SDavid du Colombier list->resources[k].type = types[i];
242*593dc095SDavid du Colombier list->resources[k].id = get_int16(p);
243*593dc095SDavid du Colombier this_name_offset = get_int16(p + 2);
244*593dc095SDavid du Colombier if (this_name_offset == 0xFFFF) { /* no name field */
245*593dc095SDavid du Colombier list->resources[k].name = NULL;
246*593dc095SDavid du Colombier } else { /* read name field (a pascal string) */
247*593dc095SDavid du Colombier char *c = buf + name_offset + this_name_offset;
248*593dc095SDavid du Colombier int len = *c;
249*593dc095SDavid du Colombier list->resources[k].name = malloc(sizeof(char)*(len+1));
250*593dc095SDavid du Colombier memcpy(list->resources[k].name, c + 1, len);
251*593dc095SDavid du Colombier list->resources[k].name[len] = '\0';
252*593dc095SDavid du Colombier }
253*593dc095SDavid du Colombier list->resources[k].flags = *(p+4);
254*593dc095SDavid du Colombier list->resources[k].offset = get_int24(p+5);
255*593dc095SDavid du Colombier /* load the actual resource data separately */
256*593dc095SDavid du Colombier list->resources[k].length = 0;
257*593dc095SDavid du Colombier list->resources[k].data = NULL;
258*593dc095SDavid du Colombier
259*593dc095SDavid du Colombier p += 12;
260*593dc095SDavid du Colombier if_debug4('s', "\tid %d offset 0x%08x flags 0x%02x '%s'\n",
261*593dc095SDavid du Colombier list->resources[k].id, list->resources[k].offset,
262*593dc095SDavid du Colombier list->resources[k].flags, list->resources[k].name);
263*593dc095SDavid du Colombier k++;
264*593dc095SDavid du Colombier }
265*593dc095SDavid du Colombier }
266*593dc095SDavid du Colombier
267*593dc095SDavid du Colombier free(buf);
268*593dc095SDavid du Colombier
269*593dc095SDavid du Colombier return list;
270*593dc095SDavid du Colombier }
271*593dc095SDavid du Colombier
272*593dc095SDavid du Colombier private
load_resource(FILE * in,resource_header * header,resource * res)273*593dc095SDavid du Colombier void load_resource(FILE *in, resource_header *header, resource *res)
274*593dc095SDavid du Colombier {
275*593dc095SDavid du Colombier unsigned int len;
276*593dc095SDavid du Colombier byte *buf;
277*593dc095SDavid du Colombier
278*593dc095SDavid du Colombier fseek(in, header->data_offset + res->offset, SEEK_SET);
279*593dc095SDavid du Colombier read_int32(in, &len);
280*593dc095SDavid du Colombier
281*593dc095SDavid du Colombier buf = malloc(len);
282*593dc095SDavid du Colombier fread(buf, 1, len, in);
283*593dc095SDavid du Colombier res->data = buf;
284*593dc095SDavid du Colombier res->length = len;
285*593dc095SDavid du Colombier
286*593dc095SDavid du Colombier return;
287*593dc095SDavid du Colombier }
288*593dc095SDavid du Colombier
289*593dc095SDavid du Colombier private
read_datafork_resource(byte * buf,const char * fname,const uint type,const ushort id)290*593dc095SDavid du Colombier int read_datafork_resource(byte *buf, const char *fname, const uint type, const ushort id)
291*593dc095SDavid du Colombier {
292*593dc095SDavid du Colombier resource_header *header;
293*593dc095SDavid du Colombier resource_list *list;
294*593dc095SDavid du Colombier FILE *in;
295*593dc095SDavid du Colombier int i;
296*593dc095SDavid du Colombier
297*593dc095SDavid du Colombier
298*593dc095SDavid du Colombier in = fopen(fname, "rb");
299*593dc095SDavid du Colombier if (in == NULL) {
300*593dc095SDavid du Colombier if_debug1('s', "[s] couldn't open '%s'\n", fname);
301*593dc095SDavid du Colombier return 0;
302*593dc095SDavid du Colombier }
303*593dc095SDavid du Colombier
304*593dc095SDavid du Colombier header = read_resource_header(in, 0);
305*593dc095SDavid du Colombier if (header == NULL) {
306*593dc095SDavid du Colombier if_debug0('s', "[s] could not read resource file header.\n");
307*593dc095SDavid du Colombier if_debug0('s', "[s] not a serialized data fork resource file?\n");
308*593dc095SDavid du Colombier return 0;
309*593dc095SDavid du Colombier }
310*593dc095SDavid du Colombier
311*593dc095SDavid du Colombier if_debug0('s', "[s] loading resource map\n");
312*593dc095SDavid du Colombier list = read_resource_map(in, header);
313*593dc095SDavid du Colombier if (list == NULL) {
314*593dc095SDavid du Colombier if_debug0('s', "[s] couldn't read resource map.\n");
315*593dc095SDavid du Colombier return 0;
316*593dc095SDavid du Colombier }
317*593dc095SDavid du Colombier
318*593dc095SDavid du Colombier /* load the resource data we're interested in */
319*593dc095SDavid du Colombier for (i = 0; i < list->n_resources; i++) {
320*593dc095SDavid du Colombier if ((list->resources[i].type == type) &&
321*593dc095SDavid du Colombier (list->resources[i].id == id)) {
322*593dc095SDavid du Colombier if_debug2('s', "[s] loading '%s' resource id %d",
323*593dc095SDavid du Colombier list->resources[i].name, list->resources[i].id);
324*593dc095SDavid du Colombier load_resource(in, header, &(list->resources[i]));
325*593dc095SDavid du Colombier if_debug1('s', " (%d bytes)\n", list->resources[i].length);
326*593dc095SDavid du Colombier fclose(in);
327*593dc095SDavid du Colombier if (buf) memcpy (buf, list->resources[i].data, list->resources[i].length);
328*593dc095SDavid du Colombier return (list->resources[i].length);
329*593dc095SDavid du Colombier }
330*593dc095SDavid du Colombier }
331*593dc095SDavid du Colombier
332*593dc095SDavid du Colombier fclose(in);
333*593dc095SDavid du Colombier free(list);
334*593dc095SDavid du Colombier free(header);
335*593dc095SDavid du Colombier
336*593dc095SDavid du Colombier return (0);
337*593dc095SDavid du Colombier }
338*593dc095SDavid du Colombier
339*593dc095SDavid du Colombier /* end dfont loading code */
340*593dc095SDavid du Colombier
341*593dc095SDavid du Colombier
342*593dc095SDavid du Colombier /* prototypes */
343*593dc095SDavid du Colombier private iodev_proc_init(iodev_macresource_init);
344*593dc095SDavid du Colombier private iodev_proc_open_file(iodev_macresource_open_file);
345*593dc095SDavid du Colombier /* there is no close_file()...stream closure takes care of it */
346*593dc095SDavid du Colombier /* ignore rest for now */
347*593dc095SDavid du Colombier
348*593dc095SDavid du Colombier /* Define the %macresource% device */
349*593dc095SDavid du Colombier const gx_io_device gs_iodev_macresource =
350*593dc095SDavid du Colombier {
351*593dc095SDavid du Colombier "%macresource%", "FileSystem",
352*593dc095SDavid du Colombier {
353*593dc095SDavid du Colombier iodev_macresource_init, iodev_no_open_device,
354*593dc095SDavid du Colombier iodev_macresource_open_file,
355*593dc095SDavid du Colombier iodev_no_fopen, iodev_no_fclose,
356*593dc095SDavid du Colombier iodev_no_delete_file, iodev_no_rename_file,
357*593dc095SDavid du Colombier iodev_no_file_status,
358*593dc095SDavid du Colombier iodev_no_enumerate_files, NULL, NULL,
359*593dc095SDavid du Colombier iodev_no_get_params, iodev_no_put_params
360*593dc095SDavid du Colombier }
361*593dc095SDavid du Colombier };
362*593dc095SDavid du Colombier
363*593dc095SDavid du Colombier /* init state. don't know if we need state yet--probably not */
364*593dc095SDavid du Colombier private int
iodev_macresource_init(gx_io_device * iodev,gs_memory_t * mem)365*593dc095SDavid du Colombier iodev_macresource_init(gx_io_device *iodev, gs_memory_t *mem)
366*593dc095SDavid du Colombier {
367*593dc095SDavid du Colombier return 0;
368*593dc095SDavid du Colombier }
369*593dc095SDavid du Colombier
370*593dc095SDavid du Colombier /* open the requested file return (in ps) a stream containing the resource data */
371*593dc095SDavid du Colombier private int
iodev_macresource_open_file(gx_io_device * iodev,const char * fname,uint namelen,const char * access,stream ** ps,gs_memory_t * mem)372*593dc095SDavid du Colombier iodev_macresource_open_file(gx_io_device *iodev, const char *fname, uint namelen,
373*593dc095SDavid du Colombier const char *access, stream **ps, gs_memory_t *mem)
374*593dc095SDavid du Colombier {
375*593dc095SDavid du Colombier char filename[gp_file_name_sizeof];
376*593dc095SDavid du Colombier char *res_type_string, *res_id_string;
377*593dc095SDavid du Colombier uint type;
378*593dc095SDavid du Colombier ushort id;
379*593dc095SDavid du Colombier bool datafork = 0;
380*593dc095SDavid du Colombier int size;
381*593dc095SDavid du Colombier byte *buf;
382*593dc095SDavid du Colombier
383*593dc095SDavid du Colombier /* return NULL if there's an error */
384*593dc095SDavid du Colombier *ps = NULL;
385*593dc095SDavid du Colombier
386*593dc095SDavid du Colombier strncpy(filename, fname, min(namelen, gp_file_name_sizeof));
387*593dc095SDavid du Colombier if (namelen < gp_file_name_sizeof) filename[namelen] = '\0';
388*593dc095SDavid du Colombier /* parse out the resource type and id. they're appended to the pathname
389*593dc095SDavid du Colombier in the form '#<type>+<id>' */
390*593dc095SDavid du Colombier res_type_string = strrchr(filename, '#');
391*593dc095SDavid du Colombier if (res_type_string == NULL) {
392*593dc095SDavid du Colombier if_debug0('s', "[s] couldn't find resource type separator\n");
393*593dc095SDavid du Colombier return_error(e_invalidfileaccess);
394*593dc095SDavid du Colombier }
395*593dc095SDavid du Colombier *res_type_string++ = '\0';
396*593dc095SDavid du Colombier res_id_string = strrchr(res_type_string, '+');
397*593dc095SDavid du Colombier if (res_id_string == NULL) {
398*593dc095SDavid du Colombier if_debug0('s', "couldn't find resource id separator\n");
399*593dc095SDavid du Colombier return_error(e_invalidfileaccess);
400*593dc095SDavid du Colombier }
401*593dc095SDavid du Colombier *res_id_string++ = '\0';
402*593dc095SDavid du Colombier type = res_string2type(res_type_string);
403*593dc095SDavid du Colombier id = (ushort)atoi(res_id_string);
404*593dc095SDavid du Colombier if_debug3('s', "[s] opening resource fork of '%s' for type '%s' id '%d'\n", filename, res_type_string, id);
405*593dc095SDavid du Colombier
406*593dc095SDavid du Colombier /* we call with a NULL buffer to get the size */
407*593dc095SDavid du Colombier size = gp_read_macresource(NULL, filename, type, id);
408*593dc095SDavid du Colombier if (size == 0) {
409*593dc095SDavid du Colombier /* this means that opening the resource fork failed */
410*593dc095SDavid du Colombier /* try to open as a .dfont from here */
411*593dc095SDavid du Colombier if_debug0('s', "[s] trying to open as a datafork file instead...\n");
412*593dc095SDavid du Colombier size = read_datafork_resource(NULL, filename, type, id);
413*593dc095SDavid du Colombier if (size != 0) {
414*593dc095SDavid du Colombier datafork = true;
415*593dc095SDavid du Colombier } else {
416*593dc095SDavid du Colombier if_debug0('s', "could not get resource size\n");
417*593dc095SDavid du Colombier return_error(e_invalidfileaccess);
418*593dc095SDavid du Colombier }
419*593dc095SDavid du Colombier }
420*593dc095SDavid du Colombier if_debug1('s', "[s] got resource size %d bytes\n", size);
421*593dc095SDavid du Colombier /* allocate a buffer */
422*593dc095SDavid du Colombier buf = gs_alloc_string(mem, size, "macresource buffer");
423*593dc095SDavid du Colombier if (buf == NULL) {
424*593dc095SDavid du Colombier if_debug0('s', "macresource: could not allocate buffer for resource data\n");
425*593dc095SDavid du Colombier return_error(e_VMerror);
426*593dc095SDavid du Colombier }
427*593dc095SDavid du Colombier /* call again to get the resource data */
428*593dc095SDavid du Colombier if (!datafork) {
429*593dc095SDavid du Colombier size = gp_read_macresource(buf, filename, type, id);
430*593dc095SDavid du Colombier } else {
431*593dc095SDavid du Colombier size = read_datafork_resource(buf, filename, type, id);
432*593dc095SDavid du Colombier }
433*593dc095SDavid du Colombier
434*593dc095SDavid du Colombier /* allocate stream *ps and set it up with the buffered data */
435*593dc095SDavid du Colombier *ps = s_alloc(mem, "macresource");
436*593dc095SDavid du Colombier sread_string(*ps, buf, size);
437*593dc095SDavid du Colombier
438*593dc095SDavid du Colombier /* return success */
439*593dc095SDavid du Colombier return 0;
440*593dc095SDavid du Colombier }
441