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