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 1996-2015 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       p += sizeof ( short );
784 
785       for ( i = 0; i < string_count && i < 64; i++ )
786       {
787         names[i] = p;
788         p       += names[i][0];
789         p++;
790       }
791 
792       {
793         size_t  ps_name_len = (size_t)names[0][0];
794 
795 
796         if ( ps_name_len != 0 )
797         {
798           ft_memcpy(ps_name, names[0] + 1, ps_name_len);
799           ps_name[ps_name_len] = 0;
800         }
801         if ( style->indexes[face_index] > 1 &&
802              style->indexes[face_index] <= FT_MIN( string_count, 64 ) )
803         {
804           unsigned char*  suffixes = names[style->indexes[face_index] - 1];
805 
806 
807           for ( i = 1; i <= suffixes[0]; i++ )
808           {
809             unsigned char*  s;
810             size_t          j = suffixes[i] - 1;
811 
812 
813             if ( j < string_count && ( s = names[j] ) != NULL )
814             {
815               size_t  s_len = (size_t)s[0];
816 
817 
818               if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) )
819               {
820                 ft_memcpy( ps_name + ps_name_len, s + 1, s_len );
821                 ps_name_len += s_len;
822                 ps_name[ps_name_len] = 0;
823               }
824             }
825           }
826         }
827       }
828 
829       create_lwfn_name( ps_name, lwfn_file_name );
830     }
831   }
832 
833 
834   static  FT_Error
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 ( FT_Err_Ok == 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_ALLOC( buffer, (FT_Long)total_size ) )
1015       goto Error;
1016 
1017     /* Second pass: append all POST data to the buffer, add PFB fields. */
1018     /* Glue all consecutive chunks of the same type together.           */
1019     p              = buffer;
1020     res_id         = 501;
1021     last_code      = -1;
1022     pfb_chunk_size = 0;
1023 
1024     for (;;)
1025     {
1026       post_data = Get1Resource( TTAG_POST, res_id++ );
1027       if ( post_data == NULL )
1028         break;  /* we are done */
1029 
1030       post_size = (FT_ULong)GetHandleSize( post_data ) - 2;
1031       code = (*post_data)[0];
1032 
1033       if ( code != last_code )
1034       {
1035         if ( last_code != -1 )
1036         {
1037           /* we are done adding a chunk, fill in the size field */
1038           if ( size_p != NULL )
1039           {
1040             *size_p++ = (FT_Byte)(   pfb_chunk_size         & 0xFF );
1041             *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8  ) & 0xFF );
1042             *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF );
1043             *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF );
1044           }
1045           pfb_chunk_size = 0;
1046         }
1047 
1048         *p++ = 0x80;
1049         if ( code == 5 )
1050           *p++ = 0x03;  /* the end */
1051         else if ( code == 2 )
1052           *p++ = 0x02;  /* binary segment */
1053         else
1054           *p++ = 0x01;  /* ASCII segment */
1055 
1056         if ( code != 5 )
1057         {
1058           size_p = p;   /* save for later */
1059           p += 4;       /* make space for size field */
1060         }
1061       }
1062 
1063       ft_memcpy( p, *post_data + 2, post_size );
1064       pfb_chunk_size += post_size;
1065       p += post_size;
1066       last_code = code;
1067     }
1068 
1069     *pfb_data = buffer;
1070     *size = total_size;
1071 
1072   Error:
1073     CloseResFile( res );
1074     return error;
1075   }
1076 
1077 
1078   /* Create a new FT_Face from a file spec to an LWFN file. */
1079   static FT_Error
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_ALLOC( sfnt_data, (FT_Long)sfnt_size ) )
1131     {
1132       ReleaseResource( sfnt );
1133       return error;
1134     }
1135 
1136     HLock( sfnt );
1137     ft_memcpy( sfnt_data, *sfnt, sfnt_size );
1138     HUnlock( sfnt );
1139     ReleaseResource( sfnt );
1140 
1141     is_cff     = sfnt_size > 4 && !ft_memcmp( sfnt_data, "OTTO", 4 );
1142     is_sfnt_ps = sfnt_size > 4 && !ft_memcmp( sfnt_data, "typ1", 4 );
1143 
1144     if ( is_sfnt_ps )
1145     {
1146       FT_Stream  stream;
1147 
1148 
1149       if ( FT_NEW( stream ) )
1150         goto Try_OpenType;
1151 
1152       FT_Stream_OpenMemory( stream, sfnt_data, sfnt_size );
1153       if ( !open_face_PS_from_sfnt_stream( library,
1154                                            stream,
1155                                            face_index,
1156                                            0, NULL,
1157                                            aface ) )
1158       {
1159         FT_Stream_Close( stream );
1160         FT_FREE( stream );
1161         FT_FREE( sfnt_data );
1162         goto Exit;
1163       }
1164 
1165       FT_FREE( stream );
1166     }
1167   Try_OpenType:
1168     error = open_face_from_buffer( library,
1169                                    sfnt_data,
1170                                    sfnt_size,
1171                                    face_index,
1172                                    is_cff ? "cff" : "truetype",
1173                                    aface );
1174   Exit:
1175     return error;
1176   }
1177 
1178 
1179   /* Create a new FT_Face from a file spec to a suitcase file. */
1180   static FT_Error
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 ( FT_Err_Ok == error && NULL != 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 ( FT_Err_Ok == 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 ( FT_Err_Ok == 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 && FT_Err_Ok != 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 == 0 )
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 != 0 || *aface != NULL )
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 != 0 || *aface != NULL )
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 != 0 || *aface != NULL )
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