tor-browser

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

pcfread.c (50270B)


      1 /*  pcfread.c
      2 
      3    FreeType font driver for pcf fonts
      4 
      5  Copyright 2000-2010, 2012-2014 by
      6  Francesco Zappa Nardelli
      7 
      8 Permission is hereby granted, free of charge, to any person obtaining a copy
      9 of this software and associated documentation files (the "Software"), to deal
     10 in the Software without restriction, including without limitation the rights
     11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     12 copies of the Software, and to permit persons to whom the Software is
     13 furnished to do so, subject to the following conditions:
     14 
     15 The above copyright notice and this permission notice shall be included in
     16 all copies or substantial portions of the Software.
     17 
     18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     24 THE SOFTWARE.
     25 */
     26 
     27 
     28 
     29 #include <freetype/internal/ftdebug.h>
     30 #include <freetype/internal/ftstream.h>
     31 #include <freetype/internal/ftobjs.h>
     32 
     33 #include "pcf.h"
     34 #include "pcfread.h"
     35 
     36 #include "pcferror.h"
     37 
     38 
     39  /**************************************************************************
     40   *
     41   * The macro FT_COMPONENT is used in trace mode.  It is an implicit
     42   * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
     43   * messages during execution.
     44   */
     45 #undef  FT_COMPONENT
     46 #define FT_COMPONENT  pcfread
     47 
     48 
     49 #ifdef FT_DEBUG_LEVEL_TRACE
     50  static const char* const  tableNames[] =
     51  {
     52    "properties",
     53    "accelerators",
     54    "metrics",
     55    "bitmaps",
     56    "ink metrics",
     57    "encodings",
     58    "swidths",
     59    "glyph names",
     60    "BDF accelerators"
     61  };
     62 #endif
     63 
     64 
     65  static
     66  const FT_Frame_Field  pcf_toc_header[] =
     67  {
     68 #undef  FT_STRUCTURE
     69 #define FT_STRUCTURE  PCF_TocRec
     70 
     71    FT_FRAME_START( 8 ),
     72      FT_FRAME_ULONG_LE( version ),
     73      FT_FRAME_ULONG_LE( count ),
     74    FT_FRAME_END
     75  };
     76 
     77 
     78  static
     79  const FT_Frame_Field  pcf_table_header[] =
     80  {
     81 #undef  FT_STRUCTURE
     82 #define FT_STRUCTURE  PCF_TableRec
     83 
     84    FT_FRAME_START( 16  ),
     85      FT_FRAME_ULONG_LE( type ),
     86      FT_FRAME_ULONG_LE( format ),
     87      FT_FRAME_ULONG_LE( size ),   /* rounded up to a multiple of 4 */
     88      FT_FRAME_ULONG_LE( offset ),
     89    FT_FRAME_END
     90  };
     91 
     92 
     93  static FT_Error
     94  pcf_read_TOC( FT_Stream  stream,
     95                PCF_Face   face )
     96  {
     97    FT_Error   error;
     98    PCF_Toc    toc = &face->toc;
     99    PCF_Table  tables;
    100 
    101    FT_Memory  memory = FT_FACE( face )->memory;
    102    FT_UInt    n;
    103 
    104    FT_ULong   size;
    105 
    106 
    107    if ( FT_STREAM_SEEK( 0 )                          ||
    108         FT_STREAM_READ_FIELDS( pcf_toc_header, toc ) )
    109      return FT_THROW( Cannot_Open_Resource );
    110 
    111    if ( toc->version != PCF_FILE_VERSION ||
    112         toc->count   == 0                )
    113      return FT_THROW( Invalid_File_Format );
    114 
    115    if ( stream->size < 16 )
    116      return FT_THROW( Invalid_File_Format );
    117 
    118    /* we need 16 bytes per TOC entry, */
    119    /* and there can be most 9 tables  */
    120    if ( toc->count > ( stream->size >> 4 ) ||
    121         toc->count > 9                     )
    122    {
    123      FT_TRACE0(( "pcf_read_TOC: adjusting number of tables"
    124                  " (from %lu to %lu)\n",
    125                  toc->count,
    126                  FT_MIN( stream->size >> 4, 9 ) ));
    127      toc->count = FT_MIN( stream->size >> 4, 9 );
    128    }
    129 
    130    if ( FT_QNEW_ARRAY( face->toc.tables, toc->count ) )
    131      return error;
    132 
    133    tables = face->toc.tables;
    134    for ( n = 0; n < toc->count; n++ )
    135    {
    136      if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )
    137        goto Exit;
    138      tables++;
    139    }
    140 
    141    /* Sort tables and check for overlaps.  Because they are almost      */
    142    /* always ordered already, an in-place bubble sort with simultaneous */
    143    /* boundary checking seems appropriate.                              */
    144    tables = face->toc.tables;
    145 
    146    for ( n = 0; n < toc->count - 1; n++ )
    147    {
    148      FT_UInt  i, have_change;
    149 
    150 
    151      have_change = 0;
    152 
    153      for ( i = 0; i < toc->count - 1 - n; i++ )
    154      {
    155        PCF_TableRec  tmp;
    156 
    157 
    158        if ( tables[i].offset > tables[i + 1].offset )
    159        {
    160          tmp           = tables[i];
    161          tables[i]     = tables[i + 1];
    162          tables[i + 1] = tmp;
    163 
    164          have_change = 1;
    165        }
    166 
    167        if ( ( tables[i].size   > tables[i + 1].offset )                  ||
    168             ( tables[i].offset > tables[i + 1].offset - tables[i].size ) )
    169        {
    170          error = FT_THROW( Invalid_Offset );
    171          goto Exit;
    172        }
    173      }
    174 
    175      if ( !have_change )
    176        break;
    177    }
    178 
    179    /*
    180     * We now check whether the `size' and `offset' values are reasonable:
    181     * `offset' + `size' must not exceed the stream size.
    182     *
    183     * Note, however, that X11's `pcfWriteFont' routine (used by the
    184     * `bdftopcf' program to create PCF font files) has two special
    185     * features.
    186     *
    187     * - It always assigns the accelerator table a size of 100 bytes in the
    188     *   TOC, regardless of its real size, which can vary between 34 and 72
    189     *   bytes.
    190     *
    191     * - Due to the way the routine is designed, it ships out the last font
    192     *   table with its real size, ignoring the TOC's size value.  Since
    193     *   the TOC size values are always rounded up to a multiple of 4, the
    194     *   difference can be up to three bytes for all tables except the
    195     *   accelerator table, for which the difference can be as large as 66
    196     *   bytes.
    197     *
    198     */
    199 
    200    tables = face->toc.tables;
    201    size   = stream->size;
    202 
    203    for ( n = 0; n < toc->count - 1; n++ )
    204    {
    205      /* we need two checks to avoid overflow */
    206      if ( ( tables->size   > size                ) ||
    207           ( tables->offset > size - tables->size ) )
    208      {
    209        error = FT_THROW( Invalid_Table );
    210        goto Exit;
    211      }
    212      tables++;
    213    }
    214 
    215    /* only check `tables->offset' for last table element ... */
    216    if ( ( tables->offset > size ) )
    217    {
    218      error = FT_THROW( Invalid_Table );
    219      goto Exit;
    220    }
    221    /* ... and adjust `tables->size' to the real value if necessary */
    222    if ( tables->size > size - tables->offset )
    223      tables->size = size - tables->offset;
    224 
    225 #ifdef FT_DEBUG_LEVEL_TRACE
    226 
    227    {
    228      FT_UInt      i, j;
    229      const char*  name = "?";
    230 
    231 
    232      FT_TRACE4(( "pcf_read_TOC:\n" ));
    233 
    234      FT_TRACE4(( "  number of tables: %lu\n", face->toc.count ));
    235 
    236      tables = face->toc.tables;
    237      for ( i = 0; i < toc->count; i++ )
    238      {
    239        for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] );
    240              j++ )
    241          if ( tables[i].type == 1UL << j )
    242            name = tableNames[j];
    243 
    244        FT_TRACE4(( "  %u: type=%s, format=0x%lX,"
    245                    " size=%lu (0x%lX), offset=%lu (0x%lX)\n",
    246                    i, name,
    247                    tables[i].format,
    248                    tables[i].size, tables[i].size,
    249                    tables[i].offset, tables[i].offset ));
    250      }
    251    }
    252 
    253 #endif
    254 
    255    return FT_Err_Ok;
    256 
    257  Exit:
    258    FT_FREE( face->toc.tables );
    259    return error;
    260  }
    261 
    262 
    263 #define PCF_METRIC_SIZE  12
    264 
    265  static
    266  const FT_Frame_Field  pcf_metric_header[] =
    267  {
    268 #undef  FT_STRUCTURE
    269 #define FT_STRUCTURE  PCF_MetricRec
    270 
    271    FT_FRAME_START( PCF_METRIC_SIZE ),
    272      FT_FRAME_SHORT_LE( leftSideBearing ),
    273      FT_FRAME_SHORT_LE( rightSideBearing ),
    274      FT_FRAME_SHORT_LE( characterWidth ),
    275      FT_FRAME_SHORT_LE( ascent ),
    276      FT_FRAME_SHORT_LE( descent ),
    277      FT_FRAME_SHORT_LE( attributes ),
    278    FT_FRAME_END
    279  };
    280 
    281 
    282  static
    283  const FT_Frame_Field  pcf_metric_msb_header[] =
    284  {
    285 #undef  FT_STRUCTURE
    286 #define FT_STRUCTURE  PCF_MetricRec
    287 
    288    FT_FRAME_START( PCF_METRIC_SIZE ),
    289      FT_FRAME_SHORT( leftSideBearing ),
    290      FT_FRAME_SHORT( rightSideBearing ),
    291      FT_FRAME_SHORT( characterWidth ),
    292      FT_FRAME_SHORT( ascent ),
    293      FT_FRAME_SHORT( descent ),
    294      FT_FRAME_SHORT( attributes ),
    295    FT_FRAME_END
    296  };
    297 
    298 
    299 #define PCF_COMPRESSED_METRIC_SIZE  5
    300 
    301  static
    302  const FT_Frame_Field  pcf_compressed_metric_header[] =
    303  {
    304 #undef  FT_STRUCTURE
    305 #define FT_STRUCTURE  PCF_Compressed_MetricRec
    306 
    307    FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ),
    308      FT_FRAME_BYTE( leftSideBearing ),
    309      FT_FRAME_BYTE( rightSideBearing ),
    310      FT_FRAME_BYTE( characterWidth ),
    311      FT_FRAME_BYTE( ascent ),
    312      FT_FRAME_BYTE( descent ),
    313    FT_FRAME_END
    314  };
    315 
    316 
    317  static FT_Error
    318  pcf_get_metric( FT_Stream   stream,
    319                  FT_ULong    format,
    320                  PCF_Metric  metric )
    321  {
    322    FT_Error  error = FT_Err_Ok;
    323 
    324 
    325    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
    326    {
    327      const FT_Frame_Field*  fields;
    328 
    329 
    330      /* parsing normal metrics */
    331      fields = ( PCF_BYTE_ORDER( format ) == MSBFirst )
    332               ? pcf_metric_msb_header
    333               : pcf_metric_header;
    334 
    335      /* the following sets `error' but doesn't return in case of failure */
    336      (void)FT_STREAM_READ_FIELDS( fields, metric );
    337    }
    338    else
    339    {
    340      PCF_Compressed_MetricRec  compr;
    341 
    342 
    343      /* parsing compressed metrics */
    344      if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )
    345        goto Exit;
    346 
    347      metric->leftSideBearing  = (FT_Short)( compr.leftSideBearing  - 0x80 );
    348      metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 );
    349      metric->characterWidth   = (FT_Short)( compr.characterWidth   - 0x80 );
    350      metric->ascent           = (FT_Short)( compr.ascent           - 0x80 );
    351      metric->descent          = (FT_Short)( compr.descent          - 0x80 );
    352      metric->attributes       = 0;
    353    }
    354 
    355    FT_TRACE5(( " width=%d,"
    356                " lsb=%d, rsb=%d,"
    357                " ascent=%d, descent=%d,"
    358                " attributes=%d\n",
    359                metric->characterWidth,
    360                metric->leftSideBearing,
    361                metric->rightSideBearing,
    362                metric->ascent,
    363                metric->descent,
    364                metric->attributes ));
    365 
    366  Exit:
    367    return error;
    368  }
    369 
    370 
    371  static FT_Error
    372  pcf_seek_to_table_type( FT_Stream  stream,
    373                          PCF_Table  tables,
    374                          FT_ULong   ntables, /* same as PCF_Toc->count */
    375                          FT_ULong   type,
    376                          FT_ULong  *aformat,
    377                          FT_ULong  *asize )
    378  {
    379    FT_Error  error = FT_ERR( Invalid_File_Format );
    380    FT_ULong  i;
    381 
    382 
    383    for ( i = 0; i < ntables; i++ )
    384      if ( tables[i].type == type )
    385      {
    386        if ( stream->pos > tables[i].offset )
    387        {
    388          error = FT_THROW( Invalid_Stream_Skip );
    389          goto Fail;
    390        }
    391 
    392        if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) )
    393        {
    394          error = FT_THROW( Invalid_Stream_Skip );
    395          goto Fail;
    396        }
    397 
    398        *asize   = tables[i].size;
    399        *aformat = tables[i].format;
    400 
    401        return FT_Err_Ok;
    402      }
    403 
    404  Fail:
    405    *asize = 0;
    406    return error;
    407  }
    408 
    409 
    410  static FT_Bool
    411  pcf_has_table_type( PCF_Table  tables,
    412                      FT_ULong   ntables, /* same as PCF_Toc->count */
    413                      FT_ULong   type )
    414  {
    415    FT_ULong  i;
    416 
    417 
    418    for ( i = 0; i < ntables; i++ )
    419      if ( tables[i].type == type )
    420        return TRUE;
    421 
    422    return FALSE;
    423  }
    424 
    425 
    426 #define PCF_PROPERTY_SIZE  9
    427 
    428  static
    429  const FT_Frame_Field  pcf_property_header[] =
    430  {
    431 #undef  FT_STRUCTURE
    432 #define FT_STRUCTURE  PCF_ParsePropertyRec
    433 
    434    FT_FRAME_START( PCF_PROPERTY_SIZE ),
    435      FT_FRAME_LONG_LE( name ),
    436      FT_FRAME_BYTE   ( isString ),
    437      FT_FRAME_LONG_LE( value ),
    438    FT_FRAME_END
    439  };
    440 
    441 
    442  static
    443  const FT_Frame_Field  pcf_property_msb_header[] =
    444  {
    445 #undef  FT_STRUCTURE
    446 #define FT_STRUCTURE  PCF_ParsePropertyRec
    447 
    448    FT_FRAME_START( PCF_PROPERTY_SIZE ),
    449      FT_FRAME_LONG( name ),
    450      FT_FRAME_BYTE( isString ),
    451      FT_FRAME_LONG( value ),
    452    FT_FRAME_END
    453  };
    454 
    455 
    456  FT_LOCAL_DEF( PCF_Property )
    457  pcf_find_property( PCF_Face          face,
    458                     const FT_String*  prop )
    459  {
    460    PCF_Property  properties = face->properties;
    461    FT_Bool       found      = 0;
    462    int           i;
    463 
    464 
    465    for ( i = 0; i < face->nprops && !found; i++ )
    466    {
    467      if ( !ft_strcmp( properties[i].name, prop ) )
    468        found = 1;
    469    }
    470 
    471    if ( found )
    472      return properties + i - 1;
    473    else
    474      return NULL;
    475  }
    476 
    477 
    478  static FT_Error
    479  pcf_get_properties( FT_Stream  stream,
    480                      PCF_Face   face )
    481  {
    482    PCF_ParseProperty  props      = NULL;
    483    PCF_Property       properties = NULL;
    484    FT_ULong           nprops, orig_nprops, i;
    485    FT_ULong           format, size;
    486    FT_Error           error;
    487    FT_Memory          memory     = FT_FACE( face )->memory;
    488    FT_ULong           string_size;
    489    FT_String*         strings    = NULL;
    490 
    491 
    492    error = pcf_seek_to_table_type( stream,
    493                                    face->toc.tables,
    494                                    face->toc.count,
    495                                    PCF_PROPERTIES,
    496                                    &format,
    497                                    &size );
    498    if ( error )
    499      goto Bail;
    500 
    501    if ( FT_READ_ULONG_LE( format ) )
    502      goto Bail;
    503 
    504    FT_TRACE4(( "pcf_get_properties:\n" ));
    505    FT_TRACE4(( "  format: 0x%lX (%s)\n",
    506                format,
    507                PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB" ));
    508 
    509    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
    510      goto Bail;
    511 
    512    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
    513      (void)FT_READ_ULONG( orig_nprops );
    514    else
    515      (void)FT_READ_ULONG_LE( orig_nprops );
    516    if ( error )
    517      goto Bail;
    518 
    519    FT_TRACE4(( "  number of properties: %lu\n", orig_nprops ));
    520 
    521    /* rough estimate */
    522    if ( orig_nprops > size / PCF_PROPERTY_SIZE )
    523    {
    524      error = FT_THROW( Invalid_Table );
    525      goto Bail;
    526    }
    527 
    528    /* as a heuristic limit to avoid excessive allocation in */
    529    /* gzip bombs (i.e., very small, invalid input data that */
    530    /* pretends to expand to an insanely large file) we only */
    531    /* load the first 256 properties                         */
    532    if ( orig_nprops > 256 )
    533    {
    534      FT_TRACE0(( "pcf_get_properties:"
    535                  " only loading first 256 properties\n" ));
    536      nprops = 256;
    537    }
    538    else
    539      nprops = orig_nprops;
    540 
    541    face->nprops = (int)nprops;
    542 
    543    if ( FT_QNEW_ARRAY( props, nprops ) )
    544      goto Bail;
    545 
    546    for ( i = 0; i < nprops; i++ )
    547    {
    548      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
    549      {
    550        if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
    551          goto Bail;
    552      }
    553      else
    554      {
    555        if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
    556          goto Bail;
    557      }
    558    }
    559 
    560    /* this skip will only work if we really have an extremely large */
    561    /* number of properties; it will fail for fake data, avoiding an */
    562    /* unnecessarily large allocation later on                       */
    563    if ( FT_STREAM_SKIP( ( orig_nprops - nprops ) * PCF_PROPERTY_SIZE ) )
    564    {
    565      error = FT_THROW( Invalid_Stream_Skip );
    566      goto Bail;
    567    }
    568 
    569    /* pad the property array                                            */
    570    /*                                                                   */
    571    /* clever here - nprops is the same as the number of odd-units read, */
    572    /* as only isStringProp are odd length   (Keith Packard)             */
    573    /*                                                                   */
    574    if ( orig_nprops & 3 )
    575    {
    576      i = 4 - ( orig_nprops & 3 );
    577      if ( FT_STREAM_SKIP( i ) )
    578      {
    579        error = FT_THROW( Invalid_Stream_Skip );
    580        goto Bail;
    581      }
    582    }
    583 
    584    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
    585      (void)FT_READ_ULONG( string_size );
    586    else
    587      (void)FT_READ_ULONG_LE( string_size );
    588    if ( error )
    589      goto Bail;
    590 
    591    FT_TRACE4(( "  string size: %lu\n", string_size ));
    592 
    593    /* rough estimate */
    594    if ( string_size > size - orig_nprops * PCF_PROPERTY_SIZE )
    595    {
    596      error = FT_THROW( Invalid_Table );
    597      goto Bail;
    598    }
    599 
    600    /* the strings in the `strings' array are PostScript strings, */
    601    /* which can have a maximum length of 65536 characters each   */
    602    if ( string_size > 16777472 )   /* 256 * (65536 + 1) */
    603    {
    604      FT_TRACE0(( "pcf_get_properties:"
    605                  " loading only 16777472 bytes of strings array\n" ));
    606      string_size = 16777472;
    607    }
    608 
    609    /* allocate one more byte so that we have a final null byte */
    610    if ( FT_QALLOC( strings, string_size + 1 )  ||
    611         FT_STREAM_READ( strings, string_size ) )
    612      goto Bail;
    613 
    614    strings[string_size] = '\0';
    615 
    616    /* zero out in case of failure */
    617    if ( FT_NEW_ARRAY( properties, nprops ) )
    618      goto Bail;
    619 
    620    face->properties = properties;
    621 
    622    FT_TRACE4(( "\n" ));
    623    for ( i = 0; i < nprops; i++ )
    624    {
    625      FT_Long  name_offset = props[i].name;
    626 
    627 
    628      if ( ( name_offset < 0 )                     ||
    629           ( (FT_ULong)name_offset > string_size ) )
    630      {
    631        error = FT_THROW( Invalid_Offset );
    632        goto Bail;
    633      }
    634 
    635      if ( FT_STRDUP( properties[i].name, strings + name_offset ) )
    636        goto Bail;
    637 
    638      FT_TRACE4(( "  %s:", properties[i].name ));
    639 
    640      properties[i].isString = props[i].isString;
    641 
    642      if ( props[i].isString )
    643      {
    644        FT_Long  value_offset = props[i].value;
    645 
    646 
    647        if ( ( value_offset < 0 )                     ||
    648             ( (FT_ULong)value_offset > string_size ) )
    649        {
    650          error = FT_THROW( Invalid_Offset );
    651          goto Bail;
    652        }
    653 
    654        if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) )
    655          goto Bail;
    656 
    657        FT_TRACE4(( " `%s'\n", properties[i].value.atom ));
    658      }
    659      else
    660      {
    661        properties[i].value.l = props[i].value;
    662 
    663        FT_TRACE4(( " %ld\n", properties[i].value.l ));
    664      }
    665    }
    666 
    667    error = FT_Err_Ok;
    668 
    669  Bail:
    670    FT_FREE( props );
    671    FT_FREE( strings );
    672 
    673    return error;
    674  }
    675 
    676 
    677  static FT_Error
    678  pcf_get_metrics( FT_Stream  stream,
    679                   PCF_Face   face )
    680  {
    681    FT_Error    error;
    682    FT_Memory   memory  = FT_FACE( face )->memory;
    683    FT_ULong    format, size;
    684    PCF_Metric  metrics = NULL;
    685    FT_ULong    nmetrics, orig_nmetrics, i;
    686 
    687 
    688    error = pcf_seek_to_table_type( stream,
    689                                    face->toc.tables,
    690                                    face->toc.count,
    691                                    PCF_METRICS,
    692                                    &format,
    693                                    &size );
    694    if ( error )
    695      return error;
    696 
    697    if ( FT_READ_ULONG_LE( format ) )
    698      goto Bail;
    699 
    700    FT_TRACE4(( "pcf_get_metrics:\n" ));
    701    FT_TRACE4(( "  format: 0x%lX (%s, %s)\n",
    702                format,
    703                PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB",
    704                PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ?
    705                  "compressed" : "uncompressed" ));
    706 
    707    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )     &&
    708         !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
    709      return FT_THROW( Invalid_File_Format );
    710 
    711    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
    712    {
    713      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
    714        (void)FT_READ_ULONG( orig_nmetrics );
    715      else
    716        (void)FT_READ_ULONG_LE( orig_nmetrics );
    717    }
    718    else
    719    {
    720      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
    721        (void)FT_READ_USHORT( orig_nmetrics );
    722      else
    723        (void)FT_READ_USHORT_LE( orig_nmetrics );
    724    }
    725    if ( error )
    726      return FT_THROW( Invalid_File_Format );
    727 
    728    FT_TRACE4(( "  number of metrics: %lu\n", orig_nmetrics ));
    729 
    730    /* rough estimate */
    731    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
    732    {
    733      if ( orig_nmetrics > size / PCF_METRIC_SIZE )
    734        return FT_THROW( Invalid_Table );
    735    }
    736    else
    737    {
    738      if ( orig_nmetrics > size / PCF_COMPRESSED_METRIC_SIZE )
    739        return FT_THROW( Invalid_Table );
    740    }
    741 
    742    if ( !orig_nmetrics )
    743      return FT_THROW( Invalid_Table );
    744 
    745    /*
    746     * PCF is a format from ancient times; Unicode was in its infancy, and
    747     * widely used two-byte character sets for CJK scripts (Big 5, GB 2312,
    748     * JIS X 0208, etc.) did have at most 15000 characters.  Even the more
    749     * exotic CNS 11643 and CCCII standards, which were essentially
    750     * three-byte character sets, provided less then 65536 assigned
    751     * characters.
    752     *
    753     * While technically possible to have a larger number of glyphs in PCF
    754     * files, we thus limit the number to 65535, taking into account that we
    755     * synthesize the metrics of glyph 0 to be a copy of the `default
    756     * character', and that 0xFFFF in the encodings array indicates a
    757     * missing glyph.
    758     */
    759    if ( orig_nmetrics > 65534 )
    760    {
    761      FT_TRACE0(( "pcf_get_metrics:"
    762                  " only loading first 65534 metrics\n" ));
    763      nmetrics = 65534;
    764    }
    765    else
    766      nmetrics = orig_nmetrics;
    767 
    768    face->nmetrics = nmetrics + 1;
    769 
    770    if ( FT_QNEW_ARRAY( face->metrics, face->nmetrics ) )
    771      return error;
    772 
    773    /* we handle glyph index 0 later on */
    774    metrics = face->metrics + 1;
    775 
    776    FT_TRACE4(( "\n" ));
    777    for ( i = 1; i < face->nmetrics; i++, metrics++ )
    778    {
    779      FT_TRACE5(( "  idx %lu:", i ));
    780      error = pcf_get_metric( stream, format, metrics );
    781 
    782      metrics->bits = 0;
    783 
    784      if ( error )
    785        break;
    786 
    787      /* sanity checks -- those values are used in `PCF_Glyph_Load' to     */
    788      /* compute a glyph's bitmap dimensions, thus setting them to zero in */
    789      /* case of an error disables this particular glyph only              */
    790      if ( metrics->rightSideBearing < metrics->leftSideBearing ||
    791           metrics->ascent < -metrics->descent                  )
    792      {
    793        metrics->characterWidth   = 0;
    794        metrics->leftSideBearing  = 0;
    795        metrics->rightSideBearing = 0;
    796        metrics->ascent           = 0;
    797        metrics->descent          = 0;
    798 
    799        FT_TRACE0(( "pcf_get_metrics:"
    800                    " invalid metrics for glyph %lu\n", i ));
    801      }
    802    }
    803 
    804    if ( error )
    805      FT_FREE( face->metrics );
    806 
    807  Bail:
    808    return error;
    809  }
    810 
    811 
    812  static FT_Error
    813  pcf_get_bitmaps( FT_Stream  stream,
    814                   PCF_Face   face )
    815  {
    816    FT_Error  error;
    817    FT_ULong  bitmapSizes[GLYPHPADOPTIONS];
    818    FT_ULong  format, size, pos;
    819    FT_ULong  nbitmaps, orig_nbitmaps, i, sizebitmaps = 0;
    820 
    821 
    822    error = pcf_seek_to_table_type( stream,
    823                                    face->toc.tables,
    824                                    face->toc.count,
    825                                    PCF_BITMAPS,
    826                                    &format,
    827                                    &size );
    828    if ( error )
    829      return error;
    830 
    831    error = FT_Stream_EnterFrame( stream, 8 );
    832    if ( error )
    833      return error;
    834 
    835    format = FT_GET_ULONG_LE();
    836    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
    837      orig_nbitmaps = FT_GET_ULONG();
    838    else
    839      orig_nbitmaps = FT_GET_ULONG_LE();
    840 
    841    FT_Stream_ExitFrame( stream );
    842 
    843    FT_TRACE4(( "pcf_get_bitmaps:\n" ));
    844    FT_TRACE4(( "  format: 0x%lX\n", format ));
    845    FT_TRACE4(( "          (%s, %s,\n",
    846                PCF_BYTE_ORDER( format ) == MSBFirst
    847                  ? "most significant byte first"
    848                  : "least significant byte first",
    849                PCF_BIT_ORDER( format ) == MSBFirst
    850                  ? "most significant bit first"
    851                  : "least significant bit first" ));
    852    FT_TRACE4(( "           padding=%d bit%s, scanning=%d bit%s)\n",
    853                8 << PCF_GLYPH_PAD_INDEX( format ),
    854                ( 8 << PCF_GLYPH_PAD_INDEX( format ) ) == 1 ? "" : "s",
    855                8 << PCF_SCAN_UNIT_INDEX( format ),
    856                ( 8 << PCF_SCAN_UNIT_INDEX( format ) ) == 1 ? "" : "s" ));
    857 
    858    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
    859      return FT_THROW( Invalid_File_Format );
    860 
    861    FT_TRACE4(( "  number of bitmaps: %lu\n", orig_nbitmaps ));
    862 
    863    /* see comment in `pcf_get_metrics' */
    864    if ( orig_nbitmaps > 65534 )
    865    {
    866      FT_TRACE0(( "pcf_get_bitmaps:"
    867                  " only loading first 65534 bitmaps\n" ));
    868      nbitmaps = 65534;
    869    }
    870    else
    871      nbitmaps = orig_nbitmaps;
    872 
    873    /* no extra bitmap for glyph 0 */
    874    if ( nbitmaps != face->nmetrics - 1 )
    875      return FT_THROW( Invalid_File_Format );
    876 
    877    /* start position of bitmap data */
    878    pos = stream->pos + nbitmaps * 4 + 4 * 4;
    879 
    880    FT_TRACE5(( "\n" ));
    881    for ( i = 1; i <= nbitmaps; i++ )
    882    {
    883      FT_ULong  offset;
    884 
    885 
    886      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
    887        (void)FT_READ_ULONG( offset );
    888      else
    889        (void)FT_READ_ULONG_LE( offset );
    890 
    891      FT_TRACE5(( "  bitmap %lu: offset %lu (0x%lX)\n",
    892                  i, offset, offset ));
    893 
    894      /* right now, we only check the offset with a rough estimate; */
    895      /* actual bitmaps are only loaded on demand                   */
    896      if ( offset > size )
    897      {
    898        FT_TRACE0(( "pcf_get_bitmaps:"
    899                    " invalid offset to bitmap data of glyph %lu\n", i ));
    900        face->metrics[i].bits = pos;
    901      }
    902      else
    903        face->metrics[i].bits = pos + offset;
    904    }
    905    if ( error )
    906      goto Bail;
    907 
    908    for ( i = 0; i < GLYPHPADOPTIONS; i++ )
    909    {
    910      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
    911        (void)FT_READ_ULONG( bitmapSizes[i] );
    912      else
    913        (void)FT_READ_ULONG_LE( bitmapSizes[i] );
    914      if ( error )
    915        goto Bail;
    916 
    917      sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
    918 
    919      FT_TRACE4(( "  %d-bit padding implies a size of %lu\n",
    920                  8 << i, bitmapSizes[i] ));
    921    }
    922 
    923    FT_TRACE4(( "  %lu bitmaps, using %d-bit padding\n",
    924                nbitmaps,
    925                8 << PCF_GLYPH_PAD_INDEX( format ) ));
    926    FT_TRACE4(( "  bitmap size: %lu\n", sizebitmaps ));
    927 
    928    FT_UNUSED( sizebitmaps );       /* only used for debugging */
    929 
    930    face->bitmapsFormat = format;
    931 
    932  Bail:
    933    return error;
    934  }
    935 
    936 
    937  /*
    938   * This file uses X11 terminology for PCF data; an `encoding' in X11 speak
    939   * is the same as a character code in FreeType speak.
    940   */
    941 #define PCF_ENC_SIZE  10
    942 
    943  static
    944  const FT_Frame_Field  pcf_enc_header[] =
    945  {
    946 #undef  FT_STRUCTURE
    947 #define FT_STRUCTURE  PCF_EncRec
    948 
    949    FT_FRAME_START( PCF_ENC_SIZE ),
    950      FT_FRAME_USHORT_LE( firstCol ),
    951      FT_FRAME_USHORT_LE( lastCol ),
    952      FT_FRAME_USHORT_LE( firstRow ),
    953      FT_FRAME_USHORT_LE( lastRow ),
    954      FT_FRAME_USHORT_LE( defaultChar ),
    955    FT_FRAME_END
    956  };
    957 
    958 
    959  static
    960  const FT_Frame_Field  pcf_enc_msb_header[] =
    961  {
    962 #undef  FT_STRUCTURE
    963 #define FT_STRUCTURE  PCF_EncRec
    964 
    965    FT_FRAME_START( PCF_ENC_SIZE ),
    966      FT_FRAME_USHORT( firstCol ),
    967      FT_FRAME_USHORT( lastCol ),
    968      FT_FRAME_USHORT( firstRow ),
    969      FT_FRAME_USHORT( lastRow ),
    970      FT_FRAME_USHORT( defaultChar ),
    971    FT_FRAME_END
    972  };
    973 
    974 
    975  static FT_Error
    976  pcf_get_encodings( FT_Stream  stream,
    977                     PCF_Face   face )
    978  {
    979    FT_Error    error;
    980    FT_Memory   memory = FT_FACE( face )->memory;
    981    FT_ULong    format, size;
    982    PCF_Enc     enc = &face->enc;
    983    FT_ULong    nencoding;
    984    FT_UShort*  offset;
    985    FT_UShort   defaultCharRow, defaultCharCol;
    986    FT_UShort   encodingOffset, defaultCharEncodingOffset;
    987    FT_UShort   i, j;
    988    FT_Byte*    pos;
    989 
    990 
    991    error = pcf_seek_to_table_type( stream,
    992                                    face->toc.tables,
    993                                    face->toc.count,
    994                                    PCF_BDF_ENCODINGS,
    995                                    &format,
    996                                    &size );
    997    if ( error )
    998      goto Bail;
    999 
   1000    if ( FT_READ_ULONG_LE( format ) )
   1001      goto Bail;
   1002 
   1003    FT_TRACE4(( "pcf_get_encodings:\n" ));
   1004    FT_TRACE4(( "  format: 0x%lX (%s)\n",
   1005                format,
   1006                PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB" ));
   1007 
   1008    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
   1009         !PCF_FORMAT_MATCH( format, PCF_BDF_ENCODINGS )  )
   1010      return FT_THROW( Invalid_File_Format );
   1011 
   1012    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
   1013    {
   1014      if ( FT_STREAM_READ_FIELDS( pcf_enc_msb_header, enc ) )
   1015        goto Bail;
   1016    }
   1017    else
   1018    {
   1019      if ( FT_STREAM_READ_FIELDS( pcf_enc_header, enc ) )
   1020        goto Bail;
   1021    }
   1022 
   1023    FT_TRACE4(( "  firstCol 0x%X, lastCol 0x%X\n",
   1024                enc->firstCol, enc->lastCol ));
   1025    FT_TRACE4(( "  firstRow 0x%X, lastRow 0x%X\n",
   1026                enc->firstRow, enc->lastRow ));
   1027    FT_TRACE4(( "  defaultChar 0x%X\n",
   1028                enc->defaultChar ));
   1029 
   1030    /* sanity checks; we limit numbers of rows and columns to 256 */
   1031    if ( enc->firstCol > enc->lastCol ||
   1032         enc->lastCol  > 0xFF         ||
   1033         enc->firstRow > enc->lastRow ||
   1034         enc->lastRow  > 0xFF         )
   1035      return FT_THROW( Invalid_Table );
   1036 
   1037    FT_TRACE5(( "\n" ));
   1038 
   1039    defaultCharRow = enc->defaultChar >> 8;
   1040    defaultCharCol = enc->defaultChar & 0xFF;
   1041 
   1042    /* validate default character */
   1043    if ( defaultCharRow < enc->firstRow ||
   1044         defaultCharRow > enc->lastRow  ||
   1045         defaultCharCol < enc->firstCol ||
   1046         defaultCharCol > enc->lastCol  )
   1047    {
   1048      enc->defaultChar = enc->firstRow * 256U + enc->firstCol;
   1049      FT_TRACE0(( "pcf_get_encodings:"
   1050                  " Invalid default character set to %u\n",
   1051                  enc->defaultChar ));
   1052 
   1053      defaultCharRow = enc->firstRow;
   1054      defaultCharCol = enc->firstCol;
   1055    }
   1056 
   1057    nencoding = (FT_ULong)( enc->lastCol - enc->firstCol + 1 ) *
   1058                (FT_ULong)( enc->lastRow - enc->firstRow + 1 );
   1059 
   1060    error = FT_Stream_EnterFrame( stream, 2 * nencoding );
   1061    if ( error )
   1062      goto Bail;
   1063 
   1064    /*
   1065     * FreeType mandates that glyph index 0 is the `undefined glyph', which
   1066     * PCF calls the `default character'.  However, FreeType needs glyph
   1067     * index 0 to be used for the undefined glyph only, which is is not the
   1068     * case for PCF.  For this reason, we add one slot for glyph index 0 and
   1069     * simply copy the default character to it.
   1070     *
   1071     * `stream->cursor' still points to the beginning of the frame; we can
   1072     * thus easily get the offset to the default character.
   1073     */
   1074    pos = stream->cursor +
   1075            2 * ( ( defaultCharRow - enc->firstRow ) *
   1076                    ( enc->lastCol - enc->firstCol + 1 ) +
   1077                  defaultCharCol - enc->firstCol );
   1078 
   1079    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
   1080      defaultCharEncodingOffset = FT_PEEK_USHORT( pos );
   1081    else
   1082      defaultCharEncodingOffset = FT_PEEK_USHORT_LE( pos );
   1083 
   1084    if ( defaultCharEncodingOffset == 0xFFFF )
   1085    {
   1086      FT_TRACE0(( "pcf_get_encodings:"
   1087                  " No glyph for default character,\n" ));
   1088      FT_TRACE0(( "                  "
   1089                  " setting it to the first glyph of the font\n" ));
   1090      defaultCharEncodingOffset = 1;
   1091    }
   1092    else
   1093    {
   1094      defaultCharEncodingOffset++;
   1095 
   1096      if ( defaultCharEncodingOffset >= face->nmetrics )
   1097      {
   1098        FT_TRACE0(( "pcf_get_encodings:"
   1099                    " Invalid glyph index for default character,\n" ));
   1100        FT_TRACE0(( "                  "
   1101                    " setting it to the first glyph of the font\n" ));
   1102        defaultCharEncodingOffset = 1;
   1103      }
   1104    }
   1105 
   1106    /* copy metrics of default character to index 0 */
   1107    face->metrics[0] = face->metrics[defaultCharEncodingOffset];
   1108 
   1109    if ( FT_QNEW_ARRAY( enc->offset, nencoding ) )
   1110      goto Bail;
   1111 
   1112    /* now loop over all values */
   1113    offset = enc->offset;
   1114    for ( i = enc->firstRow; i <= enc->lastRow; i++ )
   1115    {
   1116      for ( j = enc->firstCol; j <= enc->lastCol; j++ )
   1117      {
   1118        /* X11's reference implementation uses the equivalent to  */
   1119        /* `FT_GET_SHORT', however PCF fonts with more than 32768 */
   1120        /* characters (e.g., `unifont.pcf') clearly show that an  */
   1121        /* unsigned value is needed.                              */
   1122        if ( PCF_BYTE_ORDER( format ) == MSBFirst )
   1123          encodingOffset = FT_GET_USHORT();
   1124        else
   1125          encodingOffset = FT_GET_USHORT_LE();
   1126 
   1127        /* everything is off by 1 due to the artificial glyph 0 */
   1128        *offset++ = encodingOffset == 0xFFFF ? 0xFFFF
   1129                                             : encodingOffset + 1;
   1130      }
   1131    }
   1132    FT_Stream_ExitFrame( stream );
   1133 
   1134  Bail:
   1135    return error;
   1136  }
   1137 
   1138 
   1139  static
   1140  const FT_Frame_Field  pcf_accel_header[] =
   1141  {
   1142 #undef  FT_STRUCTURE
   1143 #define FT_STRUCTURE  PCF_AccelRec
   1144 
   1145    FT_FRAME_START( 20 ),
   1146      FT_FRAME_BYTE      ( noOverlap ),
   1147      FT_FRAME_BYTE      ( constantMetrics ),
   1148      FT_FRAME_BYTE      ( terminalFont ),
   1149      FT_FRAME_BYTE      ( constantWidth ),
   1150      FT_FRAME_BYTE      ( inkInside ),
   1151      FT_FRAME_BYTE      ( inkMetrics ),
   1152      FT_FRAME_BYTE      ( drawDirection ),
   1153      FT_FRAME_SKIP_BYTES( 1 ),
   1154      FT_FRAME_LONG_LE   ( fontAscent ),
   1155      FT_FRAME_LONG_LE   ( fontDescent ),
   1156      FT_FRAME_LONG_LE   ( maxOverlap ),
   1157    FT_FRAME_END
   1158  };
   1159 
   1160 
   1161  static
   1162  const FT_Frame_Field  pcf_accel_msb_header[] =
   1163  {
   1164 #undef  FT_STRUCTURE
   1165 #define FT_STRUCTURE  PCF_AccelRec
   1166 
   1167    FT_FRAME_START( 20 ),
   1168      FT_FRAME_BYTE      ( noOverlap ),
   1169      FT_FRAME_BYTE      ( constantMetrics ),
   1170      FT_FRAME_BYTE      ( terminalFont ),
   1171      FT_FRAME_BYTE      ( constantWidth ),
   1172      FT_FRAME_BYTE      ( inkInside ),
   1173      FT_FRAME_BYTE      ( inkMetrics ),
   1174      FT_FRAME_BYTE      ( drawDirection ),
   1175      FT_FRAME_SKIP_BYTES( 1 ),
   1176      FT_FRAME_LONG      ( fontAscent ),
   1177      FT_FRAME_LONG      ( fontDescent ),
   1178      FT_FRAME_LONG      ( maxOverlap ),
   1179    FT_FRAME_END
   1180  };
   1181 
   1182 
   1183  static FT_Error
   1184  pcf_get_accel( FT_Stream  stream,
   1185                 PCF_Face   face,
   1186                 FT_ULong   type )
   1187  {
   1188    FT_ULong   format, size;
   1189    FT_Error   error;
   1190    PCF_Accel  accel = &face->accel;
   1191 
   1192 
   1193    error = pcf_seek_to_table_type( stream,
   1194                                    face->toc.tables,
   1195                                    face->toc.count,
   1196                                    type,
   1197                                    &format,
   1198                                    &size );
   1199    if ( error )
   1200      goto Bail;
   1201 
   1202    if ( FT_READ_ULONG_LE( format ) )
   1203      goto Bail;
   1204 
   1205    FT_TRACE4(( "pcf_get_accel%s:\n",
   1206                type == PCF_BDF_ACCELERATORS ? " (getting BDF accelerators)"
   1207                                             : "" ));
   1208    FT_TRACE4(( "  format: 0x%lX (%s, %s)\n",
   1209                format,
   1210                PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB",
   1211                PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ?
   1212                  "accelerated" : "not accelerated" ));
   1213 
   1214    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )    &&
   1215         !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
   1216      goto Bail;
   1217 
   1218    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
   1219    {
   1220      if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
   1221        goto Bail;
   1222    }
   1223    else
   1224    {
   1225      if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
   1226        goto Bail;
   1227    }
   1228 
   1229    FT_TRACE5(( "  noOverlap=%s, constantMetrics=%s,"
   1230                " terminalFont=%s, constantWidth=%s\n",
   1231                accel->noOverlap ? "yes" : "no",
   1232                accel->constantMetrics ? "yes" : "no",
   1233                accel->terminalFont ? "yes" : "no",
   1234                accel->constantWidth ? "yes" : "no" ));
   1235    FT_TRACE5(( "  inkInside=%s, inkMetrics=%s, drawDirection=%s\n",
   1236                accel->inkInside ? "yes" : "no",
   1237                accel->inkMetrics ? "yes" : "no",
   1238                accel->drawDirection ? "RTL" : "LTR" ));
   1239    FT_TRACE5(( "  fontAscent=%ld, fontDescent=%ld, maxOverlap=%ld\n",
   1240                accel->fontAscent,
   1241                accel->fontDescent,
   1242                accel->maxOverlap ));
   1243 
   1244    /* sanity checks */
   1245    if ( FT_ABS( accel->fontAscent ) > 0x7FFF )
   1246    {
   1247      accel->fontAscent = accel->fontAscent < 0 ? -0x7FFF : 0x7FFF;
   1248      FT_TRACE0(( "pfc_get_accel: clamping font ascent to value %ld\n",
   1249                  accel->fontAscent ));
   1250    }
   1251    if ( FT_ABS( accel->fontDescent ) > 0x7FFF )
   1252    {
   1253      accel->fontDescent = accel->fontDescent < 0 ? -0x7FFF : 0x7FFF;
   1254      FT_TRACE0(( "pfc_get_accel: clamping font descent to value %ld\n",
   1255                  accel->fontDescent ));
   1256    }
   1257 
   1258    FT_TRACE5(( "  minbounds:" ));
   1259    error = pcf_get_metric( stream,
   1260                            format & ( ~PCF_FORMAT_MASK ),
   1261                            &(accel->minbounds) );
   1262    if ( error )
   1263      goto Bail;
   1264 
   1265    FT_TRACE5(( "  maxbounds:" ));
   1266    error = pcf_get_metric( stream,
   1267                            format & ( ~PCF_FORMAT_MASK ),
   1268                            &(accel->maxbounds) );
   1269    if ( error )
   1270      goto Bail;
   1271 
   1272    if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
   1273    {
   1274      FT_TRACE5(( "  ink minbounds:" ));
   1275      error = pcf_get_metric( stream,
   1276                              format & ( ~PCF_FORMAT_MASK ),
   1277                              &(accel->ink_minbounds) );
   1278      if ( error )
   1279        goto Bail;
   1280 
   1281      FT_TRACE5(( "  ink maxbounds:" ));
   1282      error = pcf_get_metric( stream,
   1283                              format & ( ~PCF_FORMAT_MASK ),
   1284                              &(accel->ink_maxbounds) );
   1285      if ( error )
   1286        goto Bail;
   1287    }
   1288    else
   1289    {
   1290      accel->ink_minbounds = accel->minbounds;
   1291      accel->ink_maxbounds = accel->maxbounds;
   1292    }
   1293 
   1294  Bail:
   1295    return error;
   1296  }
   1297 
   1298 
   1299  static FT_Error
   1300  pcf_interpret_style( PCF_Face  pcf )
   1301  {
   1302    FT_Error   error  = FT_Err_Ok;
   1303    FT_Face    face   = FT_FACE( pcf );
   1304    FT_Memory  memory = face->memory;
   1305 
   1306    PCF_Property  prop;
   1307 
   1308    const char*  strings[4] = { NULL, NULL, NULL, NULL };
   1309    size_t       lengths[4], nn, len;
   1310 
   1311 
   1312    face->style_flags = 0;
   1313 
   1314    prop = pcf_find_property( pcf, "SLANT" );
   1315    if ( prop && prop->isString                                       &&
   1316         ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||
   1317           *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )
   1318    {
   1319      face->style_flags |= FT_STYLE_FLAG_ITALIC;
   1320      strings[2] = ( *(prop->value.atom) == 'O' ||
   1321                     *(prop->value.atom) == 'o' ) ? "Oblique"
   1322                                                  : "Italic";
   1323    }
   1324 
   1325    prop = pcf_find_property( pcf, "WEIGHT_NAME" );
   1326    if ( prop && prop->isString                                       &&
   1327         ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
   1328    {
   1329      face->style_flags |= FT_STYLE_FLAG_BOLD;
   1330      strings[1] = "Bold";
   1331    }
   1332 
   1333    prop = pcf_find_property( pcf, "SETWIDTH_NAME" );
   1334    if ( prop && prop->isString                                        &&
   1335         *(prop->value.atom)                                           &&
   1336         !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
   1337      strings[3] = (const char*)( prop->value.atom );
   1338 
   1339    prop = pcf_find_property( pcf, "ADD_STYLE_NAME" );
   1340    if ( prop && prop->isString                                        &&
   1341         *(prop->value.atom)                                           &&
   1342         !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
   1343      strings[0] = (const char*)( prop->value.atom );
   1344 
   1345    for ( len = 0, nn = 0; nn < 4; nn++ )
   1346    {
   1347      lengths[nn] = 0;
   1348      if ( strings[nn] )
   1349      {
   1350        lengths[nn] = ft_strlen( strings[nn] );
   1351        len        += lengths[nn] + 1;
   1352      }
   1353    }
   1354 
   1355    if ( len == 0 )
   1356    {
   1357      strings[0] = "Regular";
   1358      lengths[0] = ft_strlen( strings[0] );
   1359      len        = lengths[0] + 1;
   1360    }
   1361 
   1362    {
   1363      char*  s;
   1364 
   1365 
   1366      if ( FT_QALLOC( face->style_name, len ) )
   1367        return error;
   1368 
   1369      s = face->style_name;
   1370 
   1371      for ( nn = 0; nn < 4; nn++ )
   1372      {
   1373        const char*  src = strings[nn];
   1374 
   1375 
   1376        len = lengths[nn];
   1377 
   1378        if ( !src )
   1379          continue;
   1380 
   1381        /* separate elements with a space */
   1382        if ( s != face->style_name )
   1383          *s++ = ' ';
   1384 
   1385        ft_memcpy( s, src, len );
   1386 
   1387        /* need to convert spaces to dashes for */
   1388        /* add_style_name and setwidth_name     */
   1389        if ( nn == 0 || nn == 3 )
   1390        {
   1391          size_t  mm;
   1392 
   1393 
   1394          for ( mm = 0; mm < len; mm++ )
   1395            if ( s[mm] == ' ' )
   1396              s[mm] = '-';
   1397        }
   1398 
   1399        s += len;
   1400      }
   1401      *s = 0;
   1402    }
   1403 
   1404    return error;
   1405  }
   1406 
   1407 
   1408  FT_LOCAL_DEF( FT_Error )
   1409  pcf_load_font( FT_Stream  stream,
   1410                 PCF_Face   face,
   1411                 FT_Long    face_index )
   1412  {
   1413    FT_Face    root   = FT_FACE( face );
   1414    FT_Error   error;
   1415    FT_Memory  memory = FT_FACE( face )->memory;
   1416    FT_Bool    hasBDFAccelerators;
   1417 
   1418 
   1419    error = pcf_read_TOC( stream, face );
   1420    if ( error )
   1421      goto Exit;
   1422 
   1423    root->num_faces  = 1;
   1424    root->face_index = 0;
   1425 
   1426    /* If we are performing a simple font format check, exit immediately. */
   1427    if ( face_index < 0 )
   1428      return FT_Err_Ok;
   1429 
   1430    error = pcf_get_properties( stream, face );
   1431    if ( error )
   1432      goto Exit;
   1433 
   1434    /* Use the old accelerators if no BDF accelerators are in the file. */
   1435    hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
   1436                                             face->toc.count,
   1437                                             PCF_BDF_ACCELERATORS );
   1438    if ( !hasBDFAccelerators )
   1439    {
   1440      error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
   1441      if ( error )
   1442        goto Exit;
   1443    }
   1444 
   1445    /* metrics */
   1446    error = pcf_get_metrics( stream, face );
   1447    if ( error )
   1448      goto Exit;
   1449 
   1450    /* bitmaps */
   1451    error = pcf_get_bitmaps( stream, face );
   1452    if ( error )
   1453      goto Exit;
   1454 
   1455    /* encodings */
   1456    error = pcf_get_encodings( stream, face );
   1457    if ( error )
   1458      goto Exit;
   1459 
   1460    /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
   1461    if ( hasBDFAccelerators )
   1462    {
   1463      error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
   1464      if ( error )
   1465        goto Exit;
   1466    }
   1467 
   1468    /* XXX: TO DO: inkmetrics and glyph_names are missing */
   1469 
   1470    /* now construct the face object */
   1471    {
   1472      PCF_Property  prop;
   1473 
   1474 
   1475      root->face_flags |= FT_FACE_FLAG_FIXED_SIZES |
   1476                          FT_FACE_FLAG_HORIZONTAL;
   1477 
   1478      if ( face->accel.constantWidth )
   1479        root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
   1480 
   1481      if ( FT_SET_ERROR( pcf_interpret_style( face ) ) )
   1482        goto Exit;
   1483 
   1484      prop = pcf_find_property( face, "FAMILY_NAME" );
   1485      if ( prop && prop->isString )
   1486      {
   1487 
   1488 #ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
   1489 
   1490        PCF_Driver  driver = (PCF_Driver)FT_FACE_DRIVER( face );
   1491 
   1492 
   1493        if ( !driver->no_long_family_names )
   1494        {
   1495          /* Prepend the foundry name plus a space to the family name.     */
   1496          /* There are many fonts just called `Fixed' which look           */
   1497          /* completely different, and which have nothing to do with each  */
   1498          /* other.  When selecting `Fixed' in KDE or Gnome one gets       */
   1499          /* results that appear rather random, the style changes often if */
   1500          /* one changes the size and one cannot select some fonts at all. */
   1501          /*                                                               */
   1502          /* We also check whether we have `wide' characters; all put      */
   1503          /* together, we get family names like `Sony Fixed' or `Misc      */
   1504          /* Fixed Wide'.                                                  */
   1505 
   1506          PCF_Property  foundry_prop, point_size_prop, average_width_prop;
   1507 
   1508          int  l    = ft_strlen( prop->value.atom ) + 1;
   1509          int  wide = 0;
   1510 
   1511 
   1512          foundry_prop       = pcf_find_property( face, "FOUNDRY" );
   1513          point_size_prop    = pcf_find_property( face, "POINT_SIZE" );
   1514          average_width_prop = pcf_find_property( face, "AVERAGE_WIDTH" );
   1515 
   1516          if ( point_size_prop && average_width_prop )
   1517          {
   1518            if ( average_width_prop->value.l >= point_size_prop->value.l )
   1519            {
   1520              /* This font is at least square shaped or even wider */
   1521              wide = 1;
   1522              l   += ft_strlen( " Wide" );
   1523            }
   1524          }
   1525 
   1526          if ( foundry_prop && foundry_prop->isString )
   1527          {
   1528            l += ft_strlen( foundry_prop->value.atom ) + 1;
   1529 
   1530            if ( FT_QALLOC( root->family_name, l ) )
   1531              goto Exit;
   1532 
   1533            ft_strcpy( root->family_name, foundry_prop->value.atom );
   1534            ft_strcat( root->family_name, " " );
   1535            ft_strcat( root->family_name, prop->value.atom );
   1536          }
   1537          else
   1538          {
   1539            if ( FT_QALLOC( root->family_name, l ) )
   1540              goto Exit;
   1541 
   1542            ft_strcpy( root->family_name, prop->value.atom );
   1543          }
   1544 
   1545          if ( wide )
   1546            ft_strcat( root->family_name, " Wide" );
   1547        }
   1548        else
   1549 
   1550 #endif /* PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
   1551 
   1552        {
   1553          if ( FT_STRDUP( root->family_name, prop->value.atom ) )
   1554            goto Exit;
   1555        }
   1556      }
   1557      else
   1558        root->family_name = NULL;
   1559 
   1560      root->num_glyphs = (FT_Long)face->nmetrics;
   1561 
   1562      root->num_fixed_sizes = 1;
   1563      if ( FT_NEW( root->available_sizes ) )
   1564        goto Exit;
   1565 
   1566      {
   1567        FT_Bitmap_Size*  bsize = root->available_sizes;
   1568        FT_Short         resolution_x = 0, resolution_y = 0;
   1569 
   1570 
   1571        /* for simplicity, we take absolute values of integer properties */
   1572 
   1573 #if 0
   1574        bsize->height = face->accel.maxbounds.ascent << 6;
   1575 #endif
   1576 
   1577 #ifdef FT_DEBUG_LEVEL_TRACE
   1578        if ( face->accel.fontAscent + face->accel.fontDescent < 0 )
   1579          FT_TRACE0(( "pcf_load_font: negative height\n" ));
   1580 #endif
   1581        if ( FT_ABS( face->accel.fontAscent +
   1582                     face->accel.fontDescent ) > 0x7FFF )
   1583        {
   1584          bsize->height = 0x7FFF;
   1585          FT_TRACE0(( "pcf_load_font: clamping height to value %d\n",
   1586                      bsize->height ));
   1587        }
   1588        else
   1589          bsize->height = FT_ABS( (FT_Short)( face->accel.fontAscent +
   1590                                              face->accel.fontDescent ) );
   1591 
   1592        prop = pcf_find_property( face, "AVERAGE_WIDTH" );
   1593        if ( prop )
   1594        {
   1595 #ifdef FT_DEBUG_LEVEL_TRACE
   1596          if ( prop->value.l < 0 )
   1597            FT_TRACE0(( "pcf_load_font: negative average width\n" ));
   1598 #endif
   1599          if ( ( FT_ABS( prop->value.l ) > 0x7FFFL * 10 - 5 ) )
   1600          {
   1601            bsize->width = 0x7FFF;
   1602            FT_TRACE0(( "pcf_load_font: clamping average width to value %d\n",
   1603                        bsize->width ));
   1604          }
   1605          else
   1606            bsize->width = FT_ABS( (FT_Short)( ( prop->value.l + 5 ) / 10 ) );
   1607        }
   1608        else
   1609        {
   1610          /* this is a heuristical value */
   1611          bsize->width = ( bsize->height * 2 + 1 ) / 3;
   1612        }
   1613 
   1614        prop = pcf_find_property( face, "POINT_SIZE" );
   1615        if ( prop )
   1616        {
   1617 #ifdef FT_DEBUG_LEVEL_TRACE
   1618          if ( prop->value.l < 0 )
   1619            FT_TRACE0(( "pcf_load_font: negative point size\n" ));
   1620 #endif
   1621          /* convert from 722.7 decipoints to 72 points per inch */
   1622          if ( FT_ABS( prop->value.l ) > 0x504C2L ) /* 0x7FFF * 72270/7200 */
   1623          {
   1624            bsize->size = 0x7FFF;
   1625            FT_TRACE0(( "pcf_load_font: clamping point size to value %ld\n",
   1626                        bsize->size ));
   1627          }
   1628          else
   1629            bsize->size = FT_MulDiv( FT_ABS( prop->value.l ),
   1630                                     64 * 7200,
   1631                                     72270L );
   1632        }
   1633 
   1634        prop = pcf_find_property( face, "PIXEL_SIZE" );
   1635        if ( prop )
   1636        {
   1637 #ifdef FT_DEBUG_LEVEL_TRACE
   1638          if ( prop->value.l < 0 )
   1639            FT_TRACE0(( "pcf_load_font: negative pixel size\n" ));
   1640 #endif
   1641          if ( FT_ABS( prop->value.l ) > 0x7FFF )
   1642          {
   1643            bsize->y_ppem = 0x7FFF << 6;
   1644            FT_TRACE0(( "pcf_load_font: clamping pixel size to value %ld\n",
   1645                        bsize->y_ppem ));
   1646          }
   1647          else
   1648            bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6;
   1649        }
   1650 
   1651        prop = pcf_find_property( face, "RESOLUTION_X" );
   1652        if ( prop )
   1653        {
   1654 #ifdef FT_DEBUG_LEVEL_TRACE
   1655          if ( prop->value.l < 0 )
   1656            FT_TRACE0(( "pcf_load_font: negative X resolution\n" ));
   1657 #endif
   1658          if ( FT_ABS( prop->value.l ) > 0x7FFF )
   1659          {
   1660            resolution_x = 0x7FFF;
   1661            FT_TRACE0(( "pcf_load_font: clamping X resolution to value %d\n",
   1662                        resolution_x ));
   1663          }
   1664          else
   1665            resolution_x = FT_ABS( (FT_Short)prop->value.l );
   1666        }
   1667 
   1668        prop = pcf_find_property( face, "RESOLUTION_Y" );
   1669        if ( prop )
   1670        {
   1671 #ifdef FT_DEBUG_LEVEL_TRACE
   1672          if ( prop->value.l < 0 )
   1673            FT_TRACE0(( "pcf_load_font: negative Y resolution\n" ));
   1674 #endif
   1675          if ( FT_ABS( prop->value.l ) > 0x7FFF )
   1676          {
   1677            resolution_y = 0x7FFF;
   1678            FT_TRACE0(( "pcf_load_font: clamping Y resolution to value %d\n",
   1679                        resolution_y ));
   1680          }
   1681          else
   1682            resolution_y = FT_ABS( (FT_Short)prop->value.l );
   1683        }
   1684 
   1685        if ( bsize->y_ppem == 0 )
   1686        {
   1687          bsize->y_ppem = bsize->size;
   1688          if ( resolution_y )
   1689            bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 );
   1690        }
   1691        if ( resolution_x && resolution_y )
   1692          bsize->x_ppem = FT_MulDiv( bsize->y_ppem,
   1693                                     resolution_x,
   1694                                     resolution_y );
   1695        else
   1696          bsize->x_ppem = bsize->y_ppem;
   1697      }
   1698 
   1699      /* set up charset */
   1700      {
   1701        PCF_Property  charset_registry, charset_encoding;
   1702 
   1703 
   1704        charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
   1705        charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
   1706 
   1707        if ( charset_registry && charset_registry->isString &&
   1708             charset_encoding && charset_encoding->isString )
   1709        {
   1710          if ( FT_STRDUP( face->charset_encoding,
   1711                          charset_encoding->value.atom ) ||
   1712               FT_STRDUP( face->charset_registry,
   1713                          charset_registry->value.atom ) )
   1714            goto Exit;
   1715        }
   1716      }
   1717    }
   1718 
   1719  Exit:
   1720    if ( error )
   1721    {
   1722      /* This is done to respect the behaviour of the original */
   1723      /* PCF font driver.                                      */
   1724      error = FT_THROW( Invalid_File_Format );
   1725    }
   1726 
   1727    return error;
   1728  }
   1729 
   1730 
   1731 /* END */