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