• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  *
3  * ftrfork.c
4  *
5  *   Embedded resource forks accessor (body).
6  *
7  * Copyright (C) 2004-2021 by
8  * Masatake YAMATO and Redhat K.K.
9  *
10  * FT_Raccess_Get_HeaderInfo() and raccess_guess_darwin_hfsplus() are
11  * derived from ftobjs.c.
12  *
13  * This file is part of the FreeType project, and may only be used,
14  * modified, and distributed under the terms of the FreeType project
15  * license, LICENSE.TXT.  By continuing to use, modify, or distribute
16  * this file you indicate that you have read the license and
17  * understand and accept it fully.
18  *
19  */
20 
21 /****************************************************************************
22  * Development of the code in this file is support of
23  * Information-technology Promotion Agency, Japan.
24  */
25 
26 
27 #include <freetype/internal/ftdebug.h>
28 #include <freetype/internal/ftstream.h>
29 #include <freetype/internal/ftrfork.h>
30 
31 #include "ftbase.h"
32 
33 #undef  FT_COMPONENT
34 #define FT_COMPONENT  raccess
35 
36 
37   /*************************************************************************/
38   /*************************************************************************/
39   /*************************************************************************/
40   /****                                                                 ****/
41   /****                                                                 ****/
42   /****               Resource fork directory access                    ****/
43   /****                                                                 ****/
44   /****                                                                 ****/
45   /*************************************************************************/
46   /*************************************************************************/
47   /*************************************************************************/
48 
49   FT_BASE_DEF( FT_Error )
FT_Raccess_Get_HeaderInfo(FT_Library library,FT_Stream stream,FT_Long rfork_offset,FT_Long * map_offset,FT_Long * rdata_pos)50   FT_Raccess_Get_HeaderInfo( FT_Library  library,
51                              FT_Stream   stream,
52                              FT_Long     rfork_offset,
53                              FT_Long    *map_offset,
54                              FT_Long    *rdata_pos )
55   {
56     FT_Error       error;
57     unsigned char  head[16], head2[16];
58     FT_Long        map_pos, map_len, rdata_len;
59     int            allzeros, allmatch, i;
60     FT_Long        type_list;
61 
62     FT_UNUSED( library );
63 
64 
65     error = FT_Stream_Seek( stream, (FT_ULong)rfork_offset );
66     if ( error )
67       return error;
68 
69     error = FT_Stream_Read( stream, (FT_Byte*)head, 16 );
70     if ( error )
71       return error;
72 
73     /* ensure positive values */
74     if ( head[0]  >= 0x80 ||
75          head[4]  >= 0x80 ||
76          head[8]  >= 0x80 ||
77          head[12] >= 0x80 )
78       return FT_THROW( Unknown_File_Format );
79 
80     *rdata_pos = ( head[ 0] << 24 ) |
81                  ( head[ 1] << 16 ) |
82                  ( head[ 2] <<  8 ) |
83                    head[ 3];
84     map_pos    = ( head[ 4] << 24 ) |
85                  ( head[ 5] << 16 ) |
86                  ( head[ 6] <<  8 ) |
87                    head[ 7];
88     rdata_len  = ( head[ 8] << 24 ) |
89                  ( head[ 9] << 16 ) |
90                  ( head[10] <<  8 ) |
91                    head[11];
92     map_len    = ( head[12] << 24 ) |
93                  ( head[13] << 16 ) |
94                  ( head[14] <<  8 ) |
95                    head[15];
96 
97     /* the map must not be empty */
98     if ( !map_pos )
99       return FT_THROW( Unknown_File_Format );
100 
101     /* check whether rdata and map overlap */
102     if ( *rdata_pos < map_pos )
103     {
104       if ( *rdata_pos > map_pos - rdata_len )
105         return FT_THROW( Unknown_File_Format );
106     }
107     else
108     {
109       if ( map_pos > *rdata_pos - map_len )
110         return FT_THROW( Unknown_File_Format );
111     }
112 
113     /* check whether end of rdata or map exceeds stream size */
114     if ( FT_LONG_MAX - rdata_len < *rdata_pos                               ||
115          FT_LONG_MAX - map_len < map_pos                                    ||
116 
117          FT_LONG_MAX - ( *rdata_pos + rdata_len ) < rfork_offset            ||
118          FT_LONG_MAX - ( map_pos + map_len ) < rfork_offset                 ||
119 
120          (FT_ULong)( rfork_offset + *rdata_pos + rdata_len ) > stream->size ||
121          (FT_ULong)( rfork_offset + map_pos + map_len ) > stream->size      )
122       return FT_THROW( Unknown_File_Format );
123 
124     *rdata_pos += rfork_offset;
125     map_pos    += rfork_offset;
126 
127     error = FT_Stream_Seek( stream, (FT_ULong)map_pos );
128     if ( error )
129       return error;
130 
131     head2[15] = (FT_Byte)( head[15] + 1 );       /* make it be different */
132 
133     error = FT_Stream_Read( stream, (FT_Byte*)head2, 16 );
134     if ( error )
135       return error;
136 
137     allzeros = 1;
138     allmatch = 1;
139     for ( i = 0; i < 16; i++ )
140     {
141       if ( head2[i] != 0 )
142         allzeros = 0;
143       if ( head2[i] != head[i] )
144         allmatch = 0;
145     }
146     if ( !allzeros && !allmatch )
147       return FT_THROW( Unknown_File_Format );
148 
149     /* If we have reached this point then it is probably a mac resource */
150     /* file.  Now, does it contain any interesting resources?           */
151 
152     (void)FT_STREAM_SKIP( 4        /* skip handle to next resource map */
153                           + 2      /* skip file resource number */
154                           + 2 );   /* skip attributes */
155 
156     if ( FT_READ_SHORT( type_list ) )
157       return error;
158     if ( type_list < 0 )
159       return FT_THROW( Unknown_File_Format );
160 
161     error = FT_Stream_Seek( stream, (FT_ULong)( map_pos + type_list ) );
162     if ( error )
163       return error;
164 
165     *map_offset = map_pos + type_list;
166     return FT_Err_Ok;
167   }
168 
169 
170   FT_COMPARE_DEF( int )
ft_raccess_sort_ref_by_id(const void * a,const void * b)171   ft_raccess_sort_ref_by_id( const void*  a,
172                              const void*  b )
173   {
174     return  ( (FT_RFork_Ref*)a )->res_id - ( (FT_RFork_Ref*)b )->res_id;
175   }
176 
177 
178   FT_BASE_DEF( FT_Error )
FT_Raccess_Get_DataOffsets(FT_Library library,FT_Stream stream,FT_Long map_offset,FT_Long rdata_pos,FT_Long tag,FT_Bool sort_by_res_id,FT_Long ** offsets,FT_Long * count)179   FT_Raccess_Get_DataOffsets( FT_Library  library,
180                               FT_Stream   stream,
181                               FT_Long     map_offset,
182                               FT_Long     rdata_pos,
183                               FT_Long     tag,
184                               FT_Bool     sort_by_res_id,
185                               FT_Long   **offsets,
186                               FT_Long    *count )
187   {
188     FT_Error      error;
189     int           i, j, cnt, subcnt;
190     FT_Long       tag_internal, rpos;
191     FT_Memory     memory = library->memory;
192     FT_Long       temp;
193     FT_Long       *offsets_internal = NULL;
194     FT_RFork_Ref  *ref = NULL;
195 
196 
197     FT_TRACE3(( "\n" ));
198     error = FT_Stream_Seek( stream, (FT_ULong)map_offset );
199     if ( error )
200       return error;
201 
202     if ( FT_READ_SHORT( cnt ) )
203       return error;
204     cnt++;
205 
206     /* `rpos' is a signed 16bit integer offset to resource records; the    */
207     /* size of a resource record is 12 bytes.  The map header is 28 bytes, */
208     /* and a type list needs 10 bytes or more.  If we assume that the name */
209     /* list is empty and we have only a single entry in the type list,     */
210     /* there can be at most                                                */
211     /*                                                                     */
212     /*   (32768 - 28 - 10) / 12 = 2727                                     */
213     /*                                                                     */
214     /* resources.                                                          */
215     /*                                                                     */
216     /* A type list starts with a two-byte counter, followed by 10-byte     */
217     /* type records.  Assuming that there are no resources, the number of  */
218     /* type records can be at most                                         */
219     /*                                                                     */
220     /*   (32768 - 28 - 2) / 8 = 4079                                       */
221     /*                                                                     */
222     if ( cnt > 4079 )
223       return FT_THROW( Invalid_Table );
224 
225     for ( i = 0; i < cnt; i++ )
226     {
227       if ( FT_READ_LONG( tag_internal ) ||
228            FT_READ_SHORT( subcnt )      ||
229            FT_READ_SHORT( rpos )        )
230         return error;
231 
232       FT_TRACE2(( "Resource tags: %c%c%c%c\n",
233                   (char)( 0xFF & ( tag_internal >> 24 ) ),
234                   (char)( 0xFF & ( tag_internal >> 16 ) ),
235                   (char)( 0xFF & ( tag_internal >>  8 ) ),
236                   (char)( 0xFF & ( tag_internal >>  0 ) ) ));
237       FT_TRACE3(( "             : subcount=%d, suboffset=0x%04lx\n",
238                   subcnt, rpos ));
239 
240       if ( tag_internal == tag )
241       {
242         *count = subcnt + 1;
243         rpos  += map_offset;
244 
245         /* a zero count might be valid in the resource specification, */
246         /* however, it is completely useless to us                    */
247         if ( *count < 1 || *count > 2727 )
248           return FT_THROW( Invalid_Table );
249 
250         error = FT_Stream_Seek( stream, (FT_ULong)rpos );
251         if ( error )
252           return error;
253 
254         if ( FT_QNEW_ARRAY( ref, *count ) )
255           return error;
256 
257         for ( j = 0; j < *count; j++ )
258         {
259           if ( FT_READ_SHORT( ref[j].res_id ) )
260             goto Exit;
261           if ( FT_STREAM_SKIP( 2 ) )  /* resource name offset */
262             goto Exit;
263           if ( FT_READ_LONG( temp ) ) /* attributes (8bit), offset (24bit) */
264             goto Exit;
265           if ( FT_STREAM_SKIP( 4 ) )  /* mbz */
266             goto Exit;
267 
268           /*
269            * According to Inside Macintosh: More Macintosh Toolbox,
270            * "Resource IDs" (1-46), there are some reserved IDs.
271            * However, FreeType2 is not a font synthesizer, no need
272            * to check the acceptable resource ID.
273            */
274           if ( temp < 0 )
275           {
276             error = FT_THROW( Invalid_Table );
277             goto Exit;
278           }
279 
280           ref[j].offset = temp & 0xFFFFFFL;
281 
282           FT_TRACE3(( "             [%d]:"
283                       " resource_id=0x%04x, offset=0x%08lx\n",
284                       j, (FT_UShort)ref[j].res_id, ref[j].offset ));
285         }
286 
287         if ( sort_by_res_id )
288         {
289           ft_qsort( ref,
290                     (size_t)*count,
291                     sizeof ( FT_RFork_Ref ),
292                     ft_raccess_sort_ref_by_id );
293 
294           FT_TRACE3(( "             -- sort resources by their ids --\n" ));
295 
296           for ( j = 0; j < *count; j++ )
297             FT_TRACE3(( "             [%d]:"
298                         " resource_id=0x%04x, offset=0x%08lx\n",
299                         j, ref[j].res_id, ref[j].offset ));
300         }
301 
302         if ( FT_QNEW_ARRAY( offsets_internal, *count ) )
303           goto Exit;
304 
305         /* XXX: duplicated reference ID,
306          *      gap between reference IDs are acceptable?
307          *      further investigation on Apple implementation is needed.
308          */
309         for ( j = 0; j < *count; j++ )
310           offsets_internal[j] = rdata_pos + ref[j].offset;
311 
312         *offsets = offsets_internal;
313         error    = FT_Err_Ok;
314 
315       Exit:
316         FT_FREE( ref );
317         return error;
318       }
319     }
320 
321     return FT_THROW( Cannot_Open_Resource );
322   }
323 
324 
325 #ifdef FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK
326 
327   /*************************************************************************/
328   /*************************************************************************/
329   /*************************************************************************/
330   /****                                                                 ****/
331   /****                                                                 ****/
332   /****                     Guessing functions                          ****/
333   /****                                                                 ****/
334   /****            When you add a new guessing function,                ****/
335   /****           update FT_RACCESS_N_RULES in ftrfork.h.               ****/
336   /****                                                                 ****/
337   /*************************************************************************/
338   /*************************************************************************/
339   /*************************************************************************/
340 
341   static FT_Error
342   raccess_guess_apple_double( FT_Library  library,
343                               FT_Stream   stream,
344                               char       *base_file_name,
345                               char      **result_file_name,
346                               FT_Long    *result_offset );
347 
348   static FT_Error
349   raccess_guess_apple_single( FT_Library  library,
350                               FT_Stream   stream,
351                               char       *base_file_name,
352                               char      **result_file_name,
353                               FT_Long    *result_offset );
354 
355   static FT_Error
356   raccess_guess_darwin_ufs_export( FT_Library  library,
357                                    FT_Stream   stream,
358                                    char       *base_file_name,
359                                    char      **result_file_name,
360                                    FT_Long    *result_offset );
361 
362   static FT_Error
363   raccess_guess_darwin_newvfs( FT_Library  library,
364                                FT_Stream   stream,
365                                char       *base_file_name,
366                                char      **result_file_name,
367                                FT_Long    *result_offset );
368 
369   static FT_Error
370   raccess_guess_darwin_hfsplus( FT_Library  library,
371                                 FT_Stream   stream,
372                                 char       *base_file_name,
373                                 char      **result_file_name,
374                                 FT_Long    *result_offset );
375 
376   static FT_Error
377   raccess_guess_vfat( FT_Library  library,
378                       FT_Stream   stream,
379                       char       *base_file_name,
380                       char      **result_file_name,
381                       FT_Long    *result_offset );
382 
383   static FT_Error
384   raccess_guess_linux_cap( FT_Library  library,
385                            FT_Stream   stream,
386                            char       *base_file_name,
387                            char      **result_file_name,
388                            FT_Long    *result_offset );
389 
390   static FT_Error
391   raccess_guess_linux_double( FT_Library  library,
392                               FT_Stream   stream,
393                               char       *base_file_name,
394                               char      **result_file_name,
395                               FT_Long    *result_offset );
396 
397   static FT_Error
398   raccess_guess_linux_netatalk( FT_Library  library,
399                                 FT_Stream   stream,
400                                 char       *base_file_name,
401                                 char      **result_file_name,
402                                 FT_Long    *result_offset );
403 
404 
405   CONST_FT_RFORK_RULE_ARRAY_BEGIN(ft_raccess_guess_table,
406                                   ft_raccess_guess_rec)
407   CONST_FT_RFORK_RULE_ARRAY_ENTRY(apple_double,      apple_double)
408   CONST_FT_RFORK_RULE_ARRAY_ENTRY(apple_single,      apple_single)
409   CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_ufs_export, darwin_ufs_export)
410   CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_newvfs,     darwin_newvfs)
411   CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_hfsplus,    darwin_hfsplus)
412   CONST_FT_RFORK_RULE_ARRAY_ENTRY(vfat,              vfat)
413   CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_cap,         linux_cap)
414   CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_double,      linux_double)
415   CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_netatalk,    linux_netatalk)
416   CONST_FT_RFORK_RULE_ARRAY_END
417 
418 
419   /*************************************************************************/
420   /****                                                                 ****/
421   /****                       Helper functions                          ****/
422   /****                                                                 ****/
423   /*************************************************************************/
424 
425   static FT_Error
426   raccess_guess_apple_generic( FT_Library  library,
427                                FT_Stream   stream,
428                                char       *base_file_name,
429                                FT_Int32    magic,
430                                FT_Long    *result_offset );
431 
432   static FT_Error
433   raccess_guess_linux_double_from_file_name( FT_Library  library,
434                                              char*       file_name,
435                                              FT_Long    *result_offset );
436 
437   static char *
438   raccess_make_file_name( FT_Memory    memory,
439                           const char  *original_name,
440                           const char  *insertion );
441 
442   FT_BASE_DEF( void )
FT_Raccess_Guess(FT_Library library,FT_Stream stream,char * base_name,char ** new_names,FT_Long * offsets,FT_Error * errors)443   FT_Raccess_Guess( FT_Library  library,
444                     FT_Stream   stream,
445                     char*       base_name,
446                     char      **new_names,
447                     FT_Long    *offsets,
448                     FT_Error   *errors )
449   {
450     FT_Int  i;
451 
452 
453     for ( i = 0; i < FT_RACCESS_N_RULES; i++ )
454     {
455       new_names[i] = NULL;
456       if ( NULL != stream )
457         errors[i] = FT_Stream_Seek( stream, 0 );
458       else
459         errors[i] = FT_Err_Ok;
460 
461       if ( errors[i] )
462         continue;
463 
464       errors[i] = ft_raccess_guess_table[i].func( library,
465                                                   stream, base_name,
466                                                   &(new_names[i]),
467                                                   &(offsets[i]) );
468     }
469 
470     return;
471   }
472 
473 
474 #if defined( FT_CONFIG_OPTION_MAC_FONTS ) && !defined( FT_MACINTOSH )
475   static FT_RFork_Rule
raccess_get_rule_type_from_rule_index(FT_Library library,FT_UInt rule_index)476   raccess_get_rule_type_from_rule_index( FT_Library  library,
477                                          FT_UInt     rule_index )
478   {
479     FT_UNUSED( library );
480 
481     if ( rule_index >= FT_RACCESS_N_RULES )
482       return FT_RFork_Rule_invalid;
483 
484     return ft_raccess_guess_table[rule_index].type;
485   }
486 
487 
488   /*
489    * For this function, refer ftbase.h.
490    */
491   FT_LOCAL_DEF( FT_Bool )
ft_raccess_rule_by_darwin_vfs(FT_Library library,FT_UInt rule_index)492   ft_raccess_rule_by_darwin_vfs( FT_Library  library,
493                                  FT_UInt     rule_index )
494   {
495     switch( raccess_get_rule_type_from_rule_index( library, rule_index ) )
496     {
497       case FT_RFork_Rule_darwin_newvfs:
498       case FT_RFork_Rule_darwin_hfsplus:
499         return TRUE;
500 
501       default:
502         return FALSE;
503     }
504   }
505 #endif
506 
507 
508   static FT_Error
raccess_guess_apple_double(FT_Library library,FT_Stream stream,char * base_file_name,char ** result_file_name,FT_Long * result_offset)509   raccess_guess_apple_double( FT_Library  library,
510                               FT_Stream   stream,
511                               char       *base_file_name,
512                               char      **result_file_name,
513                               FT_Long    *result_offset )
514   {
515     FT_Int32  magic = ( 0x00 << 24 ) |
516                       ( 0x05 << 16 ) |
517                       ( 0x16 <<  8 ) |
518                         0x07;
519 
520 
521     *result_file_name = NULL;
522     if ( NULL == stream )
523       return FT_THROW( Cannot_Open_Stream );
524 
525     return raccess_guess_apple_generic( library, stream, base_file_name,
526                                         magic, result_offset );
527   }
528 
529 
530   static FT_Error
raccess_guess_apple_single(FT_Library library,FT_Stream stream,char * base_file_name,char ** result_file_name,FT_Long * result_offset)531   raccess_guess_apple_single( FT_Library  library,
532                               FT_Stream   stream,
533                               char       *base_file_name,
534                               char      **result_file_name,
535                               FT_Long    *result_offset )
536   {
537     FT_Int32  magic = ( 0x00 << 24 ) |
538                       ( 0x05 << 16 ) |
539                       ( 0x16 <<  8 ) |
540                         0x00;
541 
542 
543     *result_file_name = NULL;
544     if ( NULL == stream )
545       return FT_THROW( Cannot_Open_Stream );
546 
547     return raccess_guess_apple_generic( library, stream, base_file_name,
548                                         magic, result_offset );
549   }
550 
551 
552   static FT_Error
raccess_guess_darwin_ufs_export(FT_Library library,FT_Stream stream,char * base_file_name,char ** result_file_name,FT_Long * result_offset)553   raccess_guess_darwin_ufs_export( FT_Library  library,
554                                    FT_Stream   stream,
555                                    char       *base_file_name,
556                                    char      **result_file_name,
557                                    FT_Long    *result_offset )
558   {
559     char*      newpath;
560     FT_Error   error;
561     FT_Memory  memory;
562 
563     FT_UNUSED( stream );
564 
565 
566     memory  = library->memory;
567     newpath = raccess_make_file_name( memory, base_file_name, "._" );
568     if ( !newpath )
569       return FT_THROW( Out_Of_Memory );
570 
571     error = raccess_guess_linux_double_from_file_name( library, newpath,
572                                                        result_offset );
573     if ( !error )
574       *result_file_name = newpath;
575     else
576       FT_FREE( newpath );
577 
578     return error;
579   }
580 
581 
582   static FT_Error
raccess_guess_darwin_hfsplus(FT_Library library,FT_Stream stream,char * base_file_name,char ** result_file_name,FT_Long * result_offset)583   raccess_guess_darwin_hfsplus( FT_Library  library,
584                                 FT_Stream   stream,
585                                 char       *base_file_name,
586                                 char      **result_file_name,
587                                 FT_Long    *result_offset )
588   {
589     /*
590       Only meaningful on systems with hfs+ drivers (or Macs).
591      */
592     FT_Error   error;
593     char*      newpath = NULL;
594     FT_Memory  memory;
595     FT_Long    base_file_len = (FT_Long)ft_strlen( base_file_name );
596 
597     FT_UNUSED( stream );
598 
599 
600     memory = library->memory;
601 
602     if ( base_file_len + 6 > FT_INT_MAX )
603       return FT_THROW( Array_Too_Large );
604 
605     if ( FT_QALLOC( newpath, base_file_len + 6 ) )
606       return error;
607 
608     FT_MEM_COPY( newpath, base_file_name, base_file_len );
609     FT_MEM_COPY( newpath + base_file_len, "/rsrc", 6 );
610 
611     *result_file_name = newpath;
612     *result_offset    = 0;
613 
614     return FT_Err_Ok;
615   }
616 
617 
618   static FT_Error
raccess_guess_darwin_newvfs(FT_Library library,FT_Stream stream,char * base_file_name,char ** result_file_name,FT_Long * result_offset)619   raccess_guess_darwin_newvfs( FT_Library  library,
620                                FT_Stream   stream,
621                                char       *base_file_name,
622                                char      **result_file_name,
623                                FT_Long    *result_offset )
624   {
625     /*
626       Only meaningful on systems with Mac OS X (> 10.1).
627      */
628     FT_Error   error;
629     char*      newpath = NULL;
630     FT_Memory  memory;
631     FT_Long    base_file_len = (FT_Long)ft_strlen( base_file_name );
632 
633     FT_UNUSED( stream );
634 
635 
636     memory = library->memory;
637 
638     if ( base_file_len + 18 > FT_INT_MAX )
639       return FT_THROW( Array_Too_Large );
640 
641     if ( FT_QALLOC( newpath, base_file_len + 18 ) )
642       return error;
643 
644     FT_MEM_COPY( newpath, base_file_name, base_file_len );
645     FT_MEM_COPY( newpath + base_file_len, "/..namedfork/rsrc", 18 );
646 
647     *result_file_name = newpath;
648     *result_offset    = 0;
649 
650     return FT_Err_Ok;
651   }
652 
653 
654   static FT_Error
raccess_guess_vfat(FT_Library library,FT_Stream stream,char * base_file_name,char ** result_file_name,FT_Long * result_offset)655   raccess_guess_vfat( FT_Library  library,
656                       FT_Stream   stream,
657                       char       *base_file_name,
658                       char      **result_file_name,
659                       FT_Long    *result_offset )
660   {
661     char*      newpath;
662     FT_Memory  memory;
663 
664     FT_UNUSED( stream );
665 
666 
667     memory = library->memory;
668 
669     newpath = raccess_make_file_name( memory, base_file_name,
670                                       "resource.frk/" );
671     if ( !newpath )
672       return FT_THROW( Out_Of_Memory );
673 
674     *result_file_name = newpath;
675     *result_offset    = 0;
676 
677     return FT_Err_Ok;
678   }
679 
680 
681   static FT_Error
raccess_guess_linux_cap(FT_Library library,FT_Stream stream,char * base_file_name,char ** result_file_name,FT_Long * result_offset)682   raccess_guess_linux_cap( FT_Library  library,
683                            FT_Stream   stream,
684                            char       *base_file_name,
685                            char      **result_file_name,
686                            FT_Long    *result_offset )
687   {
688     char*      newpath;
689     FT_Memory  memory;
690 
691     FT_UNUSED( stream );
692 
693 
694     memory = library->memory;
695 
696     newpath = raccess_make_file_name( memory, base_file_name, ".resource/" );
697     if ( !newpath )
698       return FT_THROW( Out_Of_Memory );
699 
700     *result_file_name = newpath;
701     *result_offset    = 0;
702 
703     return FT_Err_Ok;
704   }
705 
706 
707   static FT_Error
raccess_guess_linux_double(FT_Library library,FT_Stream stream,char * base_file_name,char ** result_file_name,FT_Long * result_offset)708   raccess_guess_linux_double( FT_Library  library,
709                               FT_Stream   stream,
710                               char       *base_file_name,
711                               char      **result_file_name,
712                               FT_Long    *result_offset )
713   {
714     char*      newpath;
715     FT_Error   error;
716     FT_Memory  memory;
717 
718     FT_UNUSED( stream );
719 
720 
721     memory = library->memory;
722 
723     newpath = raccess_make_file_name( memory, base_file_name, "%" );
724     if ( !newpath )
725       return FT_THROW( Out_Of_Memory );
726 
727     error = raccess_guess_linux_double_from_file_name( library, newpath,
728                                                        result_offset );
729     if ( !error )
730       *result_file_name = newpath;
731     else
732       FT_FREE( newpath );
733 
734     return error;
735   }
736 
737 
738   static FT_Error
raccess_guess_linux_netatalk(FT_Library library,FT_Stream stream,char * base_file_name,char ** result_file_name,FT_Long * result_offset)739   raccess_guess_linux_netatalk( FT_Library  library,
740                                 FT_Stream   stream,
741                                 char       *base_file_name,
742                                 char      **result_file_name,
743                                 FT_Long    *result_offset )
744   {
745     char*      newpath;
746     FT_Error   error;
747     FT_Memory  memory;
748 
749     FT_UNUSED( stream );
750 
751 
752     memory = library->memory;
753 
754     newpath = raccess_make_file_name( memory, base_file_name,
755                                       ".AppleDouble/" );
756     if ( !newpath )
757       return FT_THROW( Out_Of_Memory );
758 
759     error = raccess_guess_linux_double_from_file_name( library, newpath,
760                                                        result_offset );
761     if ( !error )
762       *result_file_name = newpath;
763     else
764       FT_FREE( newpath );
765 
766     return error;
767   }
768 
769 
770   static FT_Error
raccess_guess_apple_generic(FT_Library library,FT_Stream stream,char * base_file_name,FT_Int32 magic,FT_Long * result_offset)771   raccess_guess_apple_generic( FT_Library  library,
772                                FT_Stream   stream,
773                                char       *base_file_name,
774                                FT_Int32    magic,
775                                FT_Long    *result_offset )
776   {
777     FT_Int32   magic_from_stream;
778     FT_Error   error;
779     FT_Int32   version_number = 0;
780     FT_UShort  n_of_entries;
781 
782     int        i;
783     FT_Int32   entry_id, entry_offset, entry_length = 0;
784 
785     const FT_Int32  resource_fork_entry_id = 0x2;
786 
787     FT_UNUSED( library );
788     FT_UNUSED( base_file_name );
789     FT_UNUSED( version_number );
790     FT_UNUSED( entry_length   );
791 
792 
793     if ( FT_READ_LONG( magic_from_stream ) )
794       return error;
795     if ( magic_from_stream != magic )
796       return FT_THROW( Unknown_File_Format );
797 
798     if ( FT_READ_LONG( version_number ) )
799       return error;
800 
801     /* filler */
802     error = FT_Stream_Skip( stream, 16 );
803     if ( error )
804       return error;
805 
806     if ( FT_READ_USHORT( n_of_entries ) )
807       return error;
808     if ( n_of_entries == 0 )
809       return FT_THROW( Unknown_File_Format );
810 
811     for ( i = 0; i < n_of_entries; i++ )
812     {
813       if ( FT_READ_LONG( entry_id ) )
814         return error;
815       if ( entry_id == resource_fork_entry_id )
816       {
817         if ( FT_READ_LONG( entry_offset ) ||
818              FT_READ_LONG( entry_length ) )
819           continue;
820         *result_offset = entry_offset;
821 
822         return FT_Err_Ok;
823       }
824       else
825       {
826         error = FT_Stream_Skip( stream, 4 + 4 );    /* offset + length */
827         if ( error )
828           return error;
829       }
830     }
831 
832     return FT_THROW( Unknown_File_Format );
833   }
834 
835 
836   static FT_Error
raccess_guess_linux_double_from_file_name(FT_Library library,char * file_name,FT_Long * result_offset)837   raccess_guess_linux_double_from_file_name( FT_Library  library,
838                                              char       *file_name,
839                                              FT_Long    *result_offset )
840   {
841     FT_Open_Args  args2;
842     FT_Stream     stream2;
843     char*         nouse = NULL;
844     FT_Error      error;
845 
846 
847     args2.flags    = FT_OPEN_PATHNAME;
848     args2.pathname = file_name;
849     error = FT_Stream_New( library, &args2, &stream2 );
850     if ( error )
851       return error;
852 
853     error = raccess_guess_apple_double( library, stream2, file_name,
854                                         &nouse, result_offset );
855 
856     FT_Stream_Free( stream2, 0 );
857 
858     return error;
859   }
860 
861 
862   static char*
raccess_make_file_name(FT_Memory memory,const char * original_name,const char * insertion)863   raccess_make_file_name( FT_Memory    memory,
864                           const char  *original_name,
865                           const char  *insertion )
866   {
867     char*        new_name = NULL;
868     const char*  tmp;
869     const char*  slash;
870     size_t       new_length;
871     FT_Error     error = FT_Err_Ok;
872 
873     FT_UNUSED( error );
874 
875 
876     new_length = ft_strlen( original_name ) + ft_strlen( insertion );
877     if ( FT_QALLOC( new_name, new_length + 1 ) )
878       return NULL;
879 
880     tmp = ft_strrchr( original_name, '/' );
881     if ( tmp )
882     {
883       ft_strncpy( new_name,
884                   original_name,
885                   (size_t)( tmp - original_name + 1 ) );
886       new_name[tmp - original_name + 1] = '\0';
887       slash = tmp + 1;
888     }
889     else
890     {
891       slash       = original_name;
892       new_name[0] = '\0';
893     }
894 
895     ft_strcat( new_name, insertion );
896     ft_strcat( new_name, slash );
897 
898     return new_name;
899   }
900 
901 
902 #else   /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */
903 
904 
905   /**************************************************************************
906    *                 Dummy function; just sets errors
907    */
908 
909   FT_BASE_DEF( void )
FT_Raccess_Guess(FT_Library library,FT_Stream stream,char * base_name,char ** new_names,FT_Long * offsets,FT_Error * errors)910   FT_Raccess_Guess( FT_Library  library,
911                     FT_Stream   stream,
912                     char       *base_name,
913                     char      **new_names,
914                     FT_Long    *offsets,
915                     FT_Error   *errors )
916   {
917     FT_Int  i;
918 
919     FT_UNUSED( library );
920     FT_UNUSED( stream );
921     FT_UNUSED( base_name );
922 
923 
924     for ( i = 0; i < FT_RACCESS_N_RULES; i++ )
925     {
926       new_names[i] = NULL;
927       offsets[i]   = 0;
928       errors[i]    = FT_ERR( Unimplemented_Feature );
929     }
930   }
931 
932 
933 #endif  /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */
934 
935 
936 /* END */
937