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