| /**************************************************************************** |
| * |
| * ftrfork.c |
| * |
| * Embedded resource forks accessor (body). |
| * |
| * Copyright (C) 2004-2022 by |
| * Masatake YAMATO and Redhat K.K. |
| * |
| * FT_Raccess_Get_HeaderInfo() and raccess_guess_darwin_hfsplus() are |
| * derived from ftobjs.c. |
| * |
| * This file is part of the FreeType project, and may only be used, |
| * modified, and distributed under the terms of the FreeType project |
| * license, LICENSE.TXT. By continuing to use, modify, or distribute |
| * this file you indicate that you have read the license and |
| * understand and accept it fully. |
| * |
| */ |
| |
| /**************************************************************************** |
| * Development of the code in this file is support of |
| * Information-technology Promotion Agency, Japan. |
| */ |
| |
| |
| #include <freetype/internal/ftdebug.h> |
| #include <freetype/internal/ftstream.h> |
| #include <freetype/internal/ftrfork.h> |
| |
| #include "ftbase.h" |
| |
| #undef FT_COMPONENT |
| #define FT_COMPONENT raccess |
| |
| |
| /*************************************************************************/ |
| /*************************************************************************/ |
| /*************************************************************************/ |
| /**** ****/ |
| /**** ****/ |
| /**** Resource fork directory access ****/ |
| /**** ****/ |
| /**** ****/ |
| /*************************************************************************/ |
| /*************************************************************************/ |
| /*************************************************************************/ |
| |
| FT_BASE_DEF( FT_Error ) |
| FT_Raccess_Get_HeaderInfo( FT_Library library, |
| FT_Stream stream, |
| FT_Long rfork_offset, |
| FT_Long *map_offset, |
| FT_Long *rdata_pos ) |
| { |
| FT_Error error; |
| unsigned char head[16], head2[16]; |
| FT_Long map_pos, map_len, rdata_len; |
| int allzeros, allmatch, i; |
| FT_Long type_list; |
| |
| FT_UNUSED( library ); |
| |
| |
| error = FT_Stream_Seek( stream, (FT_ULong)rfork_offset ); |
| if ( error ) |
| return error; |
| |
| error = FT_Stream_Read( stream, (FT_Byte*)head, 16 ); |
| if ( error ) |
| return error; |
| |
| /* ensure positive values */ |
| if ( head[0] >= 0x80 || |
| head[4] >= 0x80 || |
| head[8] >= 0x80 || |
| head[12] >= 0x80 ) |
| return FT_THROW( Unknown_File_Format ); |
| |
| *rdata_pos = ( head[ 0] << 24 ) | |
| ( head[ 1] << 16 ) | |
| ( head[ 2] << 8 ) | |
| head[ 3]; |
| map_pos = ( head[ 4] << 24 ) | |
| ( head[ 5] << 16 ) | |
| ( head[ 6] << 8 ) | |
| head[ 7]; |
| rdata_len = ( head[ 8] << 24 ) | |
| ( head[ 9] << 16 ) | |
| ( head[10] << 8 ) | |
| head[11]; |
| map_len = ( head[12] << 24 ) | |
| ( head[13] << 16 ) | |
| ( head[14] << 8 ) | |
| head[15]; |
| |
| /* the map must not be empty */ |
| if ( !map_pos ) |
| return FT_THROW( Unknown_File_Format ); |
| |
| /* check whether rdata and map overlap */ |
| if ( *rdata_pos < map_pos ) |
| { |
| if ( *rdata_pos > map_pos - rdata_len ) |
| return FT_THROW( Unknown_File_Format ); |
| } |
| else |
| { |
| if ( map_pos > *rdata_pos - map_len ) |
| return FT_THROW( Unknown_File_Format ); |
| } |
| |
| /* check whether end of rdata or map exceeds stream size */ |
| if ( FT_LONG_MAX - rdata_len < *rdata_pos || |
| FT_LONG_MAX - map_len < map_pos || |
| |
| FT_LONG_MAX - ( *rdata_pos + rdata_len ) < rfork_offset || |
| FT_LONG_MAX - ( map_pos + map_len ) < rfork_offset || |
| |
| (FT_ULong)( rfork_offset + *rdata_pos + rdata_len ) > stream->size || |
| (FT_ULong)( rfork_offset + map_pos + map_len ) > stream->size ) |
| return FT_THROW( Unknown_File_Format ); |
| |
| *rdata_pos += rfork_offset; |
| map_pos += rfork_offset; |
| |
| error = FT_Stream_Seek( stream, (FT_ULong)map_pos ); |
| if ( error ) |
| return error; |
| |
| head2[15] = (FT_Byte)( head[15] + 1 ); /* make it be different */ |
| |
| error = FT_Stream_Read( stream, (FT_Byte*)head2, 16 ); |
| if ( error ) |
| return error; |
| |
| allzeros = 1; |
| allmatch = 1; |
| for ( i = 0; i < 16; i++ ) |
| { |
| if ( head2[i] != 0 ) |
| allzeros = 0; |
| if ( head2[i] != head[i] ) |
| allmatch = 0; |
| } |
| if ( !allzeros && !allmatch ) |
| return FT_THROW( Unknown_File_Format ); |
| |
| /* If we have reached this point then it is probably a mac resource */ |
| /* file. Now, does it contain any interesting resources? */ |
| |
| (void)FT_STREAM_SKIP( 4 /* skip handle to next resource map */ |
| + 2 /* skip file resource number */ |
| + 2 ); /* skip attributes */ |
| |
| if ( FT_READ_SHORT( type_list ) ) |
| return error; |
| if ( type_list < 0 ) |
| return FT_THROW( Unknown_File_Format ); |
| |
| error = FT_Stream_Seek( stream, (FT_ULong)( map_pos + type_list ) ); |
| if ( error ) |
| return error; |
| |
| *map_offset = map_pos + type_list; |
| return FT_Err_Ok; |
| } |
| |
| |
| FT_COMPARE_DEF( int ) |
| ft_raccess_sort_ref_by_id( const void* a, |
| const void* b ) |
| { |
| return ( (FT_RFork_Ref*)a )->res_id - ( (FT_RFork_Ref*)b )->res_id; |
| } |
| |
| |
| FT_BASE_DEF( FT_Error ) |
| FT_Raccess_Get_DataOffsets( FT_Library library, |
| FT_Stream stream, |
| FT_Long map_offset, |
| FT_Long rdata_pos, |
| FT_Long tag, |
| FT_Bool sort_by_res_id, |
| FT_Long **offsets, |
| FT_Long *count ) |
| { |
| FT_Error error; |
| int i, j, cnt, subcnt; |
| FT_Long tag_internal, rpos; |
| FT_Memory memory = library->memory; |
| FT_Long temp; |
| FT_Long *offsets_internal = NULL; |
| FT_RFork_Ref *ref = NULL; |
| |
| |
| FT_TRACE3(( "\n" )); |
| error = FT_Stream_Seek( stream, (FT_ULong)map_offset ); |
| if ( error ) |
| return error; |
| |
| if ( FT_READ_SHORT( cnt ) ) |
| return error; |
| cnt++; |
| |
| /* `rpos' is a signed 16bit integer offset to resource records; the */ |
| /* size of a resource record is 12 bytes. The map header is 28 bytes, */ |
| /* and a type list needs 10 bytes or more. If we assume that the name */ |
| /* list is empty and we have only a single entry in the type list, */ |
| /* there can be at most */ |
| /* */ |
| /* (32768 - 28 - 10) / 12 = 2727 */ |
| /* */ |
| /* resources. */ |
| /* */ |
| /* A type list starts with a two-byte counter, followed by 10-byte */ |
| /* type records. Assuming that there are no resources, the number of */ |
| /* type records can be at most */ |
| /* */ |
| /* (32768 - 28 - 2) / 8 = 4079 */ |
| /* */ |
| if ( cnt > 4079 ) |
| return FT_THROW( Invalid_Table ); |
| |
| for ( i = 0; i < cnt; i++ ) |
| { |
| if ( FT_READ_LONG( tag_internal ) || |
| FT_READ_SHORT( subcnt ) || |
| FT_READ_SHORT( rpos ) ) |
| return error; |
| |
| FT_TRACE2(( "Resource tags: %c%c%c%c\n", |
| (char)( 0xFF & ( tag_internal >> 24 ) ), |
| (char)( 0xFF & ( tag_internal >> 16 ) ), |
| (char)( 0xFF & ( tag_internal >> 8 ) ), |
| (char)( 0xFF & ( tag_internal >> 0 ) ) )); |
| FT_TRACE3(( " : subcount=%d, suboffset=0x%04lx\n", |
| subcnt, rpos )); |
| |
| if ( tag_internal == tag ) |
| { |
| *count = subcnt + 1; |
| rpos += map_offset; |
| |
| /* a zero count might be valid in the resource specification, */ |
| /* however, it is completely useless to us */ |
| if ( *count < 1 || *count > 2727 ) |
| return FT_THROW( Invalid_Table ); |
| |
| error = FT_Stream_Seek( stream, (FT_ULong)rpos ); |
| if ( error ) |
| return error; |
| |
| if ( FT_QNEW_ARRAY( ref, *count ) ) |
| return error; |
| |
| for ( j = 0; j < *count; j++ ) |
| { |
| if ( FT_READ_SHORT( ref[j].res_id ) ) |
| goto Exit; |
| if ( FT_STREAM_SKIP( 2 ) ) /* resource name offset */ |
| goto Exit; |
| if ( FT_READ_LONG( temp ) ) /* attributes (8bit), offset (24bit) */ |
| goto Exit; |
| if ( FT_STREAM_SKIP( 4 ) ) /* mbz */ |
| goto Exit; |
| |
| /* |
| * According to Inside Macintosh: More Macintosh Toolbox, |
| * "Resource IDs" (1-46), there are some reserved IDs. |
| * However, FreeType2 is not a font synthesizer, no need |
| * to check the acceptable resource ID. |
| */ |
| if ( temp < 0 ) |
| { |
| error = FT_THROW( Invalid_Table ); |
| goto Exit; |
| } |
| |
| ref[j].offset = temp & 0xFFFFFFL; |
| |
| FT_TRACE3(( " [%d]:" |
| " resource_id=0x%04x, offset=0x%08lx\n", |
| j, (FT_UShort)ref[j].res_id, ref[j].offset )); |
| } |
| |
| if ( sort_by_res_id ) |
| { |
| ft_qsort( ref, |
| (size_t)*count, |
| sizeof ( FT_RFork_Ref ), |
| ft_raccess_sort_ref_by_id ); |
| |
| FT_TRACE3(( " -- sort resources by their ids --\n" )); |
| |
| for ( j = 0; j < *count; j++ ) |
| FT_TRACE3(( " [%d]:" |
| " resource_id=0x%04x, offset=0x%08lx\n", |
| j, ref[j].res_id, ref[j].offset )); |
| } |
| |
| if ( FT_QNEW_ARRAY( offsets_internal, *count ) ) |
| goto Exit; |
| |
| /* XXX: duplicated reference ID, |
| * gap between reference IDs are acceptable? |
| * further investigation on Apple implementation is needed. |
| */ |
| for ( j = 0; j < *count; j++ ) |
| offsets_internal[j] = rdata_pos + ref[j].offset; |
| |
| *offsets = offsets_internal; |
| error = FT_Err_Ok; |
| |
| Exit: |
| FT_FREE( ref ); |
| return error; |
| } |
| } |
| |
| return FT_THROW( Cannot_Open_Resource ); |
| } |
| |
| |
| #ifdef FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK |
| |
| /*************************************************************************/ |
| /*************************************************************************/ |
| /*************************************************************************/ |
| /**** ****/ |
| /**** ****/ |
| /**** Guessing functions ****/ |
| /**** ****/ |
| /**** When you add a new guessing function, ****/ |
| /**** update FT_RACCESS_N_RULES in ftrfork.h. ****/ |
| /**** ****/ |
| /*************************************************************************/ |
| /*************************************************************************/ |
| /*************************************************************************/ |
| |
| static FT_Error |
| raccess_guess_apple_double( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| char **result_file_name, |
| FT_Long *result_offset ); |
| |
| static FT_Error |
| raccess_guess_apple_single( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| char **result_file_name, |
| FT_Long *result_offset ); |
| |
| static FT_Error |
| raccess_guess_darwin_ufs_export( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| char **result_file_name, |
| FT_Long *result_offset ); |
| |
| static FT_Error |
| raccess_guess_darwin_newvfs( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| char **result_file_name, |
| FT_Long *result_offset ); |
| |
| static FT_Error |
| raccess_guess_darwin_hfsplus( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| char **result_file_name, |
| FT_Long *result_offset ); |
| |
| static FT_Error |
| raccess_guess_vfat( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| char **result_file_name, |
| FT_Long *result_offset ); |
| |
| static FT_Error |
| raccess_guess_linux_cap( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| char **result_file_name, |
| FT_Long *result_offset ); |
| |
| static FT_Error |
| raccess_guess_linux_double( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| char **result_file_name, |
| FT_Long *result_offset ); |
| |
| static FT_Error |
| raccess_guess_linux_netatalk( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| char **result_file_name, |
| FT_Long *result_offset ); |
| |
| |
| CONST_FT_RFORK_RULE_ARRAY_BEGIN(ft_raccess_guess_table, |
| ft_raccess_guess_rec) |
| CONST_FT_RFORK_RULE_ARRAY_ENTRY(apple_double, apple_double) |
| CONST_FT_RFORK_RULE_ARRAY_ENTRY(apple_single, apple_single) |
| CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_ufs_export, darwin_ufs_export) |
| CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_newvfs, darwin_newvfs) |
| CONST_FT_RFORK_RULE_ARRAY_ENTRY(darwin_hfsplus, darwin_hfsplus) |
| CONST_FT_RFORK_RULE_ARRAY_ENTRY(vfat, vfat) |
| CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_cap, linux_cap) |
| CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_double, linux_double) |
| CONST_FT_RFORK_RULE_ARRAY_ENTRY(linux_netatalk, linux_netatalk) |
| CONST_FT_RFORK_RULE_ARRAY_END |
| |
| |
| /*************************************************************************/ |
| /**** ****/ |
| /**** Helper functions ****/ |
| /**** ****/ |
| /*************************************************************************/ |
| |
| static FT_Error |
| raccess_guess_apple_generic( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| FT_Int32 magic, |
| FT_Long *result_offset ); |
| |
| static FT_Error |
| raccess_guess_linux_double_from_file_name( FT_Library library, |
| char* file_name, |
| FT_Long *result_offset ); |
| |
| static char * |
| raccess_make_file_name( FT_Memory memory, |
| const char *original_name, |
| const char *insertion ); |
| |
| FT_BASE_DEF( void ) |
| FT_Raccess_Guess( FT_Library library, |
| FT_Stream stream, |
| char* base_name, |
| char **new_names, |
| FT_Long *offsets, |
| FT_Error *errors ) |
| { |
| FT_Int i; |
| |
| |
| for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) |
| { |
| new_names[i] = NULL; |
| if ( NULL != stream ) |
| errors[i] = FT_Stream_Seek( stream, 0 ); |
| else |
| errors[i] = FT_Err_Ok; |
| |
| if ( errors[i] ) |
| continue; |
| |
| errors[i] = ft_raccess_guess_table[i].func( library, |
| stream, base_name, |
| &(new_names[i]), |
| &(offsets[i]) ); |
| } |
| |
| return; |
| } |
| |
| |
| #if defined( FT_CONFIG_OPTION_MAC_FONTS ) && !defined( FT_MACINTOSH ) |
| static FT_RFork_Rule |
| raccess_get_rule_type_from_rule_index( FT_Library library, |
| FT_UInt rule_index ) |
| { |
| FT_UNUSED( library ); |
| |
| if ( rule_index >= FT_RACCESS_N_RULES ) |
| return FT_RFork_Rule_invalid; |
| |
| return ft_raccess_guess_table[rule_index].type; |
| } |
| |
| |
| /* |
| * For this function, refer ftbase.h. |
| */ |
| FT_LOCAL_DEF( FT_Bool ) |
| ft_raccess_rule_by_darwin_vfs( FT_Library library, |
| FT_UInt rule_index ) |
| { |
| switch( raccess_get_rule_type_from_rule_index( library, rule_index ) ) |
| { |
| case FT_RFork_Rule_darwin_newvfs: |
| case FT_RFork_Rule_darwin_hfsplus: |
| return TRUE; |
| |
| default: |
| return FALSE; |
| } |
| } |
| #endif |
| |
| |
| static FT_Error |
| raccess_guess_apple_double( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| char **result_file_name, |
| FT_Long *result_offset ) |
| { |
| FT_Int32 magic = ( 0x00 << 24 ) | |
| ( 0x05 << 16 ) | |
| ( 0x16 << 8 ) | |
| 0x07; |
| |
| |
| *result_file_name = NULL; |
| if ( NULL == stream ) |
| return FT_THROW( Cannot_Open_Stream ); |
| |
| return raccess_guess_apple_generic( library, stream, base_file_name, |
| magic, result_offset ); |
| } |
| |
| |
| static FT_Error |
| raccess_guess_apple_single( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| char **result_file_name, |
| FT_Long *result_offset ) |
| { |
| FT_Int32 magic = ( 0x00 << 24 ) | |
| ( 0x05 << 16 ) | |
| ( 0x16 << 8 ) | |
| 0x00; |
| |
| |
| *result_file_name = NULL; |
| if ( NULL == stream ) |
| return FT_THROW( Cannot_Open_Stream ); |
| |
| return raccess_guess_apple_generic( library, stream, base_file_name, |
| magic, result_offset ); |
| } |
| |
| |
| static FT_Error |
| raccess_guess_darwin_ufs_export( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| char **result_file_name, |
| FT_Long *result_offset ) |
| { |
| char* newpath; |
| FT_Error error; |
| FT_Memory memory; |
| |
| FT_UNUSED( stream ); |
| |
| |
| memory = library->memory; |
| newpath = raccess_make_file_name( memory, base_file_name, "._" ); |
| if ( !newpath ) |
| return FT_THROW( Out_Of_Memory ); |
| |
| error = raccess_guess_linux_double_from_file_name( library, newpath, |
| result_offset ); |
| if ( !error ) |
| *result_file_name = newpath; |
| else |
| FT_FREE( newpath ); |
| |
| return error; |
| } |
| |
| |
| static FT_Error |
| raccess_guess_darwin_hfsplus( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| char **result_file_name, |
| FT_Long *result_offset ) |
| { |
| /* |
| Only meaningful on systems with hfs+ drivers (or Macs). |
| */ |
| FT_Error error; |
| char* newpath = NULL; |
| FT_Memory memory; |
| FT_Long base_file_len = (FT_Long)ft_strlen( base_file_name ); |
| |
| FT_UNUSED( stream ); |
| |
| |
| memory = library->memory; |
| |
| if ( base_file_len + 6 > FT_INT_MAX ) |
| return FT_THROW( Array_Too_Large ); |
| |
| if ( FT_QALLOC( newpath, base_file_len + 6 ) ) |
| return error; |
| |
| FT_MEM_COPY( newpath, base_file_name, base_file_len ); |
| FT_MEM_COPY( newpath + base_file_len, "/rsrc", 6 ); |
| |
| *result_file_name = newpath; |
| *result_offset = 0; |
| |
| return FT_Err_Ok; |
| } |
| |
| |
| static FT_Error |
| raccess_guess_darwin_newvfs( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| char **result_file_name, |
| FT_Long *result_offset ) |
| { |
| /* |
| Only meaningful on systems with Mac OS X (> 10.1). |
| */ |
| FT_Error error; |
| char* newpath = NULL; |
| FT_Memory memory; |
| FT_Long base_file_len = (FT_Long)ft_strlen( base_file_name ); |
| |
| FT_UNUSED( stream ); |
| |
| |
| memory = library->memory; |
| |
| if ( base_file_len + 18 > FT_INT_MAX ) |
| return FT_THROW( Array_Too_Large ); |
| |
| if ( FT_QALLOC( newpath, base_file_len + 18 ) ) |
| return error; |
| |
| FT_MEM_COPY( newpath, base_file_name, base_file_len ); |
| FT_MEM_COPY( newpath + base_file_len, "/..namedfork/rsrc", 18 ); |
| |
| *result_file_name = newpath; |
| *result_offset = 0; |
| |
| return FT_Err_Ok; |
| } |
| |
| |
| static FT_Error |
| raccess_guess_vfat( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| char **result_file_name, |
| FT_Long *result_offset ) |
| { |
| char* newpath; |
| FT_Memory memory; |
| |
| FT_UNUSED( stream ); |
| |
| |
| memory = library->memory; |
| |
| newpath = raccess_make_file_name( memory, base_file_name, |
| "resource.frk/" ); |
| if ( !newpath ) |
| return FT_THROW( Out_Of_Memory ); |
| |
| *result_file_name = newpath; |
| *result_offset = 0; |
| |
| return FT_Err_Ok; |
| } |
| |
| |
| static FT_Error |
| raccess_guess_linux_cap( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| char **result_file_name, |
| FT_Long *result_offset ) |
| { |
| char* newpath; |
| FT_Memory memory; |
| |
| FT_UNUSED( stream ); |
| |
| |
| memory = library->memory; |
| |
| newpath = raccess_make_file_name( memory, base_file_name, ".resource/" ); |
| if ( !newpath ) |
| return FT_THROW( Out_Of_Memory ); |
| |
| *result_file_name = newpath; |
| *result_offset = 0; |
| |
| return FT_Err_Ok; |
| } |
| |
| |
| static FT_Error |
| raccess_guess_linux_double( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| char **result_file_name, |
| FT_Long *result_offset ) |
| { |
| char* newpath; |
| FT_Error error; |
| FT_Memory memory; |
| |
| FT_UNUSED( stream ); |
| |
| |
| memory = library->memory; |
| |
| newpath = raccess_make_file_name( memory, base_file_name, "%" ); |
| if ( !newpath ) |
| return FT_THROW( Out_Of_Memory ); |
| |
| error = raccess_guess_linux_double_from_file_name( library, newpath, |
| result_offset ); |
| if ( !error ) |
| *result_file_name = newpath; |
| else |
| FT_FREE( newpath ); |
| |
| return error; |
| } |
| |
| |
| static FT_Error |
| raccess_guess_linux_netatalk( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| char **result_file_name, |
| FT_Long *result_offset ) |
| { |
| char* newpath; |
| FT_Error error; |
| FT_Memory memory; |
| |
| FT_UNUSED( stream ); |
| |
| |
| memory = library->memory; |
| |
| newpath = raccess_make_file_name( memory, base_file_name, |
| ".AppleDouble/" ); |
| if ( !newpath ) |
| return FT_THROW( Out_Of_Memory ); |
| |
| error = raccess_guess_linux_double_from_file_name( library, newpath, |
| result_offset ); |
| if ( !error ) |
| *result_file_name = newpath; |
| else |
| FT_FREE( newpath ); |
| |
| return error; |
| } |
| |
| |
| static FT_Error |
| raccess_guess_apple_generic( FT_Library library, |
| FT_Stream stream, |
| char *base_file_name, |
| FT_Int32 magic, |
| FT_Long *result_offset ) |
| { |
| FT_Int32 magic_from_stream; |
| FT_Error error; |
| FT_Int32 version_number = 0; |
| FT_UShort n_of_entries; |
| |
| int i; |
| FT_Int32 entry_id, entry_offset, entry_length = 0; |
| |
| const FT_Int32 resource_fork_entry_id = 0x2; |
| |
| FT_UNUSED( library ); |
| FT_UNUSED( base_file_name ); |
| FT_UNUSED( version_number ); |
| FT_UNUSED( entry_length ); |
| |
| |
| if ( FT_READ_LONG( magic_from_stream ) ) |
| return error; |
| if ( magic_from_stream != magic ) |
| return FT_THROW( Unknown_File_Format ); |
| |
| if ( FT_READ_LONG( version_number ) ) |
| return error; |
| |
| /* filler */ |
| error = FT_Stream_Skip( stream, 16 ); |
| if ( error ) |
| return error; |
| |
| if ( FT_READ_USHORT( n_of_entries ) ) |
| return error; |
| if ( n_of_entries == 0 ) |
| return FT_THROW( Unknown_File_Format ); |
| |
| for ( i = 0; i < n_of_entries; i++ ) |
| { |
| if ( FT_READ_LONG( entry_id ) ) |
| return error; |
| if ( entry_id == resource_fork_entry_id ) |
| { |
| if ( FT_READ_LONG( entry_offset ) || |
| FT_READ_LONG( entry_length ) ) |
| continue; |
| *result_offset = entry_offset; |
| |
| return FT_Err_Ok; |
| } |
| else |
| { |
| error = FT_Stream_Skip( stream, 4 + 4 ); /* offset + length */ |
| if ( error ) |
| return error; |
| } |
| } |
| |
| return FT_THROW( Unknown_File_Format ); |
| } |
| |
| |
| static FT_Error |
| raccess_guess_linux_double_from_file_name( FT_Library library, |
| char *file_name, |
| FT_Long *result_offset ) |
| { |
| FT_Open_Args args2; |
| FT_Stream stream2; |
| char* nouse = NULL; |
| FT_Error error; |
| |
| |
| args2.flags = FT_OPEN_PATHNAME; |
| args2.pathname = file_name; |
| error = FT_Stream_New( library, &args2, &stream2 ); |
| if ( error ) |
| return error; |
| |
| error = raccess_guess_apple_double( library, stream2, file_name, |
| &nouse, result_offset ); |
| |
| FT_Stream_Free( stream2, 0 ); |
| |
| return error; |
| } |
| |
| |
| static char* |
| raccess_make_file_name( FT_Memory memory, |
| const char *original_name, |
| const char *insertion ) |
| { |
| char* new_name = NULL; |
| const char* tmp; |
| const char* slash; |
| size_t new_length; |
| FT_Error error = FT_Err_Ok; |
| |
| FT_UNUSED( error ); |
| |
| |
| new_length = ft_strlen( original_name ) + ft_strlen( insertion ); |
| if ( FT_QALLOC( new_name, new_length + 1 ) ) |
| return NULL; |
| |
| tmp = ft_strrchr( original_name, '/' ); |
| if ( tmp ) |
| { |
| ft_strncpy( new_name, |
| original_name, |
| (size_t)( tmp - original_name + 1 ) ); |
| new_name[tmp - original_name + 1] = '\0'; |
| slash = tmp + 1; |
| } |
| else |
| { |
| slash = original_name; |
| new_name[0] = '\0'; |
| } |
| |
| ft_strcat( new_name, insertion ); |
| ft_strcat( new_name, slash ); |
| |
| return new_name; |
| } |
| |
| |
| #else /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */ |
| |
| |
| /************************************************************************** |
| * Dummy function; just sets errors |
| */ |
| |
| FT_BASE_DEF( void ) |
| FT_Raccess_Guess( FT_Library library, |
| FT_Stream stream, |
| char *base_name, |
| char **new_names, |
| FT_Long *offsets, |
| FT_Error *errors ) |
| { |
| FT_Int i; |
| |
| FT_UNUSED( library ); |
| FT_UNUSED( stream ); |
| FT_UNUSED( base_name ); |
| |
| |
| for ( i = 0; i < FT_RACCESS_N_RULES; i++ ) |
| { |
| new_names[i] = NULL; |
| offsets[i] = 0; |
| errors[i] = FT_ERR( Unimplemented_Feature ); |
| } |
| } |
| |
| |
| #endif /* !FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK */ |
| |
| |
| /* END */ |