misc/libfreetype/src/winfonts/winfnt.c
changeset 9372 915436ff64ab
parent 9371 f3840de881bd
child 9373 b769a8e38cbd
equal deleted inserted replaced
9371:f3840de881bd 9372:915436ff64ab
     1 /***************************************************************************/
       
     2 /*                                                                         */
       
     3 /*  winfnt.c                                                               */
       
     4 /*                                                                         */
       
     5 /*    FreeType font driver for Windows FNT/FON files                       */
       
     6 /*                                                                         */
       
     7 /*  Copyright 1996-2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010 by */
       
     8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
       
     9 /*  Copyright 2003 Huw D M Davies for Codeweavers                          */
       
    10 /*  Copyright 2007 Dmitry Timoshkov for Codeweavers                        */
       
    11 /*                                                                         */
       
    12 /*  This file is part of the FreeType project, and may only be used,       */
       
    13 /*  modified, and distributed under the terms of the FreeType project      */
       
    14 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
       
    15 /*  this file you indicate that you have read the license and              */
       
    16 /*  understand and accept it fully.                                        */
       
    17 /*                                                                         */
       
    18 /***************************************************************************/
       
    19 
       
    20 
       
    21 #include <ft2build.h>
       
    22 #include FT_WINFONTS_H
       
    23 #include FT_INTERNAL_DEBUG_H
       
    24 #include FT_INTERNAL_STREAM_H
       
    25 #include FT_INTERNAL_OBJECTS_H
       
    26 #include FT_TRUETYPE_IDS_H 
       
    27 
       
    28 #include "winfnt.h"
       
    29 #include "fnterrs.h"
       
    30 #include FT_SERVICE_WINFNT_H
       
    31 #include FT_SERVICE_XFREE86_NAME_H
       
    32 
       
    33   /*************************************************************************/
       
    34   /*                                                                       */
       
    35   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
       
    36   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
       
    37   /* messages during execution.                                            */
       
    38   /*                                                                       */
       
    39 #undef  FT_COMPONENT
       
    40 #define FT_COMPONENT  trace_winfnt
       
    41 
       
    42 
       
    43   static const FT_Frame_Field  winmz_header_fields[] =
       
    44   {
       
    45 #undef  FT_STRUCTURE
       
    46 #define FT_STRUCTURE  WinMZ_HeaderRec
       
    47 
       
    48     FT_FRAME_START( 64 ),
       
    49       FT_FRAME_USHORT_LE ( magic ),
       
    50       FT_FRAME_SKIP_BYTES( 29 * 2 ),
       
    51       FT_FRAME_ULONG_LE  ( lfanew ),
       
    52     FT_FRAME_END
       
    53   };
       
    54 
       
    55   static const FT_Frame_Field  winne_header_fields[] =
       
    56   {
       
    57 #undef  FT_STRUCTURE
       
    58 #define FT_STRUCTURE  WinNE_HeaderRec
       
    59 
       
    60     FT_FRAME_START( 40 ),
       
    61       FT_FRAME_USHORT_LE ( magic ),
       
    62       FT_FRAME_SKIP_BYTES( 34 ),
       
    63       FT_FRAME_USHORT_LE ( resource_tab_offset ),
       
    64       FT_FRAME_USHORT_LE ( rname_tab_offset ),
       
    65     FT_FRAME_END
       
    66   };
       
    67 
       
    68   static const FT_Frame_Field  winpe32_header_fields[] =
       
    69   {
       
    70 #undef  FT_STRUCTURE
       
    71 #define FT_STRUCTURE  WinPE32_HeaderRec
       
    72 
       
    73     FT_FRAME_START( 248 ),
       
    74       FT_FRAME_ULONG_LE  ( magic ),   /* PE00 */
       
    75       FT_FRAME_USHORT_LE ( machine ), /* 0x014c - i386 */
       
    76       FT_FRAME_USHORT_LE ( number_of_sections ),
       
    77       FT_FRAME_SKIP_BYTES( 12 ),
       
    78       FT_FRAME_USHORT_LE ( size_of_optional_header ),
       
    79       FT_FRAME_SKIP_BYTES( 2 ),
       
    80       FT_FRAME_USHORT_LE ( magic32 ), /* 0x10b */
       
    81       FT_FRAME_SKIP_BYTES( 110 ),
       
    82       FT_FRAME_ULONG_LE  ( rsrc_virtual_address ),
       
    83       FT_FRAME_ULONG_LE  ( rsrc_size ),
       
    84       FT_FRAME_SKIP_BYTES( 104 ),
       
    85     FT_FRAME_END
       
    86   };
       
    87 
       
    88   static const FT_Frame_Field  winpe32_section_fields[] =
       
    89   {
       
    90 #undef  FT_STRUCTURE
       
    91 #define FT_STRUCTURE  WinPE32_SectionRec
       
    92 
       
    93     FT_FRAME_START( 40 ),
       
    94       FT_FRAME_BYTES     ( name, 8 ),
       
    95       FT_FRAME_SKIP_BYTES( 4 ),
       
    96       FT_FRAME_ULONG_LE  ( virtual_address ),
       
    97       FT_FRAME_ULONG_LE  ( size_of_raw_data ),
       
    98       FT_FRAME_ULONG_LE  ( pointer_to_raw_data ),
       
    99       FT_FRAME_SKIP_BYTES( 16 ),
       
   100     FT_FRAME_END
       
   101   };
       
   102 
       
   103   static const FT_Frame_Field  winpe_rsrc_dir_fields[] =
       
   104   {
       
   105 #undef  FT_STRUCTURE
       
   106 #define FT_STRUCTURE  WinPE_RsrcDirRec
       
   107 
       
   108     FT_FRAME_START( 16 ),
       
   109       FT_FRAME_ULONG_LE ( characteristics ),
       
   110       FT_FRAME_ULONG_LE ( time_date_stamp ),
       
   111       FT_FRAME_USHORT_LE( major_version ),
       
   112       FT_FRAME_USHORT_LE( minor_version ),
       
   113       FT_FRAME_USHORT_LE( number_of_named_entries ),
       
   114       FT_FRAME_USHORT_LE( number_of_id_entries ),
       
   115     FT_FRAME_END
       
   116   };
       
   117 
       
   118   static const FT_Frame_Field  winpe_rsrc_dir_entry_fields[] =
       
   119   {
       
   120 #undef  FT_STRUCTURE
       
   121 #define FT_STRUCTURE  WinPE_RsrcDirEntryRec
       
   122 
       
   123     FT_FRAME_START( 8 ),
       
   124       FT_FRAME_ULONG_LE( name ),
       
   125       FT_FRAME_ULONG_LE( offset ),
       
   126     FT_FRAME_END
       
   127   };
       
   128 
       
   129   static const FT_Frame_Field  winpe_rsrc_data_entry_fields[] =
       
   130   {
       
   131 #undef  FT_STRUCTURE
       
   132 #define FT_STRUCTURE  WinPE_RsrcDataEntryRec
       
   133 
       
   134     FT_FRAME_START( 16 ),
       
   135       FT_FRAME_ULONG_LE( offset_to_data ),
       
   136       FT_FRAME_ULONG_LE( size ),
       
   137       FT_FRAME_ULONG_LE( code_page ),
       
   138       FT_FRAME_ULONG_LE( reserved ),
       
   139     FT_FRAME_END
       
   140   };
       
   141 
       
   142   static const FT_Frame_Field  winfnt_header_fields[] =
       
   143   {
       
   144 #undef  FT_STRUCTURE
       
   145 #define FT_STRUCTURE  FT_WinFNT_HeaderRec
       
   146 
       
   147     FT_FRAME_START( 148 ),
       
   148       FT_FRAME_USHORT_LE( version ),
       
   149       FT_FRAME_ULONG_LE ( file_size ),
       
   150       FT_FRAME_BYTES    ( copyright, 60 ),
       
   151       FT_FRAME_USHORT_LE( file_type ),
       
   152       FT_FRAME_USHORT_LE( nominal_point_size ),
       
   153       FT_FRAME_USHORT_LE( vertical_resolution ),
       
   154       FT_FRAME_USHORT_LE( horizontal_resolution ),
       
   155       FT_FRAME_USHORT_LE( ascent ),
       
   156       FT_FRAME_USHORT_LE( internal_leading ),
       
   157       FT_FRAME_USHORT_LE( external_leading ),
       
   158       FT_FRAME_BYTE     ( italic ),
       
   159       FT_FRAME_BYTE     ( underline ),
       
   160       FT_FRAME_BYTE     ( strike_out ),
       
   161       FT_FRAME_USHORT_LE( weight ),
       
   162       FT_FRAME_BYTE     ( charset ),
       
   163       FT_FRAME_USHORT_LE( pixel_width ),
       
   164       FT_FRAME_USHORT_LE( pixel_height ),
       
   165       FT_FRAME_BYTE     ( pitch_and_family ),
       
   166       FT_FRAME_USHORT_LE( avg_width ),
       
   167       FT_FRAME_USHORT_LE( max_width ),
       
   168       FT_FRAME_BYTE     ( first_char ),
       
   169       FT_FRAME_BYTE     ( last_char ),
       
   170       FT_FRAME_BYTE     ( default_char ),
       
   171       FT_FRAME_BYTE     ( break_char ),
       
   172       FT_FRAME_USHORT_LE( bytes_per_row ),
       
   173       FT_FRAME_ULONG_LE ( device_offset ),
       
   174       FT_FRAME_ULONG_LE ( face_name_offset ),
       
   175       FT_FRAME_ULONG_LE ( bits_pointer ),
       
   176       FT_FRAME_ULONG_LE ( bits_offset ),
       
   177       FT_FRAME_BYTE     ( reserved ),
       
   178       FT_FRAME_ULONG_LE ( flags ),
       
   179       FT_FRAME_USHORT_LE( A_space ),
       
   180       FT_FRAME_USHORT_LE( B_space ),
       
   181       FT_FRAME_USHORT_LE( C_space ),
       
   182       FT_FRAME_ULONG_LE ( color_table_offset ),
       
   183       FT_FRAME_BYTES    ( reserved1, 16 ),
       
   184     FT_FRAME_END
       
   185   };
       
   186 
       
   187 
       
   188   static void
       
   189   fnt_font_done( FNT_Face face )
       
   190   {
       
   191     FT_Memory  memory = FT_FACE( face )->memory;
       
   192     FT_Stream  stream = FT_FACE( face )->stream;
       
   193     FNT_Font   font   = face->font;
       
   194 
       
   195 
       
   196     if ( !font )
       
   197       return;
       
   198 
       
   199     if ( font->fnt_frame )
       
   200       FT_FRAME_RELEASE( font->fnt_frame );
       
   201     FT_FREE( font->family_name );
       
   202 
       
   203     FT_FREE( font );
       
   204     face->font = 0;
       
   205   }
       
   206 
       
   207 
       
   208   static FT_Error
       
   209   fnt_font_load( FNT_Font   font,
       
   210                  FT_Stream  stream )
       
   211   {
       
   212     FT_Error          error;
       
   213     FT_WinFNT_Header  header = &font->header;
       
   214     FT_Bool           new_format;
       
   215     FT_UInt           size;
       
   216 
       
   217 
       
   218     /* first of all, read the FNT header */
       
   219     if ( FT_STREAM_SEEK( font->offset )                        ||
       
   220          FT_STREAM_READ_FIELDS( winfnt_header_fields, header ) )
       
   221       goto Exit;
       
   222 
       
   223     /* check header */
       
   224     if ( header->version != 0x200 &&
       
   225          header->version != 0x300 )
       
   226     {
       
   227       FT_TRACE2(( "[not a valid FNT file]\n" ));
       
   228       error = FNT_Err_Unknown_File_Format;
       
   229       goto Exit;
       
   230     }
       
   231 
       
   232     new_format = FT_BOOL( font->header.version == 0x300 );
       
   233     size       = new_format ? 148 : 118;
       
   234 
       
   235     if ( header->file_size < size )
       
   236     {
       
   237       FT_TRACE2(( "[not a valid FNT file]\n" ));
       
   238       error = FNT_Err_Unknown_File_Format;
       
   239       goto Exit;
       
   240     }
       
   241 
       
   242     /* Version 2 doesn't have these fields */
       
   243     if ( header->version == 0x200 )
       
   244     {
       
   245       header->flags   = 0;
       
   246       header->A_space = 0;
       
   247       header->B_space = 0;
       
   248       header->C_space = 0;
       
   249 
       
   250       header->color_table_offset = 0;
       
   251     }
       
   252 
       
   253     if ( header->file_type & 1 )
       
   254     {
       
   255       FT_TRACE2(( "[can't handle vector FNT fonts]\n" ));
       
   256       error = FNT_Err_Unknown_File_Format;
       
   257       goto Exit;
       
   258     }
       
   259 
       
   260     /* this is a FNT file/table; extract its frame */
       
   261     if ( FT_STREAM_SEEK( font->offset )                         ||
       
   262          FT_FRAME_EXTRACT( header->file_size, font->fnt_frame ) )
       
   263       goto Exit;
       
   264 
       
   265   Exit:
       
   266     return error;
       
   267   }
       
   268 
       
   269 
       
   270   static FT_Error
       
   271   fnt_face_get_dll_font( FNT_Face  face,
       
   272                          FT_Int    face_index )
       
   273   {
       
   274     FT_Error         error;
       
   275     FT_Stream        stream = FT_FACE( face )->stream;
       
   276     FT_Memory        memory = FT_FACE( face )->memory;
       
   277     WinMZ_HeaderRec  mz_header;
       
   278 
       
   279 
       
   280     face->font = 0;
       
   281 
       
   282     /* does it begin with an MZ header? */
       
   283     if ( FT_STREAM_SEEK( 0 )                                      ||
       
   284          FT_STREAM_READ_FIELDS( winmz_header_fields, &mz_header ) )
       
   285       goto Exit;
       
   286 
       
   287     error = FNT_Err_Unknown_File_Format;
       
   288     if ( mz_header.magic == WINFNT_MZ_MAGIC )
       
   289     {
       
   290       /* yes, now look for an NE header in the file */
       
   291       WinNE_HeaderRec  ne_header;
       
   292 
       
   293 
       
   294       FT_TRACE2(( "MZ signature found\n" ));
       
   295 
       
   296       if ( FT_STREAM_SEEK( mz_header.lfanew )                       ||
       
   297            FT_STREAM_READ_FIELDS( winne_header_fields, &ne_header ) )
       
   298         goto Exit;
       
   299 
       
   300       error = FNT_Err_Unknown_File_Format;
       
   301       if ( ne_header.magic == WINFNT_NE_MAGIC )
       
   302       {
       
   303         /* good, now look into the resource table for each FNT resource */
       
   304         FT_ULong   res_offset  = mz_header.lfanew +
       
   305                                    ne_header.resource_tab_offset;
       
   306         FT_UShort  size_shift;
       
   307         FT_UShort  font_count  = 0;
       
   308         FT_ULong   font_offset = 0;
       
   309 
       
   310 
       
   311         FT_TRACE2(( "NE signature found\n" ));
       
   312 
       
   313         if ( FT_STREAM_SEEK( res_offset )                    ||
       
   314              FT_FRAME_ENTER( ne_header.rname_tab_offset -
       
   315                              ne_header.resource_tab_offset ) )
       
   316           goto Exit;
       
   317 
       
   318         size_shift = FT_GET_USHORT_LE();
       
   319 
       
   320         for (;;)
       
   321         {
       
   322           FT_UShort  type_id, count;
       
   323 
       
   324 
       
   325           type_id = FT_GET_USHORT_LE();
       
   326           if ( !type_id )
       
   327             break;
       
   328 
       
   329           count = FT_GET_USHORT_LE();
       
   330 
       
   331           if ( type_id == 0x8008U )
       
   332           {
       
   333             font_count  = count;
       
   334             font_offset = (FT_ULong)( FT_STREAM_POS() + 4 +
       
   335                                       ( stream->cursor - stream->limit ) );
       
   336             break;
       
   337           }
       
   338 
       
   339           stream->cursor += 4 + count * 12;
       
   340         }
       
   341 
       
   342         FT_FRAME_EXIT();
       
   343 
       
   344         if ( !font_count || !font_offset )
       
   345         {
       
   346           FT_TRACE2(( "this file doesn't contain any FNT resources\n" ));
       
   347           error = FNT_Err_Invalid_File_Format;
       
   348           goto Exit;
       
   349         }
       
   350 
       
   351         /* loading `winfnt_header_fields' needs at least 118 bytes;    */
       
   352         /* use this as a rough measure to check the expected font size */
       
   353         if ( font_count * 118UL > stream->size )
       
   354         {
       
   355           FT_TRACE2(( "invalid number of faces\n" ));
       
   356           error = FNT_Err_Invalid_File_Format;
       
   357           goto Exit;
       
   358         }
       
   359 
       
   360         face->root.num_faces = font_count;
       
   361 
       
   362         if ( face_index >= font_count )
       
   363         {
       
   364           error = FNT_Err_Invalid_Argument;
       
   365           goto Exit;
       
   366         }
       
   367         else if ( face_index < 0 )
       
   368           goto Exit;
       
   369 
       
   370         if ( FT_NEW( face->font ) )
       
   371           goto Exit;
       
   372 
       
   373         if ( FT_STREAM_SEEK( font_offset + face_index * 12 ) ||
       
   374              FT_FRAME_ENTER( 12 )                            )
       
   375           goto Fail;
       
   376 
       
   377         face->font->offset   = (FT_ULong)FT_GET_USHORT_LE() << size_shift;
       
   378         face->font->fnt_size = (FT_ULong)FT_GET_USHORT_LE() << size_shift;
       
   379 
       
   380         stream->cursor += 8;
       
   381 
       
   382         FT_FRAME_EXIT();
       
   383 
       
   384         error = fnt_font_load( face->font, stream );
       
   385       }
       
   386       else if ( ne_header.magic == WINFNT_PE_MAGIC )
       
   387       {
       
   388         WinPE32_HeaderRec       pe32_header;
       
   389         WinPE32_SectionRec      pe32_section;
       
   390         WinPE_RsrcDirRec        root_dir, name_dir, lang_dir;
       
   391         WinPE_RsrcDirEntryRec   dir_entry1, dir_entry2, dir_entry3;
       
   392         WinPE_RsrcDataEntryRec  data_entry;
       
   393 
       
   394         FT_Long    root_dir_offset, name_dir_offset, lang_dir_offset;
       
   395         FT_UShort  i, j, k;
       
   396 
       
   397 
       
   398         FT_TRACE2(( "PE signature found\n" ));
       
   399 
       
   400         if ( FT_STREAM_SEEK( mz_header.lfanew )                           ||
       
   401              FT_STREAM_READ_FIELDS( winpe32_header_fields, &pe32_header ) )
       
   402           goto Exit;
       
   403 
       
   404         FT_TRACE2(( "magic %04lx, machine %02x, number_of_sections %u, "
       
   405                     "size_of_optional_header %02x\n"
       
   406                     "magic32 %02x, rsrc_virtual_address %04lx, "
       
   407                     "rsrc_size %04lx\n",
       
   408                     pe32_header.magic, pe32_header.machine,
       
   409                     pe32_header.number_of_sections,
       
   410                     pe32_header.size_of_optional_header,
       
   411                     pe32_header.magic32, pe32_header.rsrc_virtual_address,
       
   412                     pe32_header.rsrc_size ));
       
   413 
       
   414         if ( pe32_header.magic != WINFNT_PE_MAGIC /* check full signature */ ||
       
   415              pe32_header.machine != 0x014c /* i386 */                        ||
       
   416              pe32_header.size_of_optional_header != 0xe0 /* FIXME */         ||
       
   417              pe32_header.magic32 != 0x10b                                    )
       
   418         {
       
   419           FT_TRACE2(( "this file has an invalid PE header\n" ));
       
   420           error = FNT_Err_Invalid_File_Format;
       
   421           goto Exit;
       
   422         }
       
   423 
       
   424         face->root.num_faces = 0;
       
   425 
       
   426         for ( i = 0; i < pe32_header.number_of_sections; i++ )
       
   427         {
       
   428           if ( FT_STREAM_READ_FIELDS( winpe32_section_fields,
       
   429                                       &pe32_section ) )
       
   430             goto Exit;
       
   431 
       
   432           FT_TRACE2(( "name %.8s, va %04lx, size %04lx, offset %04lx\n",
       
   433                       pe32_section.name, pe32_section.virtual_address,
       
   434                       pe32_section.size_of_raw_data,
       
   435                       pe32_section.pointer_to_raw_data ));
       
   436 
       
   437           if ( pe32_header.rsrc_virtual_address ==
       
   438                  pe32_section.virtual_address )
       
   439             goto Found_rsrc_section;
       
   440         }
       
   441 
       
   442         FT_TRACE2(( "this file doesn't contain any resources\n" ));
       
   443         error = FNT_Err_Invalid_File_Format;
       
   444         goto Exit;
       
   445 
       
   446       Found_rsrc_section:
       
   447         FT_TRACE2(( "found resources section %.8s\n", pe32_section.name ));
       
   448 
       
   449         if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data )        ||
       
   450              FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &root_dir ) )
       
   451           goto Exit;
       
   452 
       
   453         root_dir_offset = pe32_section.pointer_to_raw_data;
       
   454 
       
   455         for ( i = 0; i < root_dir.number_of_named_entries +
       
   456                            root_dir.number_of_id_entries; i++ )
       
   457         {
       
   458           if ( FT_STREAM_SEEK( root_dir_offset + 16 + i * 8 )      ||
       
   459                FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields,
       
   460                                       &dir_entry1 )                )
       
   461             goto Exit;
       
   462 
       
   463           if ( !(dir_entry1.offset & 0x80000000UL ) /* DataIsDirectory */ )
       
   464           {
       
   465             error = FNT_Err_Invalid_File_Format;
       
   466             goto Exit;
       
   467           }
       
   468 
       
   469           dir_entry1.offset &= ~0x80000000UL;
       
   470 
       
   471           name_dir_offset = pe32_section.pointer_to_raw_data +
       
   472                             dir_entry1.offset;
       
   473 
       
   474           if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data +
       
   475                                dir_entry1.offset )                       ||
       
   476                FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &name_dir ) )
       
   477             goto Exit;
       
   478 
       
   479           for ( j = 0; j < name_dir.number_of_named_entries +
       
   480                              name_dir.number_of_id_entries; j++ )
       
   481           {
       
   482             if ( FT_STREAM_SEEK( name_dir_offset + 16 + j * 8 )      ||
       
   483                  FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields,
       
   484                                         &dir_entry2 )                )
       
   485               goto Exit;
       
   486 
       
   487             if ( !(dir_entry2.offset & 0x80000000UL ) /* DataIsDirectory */ )
       
   488             {
       
   489               error = FNT_Err_Invalid_File_Format;
       
   490               goto Exit;
       
   491             }
       
   492 
       
   493             dir_entry2.offset &= ~0x80000000UL;
       
   494 
       
   495             lang_dir_offset = pe32_section.pointer_to_raw_data +
       
   496                                 dir_entry2.offset;
       
   497 
       
   498             if ( FT_STREAM_SEEK( pe32_section.pointer_to_raw_data +
       
   499                                    dir_entry2.offset )                     ||
       
   500                  FT_STREAM_READ_FIELDS( winpe_rsrc_dir_fields, &lang_dir ) )
       
   501               goto Exit;
       
   502 
       
   503             for ( k = 0; k < lang_dir.number_of_named_entries +
       
   504                                lang_dir.number_of_id_entries; k++ )
       
   505             {
       
   506               if ( FT_STREAM_SEEK( lang_dir_offset + 16 + k * 8 )      ||
       
   507                    FT_STREAM_READ_FIELDS( winpe_rsrc_dir_entry_fields,
       
   508                                           &dir_entry3 )                )
       
   509                 goto Exit;
       
   510 
       
   511               if ( dir_entry2.offset & 0x80000000UL /* DataIsDirectory */ )
       
   512               {
       
   513                 error = FNT_Err_Invalid_File_Format;
       
   514                 goto Exit;
       
   515               }
       
   516 
       
   517               if ( dir_entry1.name == 8 /* RT_FONT */ )
       
   518               {
       
   519                 if ( FT_STREAM_SEEK( root_dir_offset + dir_entry3.offset ) ||
       
   520                      FT_STREAM_READ_FIELDS( winpe_rsrc_data_entry_fields,
       
   521                                             &data_entry )                  )
       
   522                   goto Exit;
       
   523 
       
   524                 FT_TRACE2(( "found font #%lu, offset %04lx, "
       
   525                             "size %04lx, cp %lu\n",
       
   526                             dir_entry2.name,
       
   527                             pe32_section.pointer_to_raw_data +
       
   528                               data_entry.offset_to_data -
       
   529                               pe32_section.virtual_address,
       
   530                             data_entry.size, data_entry.code_page ));
       
   531 
       
   532                 if ( face_index == face->root.num_faces )
       
   533                 {
       
   534                   if ( FT_NEW( face->font ) )
       
   535                     goto Exit;
       
   536 
       
   537                   face->font->offset   = pe32_section.pointer_to_raw_data +
       
   538                                            data_entry.offset_to_data -
       
   539                                            pe32_section.virtual_address;
       
   540                   face->font->fnt_size = data_entry.size;
       
   541 
       
   542                   error = fnt_font_load( face->font, stream );
       
   543                   if ( error )
       
   544                   {
       
   545                     FT_TRACE2(( "font #%lu load error %d\n",
       
   546                                 dir_entry2.name, error ));
       
   547                     goto Fail;
       
   548                   }
       
   549                   else
       
   550                     FT_TRACE2(( "font #%lu successfully loaded\n",
       
   551                                 dir_entry2.name ));
       
   552                 }
       
   553 
       
   554                 face->root.num_faces++;
       
   555               }
       
   556             }
       
   557           }
       
   558         }
       
   559       }
       
   560 
       
   561       if ( !face->root.num_faces )
       
   562       {
       
   563         FT_TRACE2(( "this file doesn't contain any RT_FONT resources\n" ));
       
   564         error = FNT_Err_Invalid_File_Format;
       
   565         goto Exit;
       
   566       }
       
   567 
       
   568       if ( face_index >= face->root.num_faces )
       
   569       {
       
   570         error = FNT_Err_Invalid_Argument;
       
   571         goto Exit;
       
   572       }
       
   573     }
       
   574 
       
   575   Fail:
       
   576     if ( error )
       
   577       fnt_font_done( face );
       
   578 
       
   579   Exit:
       
   580     return error;
       
   581   }
       
   582 
       
   583 
       
   584   typedef struct  FNT_CMapRec_
       
   585   {
       
   586     FT_CMapRec  cmap;
       
   587     FT_UInt32   first;
       
   588     FT_UInt32   count;
       
   589 
       
   590   } FNT_CMapRec, *FNT_CMap;
       
   591 
       
   592 
       
   593   static FT_Error
       
   594   fnt_cmap_init( FNT_CMap  cmap )
       
   595   {
       
   596     FNT_Face  face = (FNT_Face)FT_CMAP_FACE( cmap );
       
   597     FNT_Font  font = face->font;
       
   598 
       
   599 
       
   600     cmap->first = (FT_UInt32)  font->header.first_char;
       
   601     cmap->count = (FT_UInt32)( font->header.last_char - cmap->first + 1 );
       
   602 
       
   603     return 0;
       
   604   }
       
   605 
       
   606 
       
   607   static FT_UInt
       
   608   fnt_cmap_char_index( FNT_CMap   cmap,
       
   609                        FT_UInt32  char_code )
       
   610   {
       
   611     FT_UInt  gindex = 0;
       
   612 
       
   613 
       
   614     char_code -= cmap->first;
       
   615     if ( char_code < cmap->count )
       
   616       /* we artificially increase the glyph index; */
       
   617       /* FNT_Load_Glyph reverts to the right one   */
       
   618       gindex = (FT_UInt)( char_code + 1 );
       
   619     return gindex;
       
   620   }
       
   621 
       
   622 
       
   623   static FT_UInt32
       
   624   fnt_cmap_char_next( FNT_CMap    cmap,
       
   625                       FT_UInt32  *pchar_code )
       
   626   {
       
   627     FT_UInt    gindex = 0;
       
   628     FT_UInt32  result = 0;
       
   629     FT_UInt32  char_code = *pchar_code + 1;
       
   630 
       
   631 
       
   632     if ( char_code <= cmap->first )
       
   633     {
       
   634       result = cmap->first;
       
   635       gindex = 1;
       
   636     }
       
   637     else
       
   638     {
       
   639       char_code -= cmap->first;
       
   640       if ( char_code < cmap->count )
       
   641       {
       
   642         result = cmap->first + char_code;
       
   643         gindex = (FT_UInt)( char_code + 1 );
       
   644       }
       
   645     }
       
   646 
       
   647     *pchar_code = result;
       
   648     return gindex;
       
   649   }
       
   650 
       
   651 
       
   652   static const FT_CMap_ClassRec  fnt_cmap_class_rec =
       
   653   {
       
   654     sizeof ( FNT_CMapRec ),
       
   655 
       
   656     (FT_CMap_InitFunc)     fnt_cmap_init,
       
   657     (FT_CMap_DoneFunc)     NULL,
       
   658     (FT_CMap_CharIndexFunc)fnt_cmap_char_index,
       
   659     (FT_CMap_CharNextFunc) fnt_cmap_char_next,
       
   660 
       
   661     NULL, NULL, NULL, NULL, NULL
       
   662   };
       
   663 
       
   664   static FT_CMap_Class const  fnt_cmap_class = &fnt_cmap_class_rec;
       
   665 
       
   666 
       
   667   static void
       
   668   FNT_Face_Done( FNT_Face  face )
       
   669   {
       
   670     FT_Memory  memory;
       
   671 
       
   672 
       
   673     if ( !face )
       
   674       return;
       
   675 
       
   676     memory = FT_FACE_MEMORY( face );
       
   677 
       
   678     fnt_font_done( face );
       
   679 
       
   680     FT_FREE( face->root.available_sizes );
       
   681     face->root.num_fixed_sizes = 0;
       
   682   }
       
   683 
       
   684 
       
   685   static FT_Error
       
   686   FNT_Face_Init( FT_Stream      stream,
       
   687                  FNT_Face       face,
       
   688                  FT_Int         face_index,
       
   689                  FT_Int         num_params,
       
   690                  FT_Parameter*  params )
       
   691   {
       
   692     FT_Error   error;
       
   693     FT_Memory  memory = FT_FACE_MEMORY( face );
       
   694 
       
   695     FT_UNUSED( num_params );
       
   696     FT_UNUSED( params );
       
   697 
       
   698 
       
   699     /* try to load font from a DLL */
       
   700     error = fnt_face_get_dll_font( face, face_index );
       
   701     if ( !error && face_index < 0 )
       
   702       goto Exit;
       
   703 
       
   704     if ( error == FNT_Err_Unknown_File_Format )
       
   705     {
       
   706       /* this didn't work; try to load a single FNT font */
       
   707       FNT_Font  font;
       
   708 
       
   709       if ( FT_NEW( face->font ) )
       
   710         goto Exit;
       
   711 
       
   712       face->root.num_faces = 1;
       
   713 
       
   714       font           = face->font;
       
   715       font->offset   = 0;
       
   716       font->fnt_size = stream->size;
       
   717 
       
   718       error = fnt_font_load( font, stream );
       
   719 
       
   720       if ( !error )
       
   721       {
       
   722         if ( face_index > 0 )
       
   723           error = FNT_Err_Invalid_Argument;
       
   724         else if ( face_index < 0 )
       
   725           goto Exit;
       
   726       }
       
   727     }
       
   728 
       
   729     if ( error )
       
   730       goto Fail;
       
   731 
       
   732     /* we now need to fill the root FT_Face fields */
       
   733     /* with relevant information                   */
       
   734     {
       
   735       FT_Face     root = FT_FACE( face );
       
   736       FNT_Font    font = face->font;
       
   737       FT_PtrDist  family_size;
       
   738 
       
   739 
       
   740       root->face_index = face_index;
       
   741 
       
   742       root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
       
   743                          FT_FACE_FLAG_HORIZONTAL;
       
   744 
       
   745       if ( font->header.avg_width == font->header.max_width )
       
   746         root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
       
   747 
       
   748       if ( font->header.italic )
       
   749         root->style_flags |= FT_STYLE_FLAG_ITALIC;
       
   750 
       
   751       if ( font->header.weight >= 800 )
       
   752         root->style_flags |= FT_STYLE_FLAG_BOLD;
       
   753 
       
   754       /* set up the `fixed_sizes' array */
       
   755       if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
       
   756         goto Fail;
       
   757 
       
   758       root->num_fixed_sizes = 1;
       
   759 
       
   760       {
       
   761         FT_Bitmap_Size*  bsize = root->available_sizes;
       
   762         FT_UShort        x_res, y_res;
       
   763 
       
   764 
       
   765         bsize->width  = font->header.avg_width;
       
   766         bsize->height = (FT_Short)(
       
   767           font->header.pixel_height + font->header.external_leading );
       
   768         bsize->size   = font->header.nominal_point_size << 6;
       
   769 
       
   770         x_res = font->header.horizontal_resolution;
       
   771         if ( !x_res )
       
   772           x_res = 72;
       
   773 
       
   774         y_res = font->header.vertical_resolution;
       
   775         if ( !y_res )
       
   776           y_res = 72;
       
   777 
       
   778         bsize->y_ppem = FT_MulDiv( bsize->size, y_res, 72 );
       
   779         bsize->y_ppem = FT_PIX_ROUND( bsize->y_ppem );
       
   780 
       
   781         /*
       
   782          * this reads:
       
   783          *
       
   784          * the nominal height is larger than the bbox's height
       
   785          *
       
   786          * => nominal_point_size contains incorrect value;
       
   787          *    use pixel_height as the nominal height
       
   788          */
       
   789         if ( bsize->y_ppem > ( font->header.pixel_height << 6 ) )
       
   790         {
       
   791           FT_TRACE2(( "use pixel_height as the nominal height\n" ));
       
   792 
       
   793           bsize->y_ppem = font->header.pixel_height << 6;
       
   794           bsize->size   = FT_MulDiv( bsize->y_ppem, 72, y_res );
       
   795         }
       
   796 
       
   797         bsize->x_ppem = FT_MulDiv( bsize->size, x_res, 72 );
       
   798         bsize->x_ppem = FT_PIX_ROUND( bsize->x_ppem );
       
   799       }
       
   800 
       
   801       {
       
   802         FT_CharMapRec  charmap;
       
   803 
       
   804 
       
   805         charmap.encoding    = FT_ENCODING_NONE;
       
   806         /* initial platform/encoding should indicate unset status? */
       
   807         charmap.platform_id = TT_PLATFORM_APPLE_UNICODE;
       
   808         charmap.encoding_id = TT_APPLE_ID_DEFAULT;
       
   809         charmap.face        = root;
       
   810 
       
   811         if ( font->header.charset == FT_WinFNT_ID_MAC )
       
   812         {
       
   813           charmap.encoding    = FT_ENCODING_APPLE_ROMAN;
       
   814           charmap.platform_id = TT_PLATFORM_MACINTOSH;
       
   815 /*        charmap.encoding_id = TT_MAC_ID_ROMAN; */
       
   816         }
       
   817 
       
   818         error = FT_CMap_New( fnt_cmap_class,
       
   819                              NULL,
       
   820                              &charmap,
       
   821                              NULL );
       
   822         if ( error )
       
   823           goto Fail;
       
   824 
       
   825         /* Select default charmap */
       
   826         if ( root->num_charmaps )
       
   827           root->charmap = root->charmaps[0];
       
   828       }
       
   829 
       
   830       /* setup remaining flags */
       
   831 
       
   832       /* reserve one slot for the .notdef glyph at index 0 */
       
   833       root->num_glyphs = font->header.last_char -
       
   834                          font->header.first_char + 1 + 1;
       
   835 
       
   836       if ( font->header.face_name_offset >= font->header.file_size )
       
   837       {
       
   838         FT_TRACE2(( "invalid family name offset\n" ));
       
   839         error = FNT_Err_Invalid_File_Format;
       
   840         goto Fail;
       
   841       }
       
   842       family_size = font->header.file_size - font->header.face_name_offset;
       
   843       /* Some broken fonts don't delimit the face name with a final */
       
   844       /* NULL byte -- the frame is erroneously one byte too small.  */
       
   845       /* We thus allocate one more byte, setting it explicitly to   */
       
   846       /* zero.                                                      */
       
   847       if ( FT_ALLOC( font->family_name, family_size + 1 ) )
       
   848         goto Fail;
       
   849 
       
   850       FT_MEM_COPY( font->family_name,
       
   851                    font->fnt_frame + font->header.face_name_offset,
       
   852                    family_size );
       
   853 
       
   854       font->family_name[family_size] = '\0';
       
   855 
       
   856       if ( FT_REALLOC( font->family_name,
       
   857                        family_size,
       
   858                        ft_strlen( font->family_name ) + 1 ) )
       
   859         goto Fail;
       
   860 
       
   861       root->family_name = font->family_name;
       
   862       root->style_name  = (char *)"Regular";
       
   863 
       
   864       if ( root->style_flags & FT_STYLE_FLAG_BOLD )
       
   865       {
       
   866         if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
       
   867           root->style_name = (char *)"Bold Italic";
       
   868         else
       
   869           root->style_name = (char *)"Bold";
       
   870       }
       
   871       else if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
       
   872         root->style_name = (char *)"Italic";
       
   873     }
       
   874     goto Exit;
       
   875 
       
   876   Fail:
       
   877     FNT_Face_Done( face );
       
   878 
       
   879   Exit:
       
   880     return error;
       
   881   }
       
   882 
       
   883 
       
   884   static FT_Error
       
   885   FNT_Size_Select( FT_Size  size )
       
   886   {
       
   887     FNT_Face          face   = (FNT_Face)size->face;
       
   888     FT_WinFNT_Header  header = &face->font->header;
       
   889 
       
   890 
       
   891     FT_Select_Metrics( size->face, 0 );
       
   892 
       
   893     size->metrics.ascender    = header->ascent * 64;
       
   894     size->metrics.descender   = -( header->pixel_height -
       
   895                                    header->ascent ) * 64;
       
   896     size->metrics.max_advance = header->max_width * 64;
       
   897 
       
   898     return FNT_Err_Ok;
       
   899   }
       
   900 
       
   901 
       
   902   static FT_Error
       
   903   FNT_Size_Request( FT_Size          size,
       
   904                     FT_Size_Request  req )
       
   905   {
       
   906     FNT_Face          face    = (FNT_Face)size->face;
       
   907     FT_WinFNT_Header  header  = &face->font->header;
       
   908     FT_Bitmap_Size*   bsize   = size->face->available_sizes;
       
   909     FT_Error          error   = FNT_Err_Invalid_Pixel_Size;
       
   910     FT_Long           height;
       
   911 
       
   912 
       
   913     height = FT_REQUEST_HEIGHT( req );
       
   914     height = ( height + 32 ) >> 6;
       
   915 
       
   916     switch ( req->type )
       
   917     {
       
   918     case FT_SIZE_REQUEST_TYPE_NOMINAL:
       
   919       if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) )
       
   920         error = FNT_Err_Ok;
       
   921       break;
       
   922 
       
   923     case FT_SIZE_REQUEST_TYPE_REAL_DIM:
       
   924       if ( height == header->pixel_height )
       
   925         error = FNT_Err_Ok;
       
   926       break;
       
   927 
       
   928     default:
       
   929       error = FNT_Err_Unimplemented_Feature;
       
   930       break;
       
   931     }
       
   932 
       
   933     if ( error )
       
   934       return error;
       
   935     else
       
   936       return FNT_Size_Select( size );
       
   937   }
       
   938 
       
   939 
       
   940   static FT_Error
       
   941   FNT_Load_Glyph( FT_GlyphSlot  slot,
       
   942                   FT_Size       size,
       
   943                   FT_UInt       glyph_index,
       
   944                   FT_Int32      load_flags )
       
   945   {
       
   946     FNT_Face    face   = (FNT_Face)FT_SIZE_FACE( size );
       
   947     FNT_Font    font;
       
   948     FT_Error    error  = FNT_Err_Ok;
       
   949     FT_Byte*    p;
       
   950     FT_Int      len;
       
   951     FT_Bitmap*  bitmap = &slot->bitmap;
       
   952     FT_ULong    offset;
       
   953     FT_Bool     new_format;
       
   954 
       
   955     FT_UNUSED( load_flags );
       
   956 
       
   957 
       
   958     if ( !face )
       
   959     {
       
   960       error = FNT_Err_Invalid_Argument;
       
   961       goto Exit;
       
   962     }
       
   963 
       
   964     font = face->font;
       
   965 
       
   966     if ( !font ||
       
   967          glyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs ) )
       
   968     {
       
   969       error = FNT_Err_Invalid_Argument;
       
   970       goto Exit;
       
   971     }
       
   972 
       
   973     if ( glyph_index > 0 )
       
   974       glyph_index--;                           /* revert to real index */
       
   975     else
       
   976       glyph_index = font->header.default_char; /* the .notdef glyph */
       
   977 
       
   978     new_format = FT_BOOL( font->header.version == 0x300 );
       
   979     len        = new_format ? 6 : 4;
       
   980 
       
   981     /* jump to glyph entry */
       
   982     p = font->fnt_frame + ( new_format ? 148 : 118 ) + len * glyph_index;
       
   983 
       
   984     bitmap->width = FT_NEXT_SHORT_LE( p );
       
   985 
       
   986     if ( new_format )
       
   987       offset = FT_NEXT_ULONG_LE( p );
       
   988     else
       
   989       offset = FT_NEXT_USHORT_LE( p );
       
   990 
       
   991     if ( offset >= font->header.file_size )
       
   992     {
       
   993       FT_TRACE2(( "invalid FNT offset\n" ));
       
   994       error = FNT_Err_Invalid_File_Format;
       
   995       goto Exit;
       
   996     }
       
   997 
       
   998     /* jump to glyph data */
       
   999     p = font->fnt_frame + /* font->header.bits_offset */ + offset;
       
  1000 
       
  1001     /* allocate and build bitmap */
       
  1002     {
       
  1003       FT_Memory  memory = FT_FACE_MEMORY( slot->face );
       
  1004       FT_Int     pitch  = ( bitmap->width + 7 ) >> 3;
       
  1005       FT_Byte*   column;
       
  1006       FT_Byte*   write;
       
  1007 
       
  1008 
       
  1009       bitmap->pitch      = pitch;
       
  1010       bitmap->rows       = font->header.pixel_height;
       
  1011       bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
       
  1012 
       
  1013       if ( offset + pitch * bitmap->rows >= font->header.file_size )
       
  1014       {
       
  1015         FT_TRACE2(( "invalid bitmap width\n" ));
       
  1016         error = FNT_Err_Invalid_File_Format;
       
  1017         goto Exit;
       
  1018       }
       
  1019 
       
  1020       /* note: since glyphs are stored in columns and not in rows we */
       
  1021       /*       can't use ft_glyphslot_set_bitmap                     */
       
  1022       if ( FT_ALLOC_MULT( bitmap->buffer, pitch, bitmap->rows ) )
       
  1023         goto Exit;
       
  1024 
       
  1025       column = (FT_Byte*)bitmap->buffer;
       
  1026 
       
  1027       for ( ; pitch > 0; pitch--, column++ )
       
  1028       {
       
  1029         FT_Byte*  limit = p + bitmap->rows;
       
  1030 
       
  1031 
       
  1032         for ( write = column; p < limit; p++, write += bitmap->pitch )
       
  1033           *write = *p;
       
  1034       }
       
  1035     }
       
  1036 
       
  1037     slot->internal->flags = FT_GLYPH_OWN_BITMAP;
       
  1038     slot->bitmap_left     = 0;
       
  1039     slot->bitmap_top      = font->header.ascent;
       
  1040     slot->format          = FT_GLYPH_FORMAT_BITMAP;
       
  1041 
       
  1042     /* now set up metrics */
       
  1043     slot->metrics.width        = bitmap->width << 6;
       
  1044     slot->metrics.height       = bitmap->rows << 6;
       
  1045     slot->metrics.horiAdvance  = bitmap->width << 6;
       
  1046     slot->metrics.horiBearingX = 0;
       
  1047     slot->metrics.horiBearingY = slot->bitmap_top << 6;
       
  1048 
       
  1049     ft_synthesize_vertical_metrics( &slot->metrics,
       
  1050                                     bitmap->rows << 6 );
       
  1051 
       
  1052   Exit:
       
  1053     return error;
       
  1054   }
       
  1055 
       
  1056 
       
  1057   static FT_Error
       
  1058   winfnt_get_header( FT_Face               face,
       
  1059                      FT_WinFNT_HeaderRec  *aheader )
       
  1060   {
       
  1061     FNT_Font  font = ((FNT_Face)face)->font;
       
  1062 
       
  1063 
       
  1064     *aheader = font->header;
       
  1065 
       
  1066     return 0;
       
  1067   }
       
  1068 
       
  1069 
       
  1070   static const FT_Service_WinFntRec  winfnt_service_rec =
       
  1071   {
       
  1072     winfnt_get_header
       
  1073   };
       
  1074 
       
  1075  /*
       
  1076   *  SERVICE LIST
       
  1077   *
       
  1078   */
       
  1079 
       
  1080   static const FT_ServiceDescRec  winfnt_services[] =
       
  1081   {
       
  1082     { FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_WINFNT },
       
  1083     { FT_SERVICE_ID_WINFNT,    &winfnt_service_rec },
       
  1084     { NULL, NULL }
       
  1085   };
       
  1086 
       
  1087 
       
  1088   static FT_Module_Interface
       
  1089   winfnt_get_service( FT_Driver         driver,
       
  1090                       const FT_String*  service_id )
       
  1091   {
       
  1092     FT_UNUSED( driver );
       
  1093 
       
  1094     return ft_service_list_lookup( winfnt_services, service_id );
       
  1095   }
       
  1096 
       
  1097 
       
  1098 
       
  1099 
       
  1100   FT_CALLBACK_TABLE_DEF
       
  1101   const FT_Driver_ClassRec  winfnt_driver_class =
       
  1102   {
       
  1103     {
       
  1104       FT_MODULE_FONT_DRIVER        |
       
  1105       FT_MODULE_DRIVER_NO_OUTLINES,
       
  1106       sizeof ( FT_DriverRec ),
       
  1107 
       
  1108       "winfonts",
       
  1109       0x10000L,
       
  1110       0x20000L,
       
  1111 
       
  1112       0,
       
  1113 
       
  1114       (FT_Module_Constructor)0,
       
  1115       (FT_Module_Destructor) 0,
       
  1116       (FT_Module_Requester)  winfnt_get_service
       
  1117     },
       
  1118 
       
  1119     sizeof( FNT_FaceRec ),
       
  1120     sizeof( FT_SizeRec ),
       
  1121     sizeof( FT_GlyphSlotRec ),
       
  1122 
       
  1123     (FT_Face_InitFunc)        FNT_Face_Init,
       
  1124     (FT_Face_DoneFunc)        FNT_Face_Done,
       
  1125     (FT_Size_InitFunc)        0,
       
  1126     (FT_Size_DoneFunc)        0,
       
  1127     (FT_Slot_InitFunc)        0,
       
  1128     (FT_Slot_DoneFunc)        0,
       
  1129 
       
  1130 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS
       
  1131     ft_stub_set_char_sizes,
       
  1132     ft_stub_set_pixel_sizes,
       
  1133 #endif
       
  1134     (FT_Slot_LoadFunc)        FNT_Load_Glyph,
       
  1135 
       
  1136     (FT_Face_GetKerningFunc)  0,
       
  1137     (FT_Face_AttachFunc)      0,
       
  1138     (FT_Face_GetAdvancesFunc) 0,
       
  1139 
       
  1140     (FT_Size_RequestFunc)     FNT_Size_Request,
       
  1141     (FT_Size_SelectFunc)      FNT_Size_Select
       
  1142   };
       
  1143 
       
  1144 
       
  1145 /* END */