Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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