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-2021 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 FT_MAC_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 )
FT_GetFile_From_Mac_Name(const char * fontName,FSSpec * pathSpec,FT_Long * face_index)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 )
FT_GetFile_From_Mac_Name(const char * fontName,FSSpec * pathSpec,FT_Long * face_index)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
FT_ATSFontGetFileReference(ATSFontRef ats_font_id,FSRef * ats_font_ref)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
FT_GetFileRef_From_Mac_ATS_Name(const char * fontName,FSRef * ats_font_ref,FT_Long * face_index)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 )
FT_GetFilePath_From_Mac_ATS_Name(const char * fontName,UInt8 * path,UInt32 maxPathSize,FT_Long * face_index)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 )
FT_GetFilePath_From_Mac_ATS_Name(const char * fontName,UInt8 * path,UInt32 maxPathSize,FT_Long * face_index)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 )
FT_GetFile_From_Mac_ATS_Name(const char * fontName,FSSpec * pathSpec,FT_Long * face_index)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 )
FT_GetFile_From_Mac_ATS_Name(const char * fontName,FSSpec * pathSpec,FT_Long * face_index)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 )
ft_FSp_stream_close(FT_Stream stream)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 )
ft_FSp_stream_io(FT_Stream stream,unsigned long offset,unsigned char * buffer,unsigned long count)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
FT_FSPathMakeSpec(const UInt8 * pathname,FSSpec * spec_p,Boolean isDirectory)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
FT_FSpMakePath(const FSSpec * spec_p,UInt8 * path,UInt32 maxPathSize)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
FT_FSPathMakeRes(const UInt8 * pathname,ResFileRefNum * res)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
get_file_type_from_path(const UInt8 * pathname)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
create_lwfn_name(char * ps_name,Str255 lwfn_file_name)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
count_faces_sfnt(char * fond_data)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
count_faces_scalable(char * fond_data)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
parse_fond(char * fond_data,short * have_sfnt,ResID * sfnt_id,Str255 lwfn_file_name,short face_index)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
lookup_lwfn_by_fond(const UInt8 * path_fond,ConstStr255Param base_lwfn,UInt8 * path_lwfn,int path_size)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
count_faces(Handle fond,const UInt8 * pathname)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
read_lwfn(FT_Memory memory,ResFileRefNum res,FT_Byte ** pfb_data,FT_ULong * size)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
FT_New_Face_From_LWFN(FT_Library library,const UInt8 * pathname,FT_Long face_index,FT_Face * aface)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
FT_New_Face_From_SFNT(FT_Library library,ResID sfnt_id,FT_Long face_index,FT_Face * aface)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
FT_New_Face_From_Suitcase(FT_Library library,const UInt8 * pathname,FT_Long face_index,FT_Face * aface)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 )
FT_New_Face_From_FOND(FT_Library library,Handle fond,FT_Long face_index,FT_Face * aface)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
FT_New_Face_From_Resource(FT_Library library,const UInt8 * pathname,FT_Long face_index,FT_Face * aface)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 )
FT_New_Face(FT_Library library,const char * pathname,FT_Long face_index,FT_Face * aface)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 )
FT_New_Face_From_FSRef(FT_Library library,const FSRef * ref,FT_Long face_index,FT_Face * aface)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 )
FT_New_Face_From_FSSpec(FT_Library library,const FSSpec * spec,FT_Long face_index,FT_Face * aface)1486   FT_New_Face_From_FSSpec( FT_Library     library,
1487                            const FSSpec*  spec,
1488                            FT_Long        face_index,
1489                            FT_Face*       aface )
1490   {
1491 
1492 #if HAVE_FSREF
1493 
1494     FSRef  ref;
1495 
1496 
1497     if ( !spec || FSpMakeFSRef( spec, &ref ) != noErr )
1498       return FT_THROW( Invalid_Argument );
1499     else
1500       return FT_New_Face_From_FSRef( library, &ref, face_index, aface );
1501 
1502 #elif HAVE_FSSPEC
1503 
1504     FT_Error      error;
1505     FT_Open_Args  args;
1506     OSErr         err;
1507     UInt8         pathname[PATH_MAX];
1508 
1509 
1510     if ( !spec )
1511       return FT_THROW( Invalid_Argument );
1512 
1513     err = FT_FSpMakePath( spec, pathname, sizeof ( pathname ) );
1514     if ( err )
1515       error = FT_ERR( Cannot_Open_Resource );
1516 
1517     error = FT_New_Face_From_Resource( library, pathname, face_index, aface );
1518     if ( error || *aface )
1519       return error;
1520 
1521     /* fallback to datafork font */
1522     args.flags    = FT_OPEN_PATHNAME;
1523     args.pathname = (char*)pathname;
1524     return FT_Open_Face( library, &args, face_index, aface );
1525 
1526 #else
1527 
1528     FT_UNUSED( library );
1529     FT_UNUSED( spec );
1530     FT_UNUSED( face_index );
1531     FT_UNUSED( aface );
1532 
1533     return FT_THROW( Unimplemented_Feature );
1534 
1535 #endif /* HAVE_FSREF, HAVE_FSSPEC */
1536 
1537   }
1538 
1539 #endif /* FT_MACINTOSH */
1540 
1541 
1542 /* END */
1543