1 /***************************************************************************/
5 /* Embedded resource forks accessor (body). */
7 /* Copyright 2004-2018 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
, map_len
, rdata_len
;
60 int allzeros
, allmatch
, i
;
66 error
= FT_Stream_Seek( stream
, (FT_ULong
)rfork_offset
);
70 error
= FT_Stream_Read( stream
, (FT_Byte
*)head
, 16 );
74 /* ensure positive values */
75 if ( head
[0] >= 0x80 ||
79 return FT_THROW( Unknown_File_Format
);
81 *rdata_pos
= ( head
[ 0] << 24 ) |
85 map_pos
= ( head
[ 4] << 24 ) |
89 rdata_len
= ( head
[ 8] << 24 ) |
93 map_len
= ( head
[12] << 24 ) |
98 /* the map must not be empty */
100 return FT_THROW( Unknown_File_Format
);
102 /* check whether rdata and map overlap */
103 if ( *rdata_pos
< map_pos
)
105 if ( *rdata_pos
> map_pos
- rdata_len
)
106 return FT_THROW( Unknown_File_Format
);
110 if ( map_pos
> *rdata_pos
- map_len
)
111 return FT_THROW( Unknown_File_Format
);
114 /* check whether end of rdata or map exceeds stream size */
115 if ( FT_LONG_MAX
- rdata_len
< *rdata_pos
||
116 FT_LONG_MAX
- map_len
< map_pos
||
118 FT_LONG_MAX
- ( *rdata_pos
+ rdata_len
) < rfork_offset
||
119 FT_LONG_MAX
- ( map_pos
+ map_len
) < rfork_offset
||
121 (FT_ULong
)( rfork_offset
+ *rdata_pos
+ rdata_len
) > stream
->size
||
122 (FT_ULong
)( rfork_offset
+ map_pos
+ map_len
) > stream
->size
)
123 return FT_THROW( Unknown_File_Format
);
125 *rdata_pos
+= rfork_offset
;
126 map_pos
+= rfork_offset
;
128 error
= FT_Stream_Seek( stream
, (FT_ULong
)map_pos
);
132 head2
[15] = (FT_Byte
)( head
[15] + 1 ); /* make it be different */
134 error
= FT_Stream_Read( stream
, (FT_Byte
*)head2
, 16 );
140 for ( i
= 0; i
< 16; i
++ )
144 if ( head2
[i
] != head
[i
] )
147 if ( !allzeros
&& !allmatch
)
148 return FT_THROW( Unknown_File_Format
);
150 /* If we have reached this point then it is probably a mac resource */
151 /* file. Now, does it contain any interesting resources? */
153 (void)FT_STREAM_SKIP( 4 /* skip handle to next resource map */
154 + 2 /* skip file resource number */
155 + 2 ); /* skip attributes */
157 if ( FT_READ_SHORT( type_list
) )
160 return FT_THROW( Unknown_File_Format
);
162 error
= FT_Stream_Seek( stream
, (FT_ULong
)( map_pos
+ type_list
) );
166 *map_offset
= map_pos
+ type_list
;
172 ft_raccess_sort_ref_by_id( FT_RFork_Ref
* a
,
175 if ( a
->res_id
< b
->res_id
)
177 else if ( a
->res_id
> b
->res_id
)
184 FT_BASE_DEF( FT_Error
)
185 FT_Raccess_Get_DataOffsets( FT_Library library
,
190 FT_Bool sort_by_res_id
,
195 int i
, j
, cnt
, subcnt
;
196 FT_Long tag_internal
, rpos
;
197 FT_Memory memory
= library
->memory
;
199 FT_Long
*offsets_internal
= NULL
;
200 FT_RFork_Ref
*ref
= NULL
;
204 error
= FT_Stream_Seek( stream
, (FT_ULong
)map_offset
);
208 if ( FT_READ_SHORT( cnt
) )
212 /* `rpos' is a signed 16bit integer offset to resource records; the */
213 /* size of a resource record is 12 bytes. The map header is 28 bytes, */
214 /* and a type list needs 10 bytes or more. If we assume that the name */
215 /* list is empty and we have only a single entry in the type list, */
216 /* there can be at most */
218 /* (32768 - 28 - 10) / 12 = 2727 */
222 /* A type list starts with a two-byte counter, followed by 10-byte */
223 /* type records. Assuming that there are no resources, the number of */
224 /* type records can be at most */
226 /* (32768 - 28 - 2) / 8 = 4079 */
229 return FT_THROW( Invalid_Table
);
231 for ( i
= 0; i
< cnt
; i
++ )
233 if ( FT_READ_LONG( tag_internal
) ||
234 FT_READ_SHORT( subcnt
) ||
235 FT_READ_SHORT( rpos
) )
238 FT_TRACE2(( "Resource tags: %c%c%c%c\n",
239 (char)( 0xFF & ( tag_internal
>> 24 ) ),
240 (char)( 0xFF & ( tag_internal
>> 16 ) ),
241 (char)( 0xFF & ( tag_internal
>> 8 ) ),
242 (char)( 0xFF & ( tag_internal
>> 0 ) ) ));
243 FT_TRACE3(( " : subcount=%d, suboffset=0x%04x\n",
246 if ( tag_internal
== tag
)
251 /* a zero count might be valid in the resource specification, */
252 /* however, it is completely useless to us */
253 if ( *count
< 1 || *count
> 2727 )
254 return FT_THROW( Invalid_Table
);
256 error
= FT_Stream_Seek( stream
, (FT_ULong
)rpos
);
260 if ( FT_NEW_ARRAY( ref
, *count
) )
263 for ( j
= 0; j
< *count
; j
++ )
265 if ( FT_READ_SHORT( ref
[j
].res_id
) )
267 if ( FT_STREAM_SKIP( 2 ) ) /* resource name offset */
269 if ( FT_READ_LONG( temp
) ) /* attributes (8bit), offset (24bit) */
271 if ( FT_STREAM_SKIP( 4 ) ) /* mbz */
275 * According to Inside Macintosh: More Macintosh Toolbox,
276 * "Resource IDs" (1-46), there are some reserved IDs.
277 * However, FreeType2 is not a font synthesizer, no need
278 * to check the acceptable resource ID.
282 error
= FT_THROW( Invalid_Table
);
286 ref
[j
].offset
= temp
& 0xFFFFFFL
;
289 " resource_id=0x%04x, offset=0x%08x\n",
290 j
, (FT_UShort
)ref
[j
].res_id
, ref
[j
].offset
));
293 if ( sort_by_res_id
)
297 sizeof ( FT_RFork_Ref
),
298 ( int(*)(const void*,
299 const void*) )ft_raccess_sort_ref_by_id
);
301 FT_TRACE3(( " -- sort resources by their ids --\n" ));
303 for ( j
= 0; j
< *count
; j
++ )
305 " resource_id=0x%04x, offset=0x%08x\n",
306 j
, ref
[j
].res_id
, ref
[j
].offset
));
309 if ( FT_NEW_ARRAY( offsets_internal
, *count
) )
312 /* XXX: duplicated reference ID,
313 * gap between reference IDs are acceptable?
314 * further investigation on Apple implementation is needed.
316 for ( j
= 0; j
< *count
; j
++ )
317 offsets_internal
[j
] = rdata_pos
+ ref
[j
].offset
;
319 *offsets
= offsets_internal
;
328 return FT_THROW( Cannot_Open_Resource
);
332 #ifdef FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK
334 /*************************************************************************/
335 /*************************************************************************/
336 /*************************************************************************/
339 /**** Guessing functions ****/
341 /**** When you add a new guessing function, ****/
342 /**** update FT_RACCESS_N_RULES in ftrfork.h. ****/
344 /*************************************************************************/
345 /*************************************************************************/
346 /*************************************************************************/
349 raccess_guess_apple_double( FT_Library library
,
351 char *base_file_name
,
352 char **result_file_name
,
353 FT_Long
*result_offset
);
356 raccess_guess_apple_single( FT_Library library
,
358 char *base_file_name
,
359 char **result_file_name
,
360 FT_Long
*result_offset
);
363 raccess_guess_darwin_ufs_export( FT_Library library
,
365 char *base_file_name
,
366 char **result_file_name
,
367 FT_Long
*result_offset
);
370 raccess_guess_darwin_newvfs( FT_Library library
,
372 char *base_file_name
,
373 char **result_file_name
,
374 FT_Long
*result_offset
);
377 raccess_guess_darwin_hfsplus( FT_Library library
,
379 char *base_file_name
,
380 char **result_file_name
,
381 FT_Long
*result_offset
);
384 raccess_guess_vfat( FT_Library library
,
386 char *base_file_name
,
387 char **result_file_name
,
388 FT_Long
*result_offset
);
391 raccess_guess_linux_cap( FT_Library library
,
393 char *base_file_name
,
394 char **result_file_name
,
395 FT_Long
*result_offset
);
398 raccess_guess_linux_double( FT_Library library
,
400 char *base_file_name
,
401 char **result_file_name
,
402 FT_Long
*result_offset
);
405 raccess_guess_linux_netatalk( FT_Library library
,
407 char *base_file_name
,
408 char **result_file_name
,
409 FT_Long
*result_offset
);
412 CONST_FT_RFORK_RULE_ARRAY_BEGIN(ft_raccess_guess_table
,
413 ft_raccess_guess_rec
)
414 CONST_FT_RFORK_RULE_ARRAY_ENTRY(apple_double
, apple_double
)
415 CONST_FT_RFORK_RULE_ARRAY_ENTRY(apple_single
, apple_single
)
416 CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_ufs_export
, darwin_ufs_export
)
417 CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_newvfs
, darwin_newvfs
)
418 CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_hfsplus
, darwin_hfsplus
)
419 CONST_FT_RFORK_RULE_ARRAY_ENTRY(vfat
, vfat
)
420 CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_cap
, linux_cap
)
421 CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_double
, linux_double
)
422 CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_netatalk
, linux_netatalk
)
423 CONST_FT_RFORK_RULE_ARRAY_END
426 /*************************************************************************/
428 /**** Helper functions ****/
430 /*************************************************************************/
433 raccess_guess_apple_generic( FT_Library library
,
435 char *base_file_name
,
437 FT_Long
*result_offset
);
440 raccess_guess_linux_double_from_file_name( FT_Library library
,
442 FT_Long
*result_offset
);
445 raccess_make_file_name( FT_Memory memory
,
446 const char *original_name
,
447 const char *insertion
);
450 FT_Raccess_Guess( FT_Library library
,
460 for ( i
= 0; i
< FT_RACCESS_N_RULES
; i
++ )
463 if ( NULL
!= stream
)
464 errors
[i
] = FT_Stream_Seek( stream
, 0 );
466 errors
[i
] = FT_Err_Ok
;
471 errors
[i
] = (FT_RACCESS_GUESS_TABLE_GET
[i
].func
)( library
,
481 #if defined( FT_CONFIG_OPTION_MAC_FONTS ) && !defined( FT_MACINTOSH )
483 raccess_get_rule_type_from_rule_index( FT_Library library
,
486 FT_UNUSED( library
);
488 if ( rule_index
>= FT_RACCESS_N_RULES
)
489 return FT_RFork_Rule_invalid
;
491 return FT_RACCESS_GUESS_TABLE_GET
[rule_index
].type
;
496 * For this function, refer ftbase.h.
498 FT_LOCAL_DEF( FT_Bool
)
499 ft_raccess_rule_by_darwin_vfs( FT_Library library
,
502 switch( raccess_get_rule_type_from_rule_index( library
, rule_index
) )
504 case FT_RFork_Rule_darwin_newvfs
:
505 case FT_RFork_Rule_darwin_hfsplus
:
516 raccess_guess_apple_double( FT_Library library
,
518 char *base_file_name
,
519 char **result_file_name
,
520 FT_Long
*result_offset
)
522 FT_Int32 magic
= ( 0x00 << 24 ) |
528 *result_file_name
= NULL
;
529 if ( NULL
== stream
)
530 return FT_THROW( Cannot_Open_Stream
);
532 return raccess_guess_apple_generic( library
, stream
, base_file_name
,
533 magic
, result_offset
);
538 raccess_guess_apple_single( FT_Library library
,
540 char *base_file_name
,
541 char **result_file_name
,
542 FT_Long
*result_offset
)
544 FT_Int32 magic
= ( 0x00 << 24 ) |
550 *result_file_name
= NULL
;
551 if ( NULL
== stream
)
552 return FT_THROW( Cannot_Open_Stream
);
554 return raccess_guess_apple_generic( library
, stream
, base_file_name
,
555 magic
, result_offset
);
560 raccess_guess_darwin_ufs_export( FT_Library library
,
562 char *base_file_name
,
563 char **result_file_name
,
564 FT_Long
*result_offset
)
573 memory
= library
->memory
;
574 newpath
= raccess_make_file_name( memory
, base_file_name
, "._" );
576 return FT_THROW( Out_Of_Memory
);
578 error
= raccess_guess_linux_double_from_file_name( library
, newpath
,
581 *result_file_name
= newpath
;
590 raccess_guess_darwin_hfsplus( FT_Library library
,
592 char *base_file_name
,
593 char **result_file_name
,
594 FT_Long
*result_offset
)
597 Only meaningful on systems with hfs+ drivers (or Macs).
600 char* newpath
= NULL
;
602 FT_Long base_file_len
= (FT_Long
)ft_strlen( base_file_name
);
607 memory
= library
->memory
;
609 if ( base_file_len
+ 6 > FT_INT_MAX
)
610 return FT_THROW( Array_Too_Large
);
612 if ( FT_ALLOC( newpath
, base_file_len
+ 6 ) )
615 FT_MEM_COPY( newpath
, base_file_name
, base_file_len
);
616 FT_MEM_COPY( newpath
+ base_file_len
, "/rsrc", 6 );
618 *result_file_name
= newpath
;
626 raccess_guess_darwin_newvfs( FT_Library library
,
628 char *base_file_name
,
629 char **result_file_name
,
630 FT_Long
*result_offset
)
633 Only meaningful on systems with Mac OS X (> 10.1).
636 char* newpath
= NULL
;
638 FT_Long base_file_len
= (FT_Long
)ft_strlen( base_file_name
);
643 memory
= library
->memory
;
645 if ( base_file_len
+ 18 > FT_INT_MAX
)
646 return FT_THROW( Array_Too_Large
);
648 if ( FT_ALLOC( newpath
, base_file_len
+ 18 ) )
651 FT_MEM_COPY( newpath
, base_file_name
, base_file_len
);
652 FT_MEM_COPY( newpath
+ base_file_len
, "/..namedfork/rsrc", 18 );
654 *result_file_name
= newpath
;
662 raccess_guess_vfat( FT_Library library
,
664 char *base_file_name
,
665 char **result_file_name
,
666 FT_Long
*result_offset
)
674 memory
= library
->memory
;
676 newpath
= raccess_make_file_name( memory
, base_file_name
,
679 return FT_THROW( Out_Of_Memory
);
681 *result_file_name
= newpath
;
689 raccess_guess_linux_cap( FT_Library library
,
691 char *base_file_name
,
692 char **result_file_name
,
693 FT_Long
*result_offset
)
701 memory
= library
->memory
;
703 newpath
= raccess_make_file_name( memory
, base_file_name
, ".resource/" );
705 return FT_THROW( Out_Of_Memory
);
707 *result_file_name
= newpath
;
715 raccess_guess_linux_double( FT_Library library
,
717 char *base_file_name
,
718 char **result_file_name
,
719 FT_Long
*result_offset
)
728 memory
= library
->memory
;
730 newpath
= raccess_make_file_name( memory
, base_file_name
, "%" );
732 return FT_THROW( Out_Of_Memory
);
734 error
= raccess_guess_linux_double_from_file_name( library
, newpath
,
737 *result_file_name
= newpath
;
746 raccess_guess_linux_netatalk( FT_Library library
,
748 char *base_file_name
,
749 char **result_file_name
,
750 FT_Long
*result_offset
)
759 memory
= library
->memory
;
761 newpath
= raccess_make_file_name( memory
, base_file_name
,
764 return FT_THROW( Out_Of_Memory
);
766 error
= raccess_guess_linux_double_from_file_name( library
, newpath
,
769 *result_file_name
= newpath
;
778 raccess_guess_apple_generic( FT_Library library
,
780 char *base_file_name
,
782 FT_Long
*result_offset
)
784 FT_Int32 magic_from_stream
;
786 FT_Int32 version_number
= 0;
787 FT_UShort n_of_entries
;
790 FT_Int32 entry_id
, entry_offset
, entry_length
= 0;
792 const FT_Int32 resource_fork_entry_id
= 0x2;
794 FT_UNUSED( library
);
795 FT_UNUSED( base_file_name
);
796 FT_UNUSED( version_number
);
797 FT_UNUSED( entry_length
);
800 if ( FT_READ_LONG( magic_from_stream
) )
802 if ( magic_from_stream
!= magic
)
803 return FT_THROW( Unknown_File_Format
);
805 if ( FT_READ_LONG( version_number
) )
809 error
= FT_Stream_Skip( stream
, 16 );
813 if ( FT_READ_USHORT( n_of_entries
) )
815 if ( n_of_entries
== 0 )
816 return FT_THROW( Unknown_File_Format
);
818 for ( i
= 0; i
< n_of_entries
; i
++ )
820 if ( FT_READ_LONG( entry_id
) )
822 if ( entry_id
== resource_fork_entry_id
)
824 if ( FT_READ_LONG( entry_offset
) ||
825 FT_READ_LONG( entry_length
) )
827 *result_offset
= entry_offset
;
833 error
= FT_Stream_Skip( stream
, 4 + 4 ); /* offset + length */
839 return FT_THROW( Unknown_File_Format
);
844 raccess_guess_linux_double_from_file_name( FT_Library library
,
846 FT_Long
*result_offset
)
854 args2
.flags
= FT_OPEN_PATHNAME
;
855 args2
.pathname
= file_name
;
856 error
= FT_Stream_New( library
, &args2
, &stream2
);
860 error
= raccess_guess_apple_double( library
, stream2
, file_name
,
861 &nouse
, result_offset
);
863 FT_Stream_Free( stream2
, 0 );
870 raccess_make_file_name( FT_Memory memory
,
871 const char *original_name
,
872 const char *insertion
)
874 char* new_name
= NULL
;
878 FT_Error error
= FT_Err_Ok
;
883 new_length
= ft_strlen( original_name
) + ft_strlen( insertion
);
884 if ( FT_ALLOC( new_name
, new_length
+ 1 ) )
887 tmp
= ft_strrchr( original_name
, '/' );
890 ft_strncpy( new_name
,
892 (size_t)( tmp
- original_name
+ 1 ) );
893 new_name
[tmp
- original_name
+ 1] = '\0';
898 slash
= original_name
;
902 ft_strcat( new_name
, insertion
);
903 ft_strcat( new_name
, slash
);
909 #else /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */
912 /*************************************************************************/
913 /* Dummy function; just sets errors */
914 /*************************************************************************/
917 FT_Raccess_Guess( FT_Library library
,
926 FT_UNUSED( library
);
928 FT_UNUSED( base_name
);
931 for ( i
= 0; i
< FT_RACCESS_N_RULES
; i
++ )
935 errors
[i
] = FT_ERR( Unimplemented_Feature
);
940 #endif /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */