PageRenderTime 72ms CodeModel.GetById 12ms app.highlight 51ms RepoModel.GetById 1ms app.codeStats 1ms

/src/freetype/src/pcf/pcfread.c

https://bitbucket.org/cabalistic/ogredeps/
C | 1278 lines | 933 code | 275 blank | 70 comment | 194 complexity | e23fde70ecd5ca86bb2d0bab466be4c9 MD5 | raw file
   1/*  pcfread.c
   2
   3    FreeType font driver for pcf fonts
   4
   5  Copyright 2000-2010, 2012 by
   6  Francesco Zappa Nardelli
   7
   8Permission is hereby granted, free of charge, to any person obtaining a copy
   9of this software and associated documentation files (the "Software"), to deal
  10in the Software without restriction, including without limitation the rights
  11to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12copies of the Software, and to permit persons to whom the Software is
  13furnished to do so, subject to the following conditions:
  14
  15The above copyright notice and this permission notice shall be included in
  16all copies or substantial portions of the Software.
  17
  18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
  21AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24THE 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    "prop", "accl", "mtrcs", "bmps", "imtrcs",
  54    "enc", "swidth", "names", "accel"
  55  };
  56#endif
  57
  58
  59  static
  60  const FT_Frame_Field  pcf_toc_header[] =
  61  {
  62#undef  FT_STRUCTURE
  63#define FT_STRUCTURE  PCF_TocRec
  64
  65    FT_FRAME_START( 8 ),
  66      FT_FRAME_ULONG_LE( version ),
  67      FT_FRAME_ULONG_LE( count ),
  68    FT_FRAME_END
  69  };
  70
  71
  72  static
  73  const FT_Frame_Field  pcf_table_header[] =
  74  {
  75#undef  FT_STRUCTURE
  76#define FT_STRUCTURE  PCF_TableRec
  77
  78    FT_FRAME_START( 16  ),
  79      FT_FRAME_ULONG_LE( type ),
  80      FT_FRAME_ULONG_LE( format ),
  81      FT_FRAME_ULONG_LE( size ),
  82      FT_FRAME_ULONG_LE( offset ),
  83    FT_FRAME_END
  84  };
  85
  86
  87  static FT_Error
  88  pcf_read_TOC( FT_Stream  stream,
  89                PCF_Face   face )
  90  {
  91    FT_Error   error;
  92    PCF_Toc    toc = &face->toc;
  93    PCF_Table  tables;
  94
  95    FT_Memory  memory = FT_FACE(face)->memory;
  96    FT_UInt    n;
  97
  98
  99    if ( FT_STREAM_SEEK ( 0 )                          ||
 100         FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) )
 101      return PCF_Err_Cannot_Open_Resource;
 102
 103    if ( toc->version != PCF_FILE_VERSION                 ||
 104         toc->count   >  FT_ARRAY_MAX( face->toc.tables ) ||
 105         toc->count   == 0                                )
 106      return PCF_Err_Invalid_File_Format;
 107
 108    if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) )
 109      return PCF_Err_Out_Of_Memory;
 110
 111    tables = face->toc.tables;
 112    for ( n = 0; n < toc->count; n++ )
 113    {
 114      if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )
 115        goto Exit;
 116      tables++;
 117    }
 118
 119    /* Sort tables and check for overlaps.  Because they are almost      */
 120    /* always ordered already, an in-place bubble sort with simultaneous */
 121    /* boundary checking seems appropriate.                              */
 122    tables = face->toc.tables;
 123
 124    for ( n = 0; n < toc->count - 1; n++ )
 125    {
 126      FT_UInt  i, have_change;
 127
 128
 129      have_change = 0;
 130
 131      for ( i = 0; i < toc->count - 1 - n; i++ )
 132      {
 133        PCF_TableRec  tmp;
 134
 135
 136        if ( tables[i].offset > tables[i + 1].offset )
 137        {
 138          tmp           = tables[i];
 139          tables[i]     = tables[i + 1];
 140          tables[i + 1] = tmp;
 141
 142          have_change = 1;
 143        }
 144
 145        if ( ( tables[i].size   > tables[i + 1].offset )                  ||
 146             ( tables[i].offset > tables[i + 1].offset - tables[i].size ) )
 147          return PCF_Err_Invalid_Offset;
 148      }
 149
 150      if ( !have_change )
 151        break;
 152    }
 153
 154#ifdef FT_DEBUG_LEVEL_TRACE
 155
 156    {
 157      FT_UInt      i, j;
 158      const char*  name = "?";
 159
 160
 161      FT_TRACE4(( "pcf_read_TOC:\n" ));
 162
 163      FT_TRACE4(( "  number of tables: %ld\n", face->toc.count ));
 164
 165      tables = face->toc.tables;
 166      for ( i = 0; i < toc->count; i++ )
 167      {
 168        for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] );
 169              j++ )
 170          if ( tables[i].type == (FT_UInt)( 1 << j ) )
 171            name = tableNames[j];
 172
 173        FT_TRACE4(( "  %d: type=%s, format=0x%X, "
 174                    "size=%ld (0x%lX), offset=%ld (0x%lX)\n",
 175                    i, name,
 176                    tables[i].format,
 177                    tables[i].size, tables[i].size,
 178                    tables[i].offset, tables[i].offset ));
 179      }
 180    }
 181
 182#endif
 183
 184    return PCF_Err_Ok;
 185
 186  Exit:
 187    FT_FREE( face->toc.tables );
 188    return error;
 189  }
 190
 191
 192#define PCF_METRIC_SIZE  12
 193
 194  static
 195  const FT_Frame_Field  pcf_metric_header[] =
 196  {
 197#undef  FT_STRUCTURE
 198#define FT_STRUCTURE  PCF_MetricRec
 199
 200    FT_FRAME_START( PCF_METRIC_SIZE ),
 201      FT_FRAME_SHORT_LE( leftSideBearing ),
 202      FT_FRAME_SHORT_LE( rightSideBearing ),
 203      FT_FRAME_SHORT_LE( characterWidth ),
 204      FT_FRAME_SHORT_LE( ascent ),
 205      FT_FRAME_SHORT_LE( descent ),
 206      FT_FRAME_SHORT_LE( attributes ),
 207    FT_FRAME_END
 208  };
 209
 210
 211  static
 212  const FT_Frame_Field  pcf_metric_msb_header[] =
 213  {
 214#undef  FT_STRUCTURE
 215#define FT_STRUCTURE  PCF_MetricRec
 216
 217    FT_FRAME_START( PCF_METRIC_SIZE ),
 218      FT_FRAME_SHORT( leftSideBearing ),
 219      FT_FRAME_SHORT( rightSideBearing ),
 220      FT_FRAME_SHORT( characterWidth ),
 221      FT_FRAME_SHORT( ascent ),
 222      FT_FRAME_SHORT( descent ),
 223      FT_FRAME_SHORT( attributes ),
 224    FT_FRAME_END
 225  };
 226
 227
 228#define PCF_COMPRESSED_METRIC_SIZE  5
 229
 230  static
 231  const FT_Frame_Field  pcf_compressed_metric_header[] =
 232  {
 233#undef  FT_STRUCTURE
 234#define FT_STRUCTURE  PCF_Compressed_MetricRec
 235
 236    FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ),
 237      FT_FRAME_BYTE( leftSideBearing ),
 238      FT_FRAME_BYTE( rightSideBearing ),
 239      FT_FRAME_BYTE( characterWidth ),
 240      FT_FRAME_BYTE( ascent ),
 241      FT_FRAME_BYTE( descent ),
 242    FT_FRAME_END
 243  };
 244
 245
 246  static FT_Error
 247  pcf_get_metric( FT_Stream   stream,
 248                  FT_ULong    format,
 249                  PCF_Metric  metric )
 250  {
 251    FT_Error  error = PCF_Err_Ok;
 252
 253
 254    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
 255    {
 256      const FT_Frame_Field*  fields;
 257
 258
 259      /* parsing normal metrics */
 260      fields = PCF_BYTE_ORDER( format ) == MSBFirst
 261               ? pcf_metric_msb_header
 262               : pcf_metric_header;
 263
 264      /* the following sets `error' but doesn't return in case of failure */
 265      (void)FT_STREAM_READ_FIELDS( fields, metric );
 266    }
 267    else
 268    {
 269      PCF_Compressed_MetricRec  compr;
 270
 271
 272      /* parsing compressed metrics */
 273      if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )
 274        goto Exit;
 275
 276      metric->leftSideBearing  = (FT_Short)( compr.leftSideBearing  - 0x80 );
 277      metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 );
 278      metric->characterWidth   = (FT_Short)( compr.characterWidth   - 0x80 );
 279      metric->ascent           = (FT_Short)( compr.ascent           - 0x80 );
 280      metric->descent          = (FT_Short)( compr.descent          - 0x80 );
 281      metric->attributes       = 0;
 282    }
 283
 284  Exit:
 285    return error;
 286  }
 287
 288
 289  static FT_Error
 290  pcf_seek_to_table_type( FT_Stream  stream,
 291                          PCF_Table  tables,
 292                          FT_ULong   ntables, /* same as PCF_Toc->count */
 293                          FT_ULong   type,
 294                          FT_ULong  *aformat,
 295                          FT_ULong  *asize )
 296  {
 297    FT_Error  error = PCF_Err_Invalid_File_Format;
 298    FT_ULong  i;
 299
 300
 301    for ( i = 0; i < ntables; i++ )
 302      if ( tables[i].type == type )
 303      {
 304        if ( stream->pos > tables[i].offset )
 305        {
 306          error = PCF_Err_Invalid_Stream_Skip;
 307          goto Fail;
 308        }
 309
 310        if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) )
 311        {
 312          error = PCF_Err_Invalid_Stream_Skip;
 313          goto Fail;
 314        }
 315
 316        *asize   = tables[i].size;
 317        *aformat = tables[i].format;
 318
 319        return PCF_Err_Ok;
 320      }
 321
 322  Fail:
 323    *asize = 0;
 324    return error;
 325  }
 326
 327
 328  static FT_Bool
 329  pcf_has_table_type( PCF_Table  tables,
 330                      FT_ULong   ntables, /* same as PCF_Toc->count */
 331                      FT_ULong   type )
 332  {
 333    FT_ULong  i;
 334
 335
 336    for ( i = 0; i < ntables; i++ )
 337      if ( tables[i].type == type )
 338        return TRUE;
 339
 340    return FALSE;
 341  }
 342
 343
 344#define PCF_PROPERTY_SIZE  9
 345
 346  static
 347  const FT_Frame_Field  pcf_property_header[] =
 348  {
 349#undef  FT_STRUCTURE
 350#define FT_STRUCTURE  PCF_ParsePropertyRec
 351
 352    FT_FRAME_START( PCF_PROPERTY_SIZE ),
 353      FT_FRAME_LONG_LE( name ),
 354      FT_FRAME_BYTE   ( isString ),
 355      FT_FRAME_LONG_LE( value ),
 356    FT_FRAME_END
 357  };
 358
 359
 360  static
 361  const FT_Frame_Field  pcf_property_msb_header[] =
 362  {
 363#undef  FT_STRUCTURE
 364#define FT_STRUCTURE  PCF_ParsePropertyRec
 365
 366    FT_FRAME_START( PCF_PROPERTY_SIZE ),
 367      FT_FRAME_LONG( name ),
 368      FT_FRAME_BYTE( isString ),
 369      FT_FRAME_LONG( value ),
 370    FT_FRAME_END
 371  };
 372
 373
 374  FT_LOCAL_DEF( PCF_Property )
 375  pcf_find_property( PCF_Face          face,
 376                     const FT_String*  prop )
 377  {
 378    PCF_Property  properties = face->properties;
 379    FT_Bool       found      = 0;
 380    int           i;
 381
 382
 383    for ( i = 0 ; i < face->nprops && !found; i++ )
 384    {
 385      if ( !ft_strcmp( properties[i].name, prop ) )
 386        found = 1;
 387    }
 388
 389    if ( found )
 390      return properties + i - 1;
 391    else
 392      return NULL;
 393  }
 394
 395
 396  static FT_Error
 397  pcf_get_properties( FT_Stream  stream,
 398                      PCF_Face   face )
 399  {
 400    PCF_ParseProperty  props      = 0;
 401    PCF_Property       properties = NULL;
 402    FT_ULong           nprops, i;
 403    FT_ULong           format, size;
 404    FT_Error           error;
 405    FT_Memory          memory     = FT_FACE(face)->memory;
 406    FT_ULong           string_size;
 407    FT_String*         strings    = 0;
 408
 409
 410    error = pcf_seek_to_table_type( stream,
 411                                    face->toc.tables,
 412                                    face->toc.count,
 413                                    PCF_PROPERTIES,
 414                                    &format,
 415                                    &size );
 416    if ( error )
 417      goto Bail;
 418
 419    if ( FT_READ_ULONG_LE( format ) )
 420      goto Bail;
 421
 422    FT_TRACE4(( "pcf_get_properties:\n" ));
 423
 424    FT_TRACE4(( "  format = %ld\n", format ));
 425
 426    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
 427      goto Bail;
 428
 429    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
 430      (void)FT_READ_ULONG( nprops );
 431    else
 432      (void)FT_READ_ULONG_LE( nprops );
 433    if ( error )
 434      goto Bail;
 435
 436    FT_TRACE4(( "  nprop = %d (truncate %d props)\n",
 437                (int)nprops, nprops - (int)nprops ));
 438
 439    nprops = (int)nprops;
 440
 441    /* rough estimate */
 442    if ( nprops > size / PCF_PROPERTY_SIZE )
 443    {
 444      error = PCF_Err_Invalid_Table;
 445      goto Bail;
 446    }
 447
 448    face->nprops = (int)nprops;
 449
 450    if ( FT_NEW_ARRAY( props, nprops ) )
 451      goto Bail;
 452
 453    for ( i = 0; i < nprops; i++ )
 454    {
 455      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
 456      {
 457        if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
 458          goto Bail;
 459      }
 460      else
 461      {
 462        if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
 463          goto Bail;
 464      }
 465    }
 466
 467    /* pad the property array                                            */
 468    /*                                                                   */
 469    /* clever here - nprops is the same as the number of odd-units read, */
 470    /* as only isStringProp are odd length   (Keith Packard)             */
 471    /*                                                                   */
 472    if ( nprops & 3 )
 473    {
 474      i = 4 - ( nprops & 3 );
 475      if ( FT_STREAM_SKIP( i ) )
 476      {
 477        error = PCF_Err_Invalid_Stream_Skip;
 478        goto Bail;
 479      }
 480    }
 481
 482    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
 483      (void)FT_READ_ULONG( string_size );
 484    else
 485      (void)FT_READ_ULONG_LE( string_size );
 486    if ( error )
 487      goto Bail;
 488
 489    FT_TRACE4(( "  string_size = %ld\n", string_size ));
 490
 491    /* rough estimate */
 492    if ( string_size > size - nprops * PCF_PROPERTY_SIZE )
 493    {
 494      error = PCF_Err_Invalid_Table;
 495      goto Bail;
 496    }
 497
 498    /* allocate one more byte so that we have a final null byte */
 499    if ( FT_NEW_ARRAY( strings, string_size + 1 ) )
 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 = NULL;
 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 = NULL, 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 */