Home | History | Annotate | Download | only in mac
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  ftmac.c                                                                */
      4 /*                                                                         */
      5 /*    Mac FOND support.  Written by just (at) letterror.com.                    */
      6 /*  Heavily Fixed by mpsuzuki, George Williams and Sean McBride            */
      7 /*                                                                         */
      8 /*  Copyright 1996-2018 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 (at) 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 ( !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 ( !error && 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 ( !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 ( !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 && 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 )
   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 || *aface )
   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 || *aface )
   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 || *aface )
   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 */
   1543