Commit e2455bad125fab422792340e41868ffb9d4c2fb3

Werner Lemberg 2004-02-26T21:56:27

* docs/CHANGES: Updated. Improve MacOS fond support. Provide a new API `FT_New_Face_From_FSSpec' similar to `FT_New_Face'. * src/base/ftmac.c [__MWERKS__]: Include FSp_fpopen.h. STREAM_FILE [__MWERKS__]: New macro. (ft_FSp_stream_close, ft_FSp_stream_io) [__MWERKS__]: New functions. (file_spec_from_path) [__MWERKS__]: Updated #if statement. (get_file_type, make_lwfn_spec): Use `const' for argument. (is_dfont) [TARGET_API_MAC_CARBON]: Removed. (count_face_sfnt, count_faces): New functions. (parse_fond): Do some range checking. (read_lwfn): Change type of second argument. No longer call FSpOpenResFile. (OpenFileAsResource): New function. (FT_New_Face_From_LWFN): Use `const' for second argument. Use OpenFileAsResource. (FT_New_Face_From_Suitcase): Change type of second argument. No longer call FSpOpenResFile. Loop over all resource indices. (FT_New_Face_From_dfont) [TARGET_API_MAC_CARBON]: Removed. (FT_GetFile_From_Mac_Name): Use `const' for first argument. (ResourceForkSize): Removed. (FT_New_Face): Updated to use new functions. (FT_New_Face_From_FSSpec): New function. * include/freetype/ftmac.h: Updated.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
diff --git a/ChangeLog b/ChangeLog
index 92105ee..57914c5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+2004-02-25  Werner Lemberg  <wl@gnu.org>
+
+	* docs/CHANGES: Updated.
+
+2004-02-25  Garrick Meeker  <garrick@digitalanarchy.com>
+
+	Improve MacOS fond support.  Provide a new API
+	`FT_New_Face_From_FSSpec' similar to `FT_New_Face'.
+
+	* src/base/ftmac.c [__MWERKS__]: Include FSp_fpopen.h.
+	STREAM_FILE [__MWERKS__]: New macro.
+	(ft_FSp_stream_close, ft_FSp_stream_io) [__MWERKS__]: New functions.
+	(file_spec_from_path) [__MWERKS__]: Updated #if statement.
+	(get_file_type, make_lwfn_spec): Use `const' for argument.
+	(is_dfont) [TARGET_API_MAC_CARBON]: Removed.
+	(count_face_sfnt, count_faces): New functions.
+	(parse_fond): Do some range checking.
+	(read_lwfn): Change type of second argument.
+	No longer call FSpOpenResFile.
+	(OpenFileAsResource): New function.
+	(FT_New_Face_From_LWFN): Use `const' for second argument.
+	Use OpenFileAsResource.
+	(FT_New_Face_From_Suitcase): Change type of second argument.
+	No longer call FSpOpenResFile.
+	Loop over all resource indices.
+	(FT_New_Face_From_dfont) [TARGET_API_MAC_CARBON]: Removed.
+	(FT_GetFile_From_Mac_Name): Use `const' for first argument.
+	(ResourceForkSize): Removed.
+	(FT_New_Face): Updated to use new functions.
+	(FT_New_Face_From_FSSpec): New function.
+
+	* include/freetype/ftmac.h: Updated.
+
 2004-02-24  Malcolm Taylor  <mtaylor@clear.net.nz>
 
 	* src/autohint/ahhint.c (ah_hinter_load) <FT_GLYPH_FORMAT_OUTLINE>:
diff --git a/docs/CHANGES b/docs/CHANGES
index 77e815f..7c53264 100644
--- a/docs/CHANGES
+++ b/docs/CHANGES
@@ -67,6 +67,10 @@ LATEST CHANGES BETWEEN 2.1.8 and 2.1.7
       forks on non-MacOS platforms (for example, Linux can mount MacOS
       file systems).
 
+    - Support for MacOS has been improved; there is now a new function
+      `FT_New_Face_From_FSSpec'  similar to `FT_New_Face'  except that
+      it accepts an FSSpec instead of a path.
+
     - The cache sub-system has been rewritten.
 
       - There is now support for deinstallation of faces.
diff --git a/include/freetype/ftmac.h b/include/freetype/ftmac.h
index 5c29b11..78ed779 100644
--- a/include/freetype/ftmac.h
+++ b/include/freetype/ftmac.h
@@ -112,9 +112,43 @@ FT_BEGIN_HEADER
   /*    FreeType error code.  0 means success.                             */
   /*                                                                       */
   FT_EXPORT( FT_Error )
-  FT_GetFile_From_Mac_Name( char*     fontName, 
-                            FSSpec*   pathSpec,
-                            FT_Long*  face_index );
+  FT_GetFile_From_Mac_Name( const char*  fontName, 
+                            FSSpec*      pathSpec,
+                            FT_Long*     face_index );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    FT_New_Face_From_FSSpec                                            */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Creates a new face object from a given resource and typeface index */
+  /*    using an FSSpec to the font file.                                  */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    library    :: A handle to the library resource.                    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    spec       :: FSSpec to the font file.                             */
+  /*                                                                       */
+  /*    face_index :: The index of the face within the resource.  The      */
+  /*                  first face has index 0.                              */
+  /* <Output>                                                              */
+  /*    aface      :: A handle to a new face object.                       */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    @FT_New_Face_From_FSSpec is identical to @FT_New_Face except       */
+  /*    it accepts an FSSpec instead of a path.                            */
+  /*                                                                       */
+  FT_EXPORT( FT_Error )
+  FT_New_Face_From_FSSpec( FT_Library     library,
+                           const FSSpec  *spec,
+                           FT_Long        face_index,
+                           FT_Face       *aface );
 
   /* */
 
diff --git a/src/base/ftmac.c b/src/base/ftmac.c
index 04c03d9..7f05f3b 100644
--- a/src/base/ftmac.c
+++ b/src/base/ftmac.c
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    Mac FOND support.  Written by just@letterror.com.                    */
 /*                                                                         */
-/*  Copyright 1996-2001, 2002, 2003 by                                     */
+/*  Copyright 1996-2001, 2002, 2003, 2004 by                               */
 /*  Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg.     */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -77,6 +77,10 @@
 #include <TextUtils.h>
 #endif
 
+#if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
+#include <FSp_fopen.h>
+#endif
+
 #include FT_MAC_H
 
 
@@ -87,12 +91,50 @@
 #define PREFER_LWFN 1
 #endif
 
+
+#if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
+
+#define STREAM_FILE( stream )  ( (FILE*)stream->descriptor.pointer )
+
+
+  FT_CALLBACK_DEF( void )
+  ft_FSp_stream_close( FT_Stream  stream )
+  {
+    fclose( STREAM_FILE( stream ) );
+
+    stream->descriptor.pointer = NULL;
+    stream->size               = 0;
+    stream->base               = 0;
+  }
+
+
+  FT_CALLBACK_DEF( unsigned long )
+  ft_FSp_stream_io( FT_Stream       stream,
+                    unsigned long   offset,
+                    unsigned char*  buffer,
+                    unsigned long   count )
+  {
+    FILE*  file;
+
+
+    file = STREAM_FILE( stream );
+
+    fseek( file, offset, SEEK_SET );
+
+    return (unsigned long)fread( buffer, 1, count, file );
+  }
+
+#endif  /* __MWERKS__ && !TARGET_RT_MAC_MACHO */
+
+
   /* Given a pathname, fill in a file spec. */
   static int
   file_spec_from_path( const char*  pathname,
                        FSSpec*      spec )
   {
-#if defined( TARGET_API_MAC_CARBON ) && !defined( __MWERKS__ )
+
+#if TARGET_API_MAC_CARBON && \
+    !( defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO )
 
     OSErr  e;
     FSRef  ref;
@@ -123,12 +165,13 @@
       return 0;
 
 #endif
+
   }
 
 
   /* Return the file type of the file specified by spec. */
   static OSType
-  get_file_type( FSSpec*  spec )
+  get_file_type( const FSSpec*  spec )
   {
     FInfo  finfo;
 
@@ -140,22 +183,6 @@
   }
 
 
-#ifdef TARGET_API_MAC_CARBON
-
-  /* is this a Mac OS X .dfont file */
-  static Boolean
-  is_dfont( FSSpec*  spec )
-  {
-    int  nameLen = spec->name[0];
-
-
-    return nameLen >= 6                                      &&
-           !ft_memcmp( spec->name + nameLen - 5, ".dfont", 6 );
-  }
-
-#endif
-
-
   /* Given a PostScript font name, create the Macintosh LWFN file name. */
   static void
   create_lwfn_name( char*   ps_name,
@@ -217,9 +244,9 @@
   /* Make a file spec for an LWFN file from a FOND resource and
      a file name. */
   static FT_Error
-  make_lwfn_spec( Handle          fond,
-                  unsigned char*  file_name,
-                  FSSpec*         spec )
+  make_lwfn_spec( Handle               fond,
+                  const unsigned char* file_name,
+                  FSSpec*              spec )
   {
     FT_Error  error;
     short     ref_num, v_ref_num;
@@ -240,12 +267,24 @@
   }
 
 
+  static short
+  count_faces_sfnt( char *fond_data )
+  {
+    /* The count is 1 greater than the value in the FOND.  */
+    /* Isn't that cute? :-)                                */
+
+    return 1 + *( (short *)( fond_data + sizeof ( FamRec ) ) );
+  }
+
+
   /* Look inside the FOND data, answer whether there should be an SFNT
      resource, and answer the name of a possible LWFN Type 1 file.
 
      Thanks to Paul Miller (paulm@profoundeffects.com) for the fix
      to load a face OTHER than the first one in the FOND!
   */
+
+
   static void
   parse_fond( char*   fond_data,
               short*  have_sfnt,
@@ -265,19 +304,24 @@
     fond       = (FamRec*)fond_data;
     assoc      = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
     base_assoc = assoc;
-    assoc     += face_index;        /* add on the face_index! */
 
-    /* if the face at this index is not scalable,
-       fall back to the first one (old behavior) */
-    if ( assoc->fontSize == 0 )
+    /* Let's do a little range checking before we get too excited here */
+    if ( face_index < count_faces_sfnt( fond_data ) )
     {
-      *have_sfnt = 1;
-      *sfnt_id   = assoc->fontID;
-    }
-    else if ( base_assoc->fontSize == 0 )
-    {
-      *have_sfnt = 1;
-      *sfnt_id   = base_assoc->fontID;
+      assoc += face_index;        /* add on the face_index! */
+
+      /* if the face at this index is not scalable,
+         fall back to the first one (old behavior) */
+      if ( assoc->fontSize == 0 )
+      {
+        *have_sfnt = 1;
+        *sfnt_id   = assoc->fontID;
+      }
+      else if ( base_assoc->fontSize == 0 )
+      {
+        *have_sfnt = 1;
+        *sfnt_id   = base_assoc->fontID;
+      }
     }
 
     if ( fond->ffStylOff )
@@ -344,6 +388,33 @@
   }
 
 
+  static short
+  count_faces( Handle  fond )
+  {
+    short   sfnt_id, have_sfnt, have_lwfn = 0;
+    Str255  lwfn_file_name;
+    FSSpec  lwfn_spec;
+
+
+    HLock( fond );
+    parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, 0 );
+    HUnlock( fond );
+
+    if ( lwfn_file_name[0] )
+    {
+      if ( make_lwfn_spec( fond, lwfn_file_name, &lwfn_spec ) == FT_Err_Ok )
+        have_lwfn = 1;  /* yeah, we got one! */
+      else
+        have_lwfn = 0;  /* no LWFN file found */
+    }
+
+    if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
+      return 1;
+    else
+      return count_faces_sfnt( *fond );
+  }
+
+
   /* Read Type 1 data from the POST resources inside the LWFN file,
      return a PFB buffer. This is somewhat convoluted because the FT2
      PFB parser wants the ASCII header as one chunk, and the LWFN
@@ -351,12 +422,12 @@
      of the same type together. */
   static FT_Error
   read_lwfn( FT_Memory  memory,
-             FSSpec*    lwfn_spec,
+             short      res_ref,
              FT_Byte**  pfb_data,
              FT_ULong*  size )
   {
     FT_Error       error = FT_Err_Ok;
-    short          res_ref, res_id;
+    short          res_id;
     unsigned char  *buffer, *p, *size_p = NULL;
     FT_ULong       total_size = 0;
     FT_ULong       post_size, pfb_chunk_size;
@@ -364,13 +435,10 @@
     char           code, last_code;
 
 
-    res_ref = FSpOpenResFile( lwfn_spec, fsRdPerm );
-    if ( ResError() )
-      return FT_Err_Out_Of_Memory;
     UseResFile( res_ref );
 
-    /* First pass: load all POST resources, and determine the size of
-       the output buffer. */
+    /* First pass: load all POST resources, and determine the size of */
+    /* the output buffer.                                             */
     res_id    = 501;
     last_code = -1;
 
@@ -397,8 +465,8 @@
     if ( FT_ALLOC( buffer, (FT_Long)total_size ) )
       goto Error;
 
-    /* Second pass: append all POST data to the buffer, add PFB fields.
-       Glue all consecutive chunks of the same type together. */
+    /* Second pass: append all POST data to the buffer, add PFB fields. */
+    /* Glue all consecutive chunks of the same type together.           */
     p              = buffer;
     res_id         = 501;
     last_code      = -1;
@@ -551,19 +619,59 @@
   }
 
 
+  static FT_Error
+  OpenFileAsResource( const FSSpec*  spec,
+                      short         *p_res_ref )
+  {
+    FT_Error  error;
+
+#if TARGET_API_MAC_CARBON
+
+    FSRef     hostContainerRef;
+
+
+    error = FSpMakeFSRef( spec, &hostContainerRef );
+    if ( error == noErr )
+      error = FSOpenResourceFile( &hostContainerRef,
+                                  0, NULL, fsRdPerm, p_res_ref );
+
+    /* If the above fails, then it is probably not a resource file       */
+    /* However, it has been reported that FSOpenResourceFile() sometimes */
+    /* fails on some old resource-fork files, which FSpOpenResFile() can */
+    /* open.  So, just try again with FSpOpenResFile() and see what      */
+    /* happens :-)                                                       */
+
+    if ( error != noErr )
+
+#endif  /* TARGET_API_MAC_CARBON */
+
+    {
+      *p_res_ref = FSpOpenResFile( spec, fsRdPerm );
+      error = ResError();
+    }
+
+    return error ? FT_Err_Cannot_Open_Resource : FT_Err_Ok;
+  }
+
+
   /* Create a new FT_Face from a file spec to an LWFN file. */
   static FT_Error
-  FT_New_Face_From_LWFN( FT_Library  library,
-                         FSSpec*     spec,
-                         FT_Long     face_index,
-                         FT_Face    *aface )
+  FT_New_Face_From_LWFN( FT_Library     library,
+                         const FSSpec*  lwfn_spec,
+                         FT_Long        face_index,
+                         FT_Face       *aface )
   {
     FT_Byte*  pfb_data;
     FT_ULong  pfb_size;
     FT_Error  error;
+    short     res_ref;
+
 
+    error = OpenFileAsResource( lwfn_spec, &res_ref );
+    if ( error )
+      return error;
 
-    error = read_lwfn( library->memory, spec, &pfb_data, &pfb_size );
+    error = read_lwfn( library->memory, res_ref, &pfb_data, &pfb_size );
     if ( error )
       return error;
 
@@ -624,83 +732,34 @@
   /* Create a new FT_Face from a file spec to a suitcase file. */
   static FT_Error
   FT_New_Face_From_Suitcase( FT_Library  library,
-                             FSSpec*     spec,
+                             short       res_ref,
                              FT_Long     face_index,
                              FT_Face    *aface )
   {
     FT_Error  error = FT_Err_Ok;
-    short     res_ref, res_index;
+    short     res_index;
     Handle    fond;
+    short     num_faces;
 
 
-    res_ref = FSpOpenResFile( spec, fsRdPerm );
-    if ( ResError() )
-      return FT_Err_Cannot_Open_Resource;
     UseResFile( res_ref );
 
-    /* face_index may be -1, in which case we
-       just need to do a sanity check */
-    if ( face_index < 0 )
-      res_index = 1;
-    else
-    {
-      res_index = (short)( face_index + 1 );
-      face_index = 0;
-    }
-    fond = Get1IndResource( 'FOND', res_index );
-    if ( ResError() )
+    for ( res_index = 1; ; ++res_index )
     {
-      error = FT_Err_Cannot_Open_Resource;
-      goto Error;
-    }
-
-    error = FT_New_Face_From_FOND( library, fond, face_index, aface );
-
-  Error:
-    CloseResFile( res_ref );
-    return error;
-  }
-
-
-#ifdef TARGET_API_MAC_CARBON
-
-  /* Create a new FT_Face from a file spec to a suitcase file. */
-  static FT_Error
-  FT_New_Face_From_dfont( FT_Library  library,
-                          FSSpec*     spec,
-                          FT_Long     face_index,
-                          FT_Face*    aface )
-  {
-    FT_Error  error = FT_Err_Ok;
-    short     res_ref, res_index;
-    Handle    fond;
-    FSRef     hostContainerRef;
-
-
-    error = FSpMakeFSRef( spec, &hostContainerRef );
-    if ( error == noErr )
-      error = FSOpenResourceFile( &hostContainerRef,
-                                  0, NULL, fsRdPerm, &res_ref );
-
-    if ( error != noErr )
-      return FT_Err_Cannot_Open_Resource;
+      fond = Get1IndResource( 'FOND', res_index );
+      if ( ResError() )
+      {
+        error = FT_Err_Cannot_Open_Resource;
+        goto Error;
+      }
+      if ( face_index < 0 )
+        break;
 
-    UseResFile( res_ref );
+      num_faces = count_faces( fond );
+      if ( face_index < num_faces )
+        break;
 
-    /* face_index may be -1, in which case we
-       just need to do a sanity check */
-    if ( face_index < 0 )
-      res_index = 1;
-    else
-    {
-      res_index = (short)( face_index + 1 );
-      face_index = 0;
-    }
-    fond = Get1IndResource( 'FOND', res_index );
-    if ( ResError() )
-    {
-      error = FT_Err_Cannot_Open_Resource;
-      goto Error;
+      face_index -= num_faces;
     }
 
     error = FT_New_Face_From_FOND( library, fond, face_index, aface );
@@ -710,8 +769,6 @@
     return error;
   }
 
-#endif
-
 
   /* documentation is in ftmac.h */
 
@@ -763,9 +820,9 @@
   /* documentation is in ftmac.h */
 
   FT_EXPORT_DEF( FT_Error )
-  FT_GetFile_From_Mac_Name( char*     fontName,
-                            FSSpec*   pathSpec,
-                            FT_Long*  face_index )
+  FT_GetFile_From_Mac_Name( const char* fontName,
+                            FSSpec*     pathSpec,
+                            FT_Long*    face_index )
   {
     OptionBits            options = kFMUseGlobalScopeOption;
 
@@ -846,25 +903,6 @@
   }
 
 
-  static long
-  ResourceForkSize(FSSpec*  spec)
-  {
-    long   len;
-    short  refNum;
-    OSErr  e;
-
-
-    e = FSpOpenRF( spec, fsRdPerm, &refNum ); /* I.M. Files 2-155 */
-    if ( e == noErr )
-    {
-      e = GetEOF( refNum, &len );
-      FSClose( refNum );
-    }
-
-    return ( e == noErr ) ? len : 0;
-  }
-
-
   /*************************************************************************/
   /*                                                                       */
   /* <Function>                                                            */
@@ -885,6 +923,8 @@
     FT_Open_Args  args;
     FSSpec        spec;
     OSType        file_type;
+    short         res_ref;
+    FT_Error      result;
 
 
     /* test for valid `library' and `aface' delayed to FT_Open_Face() */
@@ -894,26 +934,28 @@
     if ( file_spec_from_path( pathname, &spec ) )
       return FT_Err_Invalid_Argument;
 
-    /* Regardless of type, don't try to use the resource fork if it is */
-    /* empty.  Some TTF fonts have type `FFIL', for example, but they  */
-    /* only have data forks.                                           */
-
-    if ( ResourceForkSize( &spec ) != 0 )
+    if ( OpenFileAsResource( &spec, &res_ref ) == FT_Err_Ok )
     {
-      file_type = get_file_type( &spec );
-      if ( file_type == 'FFIL' || file_type == 'tfil' )
-        return FT_New_Face_From_Suitcase( library, &spec, face_index, aface );
+      /* LWFN is a (very) specific file format, check for it explicitly */
 
+      file_type = get_file_type( &spec );
       if ( file_type == 'LWFN' )
         return FT_New_Face_From_LWFN( library, &spec, face_index, aface );
-    }
 
-#ifdef TARGET_API_MAC_CARBON
+      /* Otherwise the file type doesn't matter (there are more than   */
+      /* `FFIL' and `tfil') -- just try opening it as a font suitcase; */
+      /* if it works, fine.                                            */
 
-    if ( is_dfont( &spec ) )
-      return FT_New_Face_From_dfont( library, &spec, face_index, aface );
+      result = FT_New_Face_From_Suitcase( library, res_ref,
+                                          face_index, aface );
+      if ( result == 0 )
+        return result;
 
-#endif
+      /* else forget about the resource fork and fall through to */
+      /* data fork formats                                       */
+
+      CloseResFile( res_ref );
+    }
 
     /* let it fall through to normal loader (.ttf, .otf, etc.) */
     args.flags    = FT_OPEN_PATHNAME;
@@ -922,4 +964,116 @@
   }
 
 
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    FT_New_Face_From_FSSpec                                            */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    FT_New_Face_From_FSSpec is identical to FT_New_Face except it      */
+  /*    accepts an FSSpec instead of a path.                               */
+  /*                                                                       */
+  FT_EXPORT_DEF( FT_Error )
+  FT_New_Face_From_FSSpec( FT_Library     library,
+                           const FSSpec  *spec,
+                           FT_Long        face_index,
+                           FT_Face       *aface )
+  {
+    FT_Open_Args  args;
+    OSType        file_type;
+    short         res_ref;
+    FT_Error      error;
+    FT_Stream     stream;
+    FILE*         file;
+    FT_Memory     memory;
+
+
+    /* test for valid `library' and `aface' delayed to FT_Open_Face() */
+    if ( !spec )
+      return FT_Err_Invalid_Argument;
+
+    if ( OpenFileAsResource( spec, &res_ref ) == FT_Err_Ok )
+    {
+      /* LWFN is a (very) specific file format, check for it explicitly */
+
+      file_type = get_file_type( spec );
+      if ( file_type == 'LWFN' )
+        return FT_New_Face_From_LWFN( library, spec, face_index, aface );
+    
+      /* Otherwise the file type doesn't matter (there are more than   */
+      /* `FFIL' and `tfil') -- just try opening it as a font suitcase; */
+      /* if it works, fine.                                            */
+
+      error = FT_New_Face_From_Suitcase( library, res_ref,
+                                         face_index, aface );
+      if ( error == 0 )
+        return error;
+
+      /* else forget about the resource fork and fall through to */
+      /* data fork formats                                       */
+
+      CloseResFile( res_ref );
+    }
+
+    /* let it fall through to normal loader (.ttf, .otf, etc.) */
+
+#if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
+
+    /* Codewarrior's C library can open a FILE from a FSSpec */
+#include <FSp_fopen.h>
+
+    memory = library->memory;
+
+    if ( FT_NEW( stream ) )
+      return error;
+    stream->memory = memory;
+
+    file = FSp_fopen( spec, "rb" );
+    if ( !file )
+      return FT_Err_Cannot_Open_Resource;
+
+    fseek( file, 0, SEEK_END );
+    stream->size = ftell( file );
+    fseek( file, 0, SEEK_SET );
+
+    stream->descriptor.pointer = file;
+    stream->pathname.pointer   = NULL;
+    stream->pos                = 0;
+
+    stream->read  = ft_FSp_stream_io;
+    stream->close = ft_FSp_stream_close;
+
+    args.flags    = FT_OPEN_STREAM;
+    args.stream   = stream;
+
+    error = FT_Open_Face( library, &args, face_index, aface );
+    if ( error == FT_Err_Ok )
+      (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
+
+#else  /* !(__MWERKS__ && !TARGET_RT_MAC_MACHO) */
+
+    {
+      FSRef  ref;
+      UInt8  path[256];
+      OSErr  err;
+
+
+      err = FSpMakeFSRef(spec, &ref);
+      if ( !err )
+      {
+        err = FSRefMakePath( &ref, path, sizeof ( path ) );
+        if ( !err )
+          error = FT_New_Face( library, (const char*)path,
+                               face_index, aface );
+      }
+      if ( err )
+        error = FT_Err_Cannot_Open_Resource;
+    }
+
+#endif  /* !(__MWERKS__ && !TARGET_RT_MAC_MACHO) */
+
+    return error;
+  }
+
+
 /* END */