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 */