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