tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

winfnt.c (35776B)


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