|
|
|
@ -6,6 +6,8 @@ |
|
|
|
|
/* */ |
|
|
|
|
/* Copyright 1996-2001, 2002, 2003, 2004, 2006, 2007 by */ |
|
|
|
|
/* David Turner, Robert Wilhelm, and Werner Lemberg. */ |
|
|
|
|
/* Copyright 2003 Huw D M Davies for Codeweavers */ |
|
|
|
|
/* Copyright 2007 Dmitry Timoshkov for Codeweavers */ |
|
|
|
|
/* */ |
|
|
|
|
/* This file is part of the FreeType project, and may only be used, */ |
|
|
|
|
/* modified, and distributed under the terms of the FreeType project */ |
|
|
|
@ -62,6 +64,80 @@ |
|
|
|
|
FT_FRAME_END |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static const FT_Frame_Field winpe32_header_fields[] = |
|
|
|
|
{ |
|
|
|
|
#undef FT_STRUCTURE |
|
|
|
|
#define FT_STRUCTURE WinPE32_HeaderRec |
|
|
|
|
|
|
|
|
|
FT_FRAME_START( 248 ), |
|
|
|
|
FT_FRAME_ULONG_LE ( magic ), /* PE00 */ |
|
|
|
|
FT_FRAME_USHORT_LE ( machine ), /* 0x014c - i386 */ |
|
|
|
|
FT_FRAME_USHORT_LE ( number_of_sections ), |
|
|
|
|
FT_FRAME_SKIP_BYTES( 12 ), |
|
|
|
|
FT_FRAME_USHORT_LE ( size_of_optional_header ), |
|
|
|
|
FT_FRAME_SKIP_BYTES( 2 ), |
|
|
|
|
FT_FRAME_USHORT_LE ( magic32 ), /* 0x10b */ |
|
|
|
|
FT_FRAME_SKIP_BYTES( 110 ), |
|
|
|
|
FT_FRAME_ULONG_LE ( rsrc_virtual_address ), |
|
|
|
|
FT_FRAME_ULONG_LE ( rsrc_size ), |
|
|
|
|
FT_FRAME_SKIP_BYTES( 104 ), |
|
|
|
|
FT_FRAME_END |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static const FT_Frame_Field winpe32_section_fields[] = |
|
|
|
|
{ |
|
|
|
|
#undef FT_STRUCTURE |
|
|
|
|
#define FT_STRUCTURE WinPE32_SectionRec |
|
|
|
|
|
|
|
|
|
FT_FRAME_START( 40 ), |
|
|
|
|
FT_FRAME_BYTES ( name, 8 ), |
|
|
|
|
FT_FRAME_SKIP_BYTES( 4 ), |
|
|
|
|
FT_FRAME_ULONG_LE ( virtual_address ), |
|
|
|
|
FT_FRAME_ULONG_LE ( size_of_raw_data ), |
|
|
|
|
FT_FRAME_ULONG_LE ( pointer_to_raw_data ), |
|
|
|
|
FT_FRAME_SKIP_BYTES( 16 ), |
|
|
|
|
FT_FRAME_END |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static const FT_Frame_Field winpe_rsrc_dir_fields[] = |
|
|
|
|
{ |
|
|
|
|
#undef FT_STRUCTURE |
|
|
|
|
#define FT_STRUCTURE WinPE_RsrcDirRec |
|
|
|
|
|
|
|
|
|
FT_FRAME_START( 16 ), |
|
|
|
|
FT_FRAME_ULONG_LE ( characteristics ), |
|
|
|
|
FT_FRAME_ULONG_LE ( time_date_stamp ), |
|
|
|
|
FT_FRAME_USHORT_LE( major_version ), |
|
|
|
|
FT_FRAME_USHORT_LE( minor_version ), |
|
|
|
|
FT_FRAME_USHORT_LE( number_of_named_entries ), |
|
|
|
|
FT_FRAME_USHORT_LE( number_of_id_entries ), |
|
|
|
|
FT_FRAME_END |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static const FT_Frame_Field winpe_rsrc_dir_entry_fields[] = |
|
|
|
|
{ |
|
|
|
|
#undef FT_STRUCTURE |
|
|
|
|
#define FT_STRUCTURE WinPE_RsrcDirEntryRec |
|
|
|
|
|
|
|
|
|
FT_FRAME_START( 8 ), |
|
|
|
|
FT_FRAME_ULONG_LE( name ), |
|
|
|
|
FT_FRAME_ULONG_LE( offset ), |
|
|
|
|
FT_FRAME_END |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static const FT_Frame_Field winpe_rsrc_data_entry_fields[] = |
|
|
|
|
{ |
|
|
|
|
#undef FT_STRUCTURE |
|
|
|
|
#define FT_STRUCTURE WinPE_RsrcDataEntryRec |
|
|
|
|
|
|
|
|
|
FT_FRAME_START( 16 ), |
|
|
|
|
FT_FRAME_ULONG_LE( offset_to_data ), |
|
|
|
|
FT_FRAME_ULONG_LE( size ), |
|
|
|
|
FT_FRAME_ULONG_LE( code_page ), |
|
|
|
|
FT_FRAME_ULONG_LE( reserved ), |
|
|
|
|
FT_FRAME_END |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static const FT_Frame_Field winfnt_header_fields[] = |
|
|
|
|
{ |
|
|
|
|
#undef FT_STRUCTURE |
|
|
|
@ -214,6 +290,8 @@ |
|
|
|
|
WinNE_HeaderRec ne_header; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FT_TRACE2(( "MZ signature found\n" )); |
|
|
|
|
|
|
|
|
|
if ( FT_STREAM_SEEK( mz_header.lfanew ) || |
|
|
|
|
FT_STREAM_READ_FIELDS( winne_header_fields, &ne_header ) ) |
|
|
|
|
goto Exit; |
|
|
|
@ -229,6 +307,8 @@ |
|
|
|
|
FT_ULong font_offset = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FT_TRACE2(( "NE signature found\n" )); |
|
|
|
|
|
|
|
|
|
if ( FT_STREAM_SEEK( res_offset ) || |
|
|
|
|
FT_FRAME_ENTER( ne_header.rname_tab_offset - |
|
|
|
|
ne_header.resource_tab_offset ) ) |
|
|
|
@ -291,9 +371,8 @@ |
|
|
|
|
FT_FRAME_ENTER( 12 ) ) |
|
|
|
|
goto Fail; |
|
|
|
|
|
|
|
|
|
face->font->offset = (FT_ULong)FT_GET_USHORT_LE() << size_shift; |
|
|
|
|
face->font->fnt_size = (FT_ULong)FT_GET_USHORT_LE() << size_shift; |
|
|
|
|
face->font->size_shift = size_shift; |
|
|
|
|
face->font->offset = (FT_ULong)FT_GET_USHORT_LE() << size_shift; |
|
|
|
|
face->font->fnt_size = (FT_ULong)FT_GET_USHORT_LE() << size_shift; |
|
|
|
|
|
|
|
|
|
stream->cursor += 8; |
|
|
|
|
|
|
|
|
@ -301,6 +380,181 @@ |
|
|
|
|
|
|
|
|
|
error = fnt_font_load( face->font, stream ); |
|
|
|
|
} |
|
|
|
|
else if ( ne_header.magic == WINFNT_PE_MAGIC ) |
|
|
|
|
{ |
|
|
|
|
WinPE32_HeaderRec pe32_header; |
|
|
|
|
WinPE32_SectionRec pe32_section; |
|
|
|
|
WinPE_RsrcDirRec root_dir, name_dir, lang_dir; |
|
|
|
|
WinPE_RsrcDirEntryRec dir_entry1, dir_entry2, dir_entry3; |
|
|
|
|
WinPE_RsrcDataEntryRec data_entry; |
|
|
|
|
|
|
|
|
|
FT_Long root_dir_offset, name_dir_offset, lang_dir_offset; |
|
|
|
|
FT_UShort i, j, k; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FT_TRACE2(( "PE signature found\n" )); |
|
|
|
|
|
|
|
|
|
if ( FT_STREAM_SEEK( mz_header.lfanew ) || |
|
|
|
|
FT_STREAM_READ_FIELDS( winpe32_header_fields, &pe32_header ) ) |
|
|
|
|
goto Exit; |
|
|
|
|
|
|
|
|
|
FT_TRACE2(( "magic %04lx, machine %02x, number_of_sections %u, " |
|
|
|
|
"size_of_optional_header %02x\n" |
|
|
|
|
"magic32 %02x, rsrc_virtual_address %04lx, " |
|
|
|
|
"rsrc_size %04lx\n", |
|
|
|
|
pe32_header.magic, pe32_header.machine, |
|
|
|
|
pe32_header.number_of_sections, |
|
|
|
|
pe32_header.size_of_optional_header, |
|
|
|
|
pe32_header.magic32, pe32_header.rsrc_virtual_address, |
|
|
|
|
pe32_header.rsrc_size )); |
|
|
|
|
|
|
|
|
|
if ( pe32_header.magic != WINFNT_PE_MAGIC /* check full signature */ || |
|
|
|
|
pe32_header.machine != 0x014c /* i386 */ || |
|
|
|
|
pe32_header.size_of_optional_header != 0xe0 /* FIXME */ || |
|
|
|
|
pe32_header.magic32 != 0x10b ) |
|
|
|
|
{ |
|
|
|
|
error = FNT_Err_Invalid_File_Format; |
|
|
|
|
goto Exit; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
face->root.num_faces = 0; |
|
|
|
|
|
|
|
|
|
for ( i = 0; i < pe32_header.number_of_sections; i++ ) |
|
|
|
|
{ |
|
|
|
|
if ( FT_STREAM_READ_FIELDS( winpe32_section_fields, |
|
|
|
|
&pe32_section ) ) |
|
|
|
|
goto Exit; |
|
|
|
|
|
|
|
|
|
FT_TRACE2(( "name %.8s, va %04lx, size %04lx, offset %04lx\n", |
|
|
|
|
pe32_section.name, pe32_section.virtual_address, |
|
|
|
|
pe32_section.size_of_raw_data, |
|
|
|
|
pe32_section.pointer_to_raw_data )); |
|
|
|
|
|
|
|
|
|
if ( pe32_header.rsrc_virtual_address == |
|
|
|
|
pe32_section.virtual_address ) |
|
|
|
|
goto Found_rsrc_section; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
error = FNT_Err_Invalid_File_Format; |
|
|
|
|
goto Exit; |
|
|
|
|
|
|
|
|
|
Found_rsrc_section: |
|
|
|
|
FT_TRACE2(( "found resources section %.8s\n", pe32_section.name )); |
|
|
|
|
|
|
|
|
|
if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data ) || |
|
|
|
|
FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &root_dir ) ) |
|
|
|
|
goto Exit; |
|
|
|
|
|
|
|
|
|
root_dir_offset = pe32_section.pointer_to_raw_data; |
|
|
|
|
|
|
|
|
|
for ( i = 0; i < root_dir.number_of_named_entries + |
|
|
|
|
root_dir.number_of_id_entries; i++ ) |
|
|
|
|
{ |
|
|
|
|
if ( FT_STREAM_SEEK( root_dir_offset + 16 + i * 8 ) || |
|
|
|
|
FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, |
|
|
|
|
&dir_entry1 ) ) |
|
|
|
|
goto Exit; |
|
|
|
|
|
|
|
|
|
if ( !(dir_entry1.offset & 0x80000000UL ) /* DataIsDirectory */ ) |
|
|
|
|
{ |
|
|
|
|
error = FNT_Err_Invalid_File_Format; |
|
|
|
|
goto Exit; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
dir_entry1.offset &= ~0x80000000UL; |
|
|
|
|
|
|
|
|
|
name_dir_offset = pe32_section.pointer_to_raw_data + |
|
|
|
|
dir_entry1.offset; |
|
|
|
|
|
|
|
|
|
if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data + |
|
|
|
|
dir_entry1.offset ) || |
|
|
|
|
FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &name_dir ) ) |
|
|
|
|
goto Exit; |
|
|
|
|
|
|
|
|
|
for ( j = 0; j < name_dir.number_of_named_entries + |
|
|
|
|
name_dir.number_of_id_entries; j++ ) |
|
|
|
|
{ |
|
|
|
|
if ( FT_STREAM_SEEK( name_dir_offset + 16 + j * 8 ) || |
|
|
|
|
FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, |
|
|
|
|
&dir_entry2 ) ) |
|
|
|
|
goto Exit; |
|
|
|
|
|
|
|
|
|
if ( !(dir_entry2.offset & 0x80000000UL ) /* DataIsDirectory */ ) |
|
|
|
|
{ |
|
|
|
|
error = FNT_Err_Invalid_File_Format; |
|
|
|
|
goto Exit; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
dir_entry2.offset &= ~0x80000000UL; |
|
|
|
|
|
|
|
|
|
lang_dir_offset = pe32_section.pointer_to_raw_data + |
|
|
|
|
dir_entry2.offset; |
|
|
|
|
|
|
|
|
|
if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data + |
|
|
|
|
dir_entry2.offset ) || |
|
|
|
|
FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &lang_dir ) ) |
|
|
|
|
goto Exit; |
|
|
|
|
|
|
|
|
|
for ( k = 0; k < lang_dir.number_of_named_entries + |
|
|
|
|
lang_dir.number_of_id_entries; k++ ) |
|
|
|
|
{ |
|
|
|
|
if ( FT_STREAM_SEEK( lang_dir_offset + 16 + k * 8 ) || |
|
|
|
|
FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields, |
|
|
|
|
&dir_entry3 ) ) |
|
|
|
|
goto Exit; |
|
|
|
|
|
|
|
|
|
if ( dir_entry2.offset & 0x80000000UL /* DataIsDirectory */ ) |
|
|
|
|
{ |
|
|
|
|
error = FNT_Err_Invalid_File_Format; |
|
|
|
|
goto Exit; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ( dir_entry1.name == 8 /* RT_FONT */ ) |
|
|
|
|
{ |
|
|
|
|
if ( FT_STREAM_SEEK( root_dir_offset + dir_entry3.offset ) || |
|
|
|
|
FT_STREAM_READ_FIELDS( winpe_rsrc_data_entry_fields, |
|
|
|
|
&data_entry ) ) |
|
|
|
|
goto Exit; |
|
|
|
|
|
|
|
|
|
FT_TRACE2(( "found font #%lu, offset %04lx, " |
|
|
|
|
"size %04lx, cp %lu\n", |
|
|
|
|
dir_entry2.name, |
|
|
|
|
pe32_section.pointer_to_raw_data + |
|
|
|
|
data_entry.offset_to_data - |
|
|
|
|
pe32_section.virtual_address, |
|
|
|
|
data_entry.size, data_entry.code_page )); |
|
|
|
|
|
|
|
|
|
if ( face_index == face->root.num_faces ) |
|
|
|
|
{ |
|
|
|
|
if ( FT_NEW( face->font ) ) |
|
|
|
|
goto Exit; |
|
|
|
|
|
|
|
|
|
face->font->offset = pe32_section.pointer_to_raw_data + |
|
|
|
|
data_entry.offset_to_data - |
|
|
|
|
pe32_section.virtual_address; |
|
|
|
|
face->font->fnt_size = data_entry.size; |
|
|
|
|
|
|
|
|
|
error = fnt_font_load( face->font, stream ); |
|
|
|
|
if ( error ) |
|
|
|
|
FT_TRACE2(( "font #%lu load error %d\n", |
|
|
|
|
dir_entry2.name, error )); |
|
|
|
|
else |
|
|
|
|
FT_TRACE2(( "font #%lu successfully loaded\n", |
|
|
|
|
dir_entry2.name )); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
face->root.num_faces++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ( face_index >= face->root.num_faces ) |
|
|
|
|
{ |
|
|
|
|
error = FNT_Err_Bad_Argument; |
|
|
|
|
goto Exit; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Fail: |
|
|
|
|