Home | History | Annotate | Download | only in base
      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 )
     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
    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 )
    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 )
    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
    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 )
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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*
    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 )
    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