1 /***************************************************************************/
5 /* Embedded resource forks accessor (body). */
7 /* Copyright 2004-2010, 2013, 2014 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
35 #define FT_COMPONENT trace_raccess
38 /*************************************************************************/
39 /*************************************************************************/
40 /*************************************************************************/
43 /**** Resource fork directory access ****/
46 /*************************************************************************/
47 /*************************************************************************/
48 /*************************************************************************/
50 FT_BASE_DEF( FT_Error )
51 FT_Raccess_Get_HeaderInfo( FT_Library library,
58 unsigned char head[16], head2[16];
59 FT_Long map_pos, rdata_len;
60 int allzeros, allmatch, i;
66 error = FT_Stream_Seek( stream, rfork_offset );
70 error = FT_Stream_Read( stream, (FT_Byte *)head, 16 );
74 *rdata_pos = rfork_offset + ( ( head[0] << 24 ) |
78 map_pos = rfork_offset + ( ( head[4] << 24 ) |
82 rdata_len = ( head[ 8] << 24 ) |
87 /* map_len = head[12] .. head[15] */
89 if ( *rdata_pos + rdata_len != map_pos || map_pos == rfork_offset )
90 return FT_THROW( Unknown_File_Format );
92 error = FT_Stream_Seek( stream, map_pos );
96 head2[15] = (FT_Byte)( head[15] + 1 ); /* make it be different */
98 error = FT_Stream_Read( stream, (FT_Byte*)head2, 16 );
104 for ( i = 0; i < 16; ++i )
108 if ( head2[i] != head[i] )
111 if ( !allzeros && !allmatch )
112 return FT_THROW( Unknown_File_Format );
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 */
118 (void)FT_STREAM_SKIP( 4 /* skip handle to next resource map */
119 + 2 /* skip file resource number */
120 + 2 ); /* skip attributes */
122 if ( FT_READ_USHORT( type_list ) )
124 if ( type_list == -1 )
125 return FT_THROW( Unknown_File_Format );
127 error = FT_Stream_Seek( stream, map_pos + type_list );
131 *map_offset = map_pos + type_list;
137 ft_raccess_sort_ref_by_id( FT_RFork_Ref* a,
140 if ( a->res_id < b->res_id )
142 else if ( a->res_id > b->res_id )
149 FT_BASE_DEF( FT_Error )
150 FT_Raccess_Get_DataOffsets( FT_Library library,
155 FT_Bool sort_by_res_id,
160 int i, j, cnt, subcnt;
161 FT_Long tag_internal, rpos;
162 FT_Memory memory = library->memory;
164 FT_Long *offsets_internal = NULL;
165 FT_RFork_Ref *ref = NULL;
169 error = FT_Stream_Seek( stream, map_offset );
173 if ( FT_READ_USHORT( cnt ) )
177 for ( i = 0; i < cnt; ++i )
179 if ( FT_READ_LONG( tag_internal ) ||
180 FT_READ_USHORT( subcnt ) ||
181 FT_READ_USHORT( rpos ) )
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",
192 if ( tag_internal == tag )
197 error = FT_Stream_Seek( stream, rpos );
201 if ( FT_NEW_ARRAY( ref, *count ) )
204 for ( j = 0; j < *count; ++j )
206 if ( FT_READ_USHORT( ref[j].res_id ) )
208 if ( FT_STREAM_SKIP( 2 ) ) /* resource name */
210 if ( FT_READ_LONG( temp ) )
212 if ( FT_STREAM_SKIP( 4 ) ) /* mbz */
215 ref[j].offset = temp & 0xFFFFFFL;
217 " resource_id=0x%04x, offset=0x%08x\n",
218 j, ref[j].res_id, ref[j].offset ));
223 ft_qsort( ref, *count, sizeof ( FT_RFork_Ref ),
224 ( int(*)(const void*, const void*) )
225 ft_raccess_sort_ref_by_id );
227 FT_TRACE3(( " -- sort resources by their ids --\n" ));
228 for ( j = 0; j < *count; ++ j ) {
230 " resource_id=0x%04x, offset=0x%08x\n",
231 j, ref[j].res_id, ref[j].offset ));
235 if ( FT_NEW_ARRAY( offsets_internal, *count ) )
238 /* XXX: duplicated reference ID,
239 * gap between reference IDs are acceptable?
240 * further investigation on Apple implementation is needed.
242 for ( j = 0; j < *count; ++j )
243 offsets_internal[j] = rdata_pos + ref[j].offset;
245 *offsets = offsets_internal;
254 return FT_THROW( Cannot_Open_Resource );
258 #ifdef FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK
260 /*************************************************************************/
261 /*************************************************************************/
262 /*************************************************************************/
265 /**** Guessing functions ****/
267 /**** When you add a new guessing function, ****/
268 /**** update FT_RACCESS_N_RULES in ftrfork.h. ****/
270 /*************************************************************************/
271 /*************************************************************************/
272 /*************************************************************************/
275 raccess_guess_apple_double( FT_Library library,
277 char *base_file_name,
278 char **result_file_name,
279 FT_Long *result_offset );
282 raccess_guess_apple_single( FT_Library library,
284 char *base_file_name,
285 char **result_file_name,
286 FT_Long *result_offset );
289 raccess_guess_darwin_ufs_export( FT_Library library,
291 char *base_file_name,
292 char **result_file_name,
293 FT_Long *result_offset );
296 raccess_guess_darwin_newvfs( FT_Library library,
298 char *base_file_name,
299 char **result_file_name,
300 FT_Long *result_offset );
303 raccess_guess_darwin_hfsplus( FT_Library library,
305 char *base_file_name,
306 char **result_file_name,
307 FT_Long *result_offset );
310 raccess_guess_vfat( FT_Library library,
312 char *base_file_name,
313 char **result_file_name,
314 FT_Long *result_offset );
317 raccess_guess_linux_cap( FT_Library library,
319 char *base_file_name,
320 char **result_file_name,
321 FT_Long *result_offset );
324 raccess_guess_linux_double( FT_Library library,
326 char *base_file_name,
327 char **result_file_name,
328 FT_Long *result_offset );
331 raccess_guess_linux_netatalk( FT_Library library,
333 char *base_file_name,
334 char **result_file_name,
335 FT_Long *result_offset );
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
352 /*************************************************************************/
354 /**** Helper functions ****/
356 /*************************************************************************/
359 raccess_guess_apple_generic( FT_Library library,
361 char *base_file_name,
363 FT_Long *result_offset );
366 raccess_guess_linux_double_from_file_name( FT_Library library,
368 FT_Long *result_offset );
371 raccess_make_file_name( FT_Memory memory,
372 const char *original_name,
373 const char *insertion );
376 FT_Raccess_Guess( FT_Library library,
386 for ( i = 0; i < FT_RACCESS_N_RULES; i++ )
389 if ( NULL != stream )
390 errors[i] = FT_Stream_Seek( stream, 0 );
392 errors[i] = FT_Err_Ok;
397 errors[i] = (FT_RACCESS_GUESS_TABLE_GET[i].func)( library,
409 raccess_get_rule_type_from_rule_index( FT_Library library,
412 FT_UNUSED( library );
414 if ( rule_index >= FT_RACCESS_N_RULES )
415 return FT_RFork_Rule_invalid;
417 return FT_RACCESS_GUESS_TABLE_GET[rule_index].type;
422 * For this function, refer ftbase.h.
424 FT_LOCAL_DEF( FT_Bool )
425 ft_raccess_rule_by_darwin_vfs( FT_Library library,
428 switch( raccess_get_rule_type_from_rule_index( library, rule_index ) )
430 case FT_RFork_Rule_darwin_newvfs:
431 case FT_RFork_Rule_darwin_hfsplus:
442 raccess_guess_apple_double( FT_Library library,
444 char *base_file_name,
445 char **result_file_name,
446 FT_Long *result_offset )
448 FT_Int32 magic = ( 0x00 << 24 ) |
454 *result_file_name = NULL;
455 if ( NULL == stream )
456 return FT_THROW( Cannot_Open_Stream );
458 return raccess_guess_apple_generic( library, stream, base_file_name,
459 magic, result_offset );
464 raccess_guess_apple_single( FT_Library library,
466 char *base_file_name,
467 char **result_file_name,
468 FT_Long *result_offset )
470 FT_Int32 magic = ( 0x00 << 24 ) |
476 *result_file_name = NULL;
477 if ( NULL == stream )
478 return FT_THROW( Cannot_Open_Stream );
480 return raccess_guess_apple_generic( library, stream, base_file_name,
481 magic, result_offset );
486 raccess_guess_darwin_ufs_export( FT_Library library,
488 char *base_file_name,
489 char **result_file_name,
490 FT_Long *result_offset )
499 memory = library->memory;
500 newpath = raccess_make_file_name( memory, base_file_name, "._" );
502 return FT_THROW( Out_Of_Memory );
504 error = raccess_guess_linux_double_from_file_name( library, newpath,
507 *result_file_name = newpath;
516 raccess_guess_darwin_hfsplus( FT_Library library,
518 char *base_file_name,
519 char **result_file_name,
520 FT_Long *result_offset )
523 Only meaningful on systems with hfs+ drivers (or Macs).
526 char* newpath = NULL;
528 FT_Long base_file_len = (FT_Long)ft_strlen( base_file_name );
533 memory = library->memory;
535 if ( base_file_len + 6 > FT_INT_MAX )
536 return FT_THROW( Array_Too_Large );
538 if ( FT_ALLOC( newpath, base_file_len + 6 ) )
541 FT_MEM_COPY( newpath, base_file_name, base_file_len );
542 FT_MEM_COPY( newpath + base_file_len, "/rsrc", 6 );
544 *result_file_name = newpath;
552 raccess_guess_darwin_newvfs( FT_Library library,
554 char *base_file_name,
555 char **result_file_name,
556 FT_Long *result_offset )
559 Only meaningful on systems with Mac OS X (> 10.1).
562 char* newpath = NULL;
564 FT_Long base_file_len = (FT_Long)ft_strlen( base_file_name );
569 memory = library->memory;
571 if ( base_file_len + 18 > FT_INT_MAX )
572 return FT_THROW( Array_Too_Large );
574 if ( FT_ALLOC( newpath, base_file_len + 18 ) )
577 FT_MEM_COPY( newpath, base_file_name, base_file_len );
578 FT_MEM_COPY( newpath + base_file_len, "/..namedfork/rsrc", 18 );
580 *result_file_name = newpath;
588 raccess_guess_vfat( FT_Library library,
590 char *base_file_name,
591 char **result_file_name,
592 FT_Long *result_offset )
600 memory = library->memory;
602 newpath = raccess_make_file_name( memory, base_file_name,
605 return FT_THROW( Out_Of_Memory );
607 *result_file_name = newpath;
615 raccess_guess_linux_cap( FT_Library library,
617 char *base_file_name,
618 char **result_file_name,
619 FT_Long *result_offset )
627 memory = library->memory;
629 newpath = raccess_make_file_name( memory, base_file_name, ".resource/" );
631 return FT_THROW( Out_Of_Memory );
633 *result_file_name = newpath;
641 raccess_guess_linux_double( FT_Library library,
643 char *base_file_name,
644 char **result_file_name,
645 FT_Long *result_offset )
654 memory = library->memory;
656 newpath = raccess_make_file_name( memory, base_file_name, "%" );
658 return FT_THROW( Out_Of_Memory );
660 error = raccess_guess_linux_double_from_file_name( library, newpath,
663 *result_file_name = newpath;
672 raccess_guess_linux_netatalk( FT_Library library,
674 char *base_file_name,
675 char **result_file_name,
676 FT_Long *result_offset )
685 memory = library->memory;
687 newpath = raccess_make_file_name( memory, base_file_name,
690 return FT_THROW( Out_Of_Memory );
692 error = raccess_guess_linux_double_from_file_name( library, newpath,
695 *result_file_name = newpath;
704 raccess_guess_apple_generic( FT_Library library,
706 char *base_file_name,
708 FT_Long *result_offset )
710 FT_Int32 magic_from_stream;
712 FT_Int32 version_number = 0;
713 FT_UShort n_of_entries;
716 FT_UInt32 entry_id, entry_offset, entry_length = 0;
718 const FT_UInt32 resource_fork_entry_id = 0x2;
720 FT_UNUSED( library );
721 FT_UNUSED( base_file_name );
722 FT_UNUSED( version_number );
723 FT_UNUSED( entry_length );
726 if ( FT_READ_LONG( magic_from_stream ) )
728 if ( magic_from_stream != magic )
729 return FT_THROW( Unknown_File_Format );
731 if ( FT_READ_LONG( version_number ) )
735 error = FT_Stream_Skip( stream, 16 );
739 if ( FT_READ_USHORT( n_of_entries ) )
741 if ( n_of_entries == 0 )
742 return FT_THROW( Unknown_File_Format );
744 for ( i = 0; i < n_of_entries; i++ )
746 if ( FT_READ_LONG( entry_id ) )
748 if ( entry_id == resource_fork_entry_id )
750 if ( FT_READ_LONG( entry_offset ) ||
751 FT_READ_LONG( entry_length ) )
753 *result_offset = entry_offset;
759 error = FT_Stream_Skip( stream, 4 + 4 ); /* offset + length */
765 return FT_THROW( Unknown_File_Format );
770 raccess_guess_linux_double_from_file_name( FT_Library library,
772 FT_Long *result_offset )
780 args2.flags = FT_OPEN_PATHNAME;
781 args2.pathname = file_name;
782 error = FT_Stream_New( library, &args2, &stream2 );
786 error = raccess_guess_apple_double( library, stream2, file_name,
787 &nouse, result_offset );
789 FT_Stream_Free( stream2, 0 );
796 raccess_make_file_name( FT_Memory memory,
797 const char *original_name,
798 const char *insertion )
800 char* new_name = NULL;
804 FT_Error error = FT_Err_Ok;
809 new_length = ft_strlen( original_name ) + ft_strlen( insertion );
810 if ( FT_ALLOC( new_name, new_length + 1 ) )
813 tmp = ft_strrchr( original_name, '/' );
816 ft_strncpy( new_name, original_name, tmp - original_name + 1 );
817 new_name[tmp - original_name + 1] = '\0';
822 slash = original_name;
826 ft_strcat( new_name, insertion );
827 ft_strcat( new_name, slash );
833 #else /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */
836 /*************************************************************************/
837 /* Dummy function; just sets errors */
838 /*************************************************************************/
841 FT_Raccess_Guess( FT_Library library,
850 FT_UNUSED( library );
852 FT_UNUSED( base_name );
855 for ( i = 0; i < FT_RACCESS_N_RULES; i++ )
859 errors[i] = FT_ERR( Unimplemented_Feature );
864 #endif /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */