diff --git a/ChangeLog b/ChangeLog index 3872fe071..b5b2fdc78 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2006-06-16 Dmitry Timoshkov + + * src/winfonts/winfnt.h: Add necessary structures for PE resource + parsing. + (WinPE32_HeaderRec): New structure. + (WinPE32_SectionRec): New structure. + (WinPE_RsrcDirRec): New structure. + (WinPE_RsrcDirEntryRec): New structure. + (WinPE_RsrcDataEntryRec): New structure. + (FNT_FontRec): Remove unused `size_shift' field. + + * src/winfonts/winfnt.c (fnt_face_get_dll_font): Add support for + loading bitmap .fon files in PE format. + 2006-06-15 Dmitry Timoshkov * builds/win32/ftdebug.c: Unify debug level handling with other diff --git a/ChangeLog.21 b/ChangeLog.21 index 1d8bb3028..3a1bcf0c1 100644 --- a/ChangeLog.21 +++ b/ChangeLog.21 @@ -6391,7 +6391,7 @@ * include/freetype/internal/fnttypes.h (WinFNT_HeaderRec): Increase size of `reserved2' to avoid memory overwrites. -2003-01-08 Huw Dawies +2003-01-08 Huw Davies * src/winfonts/winfnt.c (winfnt_header_fields): Read 16 bytes into `reserved2', not `reserved'. diff --git a/docs/CHANGES b/docs/CHANGES index 6a2d7a6d5..c744cd666 100644 --- a/docs/CHANGES +++ b/docs/CHANGES @@ -32,6 +32,9 @@ CHANGES BETWEEN 2.3.5 and 2.3.4 out whether a given TrueType font uses patented bytecode instructions. + - Support for Windows FON files in PE format has been contributed + by Dmitry Timoshkov. + III. MISCELLANEOUS diff --git a/src/winfonts/winfnt.c b/src/winfonts/winfnt.c index 9ee9f6755..ff2458415 100644 --- a/src/winfonts/winfnt.c +++ b/src/winfonts/winfnt.c @@ -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: diff --git a/src/winfonts/winfnt.h b/src/winfonts/winfnt.h index 32ab6daf0..ca75c9501 100644 --- a/src/winfonts/winfnt.h +++ b/src/winfonts/winfnt.h @@ -4,8 +4,9 @@ /* */ /* FreeType font driver for Windows FNT/FON files */ /* */ -/* Copyright 1996-2001, 2002, 2003, 2004 by */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2007 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* 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 */ @@ -46,6 +47,65 @@ FT_BEGIN_HEADER } WinNE_HeaderRec; + typedef struct WinPE32_HeaderRec_ + { + FT_ULong magic; + FT_UShort machine; + FT_UShort number_of_sections; + /* skipped content */ + FT_UShort size_of_optional_header; + /* skipped content */ + FT_UShort magic32; + /* skipped content */ + FT_ULong rsrc_virtual_address; + FT_ULong rsrc_size; + /* skipped content */ + + } WinPE32_HeaderRec; + + + typedef struct WinPE32_SectionRec_ + { + FT_Byte name[8]; + /* skipped content */ + FT_ULong virtual_address; + FT_ULong size_of_raw_data; + FT_ULong pointer_to_raw_data; + /* skipped content */ + + } WinPE32_SectionRec; + + + typedef struct WinPE_RsrcDirRec_ + { + FT_ULong characteristics; + FT_ULong time_date_stamp; + FT_UShort major_version; + FT_UShort minor_version; + FT_UShort number_of_named_entries; + FT_UShort number_of_id_entries; + + } WinPE_RsrcDirRec; + + + typedef struct WinPE_RsrcDirEntryRec_ + { + FT_ULong name; + FT_ULong offset; + + } WinPE_RsrcDirEntryRec; + + + typedef struct WinPE_RsrcDataEntryRec_ + { + FT_ULong offset_to_data; + FT_ULong size; + FT_ULong code_page; + FT_ULong reserved; + + } WinPE_RsrcDataEntryRec; + + typedef struct WinNameInfoRec_ { FT_UShort offset; @@ -68,12 +128,12 @@ FT_BEGIN_HEADER #define WINFNT_MZ_MAGIC 0x5A4D #define WINFNT_NE_MAGIC 0x454E +#define WINFNT_PE_MAGIC 0x4550 typedef struct FNT_FontRec_ { FT_ULong offset; - FT_Int size_shift; FT_WinFNT_HeaderRec header;