tizen 2.3.1 release
[framework/graphics/freetype.git] / builds / mac / ftmac.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftmac.c                                                                */
4 /*                                                                         */
5 /*    Mac FOND support.  Written by just@letterror.com.                    */
6 /*  Heavily Fixed by mpsuzuki, George Williams and Sean McBride            */
7 /*                                                                         */
8 /*  Copyright 1996-2008, 2013, 2014 by                                     */
9 /*  Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg.     */
10 /*                                                                         */
11 /*  This file is part of the FreeType project, and may only be used,       */
12 /*  modified, and distributed under the terms of the FreeType project      */
13 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
14 /*  this file you indicate that you have read the license and              */
15 /*  understand and accept it fully.                                        */
16 /*                                                                         */
17 /***************************************************************************/
18
19
20   /*
21     Notes
22
23     Mac suitcase files can (and often do!) contain multiple fonts.  To
24     support this I use the face_index argument of FT_(Open|New)_Face()
25     functions, and pretend the suitcase file is a collection.
26
27     Warning: fbit and NFNT bitmap resources are not supported yet.  In old
28     sfnt fonts, bitmap glyph data for each size is stored in each `NFNT'
29     resources instead of the `bdat' table in the sfnt resource.  Therefore,
30     face->num_fixed_sizes is set to 0, because bitmap data in `NFNT'
31     resource is unavailable at present.
32
33     The Mac FOND support works roughly like this:
34
35     - Check whether the offered stream points to a Mac suitcase file.  This
36       is done by checking the file type: it has to be 'FFIL' or 'tfil'.  The
37       stream that gets passed to our init_face() routine is a stdio stream,
38       which isn't usable for us, since the FOND resources live in the
39       resource fork.  So we just grab the stream->pathname field.
40
41     - Read the FOND resource into memory, then check whether there is a
42       TrueType font and/or(!) a Type 1 font available.
43
44     - If there is a Type 1 font available (as a separate `LWFN' file), read
45       its data into memory, massage it slightly so it becomes PFB data, wrap
46       it into a memory stream, load the Type 1 driver and delegate the rest
47       of the work to it by calling FT_Open_Face().  (XXX TODO: after this
48       has been done, the kerning data from the FOND resource should be
49       appended to the face: On the Mac there are usually no AFM files
50       available.  However, this is tricky since we need to map Mac char
51       codes to ps glyph names to glyph ID's...)
52
53     - If there is a TrueType font (an `sfnt' resource), read it into memory,
54       wrap it into a memory stream, load the TrueType driver and delegate
55       the rest of the work to it, by calling FT_Open_Face().
56
57     - Some suitcase fonts (notably Onyx) might point the `LWFN' file to
58       itself, even though it doesn't contains `POST' resources.  To handle
59       this special case without opening the file an extra time, we just
60       ignore errors from the `LWFN' and fallback to the `sfnt' if both are
61       available.
62   */
63
64
65 #include <ft2build.h>
66 #include FT_FREETYPE_H
67 #include FT_TRUETYPE_TAGS_H
68 #include FT_INTERNAL_STREAM_H
69 #include "ftbase.h"
70
71 #if defined( __GNUC__ ) || defined( __IBMC__ )
72   /* This is for Mac OS X.  Without redefinition, OS_INLINE */
73   /* expands to `static inline' which doesn't survive the   */
74   /* -ansi compilation flag of GCC.                         */
75 #if !HAVE_ANSI_OS_INLINE
76 #undef  OS_INLINE
77 #define OS_INLINE   static __inline__
78 #endif
79 #include <CoreServices/CoreServices.h>
80 #include <ApplicationServices/ApplicationServices.h>
81 #include <sys/syslimits.h> /* PATH_MAX */
82 #else
83 #include <Resources.h>
84 #include <Fonts.h>
85 #include <Endian.h>
86 #include <Errors.h>
87 #include <Files.h>
88 #include <TextUtils.h>
89 #endif
90
91 #ifndef PATH_MAX
92 #define PATH_MAX 1024 /* same with Mac OS X's syslimits.h */
93 #endif
94
95 #if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
96 #include <FSp_fopen.h>
97 #endif
98
99 #define FT_DEPRECATED_ATTRIBUTE
100
101 #include FT_MAC_H
102
103   /* undefine blocking-macros in ftmac.h */
104 #undef FT_GetFile_From_Mac_Name
105 #undef FT_GetFile_From_Mac_ATS_Name
106 #undef FT_New_Face_From_FOND
107 #undef FT_New_Face_From_FSSpec
108 #undef FT_New_Face_From_FSRef
109
110
111   /* FSSpec functions are deprecated since Mac OS X 10.4 */
112 #ifndef HAVE_FSSPEC
113 #if TARGET_API_MAC_OS8 || TARGET_API_MAC_CARBON
114 #define HAVE_FSSPEC  1
115 #else
116 #define HAVE_FSSPEC  0
117 #endif
118 #endif
119
120   /* most FSRef functions were introduced since Mac OS 9 */
121 #ifndef HAVE_FSREF
122 #if TARGET_API_MAC_OSX
123 #define HAVE_FSREF  1
124 #else
125 #define HAVE_FSREF  0
126 #endif
127 #endif
128
129   /* QuickDraw is deprecated since Mac OS X 10.4 */
130 #ifndef HAVE_QUICKDRAW_CARBON
131 #if TARGET_API_MAC_OS8 || TARGET_API_MAC_CARBON
132 #define HAVE_QUICKDRAW_CARBON  1
133 #else
134 #define HAVE_QUICKDRAW_CARBON  0
135 #endif
136 #endif
137
138   /* AppleTypeService is available since Mac OS X */
139 #ifndef HAVE_ATS
140 #if TARGET_API_MAC_OSX
141 #define HAVE_ATS  1
142 #ifndef kATSOptionFlagsUnRestrictedScope /* since Mac OS X 10.1 */
143 #define kATSOptionFlagsUnRestrictedScope kATSOptionFlagsDefault
144 #endif
145 #else
146 #define HAVE_ATS  0
147 #endif
148 #endif
149
150   /* `configure' checks the availability of `ResourceIndex' strictly */
151   /* and sets HAVE_TYPE_RESOURCE_INDEX to 1 or 0 always.  If it is   */
152   /* not set (e.g., a build without `configure'), the availability   */
153   /* is guessed from the SDK version.                                */
154 #ifndef HAVE_TYPE_RESOURCE_INDEX
155 #if !defined( MAC_OS_X_VERSION_10_5 ) || \
156     ( MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 )
157 #define HAVE_TYPE_RESOURCE_INDEX 0
158 #else
159 #define HAVE_TYPE_RESOURCE_INDEX 1
160 #endif
161 #endif /* !HAVE_TYPE_RESOURCE_INDEX */
162
163 #if ( HAVE_TYPE_RESOURCE_INDEX == 0 )
164 typedef short ResourceIndex;
165 #endif
166
167   /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over
168      TrueType in case *both* are available (this is not common,
169      but it *is* possible). */
170 #ifndef PREFER_LWFN
171 #define PREFER_LWFN  1
172 #endif
173
174 #ifdef FT_MACINTOSH
175
176 #if !HAVE_QUICKDRAW_CARBON  /* QuickDraw is deprecated since Mac OS X 10.4 */
177
178   FT_EXPORT_DEF( FT_Error )
179   FT_GetFile_From_Mac_Name( const char*  fontName,
180                             FSSpec*      pathSpec,
181                             FT_Long*     face_index )
182   {
183     FT_UNUSED( fontName );
184     FT_UNUSED( pathSpec );
185     FT_UNUSED( face_index );
186
187     return FT_THROW( Unimplemented_Feature );
188   }
189
190 #else
191
192   FT_EXPORT_DEF( FT_Error )
193   FT_GetFile_From_Mac_Name( const char*  fontName,
194                             FSSpec*      pathSpec,
195                             FT_Long*     face_index )
196   {
197     OptionBits            options = kFMUseGlobalScopeOption;
198
199     FMFontFamilyIterator  famIter;
200     OSStatus              status = FMCreateFontFamilyIterator( NULL, NULL,
201                                                                options,
202                                                                &famIter );
203     FMFont                the_font = 0;
204     FMFontFamily          family   = 0;
205
206
207     if ( !fontName || !face_index )
208       return FT_THROW( Invalid_Argument );
209
210     *face_index = 0;
211     while ( status == 0 && !the_font )
212     {
213       status = FMGetNextFontFamily( &famIter, &family );
214       if ( status == 0 )
215       {
216         int                           stat2;
217         FMFontFamilyInstanceIterator  instIter;
218         Str255                        famNameStr;
219         char                          famName[256];
220
221
222         /* get the family name */
223         FMGetFontFamilyName( family, famNameStr );
224         CopyPascalStringToC( famNameStr, famName );
225
226         /* iterate through the styles */
227         FMCreateFontFamilyInstanceIterator( family, &instIter );
228
229         *face_index = 0;
230         stat2       = 0;
231
232         while ( stat2 == 0 && !the_font )
233         {
234           FMFontStyle  style;
235           FMFontSize   size;
236           FMFont       font;
237
238
239           stat2 = FMGetNextFontFamilyInstance( &instIter, &font,
240                                                &style, &size );
241           if ( stat2 == 0 && size == 0 )
242           {
243             char  fullName[256];
244
245
246             /* build up a complete face name */
247             ft_strcpy( fullName, famName );
248             if ( style & bold )
249               ft_strcat( fullName, " Bold" );
250             if ( style & italic )
251               ft_strcat( fullName, " Italic" );
252
253             /* compare with the name we are looking for */
254             if ( ft_strcmp( fullName, fontName ) == 0 )
255             {
256               /* found it! */
257               the_font = font;
258             }
259             else
260               ++(*face_index);
261           }
262         }
263
264         FMDisposeFontFamilyInstanceIterator( &instIter );
265       }
266     }
267
268     FMDisposeFontFamilyIterator( &famIter );
269
270     if ( the_font )
271     {
272       FMGetFontContainer( the_font, pathSpec );
273       return FT_Err_Ok;
274     }
275     else
276       return FT_THROW( Unknown_File_Format );
277   }
278
279 #endif /* HAVE_QUICKDRAW_CARBON */
280
281
282 #if HAVE_ATS
283
284   /* Private function.                                         */
285   /* The FSSpec type has been discouraged for a long time,     */
286   /* unfortunately an FSRef replacement API for                */
287   /* ATSFontGetFileSpecification() is only available in        */
288   /* Mac OS X 10.5 and later.                                  */
289   static OSStatus
290   FT_ATSFontGetFileReference( ATSFontRef  ats_font_id,
291                               FSRef*      ats_font_ref )
292   {
293     OSStatus  err;
294
295 #if !defined( MAC_OS_X_VERSION_10_5 ) || \
296     MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
297     FSSpec    spec;
298
299
300     err = ATSFontGetFileSpecification( ats_font_id, &spec );
301     if ( noErr == err )
302       err = FSpMakeFSRef( &spec, ats_font_ref );
303 #else
304     err = ATSFontGetFileReference( ats_font_id, ats_font_ref );
305 #endif
306
307     return err;
308   }
309
310
311   static FT_Error
312   FT_GetFileRef_From_Mac_ATS_Name( const char*  fontName,
313                                    FSRef*       ats_font_ref,
314                                    FT_Long*     face_index )
315   {
316     CFStringRef  cf_fontName;
317     ATSFontRef   ats_font_id;
318
319
320     *face_index = 0;
321
322     cf_fontName = CFStringCreateWithCString( NULL, fontName,
323                                              kCFStringEncodingMacRoman );
324     ats_font_id = ATSFontFindFromName( cf_fontName,
325                                        kATSOptionFlagsUnRestrictedScope );
326     CFRelease( cf_fontName );
327
328     if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL )
329       return FT_THROW( Unknown_File_Format );
330
331     if ( noErr != FT_ATSFontGetFileReference( ats_font_id, ats_font_ref ) )
332       return FT_THROW( Unknown_File_Format );
333
334     /* face_index calculation by searching preceding fontIDs */
335     /* with same FSRef                                       */
336     {
337       ATSFontRef  id2 = ats_font_id - 1;
338       FSRef       ref2;
339
340
341       while ( id2 > 0 )
342       {
343         if ( noErr != FT_ATSFontGetFileReference( id2, &ref2 ) )
344           break;
345         if ( noErr != FSCompareFSRefs( ats_font_ref, &ref2 ) )
346           break;
347
348         id2--;
349       }
350       *face_index = ats_font_id - ( id2 + 1 );
351     }
352
353     return FT_Err_Ok;
354   }
355
356 #endif
357
358 #if !HAVE_ATS
359
360   FT_EXPORT_DEF( FT_Error )
361   FT_GetFilePath_From_Mac_ATS_Name( const char*  fontName,
362                                     UInt8*       path,
363                                     UInt32       maxPathSize,
364                                     FT_Long*     face_index )
365   {
366     FT_UNUSED( fontName );
367     FT_UNUSED( path );
368     FT_UNUSED( maxPathSize );
369     FT_UNUSED( face_index );
370
371     return FT_THROW( Unimplemented_Feature );
372   }
373
374 #else
375
376   FT_EXPORT_DEF( FT_Error )
377   FT_GetFilePath_From_Mac_ATS_Name( const char*  fontName,
378                                     UInt8*       path,
379                                     UInt32       maxPathSize,
380                                     FT_Long*     face_index )
381   {
382     FSRef     ref;
383     FT_Error  err;
384
385
386     err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index );
387     if ( err )
388       return err;
389
390     if ( noErr != FSRefMakePath( &ref, path, maxPathSize ) )
391       return FT_THROW( Unknown_File_Format );
392
393     return FT_Err_Ok;
394   }
395
396 #endif /* HAVE_ATS */
397
398
399 #if !HAVE_FSSPEC || !HAVE_ATS
400
401   FT_EXPORT_DEF( FT_Error )
402   FT_GetFile_From_Mac_ATS_Name( const char*  fontName,
403                                 FSSpec*      pathSpec,
404                                 FT_Long*     face_index )
405   {
406     FT_UNUSED( fontName );
407     FT_UNUSED( pathSpec );
408     FT_UNUSED( face_index );
409
410     return FT_THROW( Unimplemented_Feature );
411   }
412
413 #else
414
415   /* This function is deprecated because FSSpec is deprecated in Mac OS X. */
416   FT_EXPORT_DEF( FT_Error )
417   FT_GetFile_From_Mac_ATS_Name( const char*  fontName,
418                                 FSSpec*      pathSpec,
419                                 FT_Long*     face_index )
420   {
421     FSRef     ref;
422     FT_Error  err;
423
424
425     err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index );
426     if ( err )
427       return err;
428
429     if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL,
430                                     pathSpec, NULL ) )
431       return FT_THROW( Unknown_File_Format );
432
433     return FT_Err_Ok;
434   }
435
436 #endif
437
438
439 #if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
440
441 #define STREAM_FILE( stream )  ( (FT_FILE*)stream->descriptor.pointer )
442
443
444   FT_CALLBACK_DEF( void )
445   ft_FSp_stream_close( FT_Stream  stream )
446   {
447     ft_fclose( STREAM_FILE( stream ) );
448
449     stream->descriptor.pointer = NULL;
450     stream->size               = 0;
451     stream->base               = 0;
452   }
453
454
455   FT_CALLBACK_DEF( unsigned long )
456   ft_FSp_stream_io( FT_Stream       stream,
457                     unsigned long   offset,
458                     unsigned char*  buffer,
459                     unsigned long   count )
460   {
461     FT_FILE*  file;
462
463
464     file = STREAM_FILE( stream );
465
466     ft_fseek( file, offset, SEEK_SET );
467
468     return (unsigned long)ft_fread( buffer, 1, count, file );
469   }
470
471 #endif  /* __MWERKS__ && !TARGET_RT_MAC_MACHO */
472
473
474 #if HAVE_FSSPEC && !HAVE_FSREF
475
476   /* isDirectory is a dummy to synchronize API with FSPathMakeRef() */
477   static OSErr
478   FT_FSPathMakeSpec( const UInt8*  pathname,
479                      FSSpec*       spec_p,
480                      Boolean       isDirectory )
481   {
482     const char  *p, *q;
483     short       vRefNum;
484     long        dirID;
485     Str255      nodeName;
486     OSErr       err;
487     FT_UNUSED( isDirectory );
488
489
490     p = q = (const char *)pathname;
491     dirID   = 0;
492     vRefNum = 0;
493
494     while ( 1 )
495     {
496       int  len = ft_strlen( p );
497
498
499       if ( len > 255 )
500         len = 255;
501
502       q = p + len;
503
504       if ( q == p )
505         return 0;
506
507       if ( 255 < ft_strlen( (char *)pathname ) )
508       {
509         while ( p < q && *q != ':' )
510           q--;
511       }
512
513       if ( p < q )
514         *(char *)nodeName = q - p;
515       else if ( ft_strlen( p ) < 256 )
516         *(char *)nodeName = ft_strlen( p );
517       else
518         return errFSNameTooLong;
519
520       ft_strncpy( (char *)nodeName + 1, (char *)p, *(char *)nodeName );
521       err = FSMakeFSSpec( vRefNum, dirID, nodeName, spec_p );
522       if ( err || '\0' == *q )
523         return err;
524
525       vRefNum = spec_p->vRefNum;
526       dirID   = spec_p->parID;
527
528       p = q;
529     }
530   }
531
532
533   static OSErr
534   FT_FSpMakePath( const FSSpec*  spec_p,
535                   UInt8*         path,
536                   UInt32         maxPathSize )
537   {
538     OSErr   err;
539     FSSpec  spec = *spec_p;
540     short   vRefNum;
541     long    dirID;
542     Str255  parDir_name;
543
544
545     FT_MEM_SET( path, 0, maxPathSize );
546     while ( 1 )
547     {
548       int             child_namelen = ft_strlen( (char *)path );
549       unsigned char   node_namelen  = spec.name[0];
550       unsigned char*  node_name     = spec.name + 1;
551
552
553       if ( node_namelen + child_namelen > maxPathSize )
554         return errFSNameTooLong;
555
556       FT_MEM_MOVE( path + node_namelen + 1, path, child_namelen );
557       FT_MEM_COPY( path, node_name, node_namelen );
558       if ( child_namelen > 0 )
559         path[node_namelen] = ':';
560
561       vRefNum        = spec.vRefNum;
562       dirID          = spec.parID;
563       parDir_name[0] = '\0';
564       err = FSMakeFSSpec( vRefNum, dirID, parDir_name, &spec );
565       if ( noErr != err || dirID == spec.parID )
566         break;
567     }
568     return noErr;
569   }
570
571 #endif /* HAVE_FSSPEC && !HAVE_FSREF */
572
573
574   static OSErr
575   FT_FSPathMakeRes( const UInt8*    pathname,
576                     ResFileRefNum*  res )
577   {
578
579 #if HAVE_FSREF
580
581     OSErr  err;
582     FSRef  ref;
583
584
585     if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) )
586       return FT_THROW( Cannot_Open_Resource );
587
588     /* at present, no support for dfont format */
589     err = FSOpenResourceFile( &ref, 0, NULL, fsRdPerm, res );
590     if ( noErr == err )
591       return err;
592
593     /* fallback to original resource-fork font */
594     *res = FSOpenResFile( &ref, fsRdPerm );
595     err  = ResError();
596
597 #else
598
599     OSErr   err;
600     FSSpec  spec;
601
602
603     if ( noErr != FT_FSPathMakeSpec( pathname, &spec, FALSE ) )
604       return FT_THROW( Cannot_Open_Resource );
605
606     /* at present, no support for dfont format without FSRef */
607     /* (see above), try original resource-fork font          */
608     *res = FSpOpenResFile( &spec, fsRdPerm );
609     err  = ResError();
610
611 #endif /* HAVE_FSREF */
612
613     return err;
614   }
615
616
617   /* Return the file type for given pathname */
618   static OSType
619   get_file_type_from_path( const UInt8*  pathname )
620   {
621
622 #if HAVE_FSREF
623
624     FSRef          ref;
625     FSCatalogInfo  info;
626
627
628     if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) )
629       return ( OSType ) 0;
630
631     if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoFinderInfo, &info,
632                                     NULL, NULL, NULL ) )
633       return ( OSType ) 0;
634
635     return ((FInfo *)(info.finderInfo))->fdType;
636
637 #else
638
639     FSSpec  spec;
640     FInfo   finfo;
641
642
643     if ( noErr != FT_FSPathMakeSpec( pathname, &spec, FALSE ) )
644       return ( OSType ) 0;
645
646     if ( noErr != FSpGetFInfo( &spec, &finfo ) )
647       return ( OSType ) 0;
648
649     return finfo.fdType;
650
651 #endif /* HAVE_FSREF */
652
653   }
654
655
656   /* Given a PostScript font name, create the Macintosh LWFN file name. */
657   static void
658   create_lwfn_name( char*   ps_name,
659                     Str255  lwfn_file_name )
660   {
661     int       max = 5, count = 0;
662     FT_Byte*  p = lwfn_file_name;
663     FT_Byte*  q = (FT_Byte*)ps_name;
664
665
666     lwfn_file_name[0] = 0;
667
668     while ( *q )
669     {
670       if ( ft_isupper( *q ) )
671       {
672         if ( count )
673           max = 3;
674         count = 0;
675       }
676       if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) )
677       {
678         *++p = *q;
679         lwfn_file_name[0]++;
680         count++;
681       }
682       q++;
683     }
684   }
685
686
687   static short
688   count_faces_sfnt( char*  fond_data )
689   {
690     /* The count is 1 greater than the value in the FOND.  */
691     /* Isn't that cute? :-)                                */
692
693     return EndianS16_BtoN( *( (short*)( fond_data +
694                                         sizeof ( FamRec ) ) ) ) + 1;
695   }
696
697
698   static short
699   count_faces_scalable( char*  fond_data )
700   {
701     AsscEntry*  assoc;
702     short       i, face, face_all;
703
704
705     face_all = EndianS16_BtoN( *( (short *)( fond_data +
706                                              sizeof ( FamRec ) ) ) ) + 1;
707     assoc    = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
708     face     = 0;
709
710     for ( i = 0; i < face_all; i++ )
711     {
712       if ( 0 == EndianS16_BtoN( assoc[i].fontSize ) )
713         face++;
714     }
715     return face;
716   }
717
718
719   /* Look inside the FOND data, answer whether there should be an SFNT
720      resource, and answer the name of a possible LWFN Type 1 file.
721
722      Thanks to Paul Miller (paulm@profoundeffects.com) for the fix
723      to load a face OTHER than the first one in the FOND!
724   */
725
726   static void
727   parse_fond( char*   fond_data,
728               short*  have_sfnt,
729               ResID*  sfnt_id,
730               Str255  lwfn_file_name,
731               short   face_index )
732   {
733     AsscEntry*  assoc;
734     AsscEntry*  base_assoc;
735     FamRec*     fond;
736
737
738     *sfnt_id          = 0;
739     *have_sfnt        = 0;
740     lwfn_file_name[0] = 0;
741
742     fond       = (FamRec*)fond_data;
743     assoc      = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
744     base_assoc = assoc;
745
746     /* the maximum faces in a FOND is 48, size of StyleTable.indexes[] */
747     if ( 47 < face_index )
748       return;
749
750     /* Let's do a little range checking before we get too excited here */
751     if ( face_index < count_faces_sfnt( fond_data ) )
752     {
753       assoc += face_index;        /* add on the face_index! */
754
755       /* if the face at this index is not scalable,
756          fall back to the first one (old behavior) */
757       if ( EndianS16_BtoN( assoc->fontSize ) == 0 )
758       {
759         *have_sfnt = 1;
760         *sfnt_id   = EndianS16_BtoN( assoc->fontID );
761       }
762       else if ( base_assoc->fontSize == 0 )
763       {
764         *have_sfnt = 1;
765         *sfnt_id   = EndianS16_BtoN( base_assoc->fontID );
766       }
767     }
768
769     if ( EndianS32_BtoN( fond->ffStylOff ) )
770     {
771       unsigned char*  p = (unsigned char*)fond_data;
772       StyleTable*     style;
773       unsigned short  string_count;
774       char            ps_name[256];
775       unsigned char*  names[64];
776       int             i;
777
778
779       p += EndianS32_BtoN( fond->ffStylOff );
780       style = (StyleTable*)p;
781       p += sizeof ( StyleTable );
782       string_count = EndianS16_BtoN( *(short*)(p) );
783       p += sizeof ( short );
784
785       for ( i = 0; i < string_count && i < 64; i++ )
786       {
787         names[i] = p;
788         p       += names[i][0];
789         p++;
790       }
791
792       {
793         size_t  ps_name_len = (size_t)names[0][0];
794
795
796         if ( ps_name_len != 0 )
797         {
798           ft_memcpy(ps_name, names[0] + 1, ps_name_len);
799           ps_name[ps_name_len] = 0;
800         }
801         if ( style->indexes[face_index] > 1 &&
802              style->indexes[face_index] <= FT_MIN( string_count, 64 ) )
803         {
804           unsigned char*  suffixes = names[style->indexes[face_index] - 1];
805
806
807           for ( i = 1; i <= suffixes[0]; i++ )
808           {
809             unsigned char*  s;
810             size_t          j = suffixes[i] - 1;
811
812
813             if ( j < string_count && ( s = names[j] ) != NULL )
814             {
815               size_t  s_len = (size_t)s[0];
816
817
818               if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) )
819               {
820                 ft_memcpy( ps_name + ps_name_len, s + 1, s_len );
821                 ps_name_len += s_len;
822                 ps_name[ps_name_len] = 0;
823               }
824             }
825           }
826         }
827       }
828
829       create_lwfn_name( ps_name, lwfn_file_name );
830     }
831   }
832
833
834   static  FT_Error
835   lookup_lwfn_by_fond( const UInt8*      path_fond,
836                        ConstStr255Param  base_lwfn,
837                        UInt8*            path_lwfn,
838                        int               path_size )
839   {
840
841 #if HAVE_FSREF
842
843     FSRef  ref, par_ref;
844     int    dirname_len;
845
846
847     /* Pathname for FSRef can be in various formats: HFS, HFS+, and POSIX. */
848     /* We should not extract parent directory by string manipulation.      */
849
850     if ( noErr != FSPathMakeRef( path_fond, &ref, FALSE ) )
851       return FT_THROW( Invalid_Argument );
852
853     if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone,
854                                     NULL, NULL, NULL, &par_ref ) )
855       return FT_THROW( Invalid_Argument );
856
857     if ( noErr != FSRefMakePath( &par_ref, path_lwfn, path_size ) )
858       return FT_THROW( Invalid_Argument );
859
860     if ( ft_strlen( (char *)path_lwfn ) + 1 + base_lwfn[0] > path_size )
861       return FT_THROW( Invalid_Argument );
862
863     /* now we have absolute dirname in path_lwfn */
864     if ( path_lwfn[0] == '/' )
865       ft_strcat( (char *)path_lwfn, "/" );
866     else
867       ft_strcat( (char *)path_lwfn, ":" );
868
869     dirname_len = ft_strlen( (char *)path_lwfn );
870     ft_strcat( (char *)path_lwfn, (char *)base_lwfn + 1 );
871     path_lwfn[dirname_len + base_lwfn[0]] = '\0';
872
873     if ( noErr != FSPathMakeRef( path_lwfn, &ref, FALSE ) )
874       return FT_THROW( Cannot_Open_Resource );
875
876     if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone,
877                                     NULL, NULL, NULL, NULL ) )
878       return FT_THROW( Cannot_Open_Resource );
879
880     return FT_Err_Ok;
881
882 #else
883
884     int     i;
885     FSSpec  spec;
886
887
888     /* pathname for FSSpec is always HFS format */
889     if ( ft_strlen( (char *)path_fond ) > path_size )
890       return FT_THROW( Invalid_Argument );
891
892     ft_strcpy( (char *)path_lwfn, (char *)path_fond );
893
894     i = ft_strlen( (char *)path_lwfn ) - 1;
895     while ( i > 0 && ':' != path_lwfn[i] )
896       i--;
897
898     if ( i + 1 + base_lwfn[0] > path_size )
899       return FT_THROW( Invalid_Argument );
900
901     if ( ':' == path_lwfn[i] )
902     {
903       ft_strcpy( (char *)path_lwfn + i + 1, (char *)base_lwfn + 1 );
904       path_lwfn[i + 1 + base_lwfn[0]] = '\0';
905     }
906     else
907     {
908       ft_strcpy( (char *)path_lwfn, (char *)base_lwfn + 1 );
909       path_lwfn[base_lwfn[0]] = '\0';
910     }
911
912     if ( noErr != FT_FSPathMakeSpec( path_lwfn, &spec, FALSE ) )
913       return FT_THROW( Cannot_Open_Resource );
914
915     return FT_Err_Ok;
916
917 #endif /* HAVE_FSREF */
918
919   }
920
921
922   static short
923   count_faces( Handle        fond,
924                const UInt8*  pathname )
925   {
926     ResID     sfnt_id;
927     short     have_sfnt, have_lwfn;
928     Str255    lwfn_file_name;
929     UInt8     buff[PATH_MAX];
930     FT_Error  err;
931     short     num_faces;
932
933
934     have_sfnt = have_lwfn = 0;
935
936     HLock( fond );
937     parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, 0 );
938
939     if ( lwfn_file_name[0] )
940     {
941       err = lookup_lwfn_by_fond( pathname, lwfn_file_name,
942                                  buff, sizeof ( buff )  );
943       if ( FT_Err_Ok == err )
944         have_lwfn = 1;
945     }
946
947     if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
948       num_faces = 1;
949     else
950       num_faces = count_faces_scalable( *fond );
951
952     HUnlock( fond );
953     return num_faces;
954   }
955
956
957   /* Read Type 1 data from the POST resources inside the LWFN file,
958      return a PFB buffer.  This is somewhat convoluted because the FT2
959      PFB parser wants the ASCII header as one chunk, and the LWFN
960      chunks are often not organized that way, so we glue chunks
961      of the same type together. */
962   static FT_Error
963   read_lwfn( FT_Memory      memory,
964              ResFileRefNum  res,
965              FT_Byte**      pfb_data,
966              FT_ULong*      size )
967   {
968     FT_Error       error = FT_Err_Ok;
969     ResID          res_id;
970     unsigned char  *buffer, *p, *size_p = NULL;
971     FT_ULong       total_size = 0;
972     FT_ULong       old_total_size = 0;
973     FT_ULong       post_size, pfb_chunk_size;
974     Handle         post_data;
975     char           code, last_code;
976
977
978     UseResFile( res );
979
980     /* First pass: load all POST resources, and determine the size of */
981     /* the output buffer.                                             */
982     res_id    = 501;
983     last_code = -1;
984
985     for (;;)
986     {
987       post_data = Get1Resource( TTAG_POST, res_id++ );
988       if ( post_data == NULL )
989         break;  /* we are done */
990
991       code = (*post_data)[0];
992
993       if ( code != last_code )
994       {
995         if ( code == 5 )
996           total_size += 2; /* just the end code */
997         else
998           total_size += 6; /* code + 4 bytes chunk length */
999       }
1000
1001       total_size += GetHandleSize( post_data ) - 2;
1002       last_code = code;
1003
1004       /* detect integer overflows */
1005       if ( total_size < old_total_size )
1006       {
1007         error = FT_ERR( Array_Too_Large );
1008         goto Error;
1009       }
1010
1011       old_total_size = total_size;
1012     }
1013
1014     if ( FT_ALLOC( buffer, (FT_Long)total_size ) )
1015       goto Error;
1016
1017     /* Second pass: append all POST data to the buffer, add PFB fields. */
1018     /* Glue all consecutive chunks of the same type together.           */
1019     p              = buffer;
1020     res_id         = 501;
1021     last_code      = -1;
1022     pfb_chunk_size = 0;
1023
1024     for (;;)
1025     {
1026       post_data = Get1Resource( TTAG_POST, res_id++ );
1027       if ( post_data == NULL )
1028         break;  /* we are done */
1029
1030       post_size = (FT_ULong)GetHandleSize( post_data ) - 2;
1031       code = (*post_data)[0];
1032
1033       if ( code != last_code )
1034       {
1035         if ( last_code != -1 )
1036         {
1037           /* we are done adding a chunk, fill in the size field */
1038           if ( size_p != NULL )
1039           {
1040             *size_p++ = (FT_Byte)(   pfb_chunk_size         & 0xFF );
1041             *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8  ) & 0xFF );
1042             *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF );
1043             *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF );
1044           }
1045           pfb_chunk_size = 0;
1046         }
1047
1048         *p++ = 0x80;
1049         if ( code == 5 )
1050           *p++ = 0x03;  /* the end */
1051         else if ( code == 2 )
1052           *p++ = 0x02;  /* binary segment */
1053         else
1054           *p++ = 0x01;  /* ASCII segment */
1055
1056         if ( code != 5 )
1057         {
1058           size_p = p;   /* save for later */
1059           p += 4;       /* make space for size field */
1060         }
1061       }
1062
1063       ft_memcpy( p, *post_data + 2, post_size );
1064       pfb_chunk_size += post_size;
1065       p += post_size;
1066       last_code = code;
1067     }
1068
1069     *pfb_data = buffer;
1070     *size = total_size;
1071
1072   Error:
1073     CloseResFile( res );
1074     return error;
1075   }
1076
1077
1078   /* Create a new FT_Face from a file spec to an LWFN file. */
1079   static FT_Error
1080   FT_New_Face_From_LWFN( FT_Library    library,
1081                          const UInt8*  pathname,
1082                          FT_Long       face_index,
1083                          FT_Face*      aface )
1084   {
1085     FT_Byte*       pfb_data;
1086     FT_ULong       pfb_size;
1087     FT_Error       error;
1088     ResFileRefNum  res;
1089
1090
1091     if ( noErr != FT_FSPathMakeRes( pathname, &res ) )
1092       return FT_THROW( Cannot_Open_Resource );
1093
1094     pfb_data = NULL;
1095     pfb_size = 0;
1096     error = read_lwfn( library->memory, res, &pfb_data, &pfb_size );
1097     CloseResFile( res ); /* PFB is already loaded, useless anymore */
1098     if ( error )
1099       return error;
1100
1101     return open_face_from_buffer( library,
1102                                   pfb_data,
1103                                   pfb_size,
1104                                   face_index,
1105                                   "type1",
1106                                   aface );
1107   }
1108
1109
1110   /* Create a new FT_Face from an SFNT resource, specified by res ID. */
1111   static FT_Error
1112   FT_New_Face_From_SFNT( FT_Library  library,
1113                          ResID       sfnt_id,
1114                          FT_Long     face_index,
1115                          FT_Face*    aface )
1116   {
1117     Handle     sfnt = NULL;
1118     FT_Byte*   sfnt_data;
1119     size_t     sfnt_size;
1120     FT_Error   error  = FT_Err_Ok;
1121     FT_Memory  memory = library->memory;
1122     int        is_cff, is_sfnt_ps;
1123
1124
1125     sfnt = GetResource( TTAG_sfnt, sfnt_id );
1126     if ( sfnt == NULL )
1127       return FT_THROW( Invalid_Handle );
1128
1129     sfnt_size = (FT_ULong)GetHandleSize( sfnt );
1130     if ( FT_ALLOC( sfnt_data, (FT_Long)sfnt_size ) )
1131     {
1132       ReleaseResource( sfnt );
1133       return error;
1134     }
1135
1136     HLock( sfnt );
1137     ft_memcpy( sfnt_data, *sfnt, sfnt_size );
1138     HUnlock( sfnt );
1139     ReleaseResource( sfnt );
1140
1141     is_cff     = sfnt_size > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 );
1142     is_sfnt_ps = sfnt_size > 4 && !ft_memcmp( sfnt_data, "typ1", 4 );
1143
1144     if ( is_sfnt_ps )
1145     {
1146       FT_Stream  stream;
1147
1148
1149       if ( FT_NEW( stream ) )
1150         goto Try_OpenType;
1151
1152       FT_Stream_OpenMemory( stream, sfnt_data, sfnt_size );
1153       if ( !open_face_PS_from_sfnt_stream( library,
1154                                            stream,
1155                                            face_index,
1156                                            0, NULL,
1157                                            aface ) )
1158       {
1159         FT_Stream_Close( stream );
1160         FT_FREE( stream );
1161         FT_FREE( sfnt_data );
1162         goto Exit;
1163       }
1164
1165       FT_FREE( stream );
1166     }
1167   Try_OpenType:
1168     error = open_face_from_buffer( library,
1169                                    sfnt_data,
1170                                    sfnt_size,
1171                                    face_index,
1172                                    is_cff ? "cff" : "truetype",
1173                                    aface );
1174   Exit:
1175     return error;
1176   }
1177
1178
1179   /* Create a new FT_Face from a file spec to a suitcase file. */
1180   static FT_Error
1181   FT_New_Face_From_Suitcase( FT_Library    library,
1182                              const UInt8*  pathname,
1183                              FT_Long       face_index,
1184                              FT_Face*      aface )
1185   {
1186     FT_Error       error = FT_ERR( Cannot_Open_Resource );
1187     ResFileRefNum  res_ref;
1188     ResourceIndex  res_index;
1189     Handle         fond;
1190     short          num_faces_in_res;
1191
1192
1193     if ( noErr != FT_FSPathMakeRes( pathname, &res_ref ) )
1194       return FT_THROW( Cannot_Open_Resource );
1195
1196     UseResFile( res_ref );
1197     if ( ResError() )
1198       return FT_THROW( Cannot_Open_Resource );
1199
1200     num_faces_in_res = 0;
1201     for ( res_index = 1; ; ++res_index )
1202     {
1203       short  num_faces_in_fond;
1204
1205
1206       fond = Get1IndResource( TTAG_FOND, res_index );
1207       if ( ResError() )
1208         break;
1209
1210       num_faces_in_fond  = count_faces( fond, pathname );
1211       num_faces_in_res  += num_faces_in_fond;
1212
1213       if ( 0 <= face_index && face_index < num_faces_in_fond && error )
1214         error = FT_New_Face_From_FOND( library, fond, face_index, aface );
1215
1216       face_index -= num_faces_in_fond;
1217     }
1218
1219     CloseResFile( res_ref );
1220     if ( FT_Err_Ok == error && NULL != aface )
1221       (*aface)->num_faces = num_faces_in_res;
1222     return error;
1223   }
1224
1225
1226   /* documentation is in ftmac.h */
1227
1228   FT_EXPORT_DEF( FT_Error )
1229   FT_New_Face_From_FOND( FT_Library  library,
1230                          Handle      fond,
1231                          FT_Long     face_index,
1232                          FT_Face*    aface )
1233   {
1234     short     have_sfnt, have_lwfn = 0;
1235     ResID     sfnt_id, fond_id;
1236     OSType    fond_type;
1237     Str255    fond_name;
1238     Str255    lwfn_file_name;
1239     UInt8     path_lwfn[PATH_MAX];
1240     OSErr     err;
1241     FT_Error  error = FT_Err_Ok;
1242
1243
1244     /* test for valid `aface' and `library' delayed to */
1245     /* `FT_New_Face_From_XXX'                          */
1246
1247     GetResInfo( fond, &fond_id, &fond_type, fond_name );
1248     if ( ResError() != noErr || fond_type != TTAG_FOND )
1249       return FT_THROW( Invalid_File_Format );
1250
1251     HLock( fond );
1252     parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index );
1253     HUnlock( fond );
1254
1255     if ( lwfn_file_name[0] )
1256     {
1257       ResFileRefNum  res;
1258
1259
1260       res = HomeResFile( fond );
1261       if ( noErr != ResError() )
1262         goto found_no_lwfn_file;
1263
1264 #if HAVE_FSREF
1265
1266       {
1267         UInt8  path_fond[PATH_MAX];
1268         FSRef  ref;
1269
1270
1271         err = FSGetForkCBInfo( res, kFSInvalidVolumeRefNum,
1272                                NULL, NULL, NULL, &ref, NULL );
1273         if ( noErr != err )
1274           goto found_no_lwfn_file;
1275
1276         err = FSRefMakePath( &ref, path_fond, sizeof ( path_fond ) );
1277         if ( noErr != err )
1278           goto found_no_lwfn_file;
1279
1280         error = lookup_lwfn_by_fond( path_fond, lwfn_file_name,
1281                                      path_lwfn, sizeof ( path_lwfn ) );
1282         if ( FT_Err_Ok == error )
1283           have_lwfn = 1;
1284       }
1285
1286 #elif HAVE_FSSPEC
1287
1288       {
1289         UInt8     path_fond[PATH_MAX];
1290         FCBPBRec  pb;
1291         Str255    fond_file_name;
1292         FSSpec    spec;
1293
1294
1295         FT_MEM_SET( &spec, 0, sizeof ( FSSpec ) );
1296         FT_MEM_SET( &pb,   0, sizeof ( FCBPBRec ) );
1297
1298         pb.ioNamePtr = fond_file_name;
1299         pb.ioVRefNum = 0;
1300         pb.ioRefNum  = res;
1301         pb.ioFCBIndx = 0;
1302
1303         err = PBGetFCBInfoSync( &pb );
1304         if ( noErr != err )
1305           goto found_no_lwfn_file;
1306
1307         err = FSMakeFSSpec( pb.ioFCBVRefNum, pb.ioFCBParID,
1308                             fond_file_name, &spec );
1309         if ( noErr != err )
1310           goto found_no_lwfn_file;
1311
1312         err = FT_FSpMakePath( &spec, path_fond, sizeof ( path_fond ) );
1313         if ( noErr != err )
1314           goto found_no_lwfn_file;
1315
1316         error = lookup_lwfn_by_fond( path_fond, lwfn_file_name,
1317                                      path_lwfn, sizeof ( path_lwfn ) );
1318         if ( FT_Err_Ok == error )
1319           have_lwfn = 1;
1320       }
1321
1322 #endif /* HAVE_FSREF, HAVE_FSSPEC */
1323
1324     }
1325
1326     if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
1327       error = FT_New_Face_From_LWFN( library,
1328                                      path_lwfn,
1329                                      face_index,
1330                                      aface );
1331     else
1332       error = FT_ERR( Unknown_File_Format );
1333
1334   found_no_lwfn_file:
1335     if ( have_sfnt && FT_Err_Ok != error )
1336       error = FT_New_Face_From_SFNT( library,
1337                                      sfnt_id,
1338                                      face_index,
1339                                      aface );
1340
1341     return error;
1342   }
1343
1344
1345   /* Common function to load a new FT_Face from a resource file. */
1346   static FT_Error
1347   FT_New_Face_From_Resource( FT_Library    library,
1348                              const UInt8*  pathname,
1349                              FT_Long       face_index,
1350                              FT_Face*      aface )
1351   {
1352     OSType    file_type;
1353     FT_Error  error;
1354
1355
1356     /* LWFN is a (very) specific file format, check for it explicitly */
1357     file_type = get_file_type_from_path( pathname );
1358     if ( file_type == TTAG_LWFN )
1359       return FT_New_Face_From_LWFN( library, pathname, face_index, aface );
1360
1361     /* Otherwise the file type doesn't matter (there are more than  */
1362     /* `FFIL' and `tfil').  Just try opening it as a font suitcase; */
1363     /* if it works, fine.                                           */
1364
1365     error = FT_New_Face_From_Suitcase( library, pathname, face_index, aface );
1366     if ( error == 0 )
1367       return error;
1368
1369     /* let it fall through to normal loader (.ttf, .otf, etc.); */
1370     /* we signal this by returning no error and no FT_Face      */
1371     *aface = NULL;
1372     return 0;
1373   }
1374
1375
1376   /*************************************************************************/
1377   /*                                                                       */
1378   /* <Function>                                                            */
1379   /*    FT_New_Face                                                        */
1380   /*                                                                       */
1381   /* <Description>                                                         */
1382   /*    This is the Mac-specific implementation of FT_New_Face.  In        */
1383   /*    addition to the standard FT_New_Face() functionality, it also      */
1384   /*    accepts pathnames to Mac suitcase files.  For further              */
1385   /*    documentation see the original FT_New_Face() in freetype.h.        */
1386   /*                                                                       */
1387   FT_EXPORT_DEF( FT_Error )
1388   FT_New_Face( FT_Library   library,
1389                const char*  pathname,
1390                FT_Long      face_index,
1391                FT_Face*     aface )
1392   {
1393     FT_Open_Args  args;
1394     FT_Error      error;
1395
1396
1397     /* test for valid `library' and `aface' delayed to FT_Open_Face() */
1398     if ( !pathname )
1399       return FT_THROW( Invalid_Argument );
1400
1401     *aface = NULL;
1402
1403     /* try resourcefork based font: LWFN, FFIL */
1404     error = FT_New_Face_From_Resource( library, (UInt8 *)pathname,
1405                                        face_index, aface );
1406     if ( error != 0 || *aface != NULL )
1407       return error;
1408
1409     /* let it fall through to normal loader (.ttf, .otf, etc.) */
1410     args.flags    = FT_OPEN_PATHNAME;
1411     args.pathname = (char*)pathname;
1412     return FT_Open_Face( library, &args, face_index, aface );
1413   }
1414
1415
1416   /*************************************************************************/
1417   /*                                                                       */
1418   /* <Function>                                                            */
1419   /*    FT_New_Face_From_FSRef                                             */
1420   /*                                                                       */
1421   /* <Description>                                                         */
1422   /*    FT_New_Face_From_FSRef is identical to FT_New_Face except it       */
1423   /*    accepts an FSRef instead of a path.                                */
1424   /*                                                                       */
1425   /* This function is deprecated because Carbon data types (FSRef)         */
1426   /* are not cross-platform, and thus not suitable for the freetype API.   */
1427   FT_EXPORT_DEF( FT_Error )
1428   FT_New_Face_From_FSRef( FT_Library    library,
1429                           const FSRef*  ref,
1430                           FT_Long       face_index,
1431                           FT_Face*      aface )
1432   {
1433
1434 #if !HAVE_FSREF
1435
1436     FT_UNUSED( library );
1437     FT_UNUSED( ref );
1438     FT_UNUSED( face_index );
1439     FT_UNUSED( aface );
1440
1441     return FT_THROW( Unimplemented_Feature );
1442
1443 #else
1444
1445     FT_Error      error;
1446     FT_Open_Args  args;
1447     OSErr   err;
1448     UInt8   pathname[PATH_MAX];
1449
1450
1451     /* test for valid `library' and `aface' delayed to `FT_Open_Face' */
1452
1453     if ( !ref )
1454       return FT_THROW( Invalid_Argument );
1455
1456     err = FSRefMakePath( ref, pathname, sizeof ( pathname ) );
1457     if ( err )
1458       error = FT_ERR( Cannot_Open_Resource );
1459
1460     error = FT_New_Face_From_Resource( library, pathname, face_index, aface );
1461     if ( error != 0 || *aface != NULL )
1462       return error;
1463
1464     /* fallback to datafork font */
1465     args.flags    = FT_OPEN_PATHNAME;
1466     args.pathname = (char*)pathname;
1467     return FT_Open_Face( library, &args, face_index, aface );
1468
1469 #endif /* HAVE_FSREF */
1470
1471   }
1472
1473
1474   /*************************************************************************/
1475   /*                                                                       */
1476   /* <Function>                                                            */
1477   /*    FT_New_Face_From_FSSpec                                            */
1478   /*                                                                       */
1479   /* <Description>                                                         */
1480   /*    FT_New_Face_From_FSSpec is identical to FT_New_Face except it      */
1481   /*    accepts an FSSpec instead of a path.                               */
1482   /*                                                                       */
1483   /* This function is deprecated because Carbon data types (FSSpec)        */
1484   /* are not cross-platform, and thus not suitable for the freetype API.   */
1485   FT_EXPORT_DEF( FT_Error )
1486   FT_New_Face_From_FSSpec( FT_Library     library,
1487                            const FSSpec*  spec,
1488                            FT_Long        face_index,
1489                            FT_Face*       aface )
1490   {
1491
1492 #if HAVE_FSREF
1493
1494     FSRef  ref;
1495
1496
1497     if ( !spec || FSpMakeFSRef( spec, &ref ) != noErr )
1498       return FT_THROW( Invalid_Argument );
1499     else
1500       return FT_New_Face_From_FSRef( library, &ref, face_index, aface );
1501
1502 #elif HAVE_FSSPEC
1503
1504     FT_Error      error;
1505     FT_Open_Args  args;
1506     OSErr         err;
1507     UInt8         pathname[PATH_MAX];
1508
1509
1510     if ( !spec )
1511       return FT_THROW( Invalid_Argument );
1512
1513     err = FT_FSpMakePath( spec, pathname, sizeof ( pathname ) );
1514     if ( err )
1515       error = FT_ERR( Cannot_Open_Resource );
1516
1517     error = FT_New_Face_From_Resource( library, pathname, face_index, aface );
1518     if ( error != 0 || *aface != NULL )
1519       return error;
1520
1521     /* fallback to datafork font */
1522     args.flags    = FT_OPEN_PATHNAME;
1523     args.pathname = (char*)pathname;
1524     return FT_Open_Face( library, &args, face_index, aface );
1525
1526 #else
1527
1528     FT_UNUSED( library );
1529     FT_UNUSED( spec );
1530     FT_UNUSED( face_index );
1531     FT_UNUSED( aface );
1532
1533     return FT_THROW( Unimplemented_Feature );
1534
1535 #endif /* HAVE_FSREF, HAVE_FSSPEC */
1536
1537   }
1538
1539 #endif /* FT_MACINTOSH */
1540
1541
1542 /* END */