- Remove svn:needs-lock, svn:eol-type, and svn:eol-tyle properties.
[reactos.git] / reactos / lib / 3rdparty / freetype / src / pcf / pcfread.c
index 637b265..b9123cf 100644 (file)
-/*  pcfread.c\r
-\r
-    FreeType font driver for pcf fonts\r
-\r
-  Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 by\r
-  Francesco Zappa Nardelli\r
-\r
-Permission is hereby granted, free of charge, to any person obtaining a copy\r
-of this software and associated documentation files (the "Software"), to deal\r
-in the Software without restriction, including without limitation the rights\r
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
-copies of the Software, and to permit persons to whom the Software is\r
-furnished to do so, subject to the following conditions:\r
-\r
-The above copyright notice and this permission notice shall be included in\r
-all copies or substantial portions of the Software.\r
-\r
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE\r
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
-THE SOFTWARE.\r
-*/\r
-\r
-\r
-#include <ft2build.h>\r
-\r
-#include FT_INTERNAL_DEBUG_H\r
-#include FT_INTERNAL_STREAM_H\r
-#include FT_INTERNAL_OBJECTS_H\r
-\r
-#include "pcf.h"\r
-#include "pcfdrivr.h"\r
-#include "pcfread.h"\r
-\r
-#include "pcferror.h"\r
-\r
-\r
-  /*************************************************************************/\r
-  /*                                                                       */\r
-  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */\r
-  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */\r
-  /* messages during execution.                                            */\r
-  /*                                                                       */\r
-#undef  FT_COMPONENT\r
-#define FT_COMPONENT  trace_pcfread\r
-\r
-\r
-#if defined( FT_DEBUG_LEVEL_TRACE )\r
-  static const char* const  tableNames[] =\r
-  {\r
-    "prop", "accl", "mtrcs", "bmps", "imtrcs",\r
-    "enc", "swidth", "names", "accel"\r
-  };\r
-#endif\r
-\r
-\r
-  static\r
-  const FT_Frame_Field  pcf_toc_header[] =\r
-  {\r
-#undef  FT_STRUCTURE\r
-#define FT_STRUCTURE  PCF_TocRec\r
-\r
-    FT_FRAME_START( 8 ),\r
-      FT_FRAME_ULONG_LE( version ),\r
-      FT_FRAME_ULONG_LE( count ),\r
-    FT_FRAME_END\r
-  };\r
-\r
-\r
-  static\r
-  const FT_Frame_Field  pcf_table_header[] =\r
-  {\r
-#undef  FT_STRUCTURE\r
-#define FT_STRUCTURE  PCF_TableRec\r
-\r
-    FT_FRAME_START( 16  ),\r
-      FT_FRAME_ULONG_LE( type ),\r
-      FT_FRAME_ULONG_LE( format ),\r
-      FT_FRAME_ULONG_LE( size ),\r
-      FT_FRAME_ULONG_LE( offset ),\r
-    FT_FRAME_END\r
-  };\r
-\r
-\r
-  static FT_Error\r
-  pcf_read_TOC( FT_Stream  stream,\r
-                PCF_Face   face )\r
-  {\r
-    FT_Error   error;\r
-    PCF_Toc    toc = &face->toc;\r
-    PCF_Table  tables;\r
-\r
-    FT_Memory  memory = FT_FACE(face)->memory;\r
-    FT_UInt    n;\r
-\r
-\r
-    if ( FT_STREAM_SEEK ( 0 )                          ||\r
-         FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) )\r
-      return PCF_Err_Cannot_Open_Resource;\r
-\r
-    if ( toc->version != PCF_FILE_VERSION                 ||\r
-         toc->count   >  FT_ARRAY_MAX( face->toc.tables ) ||\r
-         toc->count   == 0                                )\r
-      return PCF_Err_Invalid_File_Format;\r
-\r
-    if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) )\r
-      return PCF_Err_Out_Of_Memory;\r
-\r
-    tables = face->toc.tables;\r
-    for ( n = 0; n < toc->count; n++ )\r
-    {\r
-      if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )\r
-        goto Exit;\r
-      tables++;\r
-    }\r
-\r
-    /* Sort tables and check for overlaps.  Because they are almost      */\r
-    /* always ordered already, an in-place bubble sort with simultaneous */\r
-    /* boundary checking seems appropriate.                              */\r
-    tables = face->toc.tables;\r
-\r
-    for ( n = 0; n < toc->count - 1; n++ )\r
-    {\r
-      FT_UInt  i, have_change;\r
-\r
-\r
-      have_change = 0;\r
-\r
-      for ( i = 0; i < toc->count - 1 - n; i++ )\r
-      {\r
-        PCF_TableRec  tmp;\r
-\r
-\r
-        if ( tables[i].offset > tables[i + 1].offset )\r
-        {\r
-          tmp           = tables[i];\r
-          tables[i]     = tables[i + 1];\r
-          tables[i + 1] = tmp;\r
-\r
-          have_change = 1;\r
-        }\r
-\r
-        if ( ( tables[i].size   > tables[i + 1].offset )                  ||\r
-             ( tables[i].offset > tables[i + 1].offset - tables[i].size ) )\r
-          return PCF_Err_Invalid_Offset;\r
-      }\r
-\r
-      if ( !have_change )\r
-        break;\r
-    }\r
-\r
-#if defined( FT_DEBUG_LEVEL_TRACE )\r
-\r
-    {\r
-      FT_UInt      i, j;\r
-      const char*  name = "?";\r
-\r
-\r
-      FT_TRACE4(( "pcf_read_TOC:\n" ));\r
-\r
-      FT_TRACE4(( "  number of tables: %ld\n", face->toc.count ));\r
-\r
-      tables = face->toc.tables;\r
-      for ( i = 0; i < toc->count; i++ )\r
-      {\r
-        for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] );\r
-              j++ )\r
-          if ( tables[i].type == (FT_UInt)( 1 << j ) )\r
-            name = tableNames[j];\r
-\r
-        FT_TRACE4(( "  %d: type=%s, format=0x%X, "\r
-                    "size=%ld (0x%lX), offset=%ld (0x%lX)\n",\r
-                    i, name,\r
-                    tables[i].format,\r
-                    tables[i].size, tables[i].size,\r
-                    tables[i].offset, tables[i].offset ));\r
-      }\r
-    }\r
-\r
-#endif\r
-\r
-    return PCF_Err_Ok;\r
-\r
-  Exit:\r
-    FT_FREE( face->toc.tables );\r
-    return error;\r
-  }\r
-\r
-\r
-#define PCF_METRIC_SIZE  12\r
-\r
-  static\r
-  const FT_Frame_Field  pcf_metric_header[] =\r
-  {\r
-#undef  FT_STRUCTURE\r
-#define FT_STRUCTURE  PCF_MetricRec\r
-\r
-    FT_FRAME_START( PCF_METRIC_SIZE ),\r
-      FT_FRAME_SHORT_LE( leftSideBearing ),\r
-      FT_FRAME_SHORT_LE( rightSideBearing ),\r
-      FT_FRAME_SHORT_LE( characterWidth ),\r
-      FT_FRAME_SHORT_LE( ascent ),\r
-      FT_FRAME_SHORT_LE( descent ),\r
-      FT_FRAME_SHORT_LE( attributes ),\r
-    FT_FRAME_END\r
-  };\r
-\r
-\r
-  static\r
-  const FT_Frame_Field  pcf_metric_msb_header[] =\r
-  {\r
-#undef  FT_STRUCTURE\r
-#define FT_STRUCTURE  PCF_MetricRec\r
-\r
-    FT_FRAME_START( PCF_METRIC_SIZE ),\r
-      FT_FRAME_SHORT( leftSideBearing ),\r
-      FT_FRAME_SHORT( rightSideBearing ),\r
-      FT_FRAME_SHORT( characterWidth ),\r
-      FT_FRAME_SHORT( ascent ),\r
-      FT_FRAME_SHORT( descent ),\r
-      FT_FRAME_SHORT( attributes ),\r
-    FT_FRAME_END\r
-  };\r
-\r
-\r
-#define PCF_COMPRESSED_METRIC_SIZE  5\r
-\r
-  static\r
-  const FT_Frame_Field  pcf_compressed_metric_header[] =\r
-  {\r
-#undef  FT_STRUCTURE\r
-#define FT_STRUCTURE  PCF_Compressed_MetricRec\r
-\r
-    FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ),\r
-      FT_FRAME_BYTE( leftSideBearing ),\r
-      FT_FRAME_BYTE( rightSideBearing ),\r
-      FT_FRAME_BYTE( characterWidth ),\r
-      FT_FRAME_BYTE( ascent ),\r
-      FT_FRAME_BYTE( descent ),\r
-    FT_FRAME_END\r
-  };\r
-\r
-\r
-  static FT_Error\r
-  pcf_get_metric( FT_Stream   stream,\r
-                  FT_ULong    format,\r
-                  PCF_Metric  metric )\r
-  {\r
-    FT_Error  error = PCF_Err_Ok;\r
-\r
-\r
-    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )\r
-    {\r
-      const FT_Frame_Field*  fields;\r
-\r
-\r
-      /* parsing normal metrics */\r
-      fields = PCF_BYTE_ORDER( format ) == MSBFirst\r
-               ? pcf_metric_msb_header\r
-               : pcf_metric_header;\r
-\r
-      /* the following sets `error' but doesn't return in case of failure */\r
-      (void)FT_STREAM_READ_FIELDS( fields, metric );\r
-    }\r
-    else\r
-    {\r
-      PCF_Compressed_MetricRec  compr;\r
-\r
-\r
-      /* parsing compressed metrics */\r
-      if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )\r
-        goto Exit;\r
-\r
-      metric->leftSideBearing  = (FT_Short)( compr.leftSideBearing  - 0x80 );\r
-      metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 );\r
-      metric->characterWidth   = (FT_Short)( compr.characterWidth   - 0x80 );\r
-      metric->ascent           = (FT_Short)( compr.ascent           - 0x80 );\r
-      metric->descent          = (FT_Short)( compr.descent          - 0x80 );\r
-      metric->attributes       = 0;\r
-    }\r
-\r
-  Exit:\r
-    return error;\r
-  }\r
-\r
-\r
-  static FT_Error\r
-  pcf_seek_to_table_type( FT_Stream  stream,\r
-                          PCF_Table  tables,\r
-                          FT_Int     ntables,\r
-                          FT_ULong   type,\r
-                          FT_ULong  *aformat,\r
-                          FT_ULong  *asize )\r
-  {\r
-    FT_Error  error = PCF_Err_Invalid_File_Format;\r
-    FT_Int    i;\r
-\r
-\r
-    for ( i = 0; i < ntables; i++ )\r
-      if ( tables[i].type == type )\r
-      {\r
-        if ( stream->pos > tables[i].offset )\r
-        {\r
-          error = PCF_Err_Invalid_Stream_Skip;\r
-          goto Fail;\r
-        }\r
-\r
-        if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) )\r
-        {\r
-          error = PCF_Err_Invalid_Stream_Skip;\r
-          goto Fail;\r
-        }\r
-\r
-        *asize   = tables[i].size;\r
-        *aformat = tables[i].format;\r
-\r
-        return PCF_Err_Ok;\r
-      }\r
-\r
-  Fail:\r
-    *asize = 0;\r
-    return error;\r
-  }\r
-\r
-\r
-  static FT_Bool\r
-  pcf_has_table_type( PCF_Table  tables,\r
-                      FT_Int     ntables,\r
-                      FT_ULong   type )\r
-  {\r
-    FT_Int  i;\r
-\r
-\r
-    for ( i = 0; i < ntables; i++ )\r
-      if ( tables[i].type == type )\r
-        return TRUE;\r
-\r
-    return FALSE;\r
-  }\r
-\r
-\r
-#define PCF_PROPERTY_SIZE  9\r
-\r
-  static\r
-  const FT_Frame_Field  pcf_property_header[] =\r
-  {\r
-#undef  FT_STRUCTURE\r
-#define FT_STRUCTURE  PCF_ParsePropertyRec\r
-\r
-    FT_FRAME_START( PCF_PROPERTY_SIZE ),\r
-      FT_FRAME_LONG_LE( name ),\r
-      FT_FRAME_BYTE   ( isString ),\r
-      FT_FRAME_LONG_LE( value ),\r
-    FT_FRAME_END\r
-  };\r
-\r
-\r
-  static\r
-  const FT_Frame_Field  pcf_property_msb_header[] =\r
-  {\r
-#undef  FT_STRUCTURE\r
-#define FT_STRUCTURE  PCF_ParsePropertyRec\r
-\r
-    FT_FRAME_START( PCF_PROPERTY_SIZE ),\r
-      FT_FRAME_LONG( name ),\r
-      FT_FRAME_BYTE( isString ),\r
-      FT_FRAME_LONG( value ),\r
-    FT_FRAME_END\r
-  };\r
-\r
-\r
-  FT_LOCAL_DEF( PCF_Property )\r
-  pcf_find_property( PCF_Face          face,\r
-                     const FT_String*  prop )\r
-  {\r
-    PCF_Property  properties = face->properties;\r
-    FT_Bool       found      = 0;\r
-    int           i;\r
-\r
-\r
-    for ( i = 0 ; i < face->nprops && !found; i++ )\r
-    {\r
-      if ( !ft_strcmp( properties[i].name, prop ) )\r
-        found = 1;\r
-    }\r
-\r
-    if ( found )\r
-      return properties + i - 1;\r
-    else\r
-      return NULL;\r
-  }\r
-\r
-\r
-  static FT_Error\r
-  pcf_get_properties( FT_Stream  stream,\r
-                      PCF_Face   face )\r
-  {\r
-    PCF_ParseProperty  props      = 0;\r
-    PCF_Property       properties;\r
-    FT_UInt            nprops, i;\r
-    FT_ULong           format, size;\r
-    FT_Error           error;\r
-    FT_Memory          memory     = FT_FACE(face)->memory;\r
-    FT_ULong           string_size;\r
-    FT_String*         strings    = 0;\r
-\r
-\r
-    error = pcf_seek_to_table_type( stream,\r
-                                    face->toc.tables,\r
-                                    face->toc.count,\r
-                                    PCF_PROPERTIES,\r
-                                    &format,\r
-                                    &size );\r
-    if ( error )\r
-      goto Bail;\r
-\r
-    if ( FT_READ_ULONG_LE( format ) )\r
-      goto Bail;\r
-\r
-    FT_TRACE4(( "pcf_get_properties:\n" ));\r
-\r
-    FT_TRACE4(( "  format = %ld\n", format ));\r
-\r
-    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )\r
-      goto Bail;\r
-\r
-    if ( PCF_BYTE_ORDER( format ) == MSBFirst )\r
-      (void)FT_READ_ULONG( nprops );\r
-    else\r
-      (void)FT_READ_ULONG_LE( nprops );\r
-    if ( error )\r
-      goto Bail;\r
-\r
-    FT_TRACE4(( "  nprop = %d\n", nprops ));\r
-\r
-    /* rough estimate */\r
-    if ( nprops > size / PCF_PROPERTY_SIZE )\r
-    {\r
-      error = PCF_Err_Invalid_Table;\r
-      goto Bail;\r
-    }\r
-\r
-    face->nprops = nprops;\r
-\r
-    if ( FT_NEW_ARRAY( props, nprops ) )\r
-      goto Bail;\r
-\r
-    for ( i = 0; i < nprops; i++ )\r
-    {\r
-      if ( PCF_BYTE_ORDER( format ) == MSBFirst )\r
-      {\r
-        if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )\r
-          goto Bail;\r
-      }\r
-      else\r
-      {\r
-        if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )\r
-          goto Bail;\r
-      }\r
-    }\r
-\r
-    /* pad the property array                                            */\r
-    /*                                                                   */\r
-    /* clever here - nprops is the same as the number of odd-units read, */\r
-    /* as only isStringProp are odd length   (Keith Packard)             */\r
-    /*                                                                   */\r
-    if ( nprops & 3 )\r
-    {\r
-      i = 4 - ( nprops & 3 );\r
-      FT_Stream_Skip( stream, i );\r
-    }\r
-\r
-    if ( PCF_BYTE_ORDER( format ) == MSBFirst )\r
-      (void)FT_READ_ULONG( string_size );\r
-    else\r
-      (void)FT_READ_ULONG_LE( string_size );\r
-    if ( error )\r
-      goto Bail;\r
-\r
-    FT_TRACE4(( "  string_size = %ld\n", string_size ));\r
-\r
-    /* rough estimate */\r
-    if ( string_size > size - nprops * PCF_PROPERTY_SIZE )\r
-    {\r
-      error = PCF_Err_Invalid_Table;\r
-      goto Bail;\r
-    }\r
-\r
-    if ( FT_NEW_ARRAY( strings, string_size ) )\r
-      goto Bail;\r
-\r
-    error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size );\r
-    if ( error )\r
-      goto Bail;\r
-\r
-    if ( FT_NEW_ARRAY( properties, nprops ) )\r
-      goto Bail;\r
-\r
-    face->properties = properties;\r
-\r
-    for ( i = 0; i < nprops; i++ )\r
-    {\r
-      FT_Long  name_offset = props[i].name;\r
-\r
-\r
-      if ( ( name_offset < 0 )                     ||\r
-           ( (FT_ULong)name_offset > string_size ) )\r
-      {\r
-        error = PCF_Err_Invalid_Offset;\r
-        goto Bail;\r
-      }\r
-\r
-      if ( FT_STRDUP( properties[i].name, strings + name_offset ) )\r
-        goto Bail;\r
-\r
-      FT_TRACE4(( "  %s:", properties[i].name ));\r
-\r
-      properties[i].isString = props[i].isString;\r
-\r
-      if ( props[i].isString )\r
-      {\r
-        FT_Long  value_offset = props[i].value;\r
-\r
-\r
-        if ( ( value_offset < 0 )                     ||\r
-             ( (FT_ULong)value_offset > string_size ) )\r
-        {\r
-          error = PCF_Err_Invalid_Offset;\r
-          goto Bail;\r
-        }\r
-\r
-        if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) )\r
-          goto Bail;\r
-\r
-        FT_TRACE4(( " `%s'\n", properties[i].value.atom ));\r
-      }\r
-      else\r
-      {\r
-        properties[i].value.integer = props[i].value;\r
-\r
-        FT_TRACE4(( " %d\n", properties[i].value.integer ));\r
-      }\r
-    }\r
-\r
-    error = PCF_Err_Ok;\r
-\r
-  Bail:\r
-    FT_FREE( props );\r
-    FT_FREE( strings );\r
-\r
-    return error;\r
-  }\r
-\r
-\r
-  static FT_Error\r
-  pcf_get_metrics( FT_Stream  stream,\r
-                   PCF_Face   face )\r
-  {\r
-    FT_Error    error    = PCF_Err_Ok;\r
-    FT_Memory   memory   = FT_FACE(face)->memory;\r
-    FT_ULong    format, size;\r
-    PCF_Metric  metrics  = 0;\r
-    FT_ULong    nmetrics, i;\r
-\r
-\r
-    error = pcf_seek_to_table_type( stream,\r
-                                    face->toc.tables,\r
-                                    face->toc.count,\r
-                                    PCF_METRICS,\r
-                                    &format,\r
-                                    &size );\r
-    if ( error )\r
-      return error;\r
-\r
-    if ( FT_READ_ULONG_LE( format ) )\r
-      goto Bail;\r
-\r
-    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )     &&\r
-         !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )\r
-      return PCF_Err_Invalid_File_Format;\r
-\r
-    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )\r
-    {\r
-      if ( PCF_BYTE_ORDER( format ) == MSBFirst )\r
-        (void)FT_READ_ULONG( nmetrics );\r
-      else\r
-        (void)FT_READ_ULONG_LE( nmetrics );\r
-    }\r
-    else\r
-    {\r
-      if ( PCF_BYTE_ORDER( format ) == MSBFirst )\r
-        (void)FT_READ_USHORT( nmetrics );\r
-      else\r
-        (void)FT_READ_USHORT_LE( nmetrics );\r
-    }\r
-    if ( error )\r
-      return PCF_Err_Invalid_File_Format;\r
-\r
-    face->nmetrics = nmetrics;\r
-\r
-    FT_TRACE4(( "pcf_get_metrics:\n" ));\r
-\r
-    FT_TRACE4(( "  number of metrics: %d\n", nmetrics ));\r
-\r
-    /* rough estimate */\r
-    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )\r
-    {\r
-      if ( nmetrics > size / PCF_METRIC_SIZE )\r
-        return PCF_Err_Invalid_Table;\r
-    }\r
-    else\r
-    {\r
-      if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE )\r
-        return PCF_Err_Invalid_Table;\r
-    }\r
-\r
-    if ( FT_NEW_ARRAY( face->metrics, nmetrics ) )\r
-      return PCF_Err_Out_Of_Memory;\r
-\r
-    metrics = face->metrics;\r
-    for ( i = 0; i < nmetrics; i++ )\r
-    {\r
-      pcf_get_metric( stream, format, metrics + i );\r
-\r
-      metrics[i].bits = 0;\r
-\r
-      FT_TRACE5(( "  idx %d: width=%d, "\r
-                  "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",\r
-                  i,\r
-                  ( metrics + i )->characterWidth,\r
-                  ( metrics + i )->leftSideBearing,\r
-                  ( metrics + i )->rightSideBearing,\r
-                  ( metrics + i )->ascent,\r
-                  ( metrics + i )->descent,\r
-                  ( metrics + i )->attributes ));\r
-\r
-      if ( error )\r
-        break;\r
-    }\r
-\r
-    if ( error )\r
-      FT_FREE( face->metrics );\r
-\r
-  Bail:\r
-    return error;\r
-  }\r
-\r
-\r
-  static FT_Error\r
-  pcf_get_bitmaps( FT_Stream  stream,\r
-                   PCF_Face   face )\r
-  {\r
-    FT_Error   error  = PCF_Err_Ok;\r
-    FT_Memory  memory = FT_FACE(face)->memory;\r
-    FT_Long*   offsets;\r
-    FT_Long    bitmapSizes[GLYPHPADOPTIONS];\r
-    FT_ULong   format, size;\r
-    int        nbitmaps, i, sizebitmaps = 0;\r
-\r
-\r
-    error = pcf_seek_to_table_type( stream,\r
-                                    face->toc.tables,\r
-                                    face->toc.count,\r
-                                    PCF_BITMAPS,\r
-                                    &format,\r
-                                    &size );\r
-    if ( error )\r
-      return error;\r
-\r
-    error = FT_Stream_EnterFrame( stream, 8 );\r
-    if ( error )\r
-      return error;\r
-\r
-    format = FT_GET_ULONG_LE();\r
-    if ( PCF_BYTE_ORDER( format ) == MSBFirst )\r
-      nbitmaps  = FT_GET_ULONG();\r
-    else\r
-      nbitmaps  = FT_GET_ULONG_LE();\r
-\r
-    FT_Stream_ExitFrame( stream );\r
-\r
-    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )\r
-      return PCF_Err_Invalid_File_Format;\r
-\r
-    FT_TRACE4(( "pcf_get_bitmaps:\n" ));\r
-\r
-    FT_TRACE4(( "  number of bitmaps: %d\n", nbitmaps ));\r
-\r
-    if ( nbitmaps != face->nmetrics )\r
-      return PCF_Err_Invalid_File_Format;\r
-\r
-    if ( FT_NEW_ARRAY( offsets, nbitmaps ) )\r
-      return error;\r
-\r
-    for ( i = 0; i < nbitmaps; i++ )\r
-    {\r
-      if ( PCF_BYTE_ORDER( format ) == MSBFirst )\r
-        (void)FT_READ_LONG( offsets[i] );\r
-      else\r
-        (void)FT_READ_LONG_LE( offsets[i] );\r
-\r
-      FT_TRACE5(( "  bitmap %d: offset %ld (0x%lX)\n",\r
-                  i, offsets[i], offsets[i] ));\r
-    }\r
-    if ( error )\r
-      goto Bail;\r
-\r
-    for ( i = 0; i < GLYPHPADOPTIONS; i++ )\r
-    {\r
-      if ( PCF_BYTE_ORDER( format ) == MSBFirst )\r
-        (void)FT_READ_LONG( bitmapSizes[i] );\r
-      else\r
-        (void)FT_READ_LONG_LE( bitmapSizes[i] );\r
-      if ( error )\r
-        goto Bail;\r
-\r
-      sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];\r
-\r
-      FT_TRACE4(( "  padding %d implies a size of %ld\n", i, bitmapSizes[i] ));\r
-    }\r
-\r
-    FT_TRACE4(( "  %d bitmaps, padding index %ld\n",\r
-                nbitmaps,\r
-                PCF_GLYPH_PAD_INDEX( format ) ));\r
-    FT_TRACE4(( "  bitmap size = %d\n", sizebitmaps ));\r
-\r
-    FT_UNUSED( sizebitmaps );       /* only used for debugging */\r
-\r
-    for ( i = 0; i < nbitmaps; i++ )\r
-    {\r
-      /* rough estimate */\r
-      if ( ( offsets[i] < 0 )              ||\r
-           ( (FT_ULong)offsets[i] > size ) )\r
-      {\r
-        FT_ERROR(( "pcf_get_bitmaps:"));\r
-        FT_ERROR(( " invalid offset to bitmap data of glyph %d\n", i ));\r
-      }\r
-      else\r
-        face->metrics[i].bits = stream->pos + offsets[i];\r
-    }\r
-\r
-    face->bitmapsFormat = format;\r
-\r
-  Bail:\r
-    FT_FREE( offsets );\r
-    return error;\r
-  }\r
-\r
-\r
-  static FT_Error\r
-  pcf_get_encodings( FT_Stream  stream,\r
-                     PCF_Face   face )\r
-  {\r
-    FT_Error      error  = PCF_Err_Ok;\r
-    FT_Memory     memory = FT_FACE(face)->memory;\r
-    FT_ULong      format, size;\r
-    int           firstCol, lastCol;\r
-    int           firstRow, lastRow;\r
-    int           nencoding, encodingOffset;\r
-    int           i, j;\r
-    PCF_Encoding  tmpEncoding, encoding = 0;\r
-\r
-\r
-    error = pcf_seek_to_table_type( stream,\r
-                                    face->toc.tables,\r
-                                    face->toc.count,\r
-                                    PCF_BDF_ENCODINGS,\r
-                                    &format,\r
-                                    &size );\r
-    if ( error )\r
-      return error;\r
-\r
-    error = FT_Stream_EnterFrame( stream, 14 );\r
-    if ( error )\r
-      return error;\r
-\r
-    format = FT_GET_ULONG_LE();\r
-\r
-    if ( PCF_BYTE_ORDER( format ) == MSBFirst )\r
-    {\r
-      firstCol          = FT_GET_SHORT();\r
-      lastCol           = FT_GET_SHORT();\r
-      firstRow          = FT_GET_SHORT();\r
-      lastRow           = FT_GET_SHORT();\r
-      face->defaultChar = FT_GET_SHORT();\r
-    }\r
-    else\r
-    {\r
-      firstCol          = FT_GET_SHORT_LE();\r
-      lastCol           = FT_GET_SHORT_LE();\r
-      firstRow          = FT_GET_SHORT_LE();\r
-      lastRow           = FT_GET_SHORT_LE();\r
-      face->defaultChar = FT_GET_SHORT_LE();\r
-    }\r
-\r
-    FT_Stream_ExitFrame( stream );\r
-\r
-    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )\r
-      return PCF_Err_Invalid_File_Format;\r
-\r
-    FT_TRACE4(( "pdf_get_encodings:\n" ));\r
-\r
-    FT_TRACE4(( "  firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",\r
-                firstCol, lastCol, firstRow, lastRow ));\r
-\r
-    nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );\r
-\r
-    if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) )\r
-      return PCF_Err_Out_Of_Memory;\r
-\r
-    error = FT_Stream_EnterFrame( stream, 2 * nencoding );\r
-    if ( error )\r
-      goto Bail;\r
-\r
-    for ( i = 0, j = 0 ; i < nencoding; i++ )\r
-    {\r
-      if ( PCF_BYTE_ORDER( format ) == MSBFirst )\r
-        encodingOffset = FT_GET_SHORT();\r
-      else\r
-        encodingOffset = FT_GET_SHORT_LE();\r
-\r
-      if ( encodingOffset != -1 )\r
-      {\r
-        tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) +\r
-                                 firstRow ) * 256 ) +\r
-                               ( ( i % ( lastCol - firstCol + 1 ) ) +\r
-                                 firstCol );\r
-\r
-        tmpEncoding[j].glyph = (FT_Short)encodingOffset;\r
-\r
-        FT_TRACE5(( "  code %d (0x%04X): idx %d\n",\r
-                    tmpEncoding[j].enc, tmpEncoding[j].enc,\r
-                    tmpEncoding[j].glyph ));\r
-\r
-        j++;\r
-      }\r
-    }\r
-    FT_Stream_ExitFrame( stream );\r
-\r
-    if ( FT_NEW_ARRAY( encoding, j ) )\r
-      goto Bail;\r
-\r
-    for ( i = 0; i < j; i++ )\r
-    {\r
-      encoding[i].enc   = tmpEncoding[i].enc;\r
-      encoding[i].glyph = tmpEncoding[i].glyph;\r
-    }\r
-\r
-    face->nencodings = j;\r
-    face->encodings  = encoding;\r
-    FT_FREE( tmpEncoding );\r
-\r
-    return error;\r
-\r
-  Bail:\r
-    FT_FREE( encoding );\r
-    FT_FREE( tmpEncoding );\r
-    return error;\r
-  }\r
-\r
-\r
-  static\r
-  const FT_Frame_Field  pcf_accel_header[] =\r
-  {\r
-#undef  FT_STRUCTURE\r
-#define FT_STRUCTURE  PCF_AccelRec\r
-\r
-    FT_FRAME_START( 20 ),\r
-      FT_FRAME_BYTE      ( noOverlap ),\r
-      FT_FRAME_BYTE      ( constantMetrics ),\r
-      FT_FRAME_BYTE      ( terminalFont ),\r
-      FT_FRAME_BYTE      ( constantWidth ),\r
-      FT_FRAME_BYTE      ( inkInside ),\r
-      FT_FRAME_BYTE      ( inkMetrics ),\r
-      FT_FRAME_BYTE      ( drawDirection ),\r
-      FT_FRAME_SKIP_BYTES( 1 ),\r
-      FT_FRAME_LONG_LE   ( fontAscent ),\r
-      FT_FRAME_LONG_LE   ( fontDescent ),\r
-      FT_FRAME_LONG_LE   ( maxOverlap ),\r
-    FT_FRAME_END\r
-  };\r
-\r
-\r
-  static\r
-  const FT_Frame_Field  pcf_accel_msb_header[] =\r
-  {\r
-#undef  FT_STRUCTURE\r
-#define FT_STRUCTURE  PCF_AccelRec\r
-\r
-    FT_FRAME_START( 20 ),\r
-      FT_FRAME_BYTE      ( noOverlap ),\r
-      FT_FRAME_BYTE      ( constantMetrics ),\r
-      FT_FRAME_BYTE      ( terminalFont ),\r
-      FT_FRAME_BYTE      ( constantWidth ),\r
-      FT_FRAME_BYTE      ( inkInside ),\r
-      FT_FRAME_BYTE      ( inkMetrics ),\r
-      FT_FRAME_BYTE      ( drawDirection ),\r
-      FT_FRAME_SKIP_BYTES( 1 ),\r
-      FT_FRAME_LONG      ( fontAscent ),\r
-      FT_FRAME_LONG      ( fontDescent ),\r
-      FT_FRAME_LONG      ( maxOverlap ),\r
-    FT_FRAME_END\r
-  };\r
-\r
-\r
-  static FT_Error\r
-  pcf_get_accel( FT_Stream  stream,\r
-                 PCF_Face   face,\r
-                 FT_ULong   type )\r
-  {\r
-    FT_ULong   format, size;\r
-    FT_Error   error = PCF_Err_Ok;\r
-    PCF_Accel  accel = &face->accel;\r
-\r
-\r
-    error = pcf_seek_to_table_type( stream,\r
-                                    face->toc.tables,\r
-                                    face->toc.count,\r
-                                    type,\r
-                                    &format,\r
-                                    &size );\r
-    if ( error )\r
-      goto Bail;\r
-\r
-    if ( FT_READ_ULONG_LE( format ) )\r
-      goto Bail;\r
-\r
-    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )    &&\r
-         !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )\r
-      goto Bail;\r
-\r
-    if ( PCF_BYTE_ORDER( format ) == MSBFirst )\r
-    {\r
-      if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )\r
-        goto Bail;\r
-    }\r
-    else\r
-    {\r
-      if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )\r
-        goto Bail;\r
-    }\r
-\r
-    error = pcf_get_metric( stream,\r
-                            format & ( ~PCF_FORMAT_MASK ),\r
-                            &(accel->minbounds) );\r
-    if ( error )\r
-      goto Bail;\r
-\r
-    error = pcf_get_metric( stream,\r
-                            format & ( ~PCF_FORMAT_MASK ),\r
-                            &(accel->maxbounds) );\r
-    if ( error )\r
-      goto Bail;\r
-\r
-    if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )\r
-    {\r
-      error = pcf_get_metric( stream,\r
-                              format & ( ~PCF_FORMAT_MASK ),\r
-                              &(accel->ink_minbounds) );\r
-      if ( error )\r
-        goto Bail;\r
-\r
-      error = pcf_get_metric( stream,\r
-                              format & ( ~PCF_FORMAT_MASK ),\r
-                              &(accel->ink_maxbounds) );\r
-      if ( error )\r
-        goto Bail;\r
-    }\r
-    else\r
-    {\r
-      accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */\r
-      accel->ink_maxbounds = accel->maxbounds;\r
-    }\r
-\r
-  Bail:\r
-    return error;\r
-  }\r
-\r
-\r
-  static FT_Error\r
-  pcf_interpret_style( PCF_Face  pcf )\r
-  {\r
-    FT_Error   error  = PCF_Err_Ok;\r
-    FT_Face    face   = FT_FACE( pcf );\r
-    FT_Memory  memory = face->memory;\r
-\r
-    PCF_Property  prop;\r
-\r
-    int    nn, len;\r
-    char*  strings[4] = { NULL, NULL, NULL, NULL };\r
-    int    lengths[4];\r
-\r
-\r
-    face->style_flags = 0;\r
-\r
-    prop = pcf_find_property( pcf, "SLANT" );\r
-    if ( prop && prop->isString                                       &&\r
-         ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||\r
-           *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )\r
-    {\r
-      face->style_flags |= FT_STYLE_FLAG_ITALIC;\r
-      strings[2] = ( *(prop->value.atom) == 'O' ||\r
-                     *(prop->value.atom) == 'o' ) ? (char *)"Oblique"\r
-                                                  : (char *)"Italic";\r
-    }\r
-\r
-    prop = pcf_find_property( pcf, "WEIGHT_NAME" );\r
-    if ( prop && prop->isString                                       &&\r
-         ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )\r
-    {\r
-      face->style_flags |= FT_STYLE_FLAG_BOLD;\r
-      strings[1] = (char *)"Bold";\r
-    }\r
-\r
-    prop = pcf_find_property( pcf, "SETWIDTH_NAME" );\r
-    if ( prop && prop->isString                                        &&\r
-         *(prop->value.atom)                                           &&\r
-         !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )\r
-      strings[3] = (char *)(prop->value.atom);\r
-\r
-    prop = pcf_find_property( pcf, "ADD_STYLE_NAME" );\r
-    if ( prop && prop->isString                                        &&\r
-         *(prop->value.atom)                                           &&\r
-         !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )\r
-      strings[0] = (char *)(prop->value.atom);\r
-\r
-    for ( len = 0, nn = 0; nn < 4; nn++ )\r
-    {\r
-      lengths[nn] = 0;\r
-      if ( strings[nn] )\r
-      {\r
-        lengths[nn] = ft_strlen( strings[nn] );\r
-        len        += lengths[nn] + 1;\r
-      }\r
-    }\r
-\r
-    if ( len == 0 )\r
-    {\r
-      strings[0] = (char *)"Regular";\r
-      lengths[0] = ft_strlen( strings[0] );\r
-      len        = lengths[0] + 1;\r
-    }\r
-\r
-    {\r
-      char*  s;\r
-\r
-\r
-      if ( FT_ALLOC( face->style_name, len ) )\r
-        return error;\r
-\r
-      s = face->style_name;\r
-\r
-      for ( nn = 0; nn < 4; nn++ )\r
-      {\r
-        char*  src = strings[nn];\r
-\r
-\r
-        len = lengths[nn];\r
-\r
-        if ( src == NULL )\r
-          continue;\r
-\r
-        /* separate elements with a space */\r
-        if ( s != face->style_name )\r
-          *s++ = ' ';\r
-\r
-        ft_memcpy( s, src, len );\r
-\r
-        /* need to convert spaces to dashes for */\r
-        /* add_style_name and setwidth_name     */\r
-        if ( nn == 0 || nn == 3 )\r
-        {\r
-          int  mm;\r
-\r
-\r
-          for ( mm = 0; mm < len; mm++ )\r
-            if (s[mm] == ' ')\r
-              s[mm] = '-';\r
-        }\r
-\r
-        s += len;\r
-      }\r
-      *s = 0;\r
-    }\r
-\r
-    return error;\r
-  }\r
-\r
-\r
-  FT_LOCAL_DEF( FT_Error )\r
-  pcf_load_font( FT_Stream  stream,\r
-                 PCF_Face   face )\r
-  {\r
-    FT_Error   error  = PCF_Err_Ok;\r
-    FT_Memory  memory = FT_FACE(face)->memory;\r
-    FT_Bool    hasBDFAccelerators;\r
-\r
-\r
-    error = pcf_read_TOC( stream, face );\r
-    if ( error )\r
-      goto Exit;\r
-\r
-    error = pcf_get_properties( stream, face );\r
-    if ( error )\r
-      goto Exit;\r
-\r
-    /* Use the old accelerators if no BDF accelerators are in the file. */\r
-    hasBDFAccelerators = pcf_has_table_type( face->toc.tables,\r
-                                             face->toc.count,\r
-                                             PCF_BDF_ACCELERATORS );\r
-    if ( !hasBDFAccelerators )\r
-    {\r
-      error = pcf_get_accel( stream, face, PCF_ACCELERATORS );\r
-      if ( error )\r
-        goto Exit;\r
-    }\r
-\r
-    /* metrics */\r
-    error = pcf_get_metrics( stream, face );\r
-    if ( error )\r
-      goto Exit;\r
-\r
-    /* bitmaps */\r
-    error = pcf_get_bitmaps( stream, face );\r
-    if ( error )\r
-      goto Exit;\r
-\r
-    /* encodings */\r
-    error = pcf_get_encodings( stream, face );\r
-    if ( error )\r
-      goto Exit;\r
-\r
-    /* BDF style accelerators (i.e. bounds based on encoded glyphs) */\r
-    if ( hasBDFAccelerators )\r
-    {\r
-      error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );\r
-      if ( error )\r
-        goto Exit;\r
-    }\r
-\r
-    /* XXX: TO DO: inkmetrics and glyph_names are missing */\r
-\r
-    /* now construct the face object */\r
-    {\r
-      FT_Face       root = FT_FACE( face );\r
-      PCF_Property  prop;\r
-\r
-\r
-      root->num_faces  = 1;\r
-      root->face_index = 0;\r
-      root->face_flags = FT_FACE_FLAG_FIXED_SIZES |\r
-                         FT_FACE_FLAG_HORIZONTAL  |\r
-                         FT_FACE_FLAG_FAST_GLYPHS;\r
-\r
-      if ( face->accel.constantWidth )\r
-        root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;\r
-\r
-      if ( ( error = pcf_interpret_style( face ) ) != 0 )\r
-         goto Exit;\r
-\r
-      prop = pcf_find_property( face, "FAMILY_NAME" );\r
-      if ( prop && prop->isString )\r
-      {\r
-        if ( FT_STRDUP( root->family_name, prop->value.atom ) )\r
-          goto Exit;\r
-      }\r
-      else\r
-        root->family_name = NULL;\r
-\r
-      /*\r
-       * Note: We shift all glyph indices by +1 since we must\r
-       * respect the convention that glyph 0 always corresponds\r
-       * to the `missing glyph'.\r
-       *\r
-       * This implies bumping the number of `available' glyphs by 1.\r
-       */\r
-      root->num_glyphs = face->nmetrics + 1;\r
-\r
-      root->num_fixed_sizes = 1;\r
-      if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )\r
-        goto Exit;\r
-\r
-      {\r
-        FT_Bitmap_Size*  bsize = root->available_sizes;\r
-        FT_Short         resolution_x = 0, resolution_y = 0;\r
-\r
-\r
-        FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) );\r
-\r
-#if 0\r
-        bsize->height = face->accel.maxbounds.ascent << 6;\r
-#endif\r
-        bsize->height = (FT_Short)( face->accel.fontAscent +\r
-                                    face->accel.fontDescent );\r
-\r
-        prop = pcf_find_property( face, "AVERAGE_WIDTH" );\r
-        if ( prop )\r
-          bsize->width = (FT_Short)( ( prop->value.integer + 5 ) / 10 );\r
-        else\r
-          bsize->width = (FT_Short)( bsize->height * 2/3 );\r
-\r
-        prop = pcf_find_property( face, "POINT_SIZE" );\r
-        if ( prop )\r
-          /* convert from 722.7 decipoints to 72 points per inch */\r
-          bsize->size =\r
-            (FT_Pos)( ( prop->value.integer * 64 * 7200 + 36135L ) / 72270L );\r
-\r
-        prop = pcf_find_property( face, "PIXEL_SIZE" );\r
-        if ( prop )\r
-          bsize->y_ppem = (FT_Short)prop->value.integer << 6;\r
-\r
-        prop = pcf_find_property( face, "RESOLUTION_X" );\r
-        if ( prop )\r
-          resolution_x = (FT_Short)prop->value.integer;\r
-\r
-        prop = pcf_find_property( face, "RESOLUTION_Y" );\r
-        if ( prop )\r
-          resolution_y = (FT_Short)prop->value.integer;\r
-\r
-        if ( bsize->y_ppem == 0 )\r
-        {\r
-          bsize->y_ppem = bsize->size;\r
-          if ( resolution_y )\r
-            bsize->y_ppem = bsize->y_ppem * resolution_y / 72;\r
-        }\r
-        if ( resolution_x && resolution_y )\r
-          bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y;\r
-        else\r
-          bsize->x_ppem = bsize->y_ppem;\r
-      }\r
-\r
-      /* set up charset */\r
-      {\r
-        PCF_Property  charset_registry = 0, charset_encoding = 0;\r
-\r
-\r
-        charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );\r
-        charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );\r
-\r
-        if ( charset_registry && charset_registry->isString &&\r
-             charset_encoding && charset_encoding->isString )\r
-        {\r
-          if ( FT_STRDUP( face->charset_encoding,\r
-                          charset_encoding->value.atom ) ||\r
-               FT_STRDUP( face->charset_registry,\r
-                          charset_registry->value.atom ) )\r
-            goto Exit;\r
-        }\r
-      }\r
-    }\r
-\r
-  Exit:\r
-    if ( error )\r
-    {\r
-      /* This is done to respect the behaviour of the original */\r
-      /* PCF font driver.                                      */\r
-      error = PCF_Err_Invalid_File_Format;\r
-    }\r
-\r
-    return error;\r
-  }\r
-\r
-\r
-/* END */\r
+/*  pcfread.c
+
+    FreeType font driver for pcf fonts
+
+  Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 by
+  Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#include <ft2build.h>
+
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "pcf.h"
+#include "pcfdrivr.h"
+#include "pcfread.h"
+
+#include "pcferror.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_pcfread
+
+
+#if defined( FT_DEBUG_LEVEL_TRACE )
+  static const char* const  tableNames[] =
+  {
+    "prop", "accl", "mtrcs", "bmps", "imtrcs",
+    "enc", "swidth", "names", "accel"
+  };
+#endif
+
+
+  static
+  const FT_Frame_Field  pcf_toc_header[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PCF_TocRec
+
+    FT_FRAME_START( 8 ),
+      FT_FRAME_ULONG_LE( version ),
+      FT_FRAME_ULONG_LE( count ),
+    FT_FRAME_END
+  };
+
+
+  static
+  const FT_Frame_Field  pcf_table_header[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PCF_TableRec
+
+    FT_FRAME_START( 16  ),
+      FT_FRAME_ULONG_LE( type ),
+      FT_FRAME_ULONG_LE( format ),
+      FT_FRAME_ULONG_LE( size ),
+      FT_FRAME_ULONG_LE( offset ),
+    FT_FRAME_END
+  };
+
+
+  static FT_Error
+  pcf_read_TOC( FT_Stream  stream,
+                PCF_Face   face )
+  {
+    FT_Error   error;
+    PCF_Toc    toc = &face->toc;
+    PCF_Table  tables;
+
+    FT_Memory  memory = FT_FACE(face)->memory;
+    FT_UInt    n;
+
+
+    if ( FT_STREAM_SEEK ( 0 )                          ||
+         FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) )
+      return PCF_Err_Cannot_Open_Resource;
+
+    if ( toc->version != PCF_FILE_VERSION                 ||
+         toc->count   >  FT_ARRAY_MAX( face->toc.tables ) ||
+         toc->count   == 0                                )
+      return PCF_Err_Invalid_File_Format;
+
+    if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) )
+      return PCF_Err_Out_Of_Memory;
+
+    tables = face->toc.tables;
+    for ( n = 0; n < toc->count; n++ )
+    {
+      if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )
+        goto Exit;
+      tables++;
+    }
+
+    /* Sort tables and check for overlaps.  Because they are almost      */
+    /* always ordered already, an in-place bubble sort with simultaneous */
+    /* boundary checking seems appropriate.                              */
+    tables = face->toc.tables;
+
+    for ( n = 0; n < toc->count - 1; n++ )
+    {
+      FT_UInt  i, have_change;
+
+
+      have_change = 0;
+
+      for ( i = 0; i < toc->count - 1 - n; i++ )
+      {
+        PCF_TableRec  tmp;
+
+
+        if ( tables[i].offset > tables[i + 1].offset )
+        {
+          tmp           = tables[i];
+          tables[i]     = tables[i + 1];
+          tables[i + 1] = tmp;
+
+          have_change = 1;
+        }
+
+        if ( ( tables[i].size   > tables[i + 1].offset )                  ||
+             ( tables[i].offset > tables[i + 1].offset - tables[i].size ) )
+          return PCF_Err_Invalid_Offset;
+      }
+
+      if ( !have_change )
+        break;
+    }
+
+#if defined( FT_DEBUG_LEVEL_TRACE )
+
+    {
+      FT_UInt      i, j;
+      const char*  name = "?";
+
+
+      FT_TRACE4(( "pcf_read_TOC:\n" ));
+
+      FT_TRACE4(( "  number of tables: %ld\n", face->toc.count ));
+
+      tables = face->toc.tables;
+      for ( i = 0; i < toc->count; i++ )
+      {
+        for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] );
+              j++ )
+          if ( tables[i].type == (FT_UInt)( 1 << j ) )
+            name = tableNames[j];
+
+        FT_TRACE4(( "  %d: type=%s, format=0x%X, "
+                    "size=%ld (0x%lX), offset=%ld (0x%lX)\n",
+                    i, name,
+                    tables[i].format,
+                    tables[i].size, tables[i].size,
+                    tables[i].offset, tables[i].offset ));
+      }
+    }
+
+#endif
+
+    return PCF_Err_Ok;
+
+  Exit:
+    FT_FREE( face->toc.tables );
+    return error;
+  }
+
+
+#define PCF_METRIC_SIZE  12
+
+  static
+  const FT_Frame_Field  pcf_metric_header[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PCF_MetricRec
+
+    FT_FRAME_START( PCF_METRIC_SIZE ),
+      FT_FRAME_SHORT_LE( leftSideBearing ),
+      FT_FRAME_SHORT_LE( rightSideBearing ),
+      FT_FRAME_SHORT_LE( characterWidth ),
+      FT_FRAME_SHORT_LE( ascent ),
+      FT_FRAME_SHORT_LE( descent ),
+      FT_FRAME_SHORT_LE( attributes ),
+    FT_FRAME_END
+  };
+
+
+  static
+  const FT_Frame_Field  pcf_metric_msb_header[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PCF_MetricRec
+
+    FT_FRAME_START( PCF_METRIC_SIZE ),
+      FT_FRAME_SHORT( leftSideBearing ),
+      FT_FRAME_SHORT( rightSideBearing ),
+      FT_FRAME_SHORT( characterWidth ),
+      FT_FRAME_SHORT( ascent ),
+      FT_FRAME_SHORT( descent ),
+      FT_FRAME_SHORT( attributes ),
+    FT_FRAME_END
+  };
+
+
+#define PCF_COMPRESSED_METRIC_SIZE  5
+
+  static
+  const FT_Frame_Field  pcf_compressed_metric_header[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PCF_Compressed_MetricRec
+
+    FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ),
+      FT_FRAME_BYTE( leftSideBearing ),
+      FT_FRAME_BYTE( rightSideBearing ),
+      FT_FRAME_BYTE( characterWidth ),
+      FT_FRAME_BYTE( ascent ),
+      FT_FRAME_BYTE( descent ),
+    FT_FRAME_END
+  };
+
+
+  static FT_Error
+  pcf_get_metric( FT_Stream   stream,
+                  FT_ULong    format,
+                  PCF_Metric  metric )
+  {
+    FT_Error  error = PCF_Err_Ok;
+
+
+    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+    {
+      const FT_Frame_Field*  fields;
+
+
+      /* parsing normal metrics */
+      fields = PCF_BYTE_ORDER( format ) == MSBFirst
+               ? pcf_metric_msb_header
+               : pcf_metric_header;
+
+      /* the following sets `error' but doesn't return in case of failure */
+      (void)FT_STREAM_READ_FIELDS( fields, metric );
+    }
+    else
+    {
+      PCF_Compressed_MetricRec  compr;
+
+
+      /* parsing compressed metrics */
+      if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )
+        goto Exit;
+
+      metric->leftSideBearing  = (FT_Short)( compr.leftSideBearing  - 0x80 );
+      metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 );
+      metric->characterWidth   = (FT_Short)( compr.characterWidth   - 0x80 );
+      metric->ascent           = (FT_Short)( compr.ascent           - 0x80 );
+      metric->descent          = (FT_Short)( compr.descent          - 0x80 );
+      metric->attributes       = 0;
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  static FT_Error
+  pcf_seek_to_table_type( FT_Stream  stream,
+                          PCF_Table  tables,
+                          FT_Int     ntables,
+                          FT_ULong   type,
+                          FT_ULong  *aformat,
+                          FT_ULong  *asize )
+  {
+    FT_Error  error = PCF_Err_Invalid_File_Format;
+    FT_Int    i;
+
+
+    for ( i = 0; i < ntables; i++ )
+      if ( tables[i].type == type )
+      {
+        if ( stream->pos > tables[i].offset )
+        {
+          error = PCF_Err_Invalid_Stream_Skip;
+          goto Fail;
+        }
+
+        if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) )
+        {
+          error = PCF_Err_Invalid_Stream_Skip;
+          goto Fail;
+        }
+
+        *asize   = tables[i].size;
+        *aformat = tables[i].format;
+
+        return PCF_Err_Ok;
+      }
+
+  Fail:
+    *asize = 0;
+    return error;
+  }
+
+
+  static FT_Bool
+  pcf_has_table_type( PCF_Table  tables,
+                      FT_Int     ntables,
+                      FT_ULong   type )
+  {
+    FT_Int  i;
+
+
+    for ( i = 0; i < ntables; i++ )
+      if ( tables[i].type == type )
+        return TRUE;
+
+    return FALSE;
+  }
+
+
+#define PCF_PROPERTY_SIZE  9
+
+  static
+  const FT_Frame_Field  pcf_property_header[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PCF_ParsePropertyRec
+
+    FT_FRAME_START( PCF_PROPERTY_SIZE ),
+      FT_FRAME_LONG_LE( name ),
+      FT_FRAME_BYTE   ( isString ),
+      FT_FRAME_LONG_LE( value ),
+    FT_FRAME_END
+  };
+
+
+  static
+  const FT_Frame_Field  pcf_property_msb_header[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PCF_ParsePropertyRec
+
+    FT_FRAME_START( PCF_PROPERTY_SIZE ),
+      FT_FRAME_LONG( name ),
+      FT_FRAME_BYTE( isString ),
+      FT_FRAME_LONG( value ),
+    FT_FRAME_END
+  };
+
+
+  FT_LOCAL_DEF( PCF_Property )
+  pcf_find_property( PCF_Face          face,
+                     const FT_String*  prop )
+  {
+    PCF_Property  properties = face->properties;
+    FT_Bool       found      = 0;
+    int           i;
+
+
+    for ( i = 0 ; i < face->nprops && !found; i++ )
+    {
+      if ( !ft_strcmp( properties[i].name, prop ) )
+        found = 1;
+    }
+
+    if ( found )
+      return properties + i - 1;
+    else
+      return NULL;
+  }
+
+
+  static FT_Error
+  pcf_get_properties( FT_Stream  stream,
+                      PCF_Face   face )
+  {
+    PCF_ParseProperty  props      = 0;
+    PCF_Property       properties;
+    FT_UInt            nprops, i;
+    FT_ULong           format, size;
+    FT_Error           error;
+    FT_Memory          memory     = FT_FACE(face)->memory;
+    FT_ULong           string_size;
+    FT_String*         strings    = 0;
+
+
+    error = pcf_seek_to_table_type( stream,
+                                    face->toc.tables,
+                                    face->toc.count,
+                                    PCF_PROPERTIES,
+                                    &format,
+                                    &size );
+    if ( error )
+      goto Bail;
+
+    if ( FT_READ_ULONG_LE( format ) )
+      goto Bail;
+
+    FT_TRACE4(( "pcf_get_properties:\n" ));
+
+    FT_TRACE4(( "  format = %ld\n", format ));
+
+    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+      goto Bail;
+
+    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+      (void)FT_READ_ULONG( nprops );
+    else
+      (void)FT_READ_ULONG_LE( nprops );
+    if ( error )
+      goto Bail;
+
+    FT_TRACE4(( "  nprop = %d\n", nprops ));
+
+    /* rough estimate */
+    if ( nprops > size / PCF_PROPERTY_SIZE )
+    {
+      error = PCF_Err_Invalid_Table;
+      goto Bail;
+    }
+
+    face->nprops = nprops;
+
+    if ( FT_NEW_ARRAY( props, nprops ) )
+      goto Bail;
+
+    for ( i = 0; i < nprops; i++ )
+    {
+      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+      {
+        if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
+          goto Bail;
+      }
+      else
+      {
+        if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
+          goto Bail;
+      }
+    }
+
+    /* pad the property array                                            */
+    /*                                                                   */
+    /* clever here - nprops is the same as the number of odd-units read, */
+    /* as only isStringProp are odd length   (Keith Packard)             */
+    /*                                                                   */
+    if ( nprops & 3 )
+    {
+      i = 4 - ( nprops & 3 );
+      FT_Stream_Skip( stream, i );
+    }
+
+    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+      (void)FT_READ_ULONG( string_size );
+    else
+      (void)FT_READ_ULONG_LE( string_size );
+    if ( error )
+      goto Bail;
+
+    FT_TRACE4(( "  string_size = %ld\n", string_size ));
+
+    /* rough estimate */
+    if ( string_size > size - nprops * PCF_PROPERTY_SIZE )
+    {
+      error = PCF_Err_Invalid_Table;
+      goto Bail;
+    }
+
+    if ( FT_NEW_ARRAY( strings, string_size ) )
+      goto Bail;
+
+    error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size );
+    if ( error )
+      goto Bail;
+
+    if ( FT_NEW_ARRAY( properties, nprops ) )
+      goto Bail;
+
+    face->properties = properties;
+
+    for ( i = 0; i < nprops; i++ )
+    {
+      FT_Long  name_offset = props[i].name;
+
+
+      if ( ( name_offset < 0 )                     ||
+           ( (FT_ULong)name_offset > string_size ) )
+      {
+        error = PCF_Err_Invalid_Offset;
+        goto Bail;
+      }
+
+      if ( FT_STRDUP( properties[i].name, strings + name_offset ) )
+        goto Bail;
+
+      FT_TRACE4(( "  %s:", properties[i].name ));
+
+      properties[i].isString = props[i].isString;
+
+      if ( props[i].isString )
+      {
+        FT_Long  value_offset = props[i].value;
+
+
+        if ( ( value_offset < 0 )                     ||
+             ( (FT_ULong)value_offset > string_size ) )
+        {
+          error = PCF_Err_Invalid_Offset;
+          goto Bail;
+        }
+
+        if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) )
+          goto Bail;
+
+        FT_TRACE4(( " `%s'\n", properties[i].value.atom ));
+      }
+      else
+      {
+        properties[i].value.integer = props[i].value;
+
+        FT_TRACE4(( " %d\n", properties[i].value.integer ));
+      }
+    }
+
+    error = PCF_Err_Ok;
+
+  Bail:
+    FT_FREE( props );
+    FT_FREE( strings );
+
+    return error;
+  }
+
+
+  static FT_Error
+  pcf_get_metrics( FT_Stream  stream,
+                   PCF_Face   face )
+  {
+    FT_Error    error    = PCF_Err_Ok;
+    FT_Memory   memory   = FT_FACE(face)->memory;
+    FT_ULong    format, size;
+    PCF_Metric  metrics  = 0;
+    FT_ULong    nmetrics, i;
+
+
+    error = pcf_seek_to_table_type( stream,
+                                    face->toc.tables,
+                                    face->toc.count,
+                                    PCF_METRICS,
+                                    &format,
+                                    &size );
+    if ( error )
+      return error;
+
+    if ( FT_READ_ULONG_LE( format ) )
+      goto Bail;
+
+    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )     &&
+         !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
+      return PCF_Err_Invalid_File_Format;
+
+    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+    {
+      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+        (void)FT_READ_ULONG( nmetrics );
+      else
+        (void)FT_READ_ULONG_LE( nmetrics );
+    }
+    else
+    {
+      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+        (void)FT_READ_USHORT( nmetrics );
+      else
+        (void)FT_READ_USHORT_LE( nmetrics );
+    }
+    if ( error )
+      return PCF_Err_Invalid_File_Format;
+
+    face->nmetrics = nmetrics;
+
+    FT_TRACE4(( "pcf_get_metrics:\n" ));
+
+    FT_TRACE4(( "  number of metrics: %d\n", nmetrics ));
+
+    /* rough estimate */
+    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+    {
+      if ( nmetrics > size / PCF_METRIC_SIZE )
+        return PCF_Err_Invalid_Table;
+    }
+    else
+    {
+      if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE )
+        return PCF_Err_Invalid_Table;
+    }
+
+    if ( FT_NEW_ARRAY( face->metrics, nmetrics ) )
+      return PCF_Err_Out_Of_Memory;
+
+    metrics = face->metrics;
+    for ( i = 0; i < nmetrics; i++ )
+    {
+      pcf_get_metric( stream, format, metrics + i );
+
+      metrics[i].bits = 0;
+
+      FT_TRACE5(( "  idx %d: width=%d, "
+                  "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",
+                  i,
+                  ( metrics + i )->characterWidth,
+                  ( metrics + i )->leftSideBearing,
+                  ( metrics + i )->rightSideBearing,
+                  ( metrics + i )->ascent,
+                  ( metrics + i )->descent,
+                  ( metrics + i )->attributes ));
+
+      if ( error )
+        break;
+    }
+
+    if ( error )
+      FT_FREE( face->metrics );
+
+  Bail:
+    return error;
+  }
+
+
+  static FT_Error
+  pcf_get_bitmaps( FT_Stream  stream,
+                   PCF_Face   face )
+  {
+    FT_Error   error  = PCF_Err_Ok;
+    FT_Memory  memory = FT_FACE(face)->memory;
+    FT_Long*   offsets;
+    FT_Long    bitmapSizes[GLYPHPADOPTIONS];
+    FT_ULong   format, size;
+    int        nbitmaps, i, sizebitmaps = 0;
+
+
+    error = pcf_seek_to_table_type( stream,
+                                    face->toc.tables,
+                                    face->toc.count,
+                                    PCF_BITMAPS,
+                                    &format,
+                                    &size );
+    if ( error )
+      return error;
+
+    error = FT_Stream_EnterFrame( stream, 8 );
+    if ( error )
+      return error;
+
+    format = FT_GET_ULONG_LE();
+    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+      nbitmaps  = FT_GET_ULONG();
+    else
+      nbitmaps  = FT_GET_ULONG_LE();
+
+    FT_Stream_ExitFrame( stream );
+
+    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+      return PCF_Err_Invalid_File_Format;
+
+    FT_TRACE4(( "pcf_get_bitmaps:\n" ));
+
+    FT_TRACE4(( "  number of bitmaps: %d\n", nbitmaps ));
+
+    if ( nbitmaps != face->nmetrics )
+      return PCF_Err_Invalid_File_Format;
+
+    if ( FT_NEW_ARRAY( offsets, nbitmaps ) )
+      return error;
+
+    for ( i = 0; i < nbitmaps; i++ )
+    {
+      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+        (void)FT_READ_LONG( offsets[i] );
+      else
+        (void)FT_READ_LONG_LE( offsets[i] );
+
+      FT_TRACE5(( "  bitmap %d: offset %ld (0x%lX)\n",
+                  i, offsets[i], offsets[i] ));
+    }
+    if ( error )
+      goto Bail;
+
+    for ( i = 0; i < GLYPHPADOPTIONS; i++ )
+    {
+      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+        (void)FT_READ_LONG( bitmapSizes[i] );
+      else
+        (void)FT_READ_LONG_LE( bitmapSizes[i] );
+      if ( error )
+        goto Bail;
+
+      sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
+
+      FT_TRACE4(( "  padding %d implies a size of %ld\n", i, bitmapSizes[i] ));
+    }
+
+    FT_TRACE4(( "  %d bitmaps, padding index %ld\n",
+                nbitmaps,
+                PCF_GLYPH_PAD_INDEX( format ) ));
+    FT_TRACE4(( "  bitmap size = %d\n", sizebitmaps ));
+
+    FT_UNUSED( sizebitmaps );       /* only used for debugging */
+
+    for ( i = 0; i < nbitmaps; i++ )
+    {
+      /* rough estimate */
+      if ( ( offsets[i] < 0 )              ||
+           ( (FT_ULong)offsets[i] > size ) )
+      {
+        FT_ERROR(( "pcf_get_bitmaps:"));
+        FT_ERROR(( " invalid offset to bitmap data of glyph %d\n", i ));
+      }
+      else
+        face->metrics[i].bits = stream->pos + offsets[i];
+    }
+
+    face->bitmapsFormat = format;
+
+  Bail:
+    FT_FREE( offsets );
+    return error;
+  }
+
+
+  static FT_Error
+  pcf_get_encodings( FT_Stream  stream,
+                     PCF_Face   face )
+  {
+    FT_Error      error  = PCF_Err_Ok;
+    FT_Memory     memory = FT_FACE(face)->memory;
+    FT_ULong      format, size;
+    int           firstCol, lastCol;
+    int           firstRow, lastRow;
+    int           nencoding, encodingOffset;
+    int           i, j;
+    PCF_Encoding  tmpEncoding, encoding = 0;
+
+
+    error = pcf_seek_to_table_type( stream,
+                                    face->toc.tables,
+                                    face->toc.count,
+                                    PCF_BDF_ENCODINGS,
+                                    &format,
+                                    &size );
+    if ( error )
+      return error;
+
+    error = FT_Stream_EnterFrame( stream, 14 );
+    if ( error )
+      return error;
+
+    format = FT_GET_ULONG_LE();
+
+    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+    {
+      firstCol          = FT_GET_SHORT();
+      lastCol           = FT_GET_SHORT();
+      firstRow          = FT_GET_SHORT();
+      lastRow           = FT_GET_SHORT();
+      face->defaultChar = FT_GET_SHORT();
+    }
+    else
+    {
+      firstCol          = FT_GET_SHORT_LE();
+      lastCol           = FT_GET_SHORT_LE();
+      firstRow          = FT_GET_SHORT_LE();
+      lastRow           = FT_GET_SHORT_LE();
+      face->defaultChar = FT_GET_SHORT_LE();
+    }
+
+    FT_Stream_ExitFrame( stream );
+
+    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+      return PCF_Err_Invalid_File_Format;
+
+    FT_TRACE4(( "pdf_get_encodings:\n" ));
+
+    FT_TRACE4(( "  firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",
+                firstCol, lastCol, firstRow, lastRow ));
+
+    nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );
+
+    if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) )
+      return PCF_Err_Out_Of_Memory;
+
+    error = FT_Stream_EnterFrame( stream, 2 * nencoding );
+    if ( error )
+      goto Bail;
+
+    for ( i = 0, j = 0 ; i < nencoding; i++ )
+    {
+      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+        encodingOffset = FT_GET_SHORT();
+      else
+        encodingOffset = FT_GET_SHORT_LE();
+
+      if ( encodingOffset != -1 )
+      {
+        tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) +
+                                 firstRow ) * 256 ) +
+                               ( ( i % ( lastCol - firstCol + 1 ) ) +
+                                 firstCol );
+
+        tmpEncoding[j].glyph = (FT_Short)encodingOffset;
+
+        FT_TRACE5(( "  code %d (0x%04X): idx %d\n",
+                    tmpEncoding[j].enc, tmpEncoding[j].enc,
+                    tmpEncoding[j].glyph ));
+
+        j++;
+      }
+    }
+    FT_Stream_ExitFrame( stream );
+
+    if ( FT_NEW_ARRAY( encoding, j ) )
+      goto Bail;
+
+    for ( i = 0; i < j; i++ )
+    {
+      encoding[i].enc   = tmpEncoding[i].enc;
+      encoding[i].glyph = tmpEncoding[i].glyph;
+    }
+
+    face->nencodings = j;
+    face->encodings  = encoding;
+    FT_FREE( tmpEncoding );
+
+    return error;
+
+  Bail:
+    FT_FREE( encoding );
+    FT_FREE( tmpEncoding );
+    return error;
+  }
+
+
+  static
+  const FT_Frame_Field  pcf_accel_header[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PCF_AccelRec
+
+    FT_FRAME_START( 20 ),
+      FT_FRAME_BYTE      ( noOverlap ),
+      FT_FRAME_BYTE      ( constantMetrics ),
+      FT_FRAME_BYTE      ( terminalFont ),
+      FT_FRAME_BYTE      ( constantWidth ),
+      FT_FRAME_BYTE      ( inkInside ),
+      FT_FRAME_BYTE      ( inkMetrics ),
+      FT_FRAME_BYTE      ( drawDirection ),
+      FT_FRAME_SKIP_BYTES( 1 ),
+      FT_FRAME_LONG_LE   ( fontAscent ),
+      FT_FRAME_LONG_LE   ( fontDescent ),
+      FT_FRAME_LONG_LE   ( maxOverlap ),
+    FT_FRAME_END
+  };
+
+
+  static
+  const FT_Frame_Field  pcf_accel_msb_header[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PCF_AccelRec
+
+    FT_FRAME_START( 20 ),
+      FT_FRAME_BYTE      ( noOverlap ),
+      FT_FRAME_BYTE      ( constantMetrics ),
+      FT_FRAME_BYTE      ( terminalFont ),
+      FT_FRAME_BYTE      ( constantWidth ),
+      FT_FRAME_BYTE      ( inkInside ),
+      FT_FRAME_BYTE      ( inkMetrics ),
+      FT_FRAME_BYTE      ( drawDirection ),
+      FT_FRAME_SKIP_BYTES( 1 ),
+      FT_FRAME_LONG      ( fontAscent ),
+      FT_FRAME_LONG      ( fontDescent ),
+      FT_FRAME_LONG      ( maxOverlap ),
+    FT_FRAME_END
+  };
+
+
+  static FT_Error
+  pcf_get_accel( FT_Stream  stream,
+                 PCF_Face   face,
+                 FT_ULong   type )
+  {
+    FT_ULong   format, size;
+    FT_Error   error = PCF_Err_Ok;
+    PCF_Accel  accel = &face->accel;
+
+
+    error = pcf_seek_to_table_type( stream,
+                                    face->toc.tables,
+                                    face->toc.count,
+                                    type,
+                                    &format,
+                                    &size );
+    if ( error )
+      goto Bail;
+
+    if ( FT_READ_ULONG_LE( format ) )
+      goto Bail;
+
+    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )    &&
+         !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
+      goto Bail;
+
+    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+    {
+      if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
+        goto Bail;
+    }
+    else
+    {
+      if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
+        goto Bail;
+    }
+
+    error = pcf_get_metric( stream,
+                            format & ( ~PCF_FORMAT_MASK ),
+                            &(accel->minbounds) );
+    if ( error )
+      goto Bail;
+
+    error = pcf_get_metric( stream,
+                            format & ( ~PCF_FORMAT_MASK ),
+                            &(accel->maxbounds) );
+    if ( error )
+      goto Bail;
+
+    if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
+    {
+      error = pcf_get_metric( stream,
+                              format & ( ~PCF_FORMAT_MASK ),
+                              &(accel->ink_minbounds) );
+      if ( error )
+        goto Bail;
+
+      error = pcf_get_metric( stream,
+                              format & ( ~PCF_FORMAT_MASK ),
+                              &(accel->ink_maxbounds) );
+      if ( error )
+        goto Bail;
+    }
+    else
+    {
+      accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */
+      accel->ink_maxbounds = accel->maxbounds;
+    }
+
+  Bail:
+    return error;
+  }
+
+
+  static FT_Error
+  pcf_interpret_style( PCF_Face  pcf )
+  {
+    FT_Error   error  = PCF_Err_Ok;
+    FT_Face    face   = FT_FACE( pcf );
+    FT_Memory  memory = face->memory;
+
+    PCF_Property  prop;
+
+    int    nn, len;
+    char*  strings[4] = { NULL, NULL, NULL, NULL };
+    int    lengths[4];
+
+
+    face->style_flags = 0;
+
+    prop = pcf_find_property( pcf, "SLANT" );
+    if ( prop && prop->isString                                       &&
+         ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||
+           *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )
+    {
+      face->style_flags |= FT_STYLE_FLAG_ITALIC;
+      strings[2] = ( *(prop->value.atom) == 'O' ||
+                     *(prop->value.atom) == 'o' ) ? (char *)"Oblique"
+                                                  : (char *)"Italic";
+    }
+
+    prop = pcf_find_property( pcf, "WEIGHT_NAME" );
+    if ( prop && prop->isString                                       &&
+         ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
+    {
+      face->style_flags |= FT_STYLE_FLAG_BOLD;
+      strings[1] = (char *)"Bold";
+    }
+
+    prop = pcf_find_property( pcf, "SETWIDTH_NAME" );
+    if ( prop && prop->isString                                        &&
+         *(prop->value.atom)                                           &&
+         !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
+      strings[3] = (char *)(prop->value.atom);
+
+    prop = pcf_find_property( pcf, "ADD_STYLE_NAME" );
+    if ( prop && prop->isString                                        &&
+         *(prop->value.atom)                                           &&
+         !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
+      strings[0] = (char *)(prop->value.atom);
+
+    for ( len = 0, nn = 0; nn < 4; nn++ )
+    {
+      lengths[nn] = 0;
+      if ( strings[nn] )
+      {
+        lengths[nn] = ft_strlen( strings[nn] );
+        len        += lengths[nn] + 1;
+      }
+    }
+
+    if ( len == 0 )
+    {
+      strings[0] = (char *)"Regular";
+      lengths[0] = ft_strlen( strings[0] );
+      len        = lengths[0] + 1;
+    }
+
+    {
+      char*  s;
+
+
+      if ( FT_ALLOC( face->style_name, len ) )
+        return error;
+
+      s = face->style_name;
+
+      for ( nn = 0; nn < 4; nn++ )
+      {
+        char*  src = strings[nn];
+
+
+        len = lengths[nn];
+
+        if ( src == NULL )
+          continue;
+
+        /* separate elements with a space */
+        if ( s != face->style_name )
+          *s++ = ' ';
+
+        ft_memcpy( s, src, len );
+
+        /* need to convert spaces to dashes for */
+        /* add_style_name and setwidth_name     */
+        if ( nn == 0 || nn == 3 )
+        {
+          int  mm;
+
+
+          for ( mm = 0; mm < len; mm++ )
+            if (s[mm] == ' ')
+              s[mm] = '-';
+        }
+
+        s += len;
+      }
+      *s = 0;
+    }
+
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  pcf_load_font( FT_Stream  stream,
+                 PCF_Face   face )
+  {
+    FT_Error   error  = PCF_Err_Ok;
+    FT_Memory  memory = FT_FACE(face)->memory;
+    FT_Bool    hasBDFAccelerators;
+
+
+    error = pcf_read_TOC( stream, face );
+    if ( error )
+      goto Exit;
+
+    error = pcf_get_properties( stream, face );
+    if ( error )
+      goto Exit;
+
+    /* Use the old accelerators if no BDF accelerators are in the file. */
+    hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
+                                             face->toc.count,
+                                             PCF_BDF_ACCELERATORS );
+    if ( !hasBDFAccelerators )
+    {
+      error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
+      if ( error )
+        goto Exit;
+    }
+
+    /* metrics */
+    error = pcf_get_metrics( stream, face );
+    if ( error )
+      goto Exit;
+
+    /* bitmaps */
+    error = pcf_get_bitmaps( stream, face );
+    if ( error )
+      goto Exit;
+
+    /* encodings */
+    error = pcf_get_encodings( stream, face );
+    if ( error )
+      goto Exit;
+
+    /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
+    if ( hasBDFAccelerators )
+    {
+      error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
+      if ( error )
+        goto Exit;
+    }
+
+    /* XXX: TO DO: inkmetrics and glyph_names are missing */
+
+    /* now construct the face object */
+    {
+      FT_Face       root = FT_FACE( face );
+      PCF_Property  prop;
+
+
+      root->num_faces  = 1;
+      root->face_index = 0;
+      root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
+                         FT_FACE_FLAG_HORIZONTAL  |
+                         FT_FACE_FLAG_FAST_GLYPHS;
+
+      if ( face->accel.constantWidth )
+        root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+      if ( ( error = pcf_interpret_style( face ) ) != 0 )
+         goto Exit;
+
+      prop = pcf_find_property( face, "FAMILY_NAME" );
+      if ( prop && prop->isString )
+      {
+        if ( FT_STRDUP( root->family_name, prop->value.atom ) )
+          goto Exit;
+      }
+      else
+        root->family_name = NULL;
+
+      /*
+       * Note: We shift all glyph indices by +1 since we must
+       * respect the convention that glyph 0 always corresponds
+       * to the `missing glyph'.
+       *
+       * This implies bumping the number of `available' glyphs by 1.
+       */
+      root->num_glyphs = face->nmetrics + 1;
+
+      root->num_fixed_sizes = 1;
+      if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
+        goto Exit;
+
+      {
+        FT_Bitmap_Size*  bsize = root->available_sizes;
+        FT_Short         resolution_x = 0, resolution_y = 0;
+
+
+        FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) );
+
+#if 0
+        bsize->height = face->accel.maxbounds.ascent << 6;
+#endif
+        bsize->height = (FT_Short)( face->accel.fontAscent +
+                                    face->accel.fontDescent );
+
+        prop = pcf_find_property( face, "AVERAGE_WIDTH" );
+        if ( prop )
+          bsize->width = (FT_Short)( ( prop->value.integer + 5 ) / 10 );
+        else
+          bsize->width = (FT_Short)( bsize->height * 2/3 );
+
+        prop = pcf_find_property( face, "POINT_SIZE" );
+        if ( prop )
+          /* convert from 722.7 decipoints to 72 points per inch */
+          bsize->size =
+            (FT_Pos)( ( prop->value.integer * 64 * 7200 + 36135L ) / 72270L );
+
+        prop = pcf_find_property( face, "PIXEL_SIZE" );
+        if ( prop )
+          bsize->y_ppem = (FT_Short)prop->value.integer << 6;
+
+        prop = pcf_find_property( face, "RESOLUTION_X" );
+        if ( prop )
+          resolution_x = (FT_Short)prop->value.integer;
+
+        prop = pcf_find_property( face, "RESOLUTION_Y" );
+        if ( prop )
+          resolution_y = (FT_Short)prop->value.integer;
+
+        if ( bsize->y_ppem == 0 )
+        {
+          bsize->y_ppem = bsize->size;
+          if ( resolution_y )
+            bsize->y_ppem = bsize->y_ppem * resolution_y / 72;
+        }
+        if ( resolution_x && resolution_y )
+          bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y;
+        else
+          bsize->x_ppem = bsize->y_ppem;
+      }
+
+      /* set up charset */
+      {
+        PCF_Property  charset_registry = 0, charset_encoding = 0;
+
+
+        charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
+        charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
+
+        if ( charset_registry && charset_registry->isString &&
+             charset_encoding && charset_encoding->isString )
+        {
+          if ( FT_STRDUP( face->charset_encoding,
+                          charset_encoding->value.atom ) ||
+               FT_STRDUP( face->charset_registry,
+                          charset_registry->value.atom ) )
+            goto Exit;
+        }
+      }
+    }
+
+  Exit:
+    if ( error )
+    {
+      /* This is done to respect the behaviour of the original */
+      /* PCF font driver.                                      */
+      error = PCF_Err_Invalid_File_Format;
+    }
+
+    return error;
+  }
+
+
+/* END */