|
|
|
@ -56,7 +56,7 @@ |
|
|
|
|
{ |
|
|
|
|
FT_Error error; |
|
|
|
|
unsigned char head[16], head2[16]; |
|
|
|
|
FT_Long map_pos, rdata_len; |
|
|
|
|
FT_Long map_pos, map_len, rdata_len; |
|
|
|
|
int allzeros, allmatch, i; |
|
|
|
|
FT_Long type_list; |
|
|
|
|
|
|
|
|
@ -67,12 +67,15 @@ |
|
|
|
|
if ( error ) |
|
|
|
|
return error; |
|
|
|
|
|
|
|
|
|
error = FT_Stream_Read( stream, (FT_Byte *)head, 16 ); |
|
|
|
|
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 ) |
|
|
|
|
if ( head[0] >= 0x80 || |
|
|
|
|
head[4] >= 0x80 || |
|
|
|
|
head[8] >= 0x80 || |
|
|
|
|
head[12] >= 0x80 ) |
|
|
|
|
return FT_THROW( Unknown_File_Format ); |
|
|
|
|
|
|
|
|
|
*rdata_pos = ( head[ 0] << 24 ) | |
|
|
|
@ -87,14 +90,36 @@ |
|
|
|
|
( head[ 9] << 16 ) | |
|
|
|
|
( head[10] << 8 ) | |
|
|
|
|
head[11]; |
|
|
|
|
map_len = ( head[12] << 24 ) | |
|
|
|
|
( head[13] << 16 ) | |
|
|
|
|
( head[14] << 8 ) | |
|
|
|
|
head[15]; |
|
|
|
|
|
|
|
|
|
/* map_len = head[12] .. head[15] */ |
|
|
|
|
|
|
|
|
|
if ( *rdata_pos != map_pos - rdata_len || map_pos == 0 ) |
|
|
|
|
/* the map must not be empty */ |
|
|
|
|
if ( !map_pos ) |
|
|
|
|
return FT_THROW( Unknown_File_Format ); |
|
|
|
|
|
|
|
|
|
if ( FT_LONG_MAX - rfork_offset < *rdata_pos || |
|
|
|
|
FT_LONG_MAX - rfork_offset < map_pos ) |
|
|
|
|
/* 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; |
|
|
|
@ -124,15 +149,14 @@ |
|
|
|
|
|
|
|
|
|
/* If we have reached this point then it is probably a mac resource */ |
|
|
|
|
/* file. Now, does it contain any interesting resources? */ |
|
|
|
|
/* Skip handle to next resource map, the file resource number, and */ |
|
|
|
|
/* attributes. */ |
|
|
|
|
|
|
|
|
|
(void)FT_STREAM_SKIP( 4 /* skip handle to next resource map */ |
|
|
|
|
+ 2 /* skip file resource number */ |
|
|
|
|
+ 2 ); /* skip attributes */ |
|
|
|
|
|
|
|
|
|
if ( FT_READ_USHORT( type_list ) ) |
|
|
|
|
if ( FT_READ_SHORT( type_list ) ) |
|
|
|
|
return error; |
|
|
|
|
if ( type_list == -1 ) |
|
|
|
|
if ( type_list < 0 ) |
|
|
|
|
return FT_THROW( Unknown_File_Format ); |
|
|
|
|
|
|
|
|
|
error = FT_Stream_Seek( stream, (FT_ULong)( map_pos + type_list ) ); |
|
|
|
@ -181,15 +205,34 @@ |
|
|
|
|
if ( error ) |
|
|
|
|
return error; |
|
|
|
|
|
|
|
|
|
if ( FT_READ_USHORT( cnt ) ) |
|
|
|
|
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_USHORT( subcnt ) || |
|
|
|
|
FT_READ_USHORT( rpos ) ) |
|
|
|
|
FT_READ_SHORT( subcnt ) || |
|
|
|
|
FT_READ_SHORT( rpos ) ) |
|
|
|
|
return error; |
|
|
|
|
|
|
|
|
|
FT_TRACE2(( "Resource tags: %c%c%c%c\n", |
|
|
|
@ -205,6 +248,9 @@ |
|
|
|
|
*count = subcnt + 1; |
|
|
|
|
rpos += map_offset; |
|
|
|
|
|
|
|
|
|
if ( *count > 2727 ) |
|
|
|
|
return FT_THROW( Invalid_Table ); |
|
|
|
|
|
|
|
|
|
error = FT_Stream_Seek( stream, (FT_ULong)rpos ); |
|
|
|
|
if ( error ) |
|
|
|
|
return error; |
|
|
|
@ -214,33 +260,42 @@ |
|
|
|
|
|
|
|
|
|
for ( j = 0; j < *count; ++j ) |
|
|
|
|
{ |
|
|
|
|
if ( FT_READ_USHORT( ref[j].res_id ) ) |
|
|
|
|
if ( FT_READ_SHORT( ref[j].res_id ) ) |
|
|
|
|
goto Exit; |
|
|
|
|
if ( FT_STREAM_SKIP( 2 ) ) /* resource name */ |
|
|
|
|
if ( FT_STREAM_SKIP( 2 ) ) /* resource name offset */ |
|
|
|
|
goto Exit; |
|
|
|
|
if ( FT_READ_LONG( temp ) ) |
|
|
|
|
if ( FT_READ_LONG( temp ) ) /* attributes (8bit), offset (24bit) */ |
|
|
|
|
goto Exit; |
|
|
|
|
if ( FT_STREAM_SKIP( 4 ) ) /* mbz */ |
|
|
|
|
if ( FT_STREAM_SKIP( 4 ) ) /* mbz */ |
|
|
|
|
goto Exit; |
|
|
|
|
|
|
|
|
|
if ( ref[j].res_id < 0 || temp < 0 ) |
|
|
|
|
{ |
|
|
|
|
error = FT_THROW( Invalid_Table ); |
|
|
|
|
goto Exit; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ref[j].offset = temp & 0xFFFFFFL; |
|
|
|
|
|
|
|
|
|
FT_TRACE3(( " [%d]:" |
|
|
|
|
" resource_id=0x%04x, offset=0x%08x\n", |
|
|
|
|
j, ref[j].res_id, ref[j].offset )); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (sort_by_res_id) |
|
|
|
|
if ( sort_by_res_id ) |
|
|
|
|
{ |
|
|
|
|
ft_qsort( ref, (size_t)*count, sizeof ( FT_RFork_Ref ), |
|
|
|
|
( int(*)(const void*, const void*) ) |
|
|
|
|
ft_raccess_sort_ref_by_id ); |
|
|
|
|
ft_qsort( ref, |
|
|
|
|
(size_t)*count, |
|
|
|
|
sizeof ( FT_RFork_Ref ), |
|
|
|
|
( int(*)(const void*, |
|
|
|
|
const void*) )ft_raccess_sort_ref_by_id ); |
|
|
|
|
|
|
|
|
|
FT_TRACE3(( " -- sort resources by their ids --\n" )); |
|
|
|
|
for ( j = 0; j < *count; ++ j ) { |
|
|
|
|
|
|
|
|
|
for ( j = 0; j < *count; j++ ) |
|
|
|
|
FT_TRACE3(( " [%d]:" |
|
|
|
|
" resource_id=0x%04x, offset=0x%08x\n", |
|
|
|
|
j, ref[j].res_id, ref[j].offset )); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ( FT_NEW_ARRAY( offsets_internal, *count ) ) |
|
|
|
@ -250,7 +305,7 @@ |
|
|
|
|
* gap between reference IDs are acceptable? |
|
|
|
|
* further investigation on Apple implementation is needed. |
|
|
|
|
*/ |
|
|
|
|
for ( j = 0; j < *count; ++j ) |
|
|
|
|
for ( j = 0; j < *count; j++ ) |
|
|
|
|
offsets_internal[j] = rdata_pos + ref[j].offset; |
|
|
|
|
|
|
|
|
|
*offsets = offsets_internal; |
|
|
|
|