* 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.
diff --git a/ChangeLog b/ChangeLog
index 3872fe0..b5b2fdc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2006-06-16  Dmitry Timoshkov  <dmitry@codeweavers.com>
+
+	* 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  <dmitry@codeweavers.com>
 
 	* builds/win32/ftdebug.c: Unify debug level handling with other
diff --git a/ChangeLog.21 b/ChangeLog.21
index 1d8bb30..3a1bcf0 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  <huw@codeweavers.com>
+2003-01-08  Huw Davies  <huw@codeweavers.com>
 
 	* src/winfonts/winfnt.c (winfnt_header_fields): Read 16 bytes into
 	`reserved2', not `reserved'.
diff --git a/docs/CHANGES b/docs/CHANGES
index 6a2d7a6..c744cd6 100644
--- a/docs/CHANGES
+++ b/docs/CHANGES
@@ -32,6 +32,9 @@
       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 9ee9f67..ff24584 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 32ab6da..ca75c95 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 @@
   } 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 @@
 
 #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;