PageRenderTime 78ms CodeModel.GetById 15ms app.highlight 55ms RepoModel.GetById 1ms app.codeStats 1ms

/modules/freetype2/src/pcf/pcfread.c

http://github.com/zpao/v8monkey
C | 1278 lines | 933 code | 275 blank | 70 comment | 194 complexity | b39214848a27e15df704835ba6fbbf31 MD5 | raw file
   1/*  pcfread.c
   2
   3    FreeType font driver for pcf fonts
   4
   5  Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
   6            2010 by
   7  Francesco Zappa Nardelli
   8
   9Permission is hereby granted, free of charge, to any person obtaining a copy
  10of this software and associated documentation files (the "Software"), to deal
  11in the Software without restriction, including without limitation the rights
  12to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13copies of the Software, and to permit persons to whom the Software is
  14furnished to do so, subject to the following conditions:
  15
  16The above copyright notice and this permission notice shall be included in
  17all copies or substantial portions of the Software.
  18
  19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
  22AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25THE SOFTWARE.
  26*/
  27
  28
  29#include <ft2build.h>
  30
  31#include FT_INTERNAL_DEBUG_H
  32#include FT_INTERNAL_STREAM_H
  33#include FT_INTERNAL_OBJECTS_H
  34
  35#include "pcf.h"
  36#include "pcfread.h"
  37
  38#include "pcferror.h"
  39
  40
  41  /*************************************************************************/
  42  /*                                                                       */
  43  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  44  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  45  /* messages during execution.                                            */
  46  /*                                                                       */
  47#undef  FT_COMPONENT
  48#define FT_COMPONENT  trace_pcfread
  49
  50
  51#ifdef FT_DEBUG_LEVEL_TRACE
  52  static const char* const  tableNames[] =
  53  {
  54    "prop", "accl", "mtrcs", "bmps", "imtrcs",
  55    "enc", "swidth", "names", "accel"
  56  };
  57#endif
  58
  59
  60  static
  61  const FT_Frame_Field  pcf_toc_header[] =
  62  {
  63#undef  FT_STRUCTURE
  64#define FT_STRUCTURE  PCF_TocRec
  65
  66    FT_FRAME_START( 8 ),
  67      FT_FRAME_ULONG_LE( version ),
  68      FT_FRAME_ULONG_LE( count ),
  69    FT_FRAME_END
  70  };
  71
  72
  73  static
  74  const FT_Frame_Field  pcf_table_header[] =
  75  {
  76#undef  FT_STRUCTURE
  77#define FT_STRUCTURE  PCF_TableRec
  78
  79    FT_FRAME_START( 16  ),
  80      FT_FRAME_ULONG_LE( type ),
  81      FT_FRAME_ULONG_LE( format ),
  82      FT_FRAME_ULONG_LE( size ),
  83      FT_FRAME_ULONG_LE( offset ),
  84    FT_FRAME_END
  85  };
  86
  87
  88  static FT_Error
  89  pcf_read_TOC( FT_Stream  stream,
  90                PCF_Face   face )
  91  {
  92    FT_Error   error;
  93    PCF_Toc    toc = &face->toc;
  94    PCF_Table  tables;
  95
  96    FT_Memory  memory = FT_FACE(face)->memory;
  97    FT_UInt    n;
  98
  99
 100    if ( FT_STREAM_SEEK ( 0 )                          ||
 101         FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) )
 102      return PCF_Err_Cannot_Open_Resource;
 103
 104    if ( toc->version != PCF_FILE_VERSION                 ||
 105         toc->count   >  FT_ARRAY_MAX( face->toc.tables ) ||
 106         toc->count   == 0                                )
 107      return PCF_Err_Invalid_File_Format;
 108
 109    if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) )
 110      return PCF_Err_Out_Of_Memory;
 111
 112    tables = face->toc.tables;
 113    for ( n = 0; n < toc->count; n++ )
 114    {
 115      if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )
 116        goto Exit;
 117      tables++;
 118    }
 119
 120    /* Sort tables and check for overlaps.  Because they are almost      */
 121    /* always ordered already, an in-place bubble sort with simultaneous */
 122    /* boundary checking seems appropriate.                              */
 123    tables = face->toc.tables;
 124
 125    for ( n = 0; n < toc->count - 1; n++ )
 126    {
 127      FT_UInt  i, have_change;
 128
 129
 130      have_change = 0;
 131
 132      for ( i = 0; i < toc->count - 1 - n; i++ )
 133      {
 134        PCF_TableRec  tmp;
 135
 136
 137        if ( tables[i].offset > tables[i + 1].offset )
 138        {
 139          tmp           = tables[i];
 140          tables[i]     = tables[i + 1];
 141          tables[i + 1] = tmp;
 142
 143          have_change = 1;
 144        }
 145
 146        if ( ( tables[i].size   > tables[i + 1].offset )                  ||
 147             ( tables[i].offset > tables[i + 1].offset - tables[i].size ) )
 148          return PCF_Err_Invalid_Offset;
 149      }
 150
 151      if ( !have_change )
 152        break;
 153    }
 154
 155#ifdef FT_DEBUG_LEVEL_TRACE
 156
 157    {
 158      FT_UInt      i, j;
 159      const char*  name = "?";
 160
 161
 162      FT_TRACE4(( "pcf_read_TOC:\n" ));
 163
 164      FT_TRACE4(( "  number of tables: %ld\n", face->toc.count ));
 165
 166      tables = face->toc.tables;
 167      for ( i = 0; i < toc->count; i++ )
 168      {
 169        for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] );
 170              j++ )
 171          if ( tables[i].type == (FT_UInt)( 1 << j ) )
 172            name = tableNames[j];
 173
 174        FT_TRACE4(( "  %d: type=%s, format=0x%X, "
 175                    "size=%ld (0x%lX), offset=%ld (0x%lX)\n",
 176                    i, name,
 177                    tables[i].format,
 178                    tables[i].size, tables[i].size,
 179                    tables[i].offset, tables[i].offset ));
 180      }
 181    }
 182
 183#endif
 184
 185    return PCF_Err_Ok;
 186
 187  Exit:
 188    FT_FREE( face->toc.tables );
 189    return error;
 190  }
 191
 192
 193#define PCF_METRIC_SIZE  12
 194
 195  static
 196  const FT_Frame_Field  pcf_metric_header[] =
 197  {
 198#undef  FT_STRUCTURE
 199#define FT_STRUCTURE  PCF_MetricRec
 200
 201    FT_FRAME_START( PCF_METRIC_SIZE ),
 202      FT_FRAME_SHORT_LE( leftSideBearing ),
 203      FT_FRAME_SHORT_LE( rightSideBearing ),
 204      FT_FRAME_SHORT_LE( characterWidth ),
 205      FT_FRAME_SHORT_LE( ascent ),
 206      FT_FRAME_SHORT_LE( descent ),
 207      FT_FRAME_SHORT_LE( attributes ),
 208    FT_FRAME_END
 209  };
 210
 211
 212  static
 213  const FT_Frame_Field  pcf_metric_msb_header[] =
 214  {
 215#undef  FT_STRUCTURE
 216#define FT_STRUCTURE  PCF_MetricRec
 217
 218    FT_FRAME_START( PCF_METRIC_SIZE ),
 219      FT_FRAME_SHORT( leftSideBearing ),
 220      FT_FRAME_SHORT( rightSideBearing ),
 221      FT_FRAME_SHORT( characterWidth ),
 222      FT_FRAME_SHORT( ascent ),
 223      FT_FRAME_SHORT( descent ),
 224      FT_FRAME_SHORT( attributes ),
 225    FT_FRAME_END
 226  };
 227
 228
 229#define PCF_COMPRESSED_METRIC_SIZE  5
 230
 231  static
 232  const FT_Frame_Field  pcf_compressed_metric_header[] =
 233  {
 234#undef  FT_STRUCTURE
 235#define FT_STRUCTURE  PCF_Compressed_MetricRec
 236
 237    FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ),
 238      FT_FRAME_BYTE( leftSideBearing ),
 239      FT_FRAME_BYTE( rightSideBearing ),
 240      FT_FRAME_BYTE( characterWidth ),
 241      FT_FRAME_BYTE( ascent ),
 242      FT_FRAME_BYTE( descent ),
 243    FT_FRAME_END
 244  };
 245
 246
 247  static FT_Error
 248  pcf_get_metric( FT_Stream   stream,
 249                  FT_ULong    format,
 250                  PCF_Metric  metric )
 251  {
 252    FT_Error  error = PCF_Err_Ok;
 253
 254
 255    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
 256    {
 257      const FT_Frame_Field*  fields;
 258
 259
 260      /* parsing normal metrics */
 261      fields = PCF_BYTE_ORDER( format ) == MSBFirst
 262               ? pcf_metric_msb_header
 263               : pcf_metric_header;
 264
 265      /* the following sets `error' but doesn't return in case of failure */
 266      (void)FT_STREAM_READ_FIELDS( fields, metric );
 267    }
 268    else
 269    {
 270      PCF_Compressed_MetricRec  compr;
 271
 272
 273      /* parsing compressed metrics */
 274      if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )
 275        goto Exit;
 276
 277      metric->leftSideBearing  = (FT_Short)( compr.leftSideBearing  - 0x80 );
 278      metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 );
 279      metric->characterWidth   = (FT_Short)( compr.characterWidth   - 0x80 );
 280      metric->ascent           = (FT_Short)( compr.ascent           - 0x80 );
 281      metric->descent          = (FT_Short)( compr.descent          - 0x80 );
 282      metric->attributes       = 0;
 283    }
 284
 285  Exit:
 286    return error;
 287  }
 288
 289
 290  static FT_Error
 291  pcf_seek_to_table_type( FT_Stream  stream,
 292                          PCF_Table  tables,
 293                          FT_ULong   ntables, /* same as PCF_Toc->count */
 294                          FT_ULong   type,
 295                          FT_ULong  *aformat,
 296                          FT_ULong  *asize )
 297  {
 298    FT_Error  error = PCF_Err_Invalid_File_Format;
 299    FT_ULong  i;
 300
 301
 302    for ( i = 0; i < ntables; i++ )
 303      if ( tables[i].type == type )
 304      {
 305        if ( stream->pos > tables[i].offset )
 306        {
 307          error = PCF_Err_Invalid_Stream_Skip;
 308          goto Fail;
 309        }
 310
 311        if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) )
 312        {
 313          error = PCF_Err_Invalid_Stream_Skip;
 314          goto Fail;
 315        }
 316
 317        *asize   = tables[i].size;
 318        *aformat = tables[i].format;
 319
 320        return PCF_Err_Ok;
 321      }
 322
 323  Fail:
 324    *asize = 0;
 325    return error;
 326  }
 327
 328
 329  static FT_Bool
 330  pcf_has_table_type( PCF_Table  tables,
 331                      FT_ULong   ntables, /* same as PCF_Toc->count */
 332                      FT_ULong   type )
 333  {
 334    FT_ULong  i;
 335
 336
 337    for ( i = 0; i < ntables; i++ )
 338      if ( tables[i].type == type )
 339        return TRUE;
 340
 341    return FALSE;
 342  }
 343
 344
 345#define PCF_PROPERTY_SIZE  9
 346
 347  static
 348  const FT_Frame_Field  pcf_property_header[] =
 349  {
 350#undef  FT_STRUCTURE
 351#define FT_STRUCTURE  PCF_ParsePropertyRec
 352
 353    FT_FRAME_START( PCF_PROPERTY_SIZE ),
 354      FT_FRAME_LONG_LE( name ),
 355      FT_FRAME_BYTE   ( isString ),
 356      FT_FRAME_LONG_LE( value ),
 357    FT_FRAME_END
 358  };
 359
 360
 361  static
 362  const FT_Frame_Field  pcf_property_msb_header[] =
 363  {
 364#undef  FT_STRUCTURE
 365#define FT_STRUCTURE  PCF_ParsePropertyRec
 366
 367    FT_FRAME_START( PCF_PROPERTY_SIZE ),
 368      FT_FRAME_LONG( name ),
 369      FT_FRAME_BYTE( isString ),
 370      FT_FRAME_LONG( value ),
 371    FT_FRAME_END
 372  };
 373
 374
 375  FT_LOCAL_DEF( PCF_Property )
 376  pcf_find_property( PCF_Face          face,
 377                     const FT_String*  prop )
 378  {
 379    PCF_Property  properties = face->properties;
 380    FT_Bool       found      = 0;
 381    int           i;
 382
 383
 384    for ( i = 0 ; i < face->nprops && !found; i++ )
 385    {
 386      if ( !ft_strcmp( properties[i].name, prop ) )
 387        found = 1;
 388    }
 389
 390    if ( found )
 391      return properties + i - 1;
 392    else
 393      return NULL;
 394  }
 395
 396
 397  static FT_Error
 398  pcf_get_properties( FT_Stream  stream,
 399                      PCF_Face   face )
 400  {
 401    PCF_ParseProperty  props      = 0;
 402    PCF_Property       properties;
 403    FT_ULong           nprops, i;
 404    FT_ULong           format, size;
 405    FT_Error           error;
 406    FT_Memory          memory     = FT_FACE(face)->memory;
 407    FT_ULong           string_size;
 408    FT_String*         strings    = 0;
 409
 410
 411    error = pcf_seek_to_table_type( stream,
 412                                    face->toc.tables,
 413                                    face->toc.count,
 414                                    PCF_PROPERTIES,
 415                                    &format,
 416                                    &size );
 417    if ( error )
 418      goto Bail;
 419
 420    if ( FT_READ_ULONG_LE( format ) )
 421      goto Bail;
 422
 423    FT_TRACE4(( "pcf_get_properties:\n" ));
 424
 425    FT_TRACE4(( "  format = %ld\n", format ));
 426
 427    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
 428      goto Bail;
 429
 430    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
 431      (void)FT_READ_ULONG( nprops );
 432    else
 433      (void)FT_READ_ULONG_LE( nprops );
 434    if ( error )
 435      goto Bail;
 436
 437    FT_TRACE4(( "  nprop = %d (truncate %d props)\n",
 438                (int)nprops, nprops - (int)nprops ));
 439
 440    nprops = (int)nprops;
 441
 442    /* rough estimate */
 443    if ( nprops > size / PCF_PROPERTY_SIZE )
 444    {
 445      error = PCF_Err_Invalid_Table;
 446      goto Bail;
 447    }
 448
 449    face->nprops = (int)nprops;
 450
 451    if ( FT_NEW_ARRAY( props, nprops ) )
 452      goto Bail;
 453
 454    for ( i = 0; i < nprops; i++ )
 455    {
 456      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
 457      {
 458        if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
 459          goto Bail;
 460      }
 461      else
 462      {
 463        if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
 464          goto Bail;
 465      }
 466    }
 467
 468    /* pad the property array                                            */
 469    /*                                                                   */
 470    /* clever here - nprops is the same as the number of odd-units read, */
 471    /* as only isStringProp are odd length   (Keith Packard)             */
 472    /*                                                                   */
 473    if ( nprops & 3 )
 474    {
 475      i = 4 - ( nprops & 3 );
 476      if ( FT_STREAM_SKIP( i ) )
 477      {
 478        error = PCF_Err_Invalid_Stream_Skip;
 479        goto Bail;
 480      }
 481    }
 482
 483    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
 484      (void)FT_READ_ULONG( string_size );
 485    else
 486      (void)FT_READ_ULONG_LE( string_size );
 487    if ( error )
 488      goto Bail;
 489
 490    FT_TRACE4(( "  string_size = %ld\n", string_size ));
 491
 492    /* rough estimate */
 493    if ( string_size > size - nprops * PCF_PROPERTY_SIZE )
 494    {
 495      error = PCF_Err_Invalid_Table;
 496      goto Bail;
 497    }
 498
 499    if ( FT_NEW_ARRAY( strings, string_size ) )
 500      goto Bail;
 501
 502    error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size );
 503    if ( error )
 504      goto Bail;
 505
 506    if ( FT_NEW_ARRAY( properties, nprops ) )
 507      goto Bail;
 508
 509    face->properties = properties;
 510
 511    for ( i = 0; i < nprops; i++ )
 512    {
 513      FT_Long  name_offset = props[i].name;
 514
 515
 516      if ( ( name_offset < 0 )                     ||
 517           ( (FT_ULong)name_offset > string_size ) )
 518      {
 519        error = PCF_Err_Invalid_Offset;
 520        goto Bail;
 521      }
 522
 523      if ( FT_STRDUP( properties[i].name, strings + name_offset ) )
 524        goto Bail;
 525
 526      FT_TRACE4(( "  %s:", properties[i].name ));
 527
 528      properties[i].isString = props[i].isString;
 529
 530      if ( props[i].isString )
 531      {
 532        FT_Long  value_offset = props[i].value;
 533
 534
 535        if ( ( value_offset < 0 )                     ||
 536             ( (FT_ULong)value_offset > string_size ) )
 537        {
 538          error = PCF_Err_Invalid_Offset;
 539          goto Bail;
 540        }
 541
 542        if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) )
 543          goto Bail;
 544
 545        FT_TRACE4(( " `%s'\n", properties[i].value.atom ));
 546      }
 547      else
 548      {
 549        properties[i].value.l = props[i].value;
 550
 551        FT_TRACE4(( " %d\n", properties[i].value.l ));
 552      }
 553    }
 554
 555    error = PCF_Err_Ok;
 556
 557  Bail:
 558    FT_FREE( props );
 559    FT_FREE( strings );
 560
 561    return error;
 562  }
 563
 564
 565  static FT_Error
 566  pcf_get_metrics( FT_Stream  stream,
 567                   PCF_Face   face )
 568  {
 569    FT_Error    error    = PCF_Err_Ok;
 570    FT_Memory   memory   = FT_FACE(face)->memory;
 571    FT_ULong    format, size;
 572    PCF_Metric  metrics  = 0;
 573    FT_ULong    nmetrics, i;
 574
 575
 576    error = pcf_seek_to_table_type( stream,
 577                                    face->toc.tables,
 578                                    face->toc.count,
 579                                    PCF_METRICS,
 580                                    &format,
 581                                    &size );
 582    if ( error )
 583      return error;
 584
 585    if ( FT_READ_ULONG_LE( format ) )
 586      goto Bail;
 587
 588    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )     &&
 589         !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
 590      return PCF_Err_Invalid_File_Format;
 591
 592    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
 593    {
 594      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
 595        (void)FT_READ_ULONG( nmetrics );
 596      else
 597        (void)FT_READ_ULONG_LE( nmetrics );
 598    }
 599    else
 600    {
 601      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
 602        (void)FT_READ_USHORT( nmetrics );
 603      else
 604        (void)FT_READ_USHORT_LE( nmetrics );
 605    }
 606    if ( error )
 607      return PCF_Err_Invalid_File_Format;
 608
 609    face->nmetrics = nmetrics;
 610
 611    if ( !nmetrics )
 612      return PCF_Err_Invalid_Table;
 613
 614    FT_TRACE4(( "pcf_get_metrics:\n" ));
 615
 616    FT_TRACE4(( "  number of metrics: %d\n", nmetrics ));
 617
 618    /* rough estimate */
 619    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
 620    {
 621      if ( nmetrics > size / PCF_METRIC_SIZE )
 622        return PCF_Err_Invalid_Table;
 623    }
 624    else
 625    {
 626      if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE )
 627        return PCF_Err_Invalid_Table;
 628    }
 629
 630    if ( FT_NEW_ARRAY( face->metrics, nmetrics ) )
 631      return PCF_Err_Out_Of_Memory;
 632
 633    metrics = face->metrics;
 634    for ( i = 0; i < nmetrics; i++ )
 635    {
 636      error = pcf_get_metric( stream, format, metrics + i );
 637
 638      metrics[i].bits = 0;
 639
 640      FT_TRACE5(( "  idx %d: width=%d, "
 641                  "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",
 642                  i,
 643                  ( metrics + i )->characterWidth,
 644                  ( metrics + i )->leftSideBearing,
 645                  ( metrics + i )->rightSideBearing,
 646                  ( metrics + i )->ascent,
 647                  ( metrics + i )->descent,
 648                  ( metrics + i )->attributes ));
 649
 650      if ( error )
 651        break;
 652    }
 653
 654    if ( error )
 655      FT_FREE( face->metrics );
 656
 657  Bail:
 658    return error;
 659  }
 660
 661
 662  static FT_Error
 663  pcf_get_bitmaps( FT_Stream  stream,
 664                   PCF_Face   face )
 665  {
 666    FT_Error   error  = PCF_Err_Ok;
 667    FT_Memory  memory = FT_FACE(face)->memory;
 668    FT_Long*   offsets;
 669    FT_Long    bitmapSizes[GLYPHPADOPTIONS];
 670    FT_ULong   format, size;
 671    FT_ULong   nbitmaps, i, sizebitmaps = 0;
 672
 673
 674    error = pcf_seek_to_table_type( stream,
 675                                    face->toc.tables,
 676                                    face->toc.count,
 677                                    PCF_BITMAPS,
 678                                    &format,
 679                                    &size );
 680    if ( error )
 681      return error;
 682
 683    error = FT_Stream_EnterFrame( stream, 8 );
 684    if ( error )
 685      return error;
 686
 687    format = FT_GET_ULONG_LE();
 688    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
 689      nbitmaps  = FT_GET_ULONG();
 690    else
 691      nbitmaps  = FT_GET_ULONG_LE();
 692
 693    FT_Stream_ExitFrame( stream );
 694
 695    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
 696      return PCF_Err_Invalid_File_Format;
 697
 698    FT_TRACE4(( "pcf_get_bitmaps:\n" ));
 699
 700    FT_TRACE4(( "  number of bitmaps: %d\n", nbitmaps ));
 701
 702    /* XXX: PCF_Face->nmetrics is singed FT_Long, see pcf.h */
 703    if ( face->nmetrics < 0 || nbitmaps != ( FT_ULong )face->nmetrics )
 704      return PCF_Err_Invalid_File_Format;
 705
 706    if ( FT_NEW_ARRAY( offsets, nbitmaps ) )
 707      return error;
 708
 709    for ( i = 0; i < nbitmaps; i++ )
 710    {
 711      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
 712        (void)FT_READ_LONG( offsets[i] );
 713      else
 714        (void)FT_READ_LONG_LE( offsets[i] );
 715
 716      FT_TRACE5(( "  bitmap %d: offset %ld (0x%lX)\n",
 717                  i, offsets[i], offsets[i] ));
 718    }
 719    if ( error )
 720      goto Bail;
 721
 722    for ( i = 0; i < GLYPHPADOPTIONS; i++ )
 723    {
 724      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
 725        (void)FT_READ_LONG( bitmapSizes[i] );
 726      else
 727        (void)FT_READ_LONG_LE( bitmapSizes[i] );
 728      if ( error )
 729        goto Bail;
 730
 731      sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
 732
 733      FT_TRACE4(( "  padding %d implies a size of %ld\n", i, bitmapSizes[i] ));
 734    }
 735
 736    FT_TRACE4(( "  %d bitmaps, padding index %ld\n",
 737                nbitmaps,
 738                PCF_GLYPH_PAD_INDEX( format ) ));
 739    FT_TRACE4(( "  bitmap size = %d\n", sizebitmaps ));
 740
 741    FT_UNUSED( sizebitmaps );       /* only used for debugging */
 742
 743    for ( i = 0; i < nbitmaps; i++ )
 744    {
 745      /* rough estimate */
 746      if ( ( offsets[i] < 0 )              ||
 747           ( (FT_ULong)offsets[i] > size ) )
 748      {
 749        FT_TRACE0(( "pcf_get_bitmaps:"
 750                    " invalid offset to bitmap data of glyph %d\n", i ));
 751      }
 752      else
 753        face->metrics[i].bits = stream->pos + offsets[i];
 754    }
 755
 756    face->bitmapsFormat = format;
 757
 758  Bail:
 759    FT_FREE( offsets );
 760    return error;
 761  }
 762
 763
 764  static FT_Error
 765  pcf_get_encodings( FT_Stream  stream,
 766                     PCF_Face   face )
 767  {
 768    FT_Error      error  = PCF_Err_Ok;
 769    FT_Memory     memory = FT_FACE(face)->memory;
 770    FT_ULong      format, size;
 771    int           firstCol, lastCol;
 772    int           firstRow, lastRow;
 773    int           nencoding, encodingOffset;
 774    int           i, j;
 775    PCF_Encoding  tmpEncoding, encoding = 0;
 776
 777
 778    error = pcf_seek_to_table_type( stream,
 779                                    face->toc.tables,
 780                                    face->toc.count,
 781                                    PCF_BDF_ENCODINGS,
 782                                    &format,
 783                                    &size );
 784    if ( error )
 785      return error;
 786
 787    error = FT_Stream_EnterFrame( stream, 14 );
 788    if ( error )
 789      return error;
 790
 791    format = FT_GET_ULONG_LE();
 792
 793    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
 794    {
 795      firstCol          = FT_GET_SHORT();
 796      lastCol           = FT_GET_SHORT();
 797      firstRow          = FT_GET_SHORT();
 798      lastRow           = FT_GET_SHORT();
 799      face->defaultChar = FT_GET_SHORT();
 800    }
 801    else
 802    {
 803      firstCol          = FT_GET_SHORT_LE();
 804      lastCol           = FT_GET_SHORT_LE();
 805      firstRow          = FT_GET_SHORT_LE();
 806      lastRow           = FT_GET_SHORT_LE();
 807      face->defaultChar = FT_GET_SHORT_LE();
 808    }
 809
 810    FT_Stream_ExitFrame( stream );
 811
 812    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
 813      return PCF_Err_Invalid_File_Format;
 814
 815    FT_TRACE4(( "pdf_get_encodings:\n" ));
 816
 817    FT_TRACE4(( "  firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",
 818                firstCol, lastCol, firstRow, lastRow ));
 819
 820    nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );
 821
 822    if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) )
 823      return PCF_Err_Out_Of_Memory;
 824
 825    error = FT_Stream_EnterFrame( stream, 2 * nencoding );
 826    if ( error )
 827      goto Bail;
 828
 829    for ( i = 0, j = 0 ; i < nencoding; i++ )
 830    {
 831      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
 832        encodingOffset = FT_GET_SHORT();
 833      else
 834        encodingOffset = FT_GET_SHORT_LE();
 835
 836      if ( encodingOffset != -1 )
 837      {
 838        tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) +
 839                                 firstRow ) * 256 ) +
 840                               ( ( i % ( lastCol - firstCol + 1 ) ) +
 841                                 firstCol );
 842
 843        tmpEncoding[j].glyph = (FT_Short)encodingOffset;
 844
 845        FT_TRACE5(( "  code %d (0x%04X): idx %d\n",
 846                    tmpEncoding[j].enc, tmpEncoding[j].enc,
 847                    tmpEncoding[j].glyph ));
 848
 849        j++;
 850      }
 851    }
 852    FT_Stream_ExitFrame( stream );
 853
 854    if ( FT_NEW_ARRAY( encoding, j ) )
 855      goto Bail;
 856
 857    for ( i = 0; i < j; i++ )
 858    {
 859      encoding[i].enc   = tmpEncoding[i].enc;
 860      encoding[i].glyph = tmpEncoding[i].glyph;
 861    }
 862
 863    face->nencodings = j;
 864    face->encodings  = encoding;
 865    FT_FREE( tmpEncoding );
 866
 867    return error;
 868
 869  Bail:
 870    FT_FREE( encoding );
 871    FT_FREE( tmpEncoding );
 872    return error;
 873  }
 874
 875
 876  static
 877  const FT_Frame_Field  pcf_accel_header[] =
 878  {
 879#undef  FT_STRUCTURE
 880#define FT_STRUCTURE  PCF_AccelRec
 881
 882    FT_FRAME_START( 20 ),
 883      FT_FRAME_BYTE      ( noOverlap ),
 884      FT_FRAME_BYTE      ( constantMetrics ),
 885      FT_FRAME_BYTE      ( terminalFont ),
 886      FT_FRAME_BYTE      ( constantWidth ),
 887      FT_FRAME_BYTE      ( inkInside ),
 888      FT_FRAME_BYTE      ( inkMetrics ),
 889      FT_FRAME_BYTE      ( drawDirection ),
 890      FT_FRAME_SKIP_BYTES( 1 ),
 891      FT_FRAME_LONG_LE   ( fontAscent ),
 892      FT_FRAME_LONG_LE   ( fontDescent ),
 893      FT_FRAME_LONG_LE   ( maxOverlap ),
 894    FT_FRAME_END
 895  };
 896
 897
 898  static
 899  const FT_Frame_Field  pcf_accel_msb_header[] =
 900  {
 901#undef  FT_STRUCTURE
 902#define FT_STRUCTURE  PCF_AccelRec
 903
 904    FT_FRAME_START( 20 ),
 905      FT_FRAME_BYTE      ( noOverlap ),
 906      FT_FRAME_BYTE      ( constantMetrics ),
 907      FT_FRAME_BYTE      ( terminalFont ),
 908      FT_FRAME_BYTE      ( constantWidth ),
 909      FT_FRAME_BYTE      ( inkInside ),
 910      FT_FRAME_BYTE      ( inkMetrics ),
 911      FT_FRAME_BYTE      ( drawDirection ),
 912      FT_FRAME_SKIP_BYTES( 1 ),
 913      FT_FRAME_LONG      ( fontAscent ),
 914      FT_FRAME_LONG      ( fontDescent ),
 915      FT_FRAME_LONG      ( maxOverlap ),
 916    FT_FRAME_END
 917  };
 918
 919
 920  static FT_Error
 921  pcf_get_accel( FT_Stream  stream,
 922                 PCF_Face   face,
 923                 FT_ULong   type )
 924  {
 925    FT_ULong   format, size;
 926    FT_Error   error = PCF_Err_Ok;
 927    PCF_Accel  accel = &face->accel;
 928
 929
 930    error = pcf_seek_to_table_type( stream,
 931                                    face->toc.tables,
 932                                    face->toc.count,
 933                                    type,
 934                                    &format,
 935                                    &size );
 936    if ( error )
 937      goto Bail;
 938
 939    if ( FT_READ_ULONG_LE( format ) )
 940      goto Bail;
 941
 942    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )    &&
 943         !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
 944      goto Bail;
 945
 946    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
 947    {
 948      if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
 949        goto Bail;
 950    }
 951    else
 952    {
 953      if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
 954        goto Bail;
 955    }
 956
 957    error = pcf_get_metric( stream,
 958                            format & ( ~PCF_FORMAT_MASK ),
 959                            &(accel->minbounds) );
 960    if ( error )
 961      goto Bail;
 962
 963    error = pcf_get_metric( stream,
 964                            format & ( ~PCF_FORMAT_MASK ),
 965                            &(accel->maxbounds) );
 966    if ( error )
 967      goto Bail;
 968
 969    if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
 970    {
 971      error = pcf_get_metric( stream,
 972                              format & ( ~PCF_FORMAT_MASK ),
 973                              &(accel->ink_minbounds) );
 974      if ( error )
 975        goto Bail;
 976
 977      error = pcf_get_metric( stream,
 978                              format & ( ~PCF_FORMAT_MASK ),
 979                              &(accel->ink_maxbounds) );
 980      if ( error )
 981        goto Bail;
 982    }
 983    else
 984    {
 985      accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */
 986      accel->ink_maxbounds = accel->maxbounds;
 987    }
 988
 989  Bail:
 990    return error;
 991  }
 992
 993
 994  static FT_Error
 995  pcf_interpret_style( PCF_Face  pcf )
 996  {
 997    FT_Error   error  = PCF_Err_Ok;
 998    FT_Face    face   = FT_FACE( pcf );
 999    FT_Memory  memory = face->memory;
1000
1001    PCF_Property  prop;
1002
1003    size_t  nn, len;
1004    char*   strings[4] = { NULL, NULL, NULL, NULL };
1005    size_t  lengths[4];
1006
1007
1008    face->style_flags = 0;
1009
1010    prop = pcf_find_property( pcf, "SLANT" );
1011    if ( prop && prop->isString                                       &&
1012         ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||
1013           *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )
1014    {
1015      face->style_flags |= FT_STYLE_FLAG_ITALIC;
1016      strings[2] = ( *(prop->value.atom) == 'O' ||
1017                     *(prop->value.atom) == 'o' ) ? (char *)"Oblique"
1018                                                  : (char *)"Italic";
1019    }
1020
1021    prop = pcf_find_property( pcf, "WEIGHT_NAME" );
1022    if ( prop && prop->isString                                       &&
1023         ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
1024    {
1025      face->style_flags |= FT_STYLE_FLAG_BOLD;
1026      strings[1] = (char *)"Bold";
1027    }
1028
1029    prop = pcf_find_property( pcf, "SETWIDTH_NAME" );
1030    if ( prop && prop->isString                                        &&
1031         *(prop->value.atom)                                           &&
1032         !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1033      strings[3] = (char *)(prop->value.atom);
1034
1035    prop = pcf_find_property( pcf, "ADD_STYLE_NAME" );
1036    if ( prop && prop->isString                                        &&
1037         *(prop->value.atom)                                           &&
1038         !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1039      strings[0] = (char *)(prop->value.atom);
1040
1041    for ( len = 0, nn = 0; nn < 4; nn++ )
1042    {
1043      lengths[nn] = 0;
1044      if ( strings[nn] )
1045      {
1046        lengths[nn] = ft_strlen( strings[nn] );
1047        len        += lengths[nn] + 1;
1048      }
1049    }
1050
1051    if ( len == 0 )
1052    {
1053      strings[0] = (char *)"Regular";
1054      lengths[0] = ft_strlen( strings[0] );
1055      len        = lengths[0] + 1;
1056    }
1057
1058    {
1059      char*  s;
1060
1061
1062      if ( FT_ALLOC( face->style_name, len ) )
1063        return error;
1064
1065      s = face->style_name;
1066
1067      for ( nn = 0; nn < 4; nn++ )
1068      {
1069        char*  src = strings[nn];
1070
1071
1072        len = lengths[nn];
1073
1074        if ( src == NULL )
1075          continue;
1076
1077        /* separate elements with a space */
1078        if ( s != face->style_name )
1079          *s++ = ' ';
1080
1081        ft_memcpy( s, src, len );
1082
1083        /* need to convert spaces to dashes for */
1084        /* add_style_name and setwidth_name     */
1085        if ( nn == 0 || nn == 3 )
1086        {
1087          size_t  mm;
1088
1089
1090          for ( mm = 0; mm < len; mm++ )
1091            if (s[mm] == ' ')
1092              s[mm] = '-';
1093        }
1094
1095        s += len;
1096      }
1097      *s = 0;
1098    }
1099
1100    return error;
1101  }
1102
1103
1104  FT_LOCAL_DEF( FT_Error )
1105  pcf_load_font( FT_Stream  stream,
1106                 PCF_Face   face )
1107  {
1108    FT_Error   error  = PCF_Err_Ok;
1109    FT_Memory  memory = FT_FACE(face)->memory;
1110    FT_Bool    hasBDFAccelerators;
1111
1112
1113    error = pcf_read_TOC( stream, face );
1114    if ( error )
1115      goto Exit;
1116
1117    error = pcf_get_properties( stream, face );
1118    if ( error )
1119      goto Exit;
1120
1121    /* Use the old accelerators if no BDF accelerators are in the file. */
1122    hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
1123                                             face->toc.count,
1124                                             PCF_BDF_ACCELERATORS );
1125    if ( !hasBDFAccelerators )
1126    {
1127      error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
1128      if ( error )
1129        goto Exit;
1130    }
1131
1132    /* metrics */
1133    error = pcf_get_metrics( stream, face );
1134    if ( error )
1135      goto Exit;
1136
1137    /* bitmaps */
1138    error = pcf_get_bitmaps( stream, face );
1139    if ( error )
1140      goto Exit;
1141
1142    /* encodings */
1143    error = pcf_get_encodings( stream, face );
1144    if ( error )
1145      goto Exit;
1146
1147    /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
1148    if ( hasBDFAccelerators )
1149    {
1150      error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
1151      if ( error )
1152        goto Exit;
1153    }
1154
1155    /* XXX: TO DO: inkmetrics and glyph_names are missing */
1156
1157    /* now construct the face object */
1158    {
1159      FT_Face       root = FT_FACE( face );
1160      PCF_Property  prop;
1161
1162
1163      root->num_faces  = 1;
1164      root->face_index = 0;
1165      root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
1166                         FT_FACE_FLAG_HORIZONTAL  |
1167                         FT_FACE_FLAG_FAST_GLYPHS;
1168
1169      if ( face->accel.constantWidth )
1170        root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
1171
1172      if ( ( error = pcf_interpret_style( face ) ) != 0 )
1173         goto Exit;
1174
1175      prop = pcf_find_property( face, "FAMILY_NAME" );
1176      if ( prop && prop->isString )
1177      {
1178        if ( FT_STRDUP( root->family_name, prop->value.atom ) )
1179          goto Exit;
1180      }
1181      else
1182        root->family_name = NULL;
1183
1184      /*
1185       * Note: We shift all glyph indices by +1 since we must
1186       * respect the convention that glyph 0 always corresponds
1187       * to the `missing glyph'.
1188       *
1189       * This implies bumping the number of `available' glyphs by 1.
1190       */
1191      root->num_glyphs = face->nmetrics + 1;
1192
1193      root->num_fixed_sizes = 1;
1194      if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
1195        goto Exit;
1196
1197      {
1198        FT_Bitmap_Size*  bsize = root->available_sizes;
1199        FT_Short         resolution_x = 0, resolution_y = 0;
1200
1201
1202        FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) );
1203
1204#if 0
1205        bsize->height = face->accel.maxbounds.ascent << 6;
1206#endif
1207        bsize->height = (FT_Short)( face->accel.fontAscent +
1208                                    face->accel.fontDescent );
1209
1210        prop = pcf_find_property( face, "AVERAGE_WIDTH" );
1211        if ( prop )
1212          bsize->width = (FT_Short)( ( prop->value.l + 5 ) / 10 );
1213        else
1214          bsize->width = (FT_Short)( bsize->height * 2/3 );
1215
1216        prop = pcf_find_property( face, "POINT_SIZE" );
1217        if ( prop )
1218          /* convert from 722.7 decipoints to 72 points per inch */
1219          bsize->size =
1220            (FT_Pos)( ( prop->value.l * 64 * 7200 + 36135L ) / 72270L );
1221
1222        prop = pcf_find_property( face, "PIXEL_SIZE" );
1223        if ( prop )
1224          bsize->y_ppem = (FT_Short)prop->value.l << 6;
1225
1226        prop = pcf_find_property( face, "RESOLUTION_X" );
1227        if ( prop )
1228          resolution_x = (FT_Short)prop->value.l;
1229
1230        prop = pcf_find_property( face, "RESOLUTION_Y" );
1231        if ( prop )
1232          resolution_y = (FT_Short)prop->value.l;
1233
1234        if ( bsize->y_ppem == 0 )
1235        {
1236          bsize->y_ppem = bsize->size;
1237          if ( resolution_y )
1238            bsize->y_ppem = bsize->y_ppem * resolution_y / 72;
1239        }
1240        if ( resolution_x && resolution_y )
1241          bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y;
1242        else
1243          bsize->x_ppem = bsize->y_ppem;
1244      }
1245
1246      /* set up charset */
1247      {
1248        PCF_Property  charset_registry = 0, charset_encoding = 0;
1249
1250
1251        charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
1252        charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
1253
1254        if ( charset_registry && charset_registry->isString &&
1255             charset_encoding && charset_encoding->isString )
1256        {
1257          if ( FT_STRDUP( face->charset_encoding,
1258                          charset_encoding->value.atom ) ||
1259               FT_STRDUP( face->charset_registry,
1260                          charset_registry->value.atom ) )
1261            goto Exit;
1262        }
1263      }
1264    }
1265
1266  Exit:
1267    if ( error )
1268    {
1269      /* This is done to respect the behaviour of the original */
1270      /* PCF font driver.                                      */
1271      error = PCF_Err_Invalid_File_Format;
1272    }
1273
1274    return error;
1275  }
1276
1277
1278/* END */