1 /***************************************************************************/
5 /* Embedded resource forks accessor (body). */
7 /* Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010 by */
8 /* Masatake YAMATO and Redhat K.K. */
10 /* FT_Raccess_Get_HeaderInfo() and raccess_guess_darwin_hfsplus() are */
11 /* derived from ftobjs.c. */
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. */
19 /***************************************************************************/
21 /***************************************************************************/
22 /* Development of the code in this file is support of */
23 /* Information-technology Promotion Agency, Japan. */
24 /***************************************************************************/
28 #include FT_INTERNAL_DEBUG_H
29 #include FT_INTERNAL_STREAM_H
30 #include FT_INTERNAL_RFORK_H
34 #define FT_COMPONENT trace_raccess
37 /*************************************************************************/
38 /*************************************************************************/
39 /*************************************************************************/
42 /**** Resource fork directory access ****/
45 /*************************************************************************/
46 /*************************************************************************/
47 /*************************************************************************/
49 FT_BASE_DEF( FT_Error )
50 FT_Raccess_Get_HeaderInfo( FT_Library library,
57 unsigned char head[16], head2[16];
58 FT_Long map_pos, rdata_len;
59 int allzeros, allmatch, i;
65 error = FT_Stream_Seek( stream, rfork_offset );
69 error = FT_Stream_Read( stream, (FT_Byte *)head, 16 );
73 *rdata_pos = rfork_offset + ( ( head[0] << 24 ) |
77 map_pos = rfork_offset + ( ( head[4] << 24 ) |
81 rdata_len = ( head[ 8] << 24 ) |
86 /* map_len = head[12] .. head[15] */
88 if ( *rdata_pos + rdata_len != map_pos || map_pos == rfork_offset )
89 return FT_Err_Unknown_File_Format;
91 error = FT_Stream_Seek( stream, map_pos );
95 head2[15] = (FT_Byte)( head[15] + 1 ); /* make it be different */
97 error = FT_Stream_Read( stream, (FT_Byte*)head2, 16 );
103 for ( i = 0; i < 16; ++i )
107 if ( head2[i] != head[i] )
110 if ( !allzeros && !allmatch )
111 return FT_Err_Unknown_File_Format;
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 */
117 (void)FT_STREAM_SKIP( 4 /* skip handle to next resource map */
118 + 2 /* skip file resource number */
119 + 2 ); /* skip attributes */
121 if ( FT_READ_USHORT( type_list ) )
123 if ( type_list == -1 )
124 return FT_Err_Unknown_File_Format;
126 error = FT_Stream_Seek( stream, map_pos + type_list );
130 *map_offset = map_pos + type_list;
136 ft_raccess_sort_ref_by_id( FT_RFork_Ref* a,
139 if ( a->res_id < b->res_id )
141 else if ( a->res_id > b->res_id )
148 FT_BASE_DEF( FT_Error )
149 FT_Raccess_Get_DataOffsets( FT_Library library,
158 int i, j, cnt, subcnt;
159 FT_Long tag_internal, rpos;
160 FT_Memory memory = library->memory;
162 FT_Long *offsets_internal = NULL;
163 FT_RFork_Ref *ref = NULL;
166 error = FT_Stream_Seek( stream, map_offset );
170 if ( FT_READ_USHORT( cnt ) )
174 for ( i = 0; i < cnt; ++i )
176 if ( FT_READ_LONG( tag_internal ) ||
177 FT_READ_USHORT( subcnt ) ||
178 FT_READ_USHORT( rpos ) )
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 ) ) ));
187 if ( tag_internal == tag )
192 error = FT_Stream_Seek( stream, rpos );
196 if ( FT_NEW_ARRAY( ref, *count ) )
199 for ( j = 0; j < *count; ++j )
201 if ( FT_READ_USHORT( ref[j].res_id ) )
203 if ( FT_STREAM_SKIP( 2 ) ) /* resource name */
205 if ( FT_READ_LONG( temp ) )
207 if ( FT_STREAM_SKIP( 4 ) ) /* mbz */
210 ref[j].offset = temp & 0xFFFFFFL;
213 ft_qsort( ref, *count, sizeof ( FT_RFork_Ref ),
214 ( int(*)(const void*, const void*) )
215 ft_raccess_sort_ref_by_id );
217 if ( FT_NEW_ARRAY( offsets_internal, *count ) )
220 /* XXX: duplicated reference ID,
221 * gap between reference IDs are acceptable?
222 * further investigation on Apple implementation is needed.
224 for ( j = 0; j < *count; ++j )
225 offsets_internal[j] = rdata_pos + ref[j].offset;
227 *offsets = offsets_internal;
236 return FT_Err_Cannot_Open_Resource;
240 #ifdef FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK
242 /*************************************************************************/
243 /*************************************************************************/
244 /*************************************************************************/
247 /**** Guessing functions ****/
249 /**** When you add a new guessing function, ****/
250 /**** update FT_RACCESS_N_RULES in ftrfork.h. ****/
252 /*************************************************************************/
253 /*************************************************************************/
254 /*************************************************************************/
257 (*raccess_guess_func)( FT_Library library,
259 char *base_file_name,
260 char **result_file_name,
261 FT_Long *result_offset );
265 raccess_guess_apple_double( FT_Library library,
267 char *base_file_name,
268 char **result_file_name,
269 FT_Long *result_offset );
272 raccess_guess_apple_single( FT_Library library,
274 char *base_file_name,
275 char **result_file_name,
276 FT_Long *result_offset );
279 raccess_guess_darwin_ufs_export( FT_Library library,
281 char *base_file_name,
282 char **result_file_name,
283 FT_Long *result_offset );
286 raccess_guess_darwin_newvfs( FT_Library library,
288 char *base_file_name,
289 char **result_file_name,
290 FT_Long *result_offset );
293 raccess_guess_darwin_hfsplus( FT_Library library,
295 char *base_file_name,
296 char **result_file_name,
297 FT_Long *result_offset );
300 raccess_guess_vfat( FT_Library library,
302 char *base_file_name,
303 char **result_file_name,
304 FT_Long *result_offset );
307 raccess_guess_linux_cap( FT_Library library,
309 char *base_file_name,
310 char **result_file_name,
311 FT_Long *result_offset );
314 raccess_guess_linux_double( FT_Library library,
316 char *base_file_name,
317 char **result_file_name,
318 FT_Long *result_offset );
321 raccess_guess_linux_netatalk( FT_Library library,
323 char *base_file_name,
324 char **result_file_name,
325 FT_Long *result_offset );
328 /*************************************************************************/
330 /**** Helper functions ****/
332 /*************************************************************************/
335 raccess_guess_apple_generic( FT_Library library,
337 char *base_file_name,
339 FT_Long *result_offset );
342 raccess_guess_linux_double_from_file_name( FT_Library library,
344 FT_Long *result_offset );
347 raccess_make_file_name( FT_Memory memory,
348 const char *original_name,
349 const char *insertion );
352 typedef enum FT_RFork_Rule_ {
353 FT_RFork_Rule_invalid = -2,
354 FT_RFork_Rule_uknown, /* -1 */
355 FT_RFork_Rule_apple_double,
356 FT_RFork_Rule_apple_single,
357 FT_RFork_Rule_darwin_ufs_export,
358 FT_RFork_Rule_darwin_newvfs,
359 FT_RFork_Rule_darwin_hfsplus,
361 FT_RFork_Rule_linux_cap,
362 FT_RFork_Rule_linux_double,
363 FT_RFork_Rule_linux_netatalk
366 /* For fast translation between rule index and rule type,
367 * the macros FT_RFORK_xxx should be kept consistent with
368 * the raccess_guess_funcs table
370 typedef struct raccess_guess_rec_ {
371 raccess_guess_func func;
375 static raccess_guess_rec raccess_guess_table[FT_RACCESS_N_RULES] =
377 { raccess_guess_apple_double, FT_RFork_Rule_apple_double, },
378 { raccess_guess_apple_single, FT_RFork_Rule_apple_single, },
379 { raccess_guess_darwin_ufs_export, FT_RFork_Rule_darwin_ufs_export, },
380 { raccess_guess_darwin_newvfs, FT_RFork_Rule_darwin_newvfs, },
381 { raccess_guess_darwin_hfsplus, FT_RFork_Rule_darwin_hfsplus, },
382 { raccess_guess_vfat, FT_RFork_Rule_vfat, },
383 { raccess_guess_linux_cap, FT_RFork_Rule_linux_cap, },
384 { raccess_guess_linux_double, FT_RFork_Rule_linux_double, },
385 { raccess_guess_linux_netatalk, FT_RFork_Rule_linux_netatalk, },
389 FT_Raccess_Guess( FT_Library library,
399 for ( i = 0; i < FT_RACCESS_N_RULES; i++ )
402 if ( NULL != stream )
403 errors[i] = FT_Stream_Seek( stream, 0 );
405 errors[i] = FT_Err_Ok;
410 errors[i] = (raccess_guess_table[i].func)( library,
420 #if !defined( FT_MACINTOSH ) || defined( DARWIN_NO_CARBON )
422 raccess_get_rule_type_from_rule_index( FT_UInt rule_index )
424 if ( rule_index >= FT_RACCESS_N_RULES )
425 return FT_RFork_Rule_invalid;
427 return raccess_guess_table[rule_index].type;
431 FT_LOCAL_DEF( FT_Bool )
432 raccess_rule_by_darwin_vfs( FT_UInt rule_index )
434 switch( raccess_get_rule_type_from_rule_index( rule_index ) )
436 case FT_RFork_Rule_darwin_newvfs:
437 case FT_RFork_Rule_darwin_hfsplus:
448 raccess_guess_apple_double( FT_Library library,
450 char *base_file_name,
451 char **result_file_name,
452 FT_Long *result_offset )
454 FT_Int32 magic = ( 0x00 << 24 ) |
460 *result_file_name = NULL;
461 if ( NULL == stream )
462 return FT_Err_Cannot_Open_Stream;
464 return raccess_guess_apple_generic( library, stream, base_file_name,
465 magic, result_offset );
470 raccess_guess_apple_single( FT_Library library,
472 char *base_file_name,
473 char **result_file_name,
474 FT_Long *result_offset )
476 FT_Int32 magic = ( 0x00 << 24 ) |
482 *result_file_name = NULL;
483 if ( NULL == stream )
484 return FT_Err_Cannot_Open_Stream;
486 return raccess_guess_apple_generic( library, stream, base_file_name,
487 magic, result_offset );
492 raccess_guess_darwin_ufs_export( FT_Library library,
494 char *base_file_name,
495 char **result_file_name,
496 FT_Long *result_offset )
505 memory = library->memory;
506 newpath = raccess_make_file_name( memory, base_file_name, "._" );
508 return FT_Err_Out_Of_Memory;
510 error = raccess_guess_linux_double_from_file_name( library, newpath,
513 *result_file_name = newpath;
522 raccess_guess_darwin_hfsplus( FT_Library library,
524 char *base_file_name,
525 char **result_file_name,
526 FT_Long *result_offset )
529 Only meaningful on systems with hfs+ drivers (or Macs).
532 char* newpath = NULL;
534 FT_Long base_file_len = ft_strlen( base_file_name );
539 memory = library->memory;
541 if ( base_file_len + 6 > FT_INT_MAX )
542 return FT_Err_Array_Too_Large;
544 if ( FT_ALLOC( newpath, base_file_len + 6 ) )
547 FT_MEM_COPY( newpath, base_file_name, base_file_len );
548 FT_MEM_COPY( newpath + base_file_len, "/rsrc", 6 );
550 *result_file_name = newpath;
558 raccess_guess_darwin_newvfs( FT_Library library,
560 char *base_file_name,
561 char **result_file_name,
562 FT_Long *result_offset )
565 Only meaningful on systems with Mac OS X (> 10.1).
568 char* newpath = NULL;
570 FT_Long base_file_len = ft_strlen( base_file_name );
575 memory = library->memory;
577 if ( base_file_len + 18 > FT_INT_MAX )
578 return FT_Err_Array_Too_Large;
580 if ( FT_ALLOC( newpath, base_file_len + 18 ) )
583 FT_MEM_COPY( newpath, base_file_name, base_file_len );
584 FT_MEM_COPY( newpath + base_file_len, "/..namedfork/rsrc", 18 );
586 *result_file_name = newpath;
594 raccess_guess_vfat( FT_Library library,
596 char *base_file_name,
597 char **result_file_name,
598 FT_Long *result_offset )
606 memory = library->memory;
608 newpath = raccess_make_file_name( memory, base_file_name,
611 return FT_Err_Out_Of_Memory;
613 *result_file_name = newpath;
621 raccess_guess_linux_cap( FT_Library library,
623 char *base_file_name,
624 char **result_file_name,
625 FT_Long *result_offset )
633 memory = library->memory;
635 newpath = raccess_make_file_name( memory, base_file_name, ".resource/" );
637 return FT_Err_Out_Of_Memory;
639 *result_file_name = newpath;
647 raccess_guess_linux_double( FT_Library library,
649 char *base_file_name,
650 char **result_file_name,
651 FT_Long *result_offset )
660 memory = library->memory;
662 newpath = raccess_make_file_name( memory, base_file_name, "%" );
664 return FT_Err_Out_Of_Memory;
666 error = raccess_guess_linux_double_from_file_name( library, newpath,
669 *result_file_name = newpath;
678 raccess_guess_linux_netatalk( FT_Library library,
680 char *base_file_name,
681 char **result_file_name,
682 FT_Long *result_offset )
691 memory = library->memory;
693 newpath = raccess_make_file_name( memory, base_file_name,
696 return FT_Err_Out_Of_Memory;
698 error = raccess_guess_linux_double_from_file_name( library, newpath,
701 *result_file_name = newpath;
710 raccess_guess_apple_generic( FT_Library library,
712 char *base_file_name,
714 FT_Long *result_offset )
716 FT_Int32 magic_from_stream;
718 FT_Int32 version_number = 0;
719 FT_UShort n_of_entries;
722 FT_UInt32 entry_id, entry_offset, entry_length = 0;
724 const FT_UInt32 resource_fork_entry_id = 0x2;
726 FT_UNUSED( library );
727 FT_UNUSED( base_file_name );
728 FT_UNUSED( version_number );
729 FT_UNUSED( entry_length );
732 if ( FT_READ_LONG( magic_from_stream ) )
734 if ( magic_from_stream != magic )
735 return FT_Err_Unknown_File_Format;
737 if ( FT_READ_LONG( version_number ) )
741 error = FT_Stream_Skip( stream, 16 );
745 if ( FT_READ_USHORT( n_of_entries ) )
747 if ( n_of_entries == 0 )
748 return FT_Err_Unknown_File_Format;
750 for ( i = 0; i < n_of_entries; i++ )
752 if ( FT_READ_LONG( entry_id ) )
754 if ( entry_id == resource_fork_entry_id )
756 if ( FT_READ_LONG( entry_offset ) ||
757 FT_READ_LONG( entry_length ) )
759 *result_offset = entry_offset;
765 error = FT_Stream_Skip( stream, 4 + 4 ); /* offset + length */
771 return FT_Err_Unknown_File_Format;
776 raccess_guess_linux_double_from_file_name( FT_Library library,
778 FT_Long *result_offset )
786 args2.flags = FT_OPEN_PATHNAME;
787 args2.pathname = file_name;
788 error = FT_Stream_New( library, &args2, &stream2 );
792 error = raccess_guess_apple_double( library, stream2, file_name,
793 &nouse, result_offset );
795 FT_Stream_Free( stream2, 0 );
802 raccess_make_file_name( FT_Memory memory,
803 const char *original_name,
804 const char *insertion )
806 char* new_name = NULL;
810 FT_Error error = FT_Err_Ok;
815 new_length = ft_strlen( original_name ) + ft_strlen( insertion );
816 if ( FT_ALLOC( new_name, new_length + 1 ) )
819 tmp = ft_strrchr( original_name, '/' );
822 ft_strncpy( new_name, original_name, tmp - original_name + 1 );
823 new_name[tmp - original_name + 1] = '\0';
828 slash = original_name;
832 ft_strcat( new_name, insertion );
833 ft_strcat( new_name, slash );
839 #else /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */
842 /*************************************************************************/
843 /* Dummy function; just sets errors */
844 /*************************************************************************/
847 FT_Raccess_Guess( FT_Library library,
856 FT_UNUSED( library );
858 FT_UNUSED( base_name );
861 for ( i = 0; i < FT_RACCESS_N_RULES; i++ )
865 errors[i] = FT_Err_Unimplemented_Feature;
870 #endif /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */