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
;
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
,
421 raccess_get_rule_type_from_rule_index( FT_UInt rule_index
)
423 if ( rule_index
>= FT_RACCESS_N_RULES
)
424 return FT_RFork_Rule_invalid
;
426 return raccess_guess_table
[rule_index
].type
;
430 FT_LOCAL_DEF( FT_Bool
)
431 raccess_rule_by_darwin_vfs( FT_UInt rule_index
)
433 switch( raccess_get_rule_type_from_rule_index( rule_index
) )
435 case FT_RFork_Rule_darwin_newvfs
:
436 case FT_RFork_Rule_darwin_hfsplus
:
446 raccess_guess_apple_double( FT_Library library
,
448 char *base_file_name
,
449 char **result_file_name
,
450 FT_Long
*result_offset
)
452 FT_Int32 magic
= ( 0x00 << 24 ) |
458 *result_file_name
= NULL
;
459 if ( NULL
== stream
)
460 return FT_Err_Cannot_Open_Stream
;
462 return raccess_guess_apple_generic( library
, stream
, base_file_name
,
463 magic
, result_offset
);
468 raccess_guess_apple_single( FT_Library library
,
470 char *base_file_name
,
471 char **result_file_name
,
472 FT_Long
*result_offset
)
474 FT_Int32 magic
= ( 0x00 << 24 ) |
480 *result_file_name
= NULL
;
481 if ( NULL
== stream
)
482 return FT_Err_Cannot_Open_Stream
;
484 return raccess_guess_apple_generic( library
, stream
, base_file_name
,
485 magic
, result_offset
);
490 raccess_guess_darwin_ufs_export( FT_Library library
,
492 char *base_file_name
,
493 char **result_file_name
,
494 FT_Long
*result_offset
)
503 memory
= library
->memory
;
504 newpath
= raccess_make_file_name( memory
, base_file_name
, "._" );
506 return FT_Err_Out_Of_Memory
;
508 error
= raccess_guess_linux_double_from_file_name( library
, newpath
,
511 *result_file_name
= newpath
;
520 raccess_guess_darwin_hfsplus( FT_Library library
,
522 char *base_file_name
,
523 char **result_file_name
,
524 FT_Long
*result_offset
)
527 Only meaningful on systems with hfs+ drivers (or Macs).
532 FT_Long base_file_len
= ft_strlen( base_file_name
);
537 memory
= library
->memory
;
539 if ( base_file_len
+ 6 > FT_INT_MAX
)
540 return FT_Err_Array_Too_Large
;
542 if ( FT_ALLOC( newpath
, base_file_len
+ 6 ) )
545 FT_MEM_COPY( newpath
, base_file_name
, base_file_len
);
546 FT_MEM_COPY( newpath
+ base_file_len
, "/rsrc", 6 );
548 *result_file_name
= newpath
;
556 raccess_guess_darwin_newvfs( FT_Library library
,
558 char *base_file_name
,
559 char **result_file_name
,
560 FT_Long
*result_offset
)
563 Only meaningful on systems with Mac OS X (> 10.1).
568 FT_Long base_file_len
= ft_strlen( base_file_name
);
573 memory
= library
->memory
;
575 if ( base_file_len
+ 18 > FT_INT_MAX
)
576 return FT_Err_Array_Too_Large
;
578 if ( FT_ALLOC( newpath
, base_file_len
+ 18 ) )
581 FT_MEM_COPY( newpath
, base_file_name
, base_file_len
);
582 FT_MEM_COPY( newpath
+ base_file_len
, "/..namedfork/rsrc", 18 );
584 *result_file_name
= newpath
;
592 raccess_guess_vfat( FT_Library library
,
594 char *base_file_name
,
595 char **result_file_name
,
596 FT_Long
*result_offset
)
604 memory
= library
->memory
;
606 newpath
= raccess_make_file_name( memory
, base_file_name
,
609 return FT_Err_Out_Of_Memory
;
611 *result_file_name
= newpath
;
619 raccess_guess_linux_cap( FT_Library library
,
621 char *base_file_name
,
622 char **result_file_name
,
623 FT_Long
*result_offset
)
631 memory
= library
->memory
;
633 newpath
= raccess_make_file_name( memory
, base_file_name
, ".resource/" );
635 return FT_Err_Out_Of_Memory
;
637 *result_file_name
= newpath
;
645 raccess_guess_linux_double( FT_Library library
,
647 char *base_file_name
,
648 char **result_file_name
,
649 FT_Long
*result_offset
)
658 memory
= library
->memory
;
660 newpath
= raccess_make_file_name( memory
, base_file_name
, "%" );
662 return FT_Err_Out_Of_Memory
;
664 error
= raccess_guess_linux_double_from_file_name( library
, newpath
,
667 *result_file_name
= newpath
;
676 raccess_guess_linux_netatalk( FT_Library library
,
678 char *base_file_name
,
679 char **result_file_name
,
680 FT_Long
*result_offset
)
689 memory
= library
->memory
;
691 newpath
= raccess_make_file_name( memory
, base_file_name
,
694 return FT_Err_Out_Of_Memory
;
696 error
= raccess_guess_linux_double_from_file_name( library
, newpath
,
699 *result_file_name
= newpath
;
708 raccess_guess_apple_generic( FT_Library library
,
710 char *base_file_name
,
712 FT_Long
*result_offset
)
714 FT_Int32 magic_from_stream
;
716 FT_Int32 version_number
= 0;
717 FT_UShort n_of_entries
;
720 FT_UInt32 entry_id
, entry_offset
, entry_length
= 0;
722 const FT_UInt32 resource_fork_entry_id
= 0x2;
724 FT_UNUSED( library
);
725 FT_UNUSED( base_file_name
);
726 FT_UNUSED( version_number
);
727 FT_UNUSED( entry_length
);
730 if ( FT_READ_LONG( magic_from_stream
) )
732 if ( magic_from_stream
!= magic
)
733 return FT_Err_Unknown_File_Format
;
735 if ( FT_READ_LONG( version_number
) )
739 error
= FT_Stream_Skip( stream
, 16 );
743 if ( FT_READ_USHORT( n_of_entries
) )
745 if ( n_of_entries
== 0 )
746 return FT_Err_Unknown_File_Format
;
748 for ( i
= 0; i
< n_of_entries
; i
++ )
750 if ( FT_READ_LONG( entry_id
) )
752 if ( entry_id
== resource_fork_entry_id
)
754 if ( FT_READ_LONG( entry_offset
) ||
755 FT_READ_LONG( entry_length
) )
757 *result_offset
= entry_offset
;
763 error
= FT_Stream_Skip( stream
, 4 + 4 ); /* offset + length */
769 return FT_Err_Unknown_File_Format
;
774 raccess_guess_linux_double_from_file_name( FT_Library library
,
776 FT_Long
*result_offset
)
784 args2
.flags
= FT_OPEN_PATHNAME
;
785 args2
.pathname
= file_name
;
786 error
= FT_Stream_New( library
, &args2
, &stream2
);
790 error
= raccess_guess_apple_double( library
, stream2
, file_name
,
791 &nouse
, result_offset
);
793 FT_Stream_Free( stream2
, 0 );
800 raccess_make_file_name( FT_Memory memory
,
801 const char *original_name
,
802 const char *insertion
)
804 char* new_name
= NULL
;
808 FT_Error error
= FT_Err_Ok
;
813 new_length
= ft_strlen( original_name
) + ft_strlen( insertion
);
814 if ( FT_ALLOC( new_name
, new_length
+ 1 ) )
817 tmp
= ft_strrchr( original_name
, '/' );
820 ft_strncpy( new_name
, original_name
, tmp
- original_name
+ 1 );
821 new_name
[tmp
- original_name
+ 1] = '\0';
826 slash
= original_name
;
830 ft_strcat( new_name
, insertion
);
831 ft_strcat( new_name
, slash
);
837 #else /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */
840 /*************************************************************************/
841 /* Dummy function; just sets errors */
842 /*************************************************************************/
845 FT_Raccess_Guess( FT_Library library
,
854 FT_UNUSED( library
);
856 FT_UNUSED( base_name
);
859 for ( i
= 0; i
< FT_RACCESS_N_RULES
; i
++ )
863 errors
[i
] = FT_Err_Unimplemented_Feature
;
868 #endif /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */