(root)/
freetype-2.13.2/
builds/
mac/
ftmac.c
       1  /***************************************************************************/
       2  /*                                                                         */
       3  /*  ftmac.c                                                                */
       4  /*                                                                         */
       5  /*    Mac FOND support.  Written by just@letterror.com.                    */
       6  /*  Heavily Fixed by mpsuzuki, George Williams and Sean McBride            */
       7  /*                                                                         */
       8  /*  Copyright (C) 1996-2023 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 */