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