pcfread.c

Go to the documentation of this file.
00001 /*  pcfread.c
00002 
00003     FreeType font driver for pcf fonts
00004 
00005   Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by
00006   Francesco Zappa Nardelli
00007 
00008 Permission is hereby granted, free of charge, to any person obtaining a copy
00009 of this software and associated documentation files (the "Software"), to deal
00010 in the Software without restriction, including without limitation the rights
00011 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00012 copies of the Software, and to permit persons to whom the Software is
00013 furnished to do so, subject to the following conditions:
00014 
00015 The above copyright notice and this permission notice shall be included in
00016 all copies or substantial portions of the Software.
00017 
00018 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00019 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00020 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00021 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00022 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00023 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00024 THE SOFTWARE.
00025 */
00026 
00027 
00028 #include <ft2build.h>
00029 
00030 #include FT_INTERNAL_DEBUG_H
00031 #include FT_INTERNAL_STREAM_H
00032 #include FT_INTERNAL_OBJECTS_H
00033 
00034 #include "pcf.h"
00035 #include "pcfread.h"
00036 
00037 #include "pcferror.h"
00038 
00039 
00040   /*************************************************************************/
00041   /*                                                                       */
00042   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
00043   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
00044   /* messages during execution.                                            */
00045   /*                                                                       */
00046 #undef  FT_COMPONENT
00047 #define FT_COMPONENT  trace_pcfread
00048 
00049 
00050 #ifdef FT_DEBUG_LEVEL_TRACE
00051   static const char* const  tableNames[] =
00052   {
00053     "prop", "accl", "mtrcs", "bmps", "imtrcs",
00054     "enc", "swidth", "names", "accel"
00055   };
00056 #endif
00057 
00058 
00059   static
00060   const FT_Frame_Field  pcf_toc_header[] =
00061   {
00062 #undef  FT_STRUCTURE
00063 #define FT_STRUCTURE  PCF_TocRec
00064 
00065     FT_FRAME_START( 8 ),
00066       FT_FRAME_ULONG_LE( version ),
00067       FT_FRAME_ULONG_LE( count ),
00068     FT_FRAME_END
00069   };
00070 
00071 
00072   static
00073   const FT_Frame_Field  pcf_table_header[] =
00074   {
00075 #undef  FT_STRUCTURE
00076 #define FT_STRUCTURE  PCF_TableRec
00077 
00078     FT_FRAME_START( 16  ),
00079       FT_FRAME_ULONG_LE( type ),
00080       FT_FRAME_ULONG_LE( format ),
00081       FT_FRAME_ULONG_LE( size ),
00082       FT_FRAME_ULONG_LE( offset ),
00083     FT_FRAME_END
00084   };
00085 
00086 
00087   static FT_Error
00088   pcf_read_TOC( FT_Stream  stream,
00089                 PCF_Face   face )
00090   {
00091     FT_Error   error;
00092     PCF_Toc    toc = &face->toc;
00093     PCF_Table  tables;
00094 
00095     FT_Memory  memory = FT_FACE(face)->memory;
00096     FT_UInt    n;
00097 
00098 
00099     if ( FT_STREAM_SEEK ( 0 )                          ||
00100          FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) )
00101       return PCF_Err_Cannot_Open_Resource;
00102 
00103     if ( toc->version != PCF_FILE_VERSION                 ||
00104          toc->count   >  FT_ARRAY_MAX( face->toc.tables ) ||
00105          toc->count   == 0                                )
00106       return PCF_Err_Invalid_File_Format;
00107 
00108     if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) )
00109       return PCF_Err_Out_Of_Memory;
00110 
00111     tables = face->toc.tables;
00112     for ( n = 0; n < toc->count; n++ )
00113     {
00114       if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )
00115         goto Exit;
00116       tables++;
00117     }
00118 
00119     /* Sort tables and check for overlaps.  Because they are almost      */
00120     /* always ordered already, an in-place bubble sort with simultaneous */
00121     /* boundary checking seems appropriate.                              */
00122     tables = face->toc.tables;
00123 
00124     for ( n = 0; n < toc->count - 1; n++ )
00125     {
00126       FT_UInt  i, have_change;
00127 
00128 
00129       have_change = 0;
00130 
00131       for ( i = 0; i < toc->count - 1 - n; i++ )
00132       {
00133         PCF_TableRec  tmp;
00134 
00135 
00136         if ( tables[i].offset > tables[i + 1].offset )
00137         {
00138           tmp           = tables[i];
00139           tables[i]     = tables[i + 1];
00140           tables[i + 1] = tmp;
00141 
00142           have_change = 1;
00143         }
00144 
00145         if ( ( tables[i].size   > tables[i + 1].offset )                  ||
00146              ( tables[i].offset > tables[i + 1].offset - tables[i].size ) )
00147           return PCF_Err_Invalid_Offset;
00148       }
00149 
00150       if ( !have_change )
00151         break;
00152     }
00153 
00154 #ifdef FT_DEBUG_LEVEL_TRACE
00155 
00156     {
00157       FT_UInt      i, j;
00158       const char*  name = "?";
00159 
00160 
00161       FT_TRACE4(( "pcf_read_TOC:\n" ));
00162 
00163       FT_TRACE4(( "  number of tables: %ld\n", face->toc.count ));
00164 
00165       tables = face->toc.tables;
00166       for ( i = 0; i < toc->count; i++ )
00167       {
00168         for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] );
00169               j++ )
00170           if ( tables[i].type == (FT_UInt)( 1 << j ) )
00171             name = tableNames[j];
00172 
00173         FT_TRACE4(( "  %d: type=%s, format=0x%X, "
00174                     "size=%ld (0x%lX), offset=%ld (0x%lX)\n",
00175                     i, name,
00176                     tables[i].format,
00177                     tables[i].size, tables[i].size,
00178                     tables[i].offset, tables[i].offset ));
00179       }
00180     }
00181 
00182 #endif
00183 
00184     return PCF_Err_Ok;
00185 
00186   Exit:
00187     FT_FREE( face->toc.tables );
00188     return error;
00189   }
00190 
00191 
00192 #define PCF_METRIC_SIZE  12
00193 
00194   static
00195   const FT_Frame_Field  pcf_metric_header[] =
00196   {
00197 #undef  FT_STRUCTURE
00198 #define FT_STRUCTURE  PCF_MetricRec
00199 
00200     FT_FRAME_START( PCF_METRIC_SIZE ),
00201       FT_FRAME_SHORT_LE( leftSideBearing ),
00202       FT_FRAME_SHORT_LE( rightSideBearing ),
00203       FT_FRAME_SHORT_LE( characterWidth ),
00204       FT_FRAME_SHORT_LE( ascent ),
00205       FT_FRAME_SHORT_LE( descent ),
00206       FT_FRAME_SHORT_LE( attributes ),
00207     FT_FRAME_END
00208   };
00209 
00210 
00211   static
00212   const FT_Frame_Field  pcf_metric_msb_header[] =
00213   {
00214 #undef  FT_STRUCTURE
00215 #define FT_STRUCTURE  PCF_MetricRec
00216 
00217     FT_FRAME_START( PCF_METRIC_SIZE ),
00218       FT_FRAME_SHORT( leftSideBearing ),
00219       FT_FRAME_SHORT( rightSideBearing ),
00220       FT_FRAME_SHORT( characterWidth ),
00221       FT_FRAME_SHORT( ascent ),
00222       FT_FRAME_SHORT( descent ),
00223       FT_FRAME_SHORT( attributes ),
00224     FT_FRAME_END
00225   };
00226 
00227 
00228 #define PCF_COMPRESSED_METRIC_SIZE  5
00229 
00230   static
00231   const FT_Frame_Field  pcf_compressed_metric_header[] =
00232   {
00233 #undef  FT_STRUCTURE
00234 #define FT_STRUCTURE  PCF_Compressed_MetricRec
00235 
00236     FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ),
00237       FT_FRAME_BYTE( leftSideBearing ),
00238       FT_FRAME_BYTE( rightSideBearing ),
00239       FT_FRAME_BYTE( characterWidth ),
00240       FT_FRAME_BYTE( ascent ),
00241       FT_FRAME_BYTE( descent ),
00242     FT_FRAME_END
00243   };
00244 
00245 
00246   static FT_Error
00247   pcf_get_metric( FT_Stream   stream,
00248                   FT_ULong    format,
00249                   PCF_Metric  metric )
00250   {
00251     FT_Error  error = PCF_Err_Ok;
00252 
00253 
00254     if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
00255     {
00256       const FT_Frame_Field*  fields;
00257 
00258 
00259       /* parsing normal metrics */
00260       fields = PCF_BYTE_ORDER( format ) == MSBFirst
00261                ? pcf_metric_msb_header
00262                : pcf_metric_header;
00263 
00264       /* the following sets `error' but doesn't return in case of failure */
00265       (void)FT_STREAM_READ_FIELDS( fields, metric );
00266     }
00267     else
00268     {
00269       PCF_Compressed_MetricRec  compr;
00270 
00271 
00272       /* parsing compressed metrics */
00273       if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )
00274         goto Exit;
00275 
00276       metric->leftSideBearing  = (FT_Short)( compr.leftSideBearing  - 0x80 );
00277       metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 );
00278       metric->characterWidth   = (FT_Short)( compr.characterWidth   - 0x80 );
00279       metric->ascent           = (FT_Short)( compr.ascent           - 0x80 );
00280       metric->descent          = (FT_Short)( compr.descent          - 0x80 );
00281       metric->attributes       = 0;
00282     }
00283 
00284   Exit:
00285     return error;
00286   }
00287 
00288 
00289   static FT_Error
00290   pcf_seek_to_table_type( FT_Stream  stream,
00291                           PCF_Table  tables,
00292                           FT_ULong   ntables, /* same as PCF_Toc->count */
00293                           FT_ULong   type,
00294                           FT_ULong  *aformat,
00295                           FT_ULong  *asize )
00296   {
00297     FT_Error  error = PCF_Err_Invalid_File_Format;
00298     FT_ULong  i;
00299 
00300 
00301     for ( i = 0; i < ntables; i++ )
00302       if ( tables[i].type == type )
00303       {
00304         if ( stream->pos > tables[i].offset )
00305         {
00306           error = PCF_Err_Invalid_Stream_Skip;
00307           goto Fail;
00308         }
00309 
00310         if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) )
00311         {
00312           error = PCF_Err_Invalid_Stream_Skip;
00313           goto Fail;
00314         }
00315 
00316         *asize   = tables[i].size;
00317         *aformat = tables[i].format;
00318 
00319         return PCF_Err_Ok;
00320       }
00321 
00322   Fail:
00323     *asize = 0;
00324     return error;
00325   }
00326 
00327 
00328   static FT_Bool
00329   pcf_has_table_type( PCF_Table  tables,
00330                       FT_ULong   ntables, /* same as PCF_Toc->count */
00331                       FT_ULong   type )
00332   {
00333     FT_ULong  i;
00334 
00335 
00336     for ( i = 0; i < ntables; i++ )
00337       if ( tables[i].type == type )
00338         return TRUE;
00339 
00340     return FALSE;
00341   }
00342 
00343 
00344 #define PCF_PROPERTY_SIZE  9
00345 
00346   static
00347   const FT_Frame_Field  pcf_property_header[] =
00348   {
00349 #undef  FT_STRUCTURE
00350 #define FT_STRUCTURE  PCF_ParsePropertyRec
00351 
00352     FT_FRAME_START( PCF_PROPERTY_SIZE ),
00353       FT_FRAME_LONG_LE( name ),
00354       FT_FRAME_BYTE   ( isString ),
00355       FT_FRAME_LONG_LE( value ),
00356     FT_FRAME_END
00357   };
00358 
00359 
00360   static
00361   const FT_Frame_Field  pcf_property_msb_header[] =
00362   {
00363 #undef  FT_STRUCTURE
00364 #define FT_STRUCTURE  PCF_ParsePropertyRec
00365 
00366     FT_FRAME_START( PCF_PROPERTY_SIZE ),
00367       FT_FRAME_LONG( name ),
00368       FT_FRAME_BYTE( isString ),
00369       FT_FRAME_LONG( value ),
00370     FT_FRAME_END
00371   };
00372 
00373 
00374   FT_LOCAL_DEF( PCF_Property )
00375   pcf_find_property( PCF_Face          face,
00376                      const FT_String*  prop )
00377   {
00378     PCF_Property  properties = face->properties;
00379     FT_Bool       found      = 0;
00380     int           i;
00381 
00382 
00383     for ( i = 0 ; i < face->nprops && !found; i++ )
00384     {
00385       if ( !ft_strcmp( properties[i].name, prop ) )
00386         found = 1;
00387     }
00388 
00389     if ( found )
00390       return properties + i - 1;
00391     else
00392       return NULL;
00393   }
00394 
00395 
00396   static FT_Error
00397   pcf_get_properties( FT_Stream  stream,
00398                       PCF_Face   face )
00399   {
00400     PCF_ParseProperty  props      = 0;
00401     PCF_Property       properties;
00402     FT_ULong           nprops, i;
00403     FT_ULong           format, size;
00404     FT_Error           error;
00405     FT_Memory          memory     = FT_FACE(face)->memory;
00406     FT_ULong           string_size;
00407     FT_String*         strings    = 0;
00408 
00409 
00410     error = pcf_seek_to_table_type( stream,
00411                                     face->toc.tables,
00412                                     face->toc.count,
00413                                     PCF_PROPERTIES,
00414                                     &format,
00415                                     &size );
00416     if ( error )
00417       goto Bail;
00418 
00419     if ( FT_READ_ULONG_LE( format ) )
00420       goto Bail;
00421 
00422     FT_TRACE4(( "pcf_get_properties:\n" ));
00423 
00424     FT_TRACE4(( "  format = %ld\n", format ));
00425 
00426     if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
00427       goto Bail;
00428 
00429     if ( PCF_BYTE_ORDER( format ) == MSBFirst )
00430       (void)FT_READ_ULONG( nprops );
00431     else
00432       (void)FT_READ_ULONG_LE( nprops );
00433     if ( error )
00434       goto Bail;
00435 
00436     FT_TRACE4(( "  nprop = %d (truncate %d props)\n",
00437                 (int)nprops, nprops - (int)nprops ));
00438 
00439     nprops = (int)nprops;
00440 
00441     /* rough estimate */
00442     if ( nprops > size / PCF_PROPERTY_SIZE )
00443     {
00444       error = PCF_Err_Invalid_Table;
00445       goto Bail;
00446     }
00447 
00448     face->nprops = (int)nprops;
00449 
00450     if ( FT_NEW_ARRAY( props, nprops ) )
00451       goto Bail;
00452 
00453     for ( i = 0; i < nprops; i++ )
00454     {
00455       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
00456       {
00457         if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
00458           goto Bail;
00459       }
00460       else
00461       {
00462         if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
00463           goto Bail;
00464       }
00465     }
00466 
00467     /* pad the property array                                            */
00468     /*                                                                   */
00469     /* clever here - nprops is the same as the number of odd-units read, */
00470     /* as only isStringProp are odd length   (Keith Packard)             */
00471     /*                                                                   */
00472     if ( nprops & 3 )
00473     {
00474       i = 4 - ( nprops & 3 );
00475       if ( FT_STREAM_SKIP( i ) )
00476       {
00477         error = PCF_Err_Invalid_Stream_Skip;
00478         goto Bail;
00479       }
00480     }
00481 
00482     if ( PCF_BYTE_ORDER( format ) == MSBFirst )
00483       (void)FT_READ_ULONG( string_size );
00484     else
00485       (void)FT_READ_ULONG_LE( string_size );
00486     if ( error )
00487       goto Bail;
00488 
00489     FT_TRACE4(( "  string_size = %ld\n", string_size ));
00490 
00491     /* rough estimate */
00492     if ( string_size > size - nprops * PCF_PROPERTY_SIZE )
00493     {
00494       error = PCF_Err_Invalid_Table;
00495       goto Bail;
00496     }
00497 
00498     if ( FT_NEW_ARRAY( strings, string_size ) )
00499       goto Bail;
00500 
00501     error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size );
00502     if ( error )
00503       goto Bail;
00504 
00505     if ( FT_NEW_ARRAY( properties, nprops ) )
00506       goto Bail;
00507 
00508     face->properties = properties;
00509 
00510     for ( i = 0; i < nprops; i++ )
00511     {
00512       FT_Long  name_offset = props[i].name;
00513 
00514 
00515       if ( ( name_offset < 0 )                     ||
00516            ( (FT_ULong)name_offset > string_size ) )
00517       {
00518         error = PCF_Err_Invalid_Offset;
00519         goto Bail;
00520       }
00521 
00522       if ( FT_STRDUP( properties[i].name, strings + name_offset ) )
00523         goto Bail;
00524 
00525       FT_TRACE4(( "  %s:", properties[i].name ));
00526 
00527       properties[i].isString = props[i].isString;
00528 
00529       if ( props[i].isString )
00530       {
00531         FT_Long  value_offset = props[i].value;
00532 
00533 
00534         if ( ( value_offset < 0 )                     ||
00535              ( (FT_ULong)value_offset > string_size ) )
00536         {
00537           error = PCF_Err_Invalid_Offset;
00538           goto Bail;
00539         }
00540 
00541         if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) )
00542           goto Bail;
00543 
00544         FT_TRACE4(( " `%s'\n", properties[i].value.atom ));
00545       }
00546       else
00547       {
00548         properties[i].value.l = props[i].value;
00549 
00550         FT_TRACE4(( " %d\n", properties[i].value.l ));
00551       }
00552     }
00553 
00554     error = PCF_Err_Ok;
00555 
00556   Bail:
00557     FT_FREE( props );
00558     FT_FREE( strings );
00559 
00560     return error;
00561   }
00562 
00563 
00564   static FT_Error
00565   pcf_get_metrics( FT_Stream  stream,
00566                    PCF_Face   face )
00567   {
00568     FT_Error    error    = PCF_Err_Ok;
00569     FT_Memory   memory   = FT_FACE(face)->memory;
00570     FT_ULong    format, size;
00571     PCF_Metric  metrics  = 0;
00572     FT_ULong    nmetrics, i;
00573 
00574 
00575     error = pcf_seek_to_table_type( stream,
00576                                     face->toc.tables,
00577                                     face->toc.count,
00578                                     PCF_METRICS,
00579                                     &format,
00580                                     &size );
00581     if ( error )
00582       return error;
00583 
00584     if ( FT_READ_ULONG_LE( format ) )
00585       goto Bail;
00586 
00587     if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )     &&
00588          !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
00589       return PCF_Err_Invalid_File_Format;
00590 
00591     if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
00592     {
00593       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
00594         (void)FT_READ_ULONG( nmetrics );
00595       else
00596         (void)FT_READ_ULONG_LE( nmetrics );
00597     }
00598     else
00599     {
00600       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
00601         (void)FT_READ_USHORT( nmetrics );
00602       else
00603         (void)FT_READ_USHORT_LE( nmetrics );
00604     }
00605     if ( error )
00606       return PCF_Err_Invalid_File_Format;
00607 
00608     face->nmetrics = nmetrics;
00609 
00610     FT_TRACE4(( "pcf_get_metrics:\n" ));
00611 
00612     FT_TRACE4(( "  number of metrics: %d\n", nmetrics ));
00613 
00614     /* rough estimate */
00615     if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
00616     {
00617       if ( nmetrics > size / PCF_METRIC_SIZE )
00618         return PCF_Err_Invalid_Table;
00619     }
00620     else
00621     {
00622       if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE )
00623         return PCF_Err_Invalid_Table;
00624     }
00625 
00626     if ( FT_NEW_ARRAY( face->metrics, nmetrics ) )
00627       return PCF_Err_Out_Of_Memory;
00628 
00629     metrics = face->metrics;
00630     for ( i = 0; i < nmetrics; i++ )
00631     {
00632       error = pcf_get_metric( stream, format, metrics + i );
00633 
00634       metrics[i].bits = 0;
00635 
00636       FT_TRACE5(( "  idx %d: width=%d, "
00637                   "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",
00638                   i,
00639                   ( metrics + i )->characterWidth,
00640                   ( metrics + i )->leftSideBearing,
00641                   ( metrics + i )->rightSideBearing,
00642                   ( metrics + i )->ascent,
00643                   ( metrics + i )->descent,
00644                   ( metrics + i )->attributes ));
00645 
00646       if ( error )
00647         break;
00648     }
00649 
00650     if ( error )
00651       FT_FREE( face->metrics );
00652 
00653   Bail:
00654     return error;
00655   }
00656 
00657 
00658   static FT_Error
00659   pcf_get_bitmaps( FT_Stream  stream,
00660                    PCF_Face   face )
00661   {
00662     FT_Error   error  = PCF_Err_Ok;
00663     FT_Memory  memory = FT_FACE(face)->memory;
00664     FT_Long*   offsets;
00665     FT_Long    bitmapSizes[GLYPHPADOPTIONS];
00666     FT_ULong   format, size;
00667     FT_ULong   nbitmaps, i, sizebitmaps = 0;
00668 
00669 
00670     error = pcf_seek_to_table_type( stream,
00671                                     face->toc.tables,
00672                                     face->toc.count,
00673                                     PCF_BITMAPS,
00674                                     &format,
00675                                     &size );
00676     if ( error )
00677       return error;
00678 
00679     error = FT_Stream_EnterFrame( stream, 8 );
00680     if ( error )
00681       return error;
00682 
00683     format = FT_GET_ULONG_LE();
00684     if ( PCF_BYTE_ORDER( format ) == MSBFirst )
00685       nbitmaps  = FT_GET_ULONG();
00686     else
00687       nbitmaps  = FT_GET_ULONG_LE();
00688 
00689     FT_Stream_ExitFrame( stream );
00690 
00691     if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
00692       return PCF_Err_Invalid_File_Format;
00693 
00694     FT_TRACE4(( "pcf_get_bitmaps:\n" ));
00695 
00696     FT_TRACE4(( "  number of bitmaps: %d\n", nbitmaps ));
00697 
00698     /* XXX: PCF_Face->nmetrics is singed FT_Long, see pcf.h */
00699     if ( face->nmetrics < 0 || nbitmaps != ( FT_ULong )face->nmetrics )
00700       return PCF_Err_Invalid_File_Format;
00701 
00702     if ( FT_NEW_ARRAY( offsets, nbitmaps ) )
00703       return error;
00704 
00705     for ( i = 0; i < nbitmaps; i++ )
00706     {
00707       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
00708         (void)FT_READ_LONG( offsets[i] );
00709       else
00710         (void)FT_READ_LONG_LE( offsets[i] );
00711 
00712       FT_TRACE5(( "  bitmap %d: offset %ld (0x%lX)\n",
00713                   i, offsets[i], offsets[i] ));
00714     }
00715     if ( error )
00716       goto Bail;
00717 
00718     for ( i = 0; i < GLYPHPADOPTIONS; i++ )
00719     {
00720       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
00721         (void)FT_READ_LONG( bitmapSizes[i] );
00722       else
00723         (void)FT_READ_LONG_LE( bitmapSizes[i] );
00724       if ( error )
00725         goto Bail;
00726 
00727       sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
00728 
00729       FT_TRACE4(( "  padding %d implies a size of %ld\n", i, bitmapSizes[i] ));
00730     }
00731 
00732     FT_TRACE4(( "  %d bitmaps, padding index %ld\n",
00733                 nbitmaps,
00734                 PCF_GLYPH_PAD_INDEX( format ) ));
00735     FT_TRACE4(( "  bitmap size = %d\n", sizebitmaps ));
00736 
00737     FT_UNUSED( sizebitmaps );       /* only used for debugging */
00738 
00739     for ( i = 0; i < nbitmaps; i++ )
00740     {
00741       /* rough estimate */
00742       if ( ( offsets[i] < 0 )              ||
00743            ( (FT_ULong)offsets[i] > size ) )
00744       {
00745         FT_TRACE0(( "pcf_get_bitmaps:"
00746                     " invalid offset to bitmap data of glyph %d\n", i ));
00747       }
00748       else
00749         face->metrics[i].bits = stream->pos + offsets[i];
00750     }
00751 
00752     face->bitmapsFormat = format;
00753 
00754   Bail:
00755     FT_FREE( offsets );
00756     return error;
00757   }
00758 
00759 
00760   static FT_Error
00761   pcf_get_encodings( FT_Stream  stream,
00762                      PCF_Face   face )
00763   {
00764     FT_Error      error  = PCF_Err_Ok;
00765     FT_Memory     memory = FT_FACE(face)->memory;
00766     FT_ULong      format, size;
00767     int           firstCol, lastCol;
00768     int           firstRow, lastRow;
00769     int           nencoding, encodingOffset;
00770     int           i, j;
00771     PCF_Encoding  tmpEncoding, encoding = 0;
00772 
00773 
00774     error = pcf_seek_to_table_type( stream,
00775                                     face->toc.tables,
00776                                     face->toc.count,
00777                                     PCF_BDF_ENCODINGS,
00778                                     &format,
00779                                     &size );
00780     if ( error )
00781       return error;
00782 
00783     error = FT_Stream_EnterFrame( stream, 14 );
00784     if ( error )
00785       return error;
00786 
00787     format = FT_GET_ULONG_LE();
00788 
00789     if ( PCF_BYTE_ORDER( format ) == MSBFirst )
00790     {
00791       firstCol          = FT_GET_SHORT();
00792       lastCol           = FT_GET_SHORT();
00793       firstRow          = FT_GET_SHORT();
00794       lastRow           = FT_GET_SHORT();
00795       face->defaultChar = FT_GET_SHORT();
00796     }
00797     else
00798     {
00799       firstCol          = FT_GET_SHORT_LE();
00800       lastCol           = FT_GET_SHORT_LE();
00801       firstRow          = FT_GET_SHORT_LE();
00802       lastRow           = FT_GET_SHORT_LE();
00803       face->defaultChar = FT_GET_SHORT_LE();
00804     }
00805 
00806     FT_Stream_ExitFrame( stream );
00807 
00808     if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
00809       return PCF_Err_Invalid_File_Format;
00810 
00811     FT_TRACE4(( "pdf_get_encodings:\n" ));
00812 
00813     FT_TRACE4(( "  firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",
00814                 firstCol, lastCol, firstRow, lastRow ));
00815 
00816     nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );
00817 
00818     if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) )
00819       return PCF_Err_Out_Of_Memory;
00820 
00821     error = FT_Stream_EnterFrame( stream, 2 * nencoding );
00822     if ( error )
00823       goto Bail;
00824 
00825     for ( i = 0, j = 0 ; i < nencoding; i++ )
00826     {
00827       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
00828         encodingOffset = FT_GET_SHORT();
00829       else
00830         encodingOffset = FT_GET_SHORT_LE();
00831 
00832       if ( encodingOffset != -1 )
00833       {
00834         tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) +
00835                                  firstRow ) * 256 ) +
00836                                ( ( i % ( lastCol - firstCol + 1 ) ) +
00837                                  firstCol );
00838 
00839         tmpEncoding[j].glyph = (FT_Short)encodingOffset;
00840 
00841         FT_TRACE5(( "  code %d (0x%04X): idx %d\n",
00842                     tmpEncoding[j].enc, tmpEncoding[j].enc,
00843                     tmpEncoding[j].glyph ));
00844 
00845         j++;
00846       }
00847     }
00848     FT_Stream_ExitFrame( stream );
00849 
00850     if ( FT_NEW_ARRAY( encoding, j ) )
00851       goto Bail;
00852 
00853     for ( i = 0; i < j; i++ )
00854     {
00855       encoding[i].enc   = tmpEncoding[i].enc;
00856       encoding[i].glyph = tmpEncoding[i].glyph;
00857     }
00858 
00859     face->nencodings = j;
00860     face->encodings  = encoding;
00861     FT_FREE( tmpEncoding );
00862 
00863     return error;
00864 
00865   Bail:
00866     FT_FREE( encoding );
00867     FT_FREE( tmpEncoding );
00868     return error;
00869   }
00870 
00871 
00872   static
00873   const FT_Frame_Field  pcf_accel_header[] =
00874   {
00875 #undef  FT_STRUCTURE
00876 #define FT_STRUCTURE  PCF_AccelRec
00877 
00878     FT_FRAME_START( 20 ),
00879       FT_FRAME_BYTE      ( noOverlap ),
00880       FT_FRAME_BYTE      ( constantMetrics ),
00881       FT_FRAME_BYTE      ( terminalFont ),
00882       FT_FRAME_BYTE      ( constantWidth ),
00883       FT_FRAME_BYTE      ( inkInside ),
00884       FT_FRAME_BYTE      ( inkMetrics ),
00885       FT_FRAME_BYTE      ( drawDirection ),
00886       FT_FRAME_SKIP_BYTES( 1 ),
00887       FT_FRAME_LONG_LE   ( fontAscent ),
00888       FT_FRAME_LONG_LE   ( fontDescent ),
00889       FT_FRAME_LONG_LE   ( maxOverlap ),
00890     FT_FRAME_END
00891   };
00892 
00893 
00894   static
00895   const FT_Frame_Field  pcf_accel_msb_header[] =
00896   {
00897 #undef  FT_STRUCTURE
00898 #define FT_STRUCTURE  PCF_AccelRec
00899 
00900     FT_FRAME_START( 20 ),
00901       FT_FRAME_BYTE      ( noOverlap ),
00902       FT_FRAME_BYTE      ( constantMetrics ),
00903       FT_FRAME_BYTE      ( terminalFont ),
00904       FT_FRAME_BYTE      ( constantWidth ),
00905       FT_FRAME_BYTE      ( inkInside ),
00906       FT_FRAME_BYTE      ( inkMetrics ),
00907       FT_FRAME_BYTE      ( drawDirection ),
00908       FT_FRAME_SKIP_BYTES( 1 ),
00909       FT_FRAME_LONG      ( fontAscent ),
00910       FT_FRAME_LONG      ( fontDescent ),
00911       FT_FRAME_LONG      ( maxOverlap ),
00912     FT_FRAME_END
00913   };
00914 
00915 
00916   static FT_Error
00917   pcf_get_accel( FT_Stream  stream,
00918                  PCF_Face   face,
00919                  FT_ULong   type )
00920   {
00921     FT_ULong   format, size;
00922     FT_Error   error = PCF_Err_Ok;
00923     PCF_Accel  accel = &face->accel;
00924 
00925 
00926     error = pcf_seek_to_table_type( stream,
00927                                     face->toc.tables,
00928                                     face->toc.count,
00929                                     type,
00930                                     &format,
00931                                     &size );
00932     if ( error )
00933       goto Bail;
00934 
00935     if ( FT_READ_ULONG_LE( format ) )
00936       goto Bail;
00937 
00938     if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )    &&
00939          !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
00940       goto Bail;
00941 
00942     if ( PCF_BYTE_ORDER( format ) == MSBFirst )
00943     {
00944       if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
00945         goto Bail;
00946     }
00947     else
00948     {
00949       if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
00950         goto Bail;
00951     }
00952 
00953     error = pcf_get_metric( stream,
00954                             format & ( ~PCF_FORMAT_MASK ),
00955                             &(accel->minbounds) );
00956     if ( error )
00957       goto Bail;
00958 
00959     error = pcf_get_metric( stream,
00960                             format & ( ~PCF_FORMAT_MASK ),
00961                             &(accel->maxbounds) );
00962     if ( error )
00963       goto Bail;
00964 
00965     if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
00966     {
00967       error = pcf_get_metric( stream,
00968                               format & ( ~PCF_FORMAT_MASK ),
00969                               &(accel->ink_minbounds) );
00970       if ( error )
00971         goto Bail;
00972 
00973       error = pcf_get_metric( stream,
00974                               format & ( ~PCF_FORMAT_MASK ),
00975                               &(accel->ink_maxbounds) );
00976       if ( error )
00977         goto Bail;
00978     }
00979     else
00980     {
00981       accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */
00982       accel->ink_maxbounds = accel->maxbounds;
00983     }
00984 
00985   Bail:
00986     return error;
00987   }
00988 
00989 
00990   static FT_Error
00991   pcf_interpret_style( PCF_Face  pcf )
00992   {
00993     FT_Error   error  = PCF_Err_Ok;
00994     FT_Face    face   = FT_FACE( pcf );
00995     FT_Memory  memory = face->memory;
00996 
00997     PCF_Property  prop;
00998 
00999     size_t  nn, len;
01000     char*   strings[4] = { NULL, NULL, NULL, NULL };
01001     size_t  lengths[4];
01002 
01003 
01004     face->style_flags = 0;
01005 
01006     prop = pcf_find_property( pcf, "SLANT" );
01007     if ( prop && prop->isString                                       &&
01008          ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||
01009            *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )
01010     {
01011       face->style_flags |= FT_STYLE_FLAG_ITALIC;
01012       strings[2] = ( *(prop->value.atom) == 'O' ||
01013                      *(prop->value.atom) == 'o' ) ? (char *)"Oblique"
01014                                                   : (char *)"Italic";
01015     }
01016 
01017     prop = pcf_find_property( pcf, "WEIGHT_NAME" );
01018     if ( prop && prop->isString                                       &&
01019          ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
01020     {
01021       face->style_flags |= FT_STYLE_FLAG_BOLD;
01022       strings[1] = (char *)"Bold";
01023     }
01024 
01025     prop = pcf_find_property( pcf, "SETWIDTH_NAME" );
01026     if ( prop && prop->isString                                        &&
01027          *(prop->value.atom)                                           &&
01028          !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
01029       strings[3] = (char *)(prop->value.atom);
01030 
01031     prop = pcf_find_property( pcf, "ADD_STYLE_NAME" );
01032     if ( prop && prop->isString                                        &&
01033          *(prop->value.atom)                                           &&
01034          !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
01035       strings[0] = (char *)(prop->value.atom);
01036 
01037     for ( len = 0, nn = 0; nn < 4; nn++ )
01038     {
01039       lengths[nn] = 0;
01040       if ( strings[nn] )
01041       {
01042         lengths[nn] = ft_strlen( strings[nn] );
01043         len        += lengths[nn] + 1;
01044       }
01045     }
01046 
01047     if ( len == 0 )
01048     {
01049       strings[0] = (char *)"Regular";
01050       lengths[0] = ft_strlen( strings[0] );
01051       len        = lengths[0] + 1;
01052     }
01053 
01054     {
01055       char*  s;
01056 
01057 
01058       if ( FT_ALLOC( face->style_name, len ) )
01059         return error;
01060 
01061       s = face->style_name;
01062 
01063       for ( nn = 0; nn < 4; nn++ )
01064       {
01065         char*  src = strings[nn];
01066 
01067 
01068         len = lengths[nn];
01069 
01070         if ( src == NULL )
01071           continue;
01072 
01073         /* separate elements with a space */
01074         if ( s != face->style_name )
01075           *s++ = ' ';
01076 
01077         ft_memcpy( s, src, len );
01078 
01079         /* need to convert spaces to dashes for */
01080         /* add_style_name and setwidth_name     */
01081         if ( nn == 0 || nn == 3 )
01082         {
01083           size_t  mm;
01084 
01085 
01086           for ( mm = 0; mm < len; mm++ )
01087             if (s[mm] == ' ')
01088               s[mm] = '-';
01089         }
01090 
01091         s += len;
01092       }
01093       *s = 0;
01094     }
01095 
01096     return error;
01097   }
01098 
01099 
01100   FT_LOCAL_DEF( FT_Error )
01101   pcf_load_font( FT_Stream  stream,
01102                  PCF_Face   face )
01103   {
01104     FT_Error   error  = PCF_Err_Ok;
01105     FT_Memory  memory = FT_FACE(face)->memory;
01106     FT_Bool    hasBDFAccelerators;
01107 
01108 
01109     error = pcf_read_TOC( stream, face );
01110     if ( error )
01111       goto Exit;
01112 
01113     error = pcf_get_properties( stream, face );
01114     if ( error )
01115       goto Exit;
01116 
01117     /* Use the old accelerators if no BDF accelerators are in the file. */
01118     hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
01119                                              face->toc.count,
01120                                              PCF_BDF_ACCELERATORS );
01121     if ( !hasBDFAccelerators )
01122     {
01123       error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
01124       if ( error )
01125         goto Exit;
01126     }
01127 
01128     /* metrics */
01129     error = pcf_get_metrics( stream, face );
01130     if ( error )
01131       goto Exit;
01132 
01133     /* bitmaps */
01134     error = pcf_get_bitmaps( stream, face );
01135     if ( error )
01136       goto Exit;
01137 
01138     /* encodings */
01139     error = pcf_get_encodings( stream, face );
01140     if ( error )
01141       goto Exit;
01142 
01143     /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
01144     if ( hasBDFAccelerators )
01145     {
01146       error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
01147       if ( error )
01148         goto Exit;
01149     }
01150 
01151     /* XXX: TO DO: inkmetrics and glyph_names are missing */
01152 
01153     /* now construct the face object */
01154     {
01155       FT_Face       root = FT_FACE( face );
01156       PCF_Property  prop;
01157 
01158 
01159       root->num_faces  = 1;
01160       root->face_index = 0;
01161       root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
01162                          FT_FACE_FLAG_HORIZONTAL  |
01163                          FT_FACE_FLAG_FAST_GLYPHS;
01164 
01165       if ( face->accel.constantWidth )
01166         root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
01167 
01168       if ( ( error = pcf_interpret_style( face ) ) != 0 )
01169          goto Exit;
01170 
01171       prop = pcf_find_property( face, "FAMILY_NAME" );
01172       if ( prop && prop->isString )
01173       {
01174         if ( FT_STRDUP( root->family_name, prop->value.atom ) )
01175           goto Exit;
01176       }
01177       else
01178         root->family_name = NULL;
01179 
01180       /*
01181        * Note: We shift all glyph indices by +1 since we must
01182        * respect the convention that glyph 0 always corresponds
01183        * to the `missing glyph'.
01184        *
01185        * This implies bumping the number of `available' glyphs by 1.
01186        */
01187       root->num_glyphs = face->nmetrics + 1;
01188 
01189       root->num_fixed_sizes = 1;
01190       if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
01191         goto Exit;
01192 
01193       {
01194         FT_Bitmap_Size*  bsize = root->available_sizes;
01195         FT_Short         resolution_x = 0, resolution_y = 0;
01196 
01197 
01198         FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) );
01199 
01200 #if 0
01201         bsize->height = face->accel.maxbounds.ascent << 6;
01202 #endif
01203         bsize->height = (FT_Short)( face->accel.fontAscent +
01204                                     face->accel.fontDescent );
01205 
01206         prop = pcf_find_property( face, "AVERAGE_WIDTH" );
01207         if ( prop )
01208           bsize->width = (FT_Short)( ( prop->value.l + 5 ) / 10 );
01209         else
01210           bsize->width = (FT_Short)( bsize->height * 2/3 );
01211 
01212         prop = pcf_find_property( face, "POINT_SIZE" );
01213         if ( prop )
01214           /* convert from 722.7 decipoints to 72 points per inch */
01215           bsize->size =
01216             (FT_Pos)( ( prop->value.l * 64 * 7200 + 36135L ) / 72270L );
01217 
01218         prop = pcf_find_property( face, "PIXEL_SIZE" );
01219         if ( prop )
01220           bsize->y_ppem = (FT_Short)prop->value.l << 6;
01221 
01222         prop = pcf_find_property( face, "RESOLUTION_X" );
01223         if ( prop )
01224           resolution_x = (FT_Short)prop->value.l;
01225 
01226         prop = pcf_find_property( face, "RESOLUTION_Y" );
01227         if ( prop )
01228           resolution_y = (FT_Short)prop->value.l;
01229 
01230         if ( bsize->y_ppem == 0 )
01231         {
01232           bsize->y_ppem = bsize->size;
01233           if ( resolution_y )
01234             bsize->y_ppem = bsize->y_ppem * resolution_y / 72;
01235         }
01236         if ( resolution_x && resolution_y )
01237           bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y;
01238         else
01239           bsize->x_ppem = bsize->y_ppem;
01240       }
01241 
01242       /* set up charset */
01243       {
01244         PCF_Property  charset_registry = 0, charset_encoding = 0;
01245 
01246 
01247         charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
01248         charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
01249 
01250         if ( charset_registry && charset_registry->isString &&
01251              charset_encoding && charset_encoding->isString )
01252         {
01253           if ( FT_STRDUP( face->charset_encoding,
01254                           charset_encoding->value.atom ) ||
01255                FT_STRDUP( face->charset_registry,
01256                           charset_registry->value.atom ) )
01257             goto Exit;
01258         }
01259       }
01260     }
01261 
01262   Exit:
01263     if ( error )
01264     {
01265       /* This is done to respect the behaviour of the original */
01266       /* PCF font driver.                                      */
01267       error = PCF_Err_Invalid_File_Format;
01268     }
01269 
01270     return error;
01271   }
01272 
01273 
01274 /* END */

Generated on Tue Jul 5 14:13:48 2011 for ROOT_528-00b_version by  doxygen 1.5.1