tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ftmac.c (43736B)


      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 (C) 1996-2025 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 <freetype/freetype.h>
     66 #include <freetype/tttags.h>
     67 #include <freetype/internal/ftstream.h>
     68 #include "ftbase.h"
     69 
     70 #if defined( __GNUC__ ) || defined( __IBMC__ )
     71  /* This is for Mac OS X.  Without redefinition, OS_INLINE */
     72  /* expands to `static inline' which doesn't survive the   */
     73  /* -ansi compilation flag of GCC.                         */
     74 #if !HAVE_ANSI_OS_INLINE
     75 #undef  OS_INLINE
     76 #define OS_INLINE   static __inline__
     77 #endif
     78 #include <CoreServices/CoreServices.h>
     79 #include <ApplicationServices/ApplicationServices.h>
     80 #include <sys/syslimits.h> /* PATH_MAX */
     81 #else
     82 #include <Resources.h>
     83 #include <Fonts.h>
     84 #include <Endian.h>
     85 #include <Errors.h>
     86 #include <Files.h>
     87 #include <TextUtils.h>
     88 #endif
     89 
     90 #ifndef PATH_MAX
     91 #define PATH_MAX 1024 /* same with Mac OS X's syslimits.h */
     92 #endif
     93 
     94 #if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
     95 #include <FSp_fopen.h>
     96 #endif
     97 
     98 #define FT_DEPRECATED_ATTRIBUTE
     99 
    100 #include <freetype/ftmac.h>
    101 
    102  /* undefine blocking-macros in ftmac.h */
    103 #undef FT_GetFile_From_Mac_Name
    104 #undef FT_GetFile_From_Mac_ATS_Name
    105 #undef FT_New_Face_From_FOND
    106 #undef FT_New_Face_From_FSSpec
    107 #undef FT_New_Face_From_FSRef
    108 
    109 
    110  /* FSSpec functions are deprecated since Mac OS X 10.4 */
    111 #ifndef HAVE_FSSPEC
    112 #if TARGET_API_MAC_OS8 || TARGET_API_MAC_CARBON
    113 #define HAVE_FSSPEC  1
    114 #else
    115 #define HAVE_FSSPEC  0
    116 #endif
    117 #endif
    118 
    119  /* most FSRef functions were introduced since Mac OS 9 */
    120 #ifndef HAVE_FSREF
    121 #if TARGET_API_MAC_OSX
    122 #define HAVE_FSREF  1
    123 #else
    124 #define HAVE_FSREF  0
    125 #endif
    126 #endif
    127 
    128  /* QuickDraw is deprecated since Mac OS X 10.4 */
    129 #ifndef HAVE_QUICKDRAW_CARBON
    130 #if TARGET_API_MAC_OS8 || TARGET_API_MAC_CARBON
    131 #define HAVE_QUICKDRAW_CARBON  1
    132 #else
    133 #define HAVE_QUICKDRAW_CARBON  0
    134 #endif
    135 #endif
    136 
    137  /* AppleTypeService is available since Mac OS X */
    138 #ifndef HAVE_ATS
    139 #if TARGET_API_MAC_OSX
    140 #define HAVE_ATS  1
    141 #ifndef kATSOptionFlagsUnRestrictedScope /* since Mac OS X 10.1 */
    142 #define kATSOptionFlagsUnRestrictedScope kATSOptionFlagsDefault
    143 #endif
    144 #else
    145 #define HAVE_ATS  0
    146 #endif
    147 #endif
    148 
    149  /* `configure' checks the availability of `ResourceIndex' strictly */
    150  /* and sets HAVE_TYPE_RESOURCE_INDEX to 1 or 0 always.  If it is   */
    151  /* not set (e.g., a build without `configure'), the availability   */
    152  /* is guessed from the SDK version.                                */
    153 #ifndef HAVE_TYPE_RESOURCE_INDEX
    154 #if !defined( MAC_OS_X_VERSION_10_5 ) || \
    155    ( MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 )
    156 #define HAVE_TYPE_RESOURCE_INDEX 0
    157 #else
    158 #define HAVE_TYPE_RESOURCE_INDEX 1
    159 #endif
    160 #endif /* !HAVE_TYPE_RESOURCE_INDEX */
    161 
    162 #if ( HAVE_TYPE_RESOURCE_INDEX == 0 )
    163 typedef short ResourceIndex;
    164 #endif
    165 
    166  /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over
    167     TrueType in case *both* are available (this is not common,
    168     but it *is* possible). */
    169 #ifndef PREFER_LWFN
    170 #define PREFER_LWFN  1
    171 #endif
    172 
    173 #ifdef FT_MACINTOSH
    174 
    175 #if !HAVE_QUICKDRAW_CARBON  /* QuickDraw is deprecated since Mac OS X 10.4 */
    176 
    177  FT_EXPORT_DEF( FT_Error )
    178  FT_GetFile_From_Mac_Name( const char*  fontName,
    179                            FSSpec*      pathSpec,
    180                            FT_Long*     face_index )
    181  {
    182    FT_UNUSED( fontName );
    183    FT_UNUSED( pathSpec );
    184    FT_UNUSED( face_index );
    185 
    186    return FT_THROW( Unimplemented_Feature );
    187  }
    188 
    189 #else
    190 
    191  FT_EXPORT_DEF( FT_Error )
    192  FT_GetFile_From_Mac_Name( const char*  fontName,
    193                            FSSpec*      pathSpec,
    194                            FT_Long*     face_index )
    195  {
    196    OptionBits            options = kFMUseGlobalScopeOption;
    197 
    198    FMFontFamilyIterator  famIter;
    199    OSStatus              status = FMCreateFontFamilyIterator( NULL, NULL,
    200                                                               options,
    201                                                               &famIter );
    202    FMFont                the_font = 0;
    203    FMFontFamily          family   = 0;
    204 
    205 
    206    if ( !fontName || !face_index )
    207      return FT_THROW( Invalid_Argument );
    208 
    209    *face_index = 0;
    210    while ( status == 0 && !the_font )
    211    {
    212      status = FMGetNextFontFamily( &famIter, &family );
    213      if ( status == 0 )
    214      {
    215        int                           stat2;
    216        FMFontFamilyInstanceIterator  instIter;
    217        Str255                        famNameStr;
    218        char                          famName[256];
    219 
    220 
    221        /* get the family name */
    222        FMGetFontFamilyName( family, famNameStr );
    223        CopyPascalStringToC( famNameStr, famName );
    224 
    225        /* iterate through the styles */
    226        FMCreateFontFamilyInstanceIterator( family, &instIter );
    227 
    228        *face_index = 0;
    229        stat2       = 0;
    230 
    231        while ( stat2 == 0 && !the_font )
    232        {
    233          FMFontStyle  style;
    234          FMFontSize   size;
    235          FMFont       font;
    236 
    237 
    238          stat2 = FMGetNextFontFamilyInstance( &instIter, &font,
    239                                               &style, &size );
    240          if ( stat2 == 0 && size == 0 )
    241          {
    242            char  fullName[256];
    243 
    244 
    245            /* build up a complete face name */
    246            ft_strcpy( fullName, famName );
    247            if ( style & bold )
    248              ft_strcat( fullName, " Bold" );
    249            if ( style & italic )
    250              ft_strcat( fullName, " Italic" );
    251 
    252            /* compare with the name we are looking for */
    253            if ( ft_strcmp( fullName, fontName ) == 0 )
    254            {
    255              /* found it! */
    256              the_font = font;
    257            }
    258            else
    259              ++(*face_index);
    260          }
    261        }
    262 
    263        FMDisposeFontFamilyInstanceIterator( &instIter );
    264      }
    265    }
    266 
    267    FMDisposeFontFamilyIterator( &famIter );
    268 
    269    if ( the_font )
    270    {
    271      FMGetFontContainer( the_font, pathSpec );
    272      return FT_Err_Ok;
    273    }
    274    else
    275      return FT_THROW( Unknown_File_Format );
    276  }
    277 
    278 #endif /* HAVE_QUICKDRAW_CARBON */
    279 
    280 
    281 #if HAVE_ATS
    282 
    283  /* Private function.                                         */
    284  /* The FSSpec type has been discouraged for a long time,     */
    285  /* unfortunately an FSRef replacement API for                */
    286  /* ATSFontGetFileSpecification() is only available in        */
    287  /* Mac OS X 10.5 and later.                                  */
    288  static OSStatus
    289  FT_ATSFontGetFileReference( ATSFontRef  ats_font_id,
    290                              FSRef*      ats_font_ref )
    291  {
    292    OSStatus  err;
    293 
    294 #if !defined( MAC_OS_X_VERSION_10_5 ) || \
    295    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
    296    FSSpec    spec;
    297 
    298 
    299    err = ATSFontGetFileSpecification( ats_font_id, &spec );
    300    if ( noErr == err )
    301      err = FSpMakeFSRef( &spec, ats_font_ref );
    302 #else
    303    err = ATSFontGetFileReference( ats_font_id, ats_font_ref );
    304 #endif
    305 
    306    return err;
    307  }
    308 
    309 
    310  static FT_Error
    311  FT_GetFileRef_From_Mac_ATS_Name( const char*  fontName,
    312                                   FSRef*       ats_font_ref,
    313                                   FT_Long*     face_index )
    314  {
    315    CFStringRef  cf_fontName;
    316    ATSFontRef   ats_font_id;
    317 
    318 
    319    *face_index = 0;
    320 
    321    cf_fontName = CFStringCreateWithCString( NULL, fontName,
    322                                             kCFStringEncodingMacRoman );
    323    ats_font_id = ATSFontFindFromName( cf_fontName,
    324                                       kATSOptionFlagsUnRestrictedScope );
    325    CFRelease( cf_fontName );
    326 
    327    if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL )
    328      return FT_THROW( Unknown_File_Format );
    329 
    330    if ( noErr != FT_ATSFontGetFileReference( ats_font_id, ats_font_ref ) )
    331      return FT_THROW( Unknown_File_Format );
    332 
    333    /* face_index calculation by searching preceding fontIDs */
    334    /* with same FSRef                                       */
    335    {
    336      ATSFontRef  id2 = ats_font_id - 1;
    337      FSRef       ref2;
    338 
    339 
    340      while ( id2 > 0 )
    341      {
    342        if ( noErr != FT_ATSFontGetFileReference( id2, &ref2 ) )
    343          break;
    344        if ( noErr != FSCompareFSRefs( ats_font_ref, &ref2 ) )
    345          break;
    346 
    347        id2--;
    348      }
    349      *face_index = ats_font_id - ( id2 + 1 );
    350    }
    351 
    352    return FT_Err_Ok;
    353  }
    354 
    355 #endif
    356 
    357 #if !HAVE_ATS
    358 
    359  FT_EXPORT_DEF( FT_Error )
    360  FT_GetFilePath_From_Mac_ATS_Name( const char*  fontName,
    361                                    UInt8*       path,
    362                                    UInt32       maxPathSize,
    363                                    FT_Long*     face_index )
    364  {
    365    FT_UNUSED( fontName );
    366    FT_UNUSED( path );
    367    FT_UNUSED( maxPathSize );
    368    FT_UNUSED( face_index );
    369 
    370    return FT_THROW( Unimplemented_Feature );
    371  }
    372 
    373 #else
    374 
    375  FT_EXPORT_DEF( FT_Error )
    376  FT_GetFilePath_From_Mac_ATS_Name( const char*  fontName,
    377                                    UInt8*       path,
    378                                    UInt32       maxPathSize,
    379                                    FT_Long*     face_index )
    380  {
    381    FSRef     ref;
    382    FT_Error  err;
    383 
    384 
    385    err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index );
    386    if ( err )
    387      return err;
    388 
    389    if ( noErr != FSRefMakePath( &ref, path, maxPathSize ) )
    390      return FT_THROW( Unknown_File_Format );
    391 
    392    return FT_Err_Ok;
    393  }
    394 
    395 #endif /* HAVE_ATS */
    396 
    397 
    398 #if !HAVE_FSSPEC || !HAVE_ATS
    399 
    400  FT_EXPORT_DEF( FT_Error )
    401  FT_GetFile_From_Mac_ATS_Name( const char*  fontName,
    402                                FSSpec*      pathSpec,
    403                                FT_Long*     face_index )
    404  {
    405    FT_UNUSED( fontName );
    406    FT_UNUSED( pathSpec );
    407    FT_UNUSED( face_index );
    408 
    409    return FT_THROW( Unimplemented_Feature );
    410  }
    411 
    412 #else
    413 
    414  /* This function is deprecated because FSSpec is deprecated in Mac OS X. */
    415  FT_EXPORT_DEF( FT_Error )
    416  FT_GetFile_From_Mac_ATS_Name( const char*  fontName,
    417                                FSSpec*      pathSpec,
    418                                FT_Long*     face_index )
    419  {
    420    FSRef     ref;
    421    FT_Error  err;
    422 
    423 
    424    err = FT_GetFileRef_From_Mac_ATS_Name( fontName, &ref, face_index );
    425    if ( err )
    426      return err;
    427 
    428    if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL,
    429                                    pathSpec, NULL ) )
    430      return FT_THROW( Unknown_File_Format );
    431 
    432    return FT_Err_Ok;
    433  }
    434 
    435 #endif
    436 
    437 
    438 #if defined( __MWERKS__ ) && !TARGET_RT_MAC_MACHO
    439 
    440 #define STREAM_FILE( stream )  ( (FT_FILE*)stream->descriptor.pointer )
    441 
    442 
    443  FT_CALLBACK_DEF( void )
    444  ft_FSp_stream_close( FT_Stream  stream )
    445  {
    446    ft_fclose( STREAM_FILE( stream ) );
    447 
    448    stream->descriptor.pointer = NULL;
    449    stream->size               = 0;
    450    stream->base               = NULL;
    451  }
    452 
    453 
    454  FT_CALLBACK_DEF( unsigned long )
    455  ft_FSp_stream_io( FT_Stream       stream,
    456                    unsigned long   offset,
    457                    unsigned char*  buffer,
    458                    unsigned long   count )
    459  {
    460    FT_FILE*  file;
    461 
    462 
    463    file = STREAM_FILE( stream );
    464 
    465    ft_fseek( file, offset, SEEK_SET );
    466 
    467    return (unsigned long)ft_fread( buffer, 1, count, file );
    468  }
    469 
    470 #endif  /* __MWERKS__ && !TARGET_RT_MAC_MACHO */
    471 
    472 
    473 #if HAVE_FSSPEC && !HAVE_FSREF
    474 
    475  /* isDirectory is a dummy to synchronize API with FSPathMakeRef() */
    476  static OSErr
    477  FT_FSPathMakeSpec( const UInt8*  pathname,
    478                     FSSpec*       spec_p,
    479                     Boolean       isDirectory )
    480  {
    481    const char  *p, *q;
    482    short       vRefNum;
    483    long        dirID;
    484    Str255      nodeName;
    485    OSErr       err;
    486    FT_UNUSED( isDirectory );
    487 
    488 
    489    p = q = (const char *)pathname;
    490    dirID   = 0;
    491    vRefNum = 0;
    492 
    493    while ( 1 )
    494    {
    495      int  len = ft_strlen( p );
    496 
    497 
    498      if ( len > 255 )
    499        len = 255;
    500 
    501      q = p + len;
    502 
    503      if ( q == p )
    504        return 0;
    505 
    506      if ( 255 < ft_strlen( (char *)pathname ) )
    507      {
    508        while ( p < q && *q != ':' )
    509          q--;
    510      }
    511 
    512      if ( p < q )
    513        *(char *)nodeName = q - p;
    514      else if ( ft_strlen( p ) < 256 )
    515        *(char *)nodeName = ft_strlen( p );
    516      else
    517        return errFSNameTooLong;
    518 
    519      ft_strncpy( (char *)nodeName + 1, (char *)p, *(char *)nodeName );
    520      err = FSMakeFSSpec( vRefNum, dirID, nodeName, spec_p );
    521      if ( err || '\0' == *q )
    522        return err;
    523 
    524      vRefNum = spec_p->vRefNum;
    525      dirID   = spec_p->parID;
    526 
    527      p = q;
    528    }
    529  }
    530 
    531 
    532  static OSErr
    533  FT_FSpMakePath( const FSSpec*  spec_p,
    534                  UInt8*         path,
    535                  UInt32         maxPathSize )
    536  {
    537    OSErr   err;
    538    FSSpec  spec = *spec_p;
    539    short   vRefNum;
    540    long    dirID;
    541    Str255  parDir_name;
    542 
    543 
    544    FT_MEM_SET( path, 0, maxPathSize );
    545    while ( 1 )
    546    {
    547      int             child_namelen = ft_strlen( (char *)path );
    548      unsigned char   node_namelen  = spec.name[0];
    549      unsigned char*  node_name     = spec.name + 1;
    550 
    551 
    552      if ( node_namelen + child_namelen > maxPathSize )
    553        return errFSNameTooLong;
    554 
    555      FT_MEM_MOVE( path + node_namelen + 1, path, child_namelen );
    556      FT_MEM_COPY( path, node_name, node_namelen );
    557      if ( child_namelen > 0 )
    558        path[node_namelen] = ':';
    559 
    560      vRefNum        = spec.vRefNum;
    561      dirID          = spec.parID;
    562      parDir_name[0] = '\0';
    563      err = FSMakeFSSpec( vRefNum, dirID, parDir_name, &spec );
    564      if ( noErr != err || dirID == spec.parID )
    565        break;
    566    }
    567    return noErr;
    568  }
    569 
    570 #endif /* HAVE_FSSPEC && !HAVE_FSREF */
    571 
    572 
    573  static OSErr
    574  FT_FSPathMakeRes( const UInt8*    pathname,
    575                    ResFileRefNum*  res )
    576  {
    577 
    578 #if HAVE_FSREF
    579 
    580    OSErr  err;
    581    FSRef  ref;
    582 
    583 
    584    if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) )
    585      return FT_THROW( Cannot_Open_Resource );
    586 
    587    /* at present, no support for dfont format */
    588    err = FSOpenResourceFile( &ref, 0, NULL, fsRdPerm, res );
    589    if ( noErr == err )
    590      return err;
    591 
    592    /* fallback to original resource-fork font */
    593    *res = FSOpenResFile( &ref, fsRdPerm );
    594    err  = ResError();
    595 
    596 #else
    597 
    598    OSErr   err;
    599    FSSpec  spec;
    600 
    601 
    602    if ( noErr != FT_FSPathMakeSpec( pathname, &spec, FALSE ) )
    603      return FT_THROW( Cannot_Open_Resource );
    604 
    605    /* at present, no support for dfont format without FSRef */
    606    /* (see above), try original resource-fork font          */
    607    *res = FSpOpenResFile( &spec, fsRdPerm );
    608    err  = ResError();
    609 
    610 #endif /* HAVE_FSREF */
    611 
    612    return err;
    613  }
    614 
    615 
    616  /* Return the file type for given pathname */
    617  static OSType
    618  get_file_type_from_path( const UInt8*  pathname )
    619  {
    620 
    621 #if HAVE_FSREF
    622 
    623    FSRef          ref;
    624    FSCatalogInfo  info;
    625 
    626 
    627    if ( noErr != FSPathMakeRef( pathname, &ref, FALSE ) )
    628      return ( OSType ) 0;
    629 
    630    if ( noErr != FSGetCatalogInfo( &ref, kFSCatInfoFinderInfo, &info,
    631                                    NULL, NULL, NULL ) )
    632      return ( OSType ) 0;
    633 
    634    return ((FInfo *)(info.finderInfo))->fdType;
    635 
    636 #else
    637 
    638    FSSpec  spec;
    639    FInfo   finfo;
    640 
    641 
    642    if ( noErr != FT_FSPathMakeSpec( pathname, &spec, FALSE ) )
    643      return ( OSType ) 0;
    644 
    645    if ( noErr != FSpGetFInfo( &spec, &finfo ) )
    646      return ( OSType ) 0;
    647 
    648    return finfo.fdType;
    649 
    650 #endif /* HAVE_FSREF */
    651 
    652  }
    653 
    654 
    655  /* Given a PostScript font name, create the Macintosh LWFN file name. */
    656  static void
    657  create_lwfn_name( char*   ps_name,
    658                    Str255  lwfn_file_name )
    659  {
    660    int       max = 5, count = 0;
    661    FT_Byte*  p = lwfn_file_name;
    662    FT_Byte*  q = (FT_Byte*)ps_name;
    663 
    664 
    665    lwfn_file_name[0] = 0;
    666 
    667    while ( *q )
    668    {
    669      if ( ft_isupper( *q ) )
    670      {
    671        if ( count )
    672          max = 3;
    673        count = 0;
    674      }
    675      if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) )
    676      {
    677        *++p = *q;
    678        lwfn_file_name[0]++;
    679        count++;
    680      }
    681      q++;
    682    }
    683  }
    684 
    685 
    686  static short
    687  count_faces_sfnt( char*  fond_data )
    688  {
    689    /* The count is 1 greater than the value in the FOND.  */
    690    /* Isn't that cute? :-)                                */
    691 
    692    return EndianS16_BtoN( *( (short*)( fond_data +
    693                                        sizeof ( FamRec ) ) ) ) + 1;
    694  }
    695 
    696 
    697  static short
    698  count_faces_scalable( char*  fond_data )
    699  {
    700    AsscEntry*  assoc;
    701    short       i, face, face_all;
    702 
    703 
    704    face_all = EndianS16_BtoN( *( (short *)( fond_data +
    705                                             sizeof ( FamRec ) ) ) ) + 1;
    706    assoc    = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
    707    face     = 0;
    708 
    709    for ( i = 0; i < face_all; i++ )
    710    {
    711      if ( 0 == EndianS16_BtoN( assoc[i].fontSize ) )
    712        face++;
    713    }
    714    return face;
    715  }
    716 
    717 
    718  /* Look inside the FOND data, answer whether there should be an SFNT
    719     resource, and answer the name of a possible LWFN Type 1 file.
    720 
    721     Thanks to Paul Miller (paulm@profoundeffects.com) for the fix
    722     to load a face OTHER than the first one in the FOND!
    723  */
    724 
    725  static void
    726  parse_fond( char*   fond_data,
    727              short*  have_sfnt,
    728              ResID*  sfnt_id,
    729              Str255  lwfn_file_name,
    730              short   face_index )
    731  {
    732    AsscEntry*  assoc;
    733    AsscEntry*  base_assoc;
    734    FamRec*     fond;
    735 
    736 
    737    *sfnt_id          = 0;
    738    *have_sfnt        = 0;
    739    lwfn_file_name[0] = 0;
    740 
    741    fond       = (FamRec*)fond_data;
    742    assoc      = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
    743    base_assoc = assoc;
    744 
    745    /* the maximum faces in a FOND is 48, size of StyleTable.indexes[] */
    746    if ( 47 < face_index )
    747      return;
    748 
    749    /* Let's do a little range checking before we get too excited here */
    750    if ( face_index < count_faces_sfnt( fond_data ) )
    751    {
    752      assoc += face_index;        /* add on the face_index! */
    753 
    754      /* if the face at this index is not scalable,
    755         fall back to the first one (old behavior) */
    756      if ( EndianS16_BtoN( assoc->fontSize ) == 0 )
    757      {
    758        *have_sfnt = 1;
    759        *sfnt_id   = EndianS16_BtoN( assoc->fontID );
    760      }
    761      else if ( base_assoc->fontSize == 0 )
    762      {
    763        *have_sfnt = 1;
    764        *sfnt_id   = EndianS16_BtoN( base_assoc->fontID );
    765      }
    766    }
    767 
    768    if ( EndianS32_BtoN( fond->ffStylOff ) )
    769    {
    770      unsigned char*  p = (unsigned char*)fond_data;
    771      StyleTable*     style;
    772      unsigned short  string_count;
    773      char            ps_name[256];
    774      unsigned char*  names[64];
    775      int             i;
    776 
    777 
    778      p += EndianS32_BtoN( fond->ffStylOff );
    779      style = (StyleTable*)p;
    780      p += sizeof ( StyleTable );
    781      string_count = EndianS16_BtoN( *(short*)(p) );
    782      string_count = FT_MIN( 64, string_count );
    783      p += sizeof ( short );
    784 
    785      for ( i = 0; i < string_count; 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] <= string_count )
    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_QALLOC( 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_QALLOC( 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 */