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