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