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