xref: /aosp_15_r20/external/freetype/src/pcf/pcfread.c (revision 63949dbd25bcc50c4e1178497ff9e9574d44fc5a)
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_QNEW_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 == 1UL << 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     FT_TRACE4(( "  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_QNEW_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_QALLOC( strings, string_size + 1 )  ||
611          FT_STREAM_READ( strings, string_size ) )
612       goto Bail;
613 
614     strings[string_size] = '\0';
615 
616     /* zero out in case of failure */
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     FT_TRACE4(( "  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_QNEW_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     FT_TRACE4(( "  format: 0x%lX\n", format ));
845     FT_TRACE4(( "          (%s, %s,\n",
846                 PCF_BYTE_ORDER( format ) == MSBFirst
847                   ? "most significant byte first"
848                   : "least significant byte first",
849                 PCF_BIT_ORDER( format ) == MSBFirst
850                   ? "most significant bit first"
851                   : "least significant bit first" ));
852     FT_TRACE4(( "           padding=%d bit%s, scanning=%d bit%s)\n",
853                 8 << PCF_GLYPH_PAD_INDEX( format ),
854                 ( 8 << PCF_GLYPH_PAD_INDEX( format ) ) == 1 ? "" : "s",
855                 8 << PCF_SCAN_UNIT_INDEX( format ),
856                 ( 8 << PCF_SCAN_UNIT_INDEX( format ) ) == 1 ? "" : "s" ));
857 
858     if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
859       return FT_THROW( Invalid_File_Format );
860 
861     FT_TRACE4(( "  number of bitmaps: %ld\n", orig_nbitmaps ));
862 
863     /* see comment in `pcf_get_metrics' */
864     if ( orig_nbitmaps > 65534 )
865     {
866       FT_TRACE0(( "pcf_get_bitmaps:"
867                   " only loading first 65534 bitmaps\n" ));
868       nbitmaps = 65534;
869     }
870     else
871       nbitmaps = orig_nbitmaps;
872 
873     /* no extra bitmap for glyph 0 */
874     if ( nbitmaps != face->nmetrics - 1 )
875       return FT_THROW( Invalid_File_Format );
876 
877     /* start position of bitmap data */
878     pos = stream->pos + nbitmaps * 4 + 4 * 4;
879 
880     FT_TRACE5(( "\n" ));
881     for ( i = 1; i <= nbitmaps; i++ )
882     {
883       FT_ULong  offset;
884 
885 
886       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
887         (void)FT_READ_ULONG( offset );
888       else
889         (void)FT_READ_ULONG_LE( offset );
890 
891       FT_TRACE5(( "  bitmap %lu: offset %lu (0x%lX)\n",
892                   i, offset, offset ));
893 
894       /* right now, we only check the offset with a rough estimate; */
895       /* actual bitmaps are only loaded on demand                   */
896       if ( offset > size )
897       {
898         FT_TRACE0(( "pcf_get_bitmaps:"
899                     " invalid offset to bitmap data of glyph %lu\n", i ));
900         face->metrics[i].bits = pos;
901       }
902       else
903         face->metrics[i].bits = pos + offset;
904     }
905     if ( error )
906       goto Bail;
907 
908     for ( i = 0; i < GLYPHPADOPTIONS; i++ )
909     {
910       if ( PCF_BYTE_ORDER( format ) == MSBFirst )
911         (void)FT_READ_ULONG( bitmapSizes[i] );
912       else
913         (void)FT_READ_ULONG_LE( bitmapSizes[i] );
914       if ( error )
915         goto Bail;
916 
917       sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
918 
919       FT_TRACE4(( "  %d-bit padding implies a size of %lu\n",
920                   8 << i, bitmapSizes[i] ));
921     }
922 
923     FT_TRACE4(( "  %lu bitmaps, using %d-bit padding\n",
924                 nbitmaps,
925                 8 << PCF_GLYPH_PAD_INDEX( format ) ));
926     FT_TRACE4(( "  bitmap size: %lu\n", sizebitmaps ));
927 
928     FT_UNUSED( sizebitmaps );       /* only used for debugging */
929 
930     face->bitmapsFormat = format;
931 
932   Bail:
933     return error;
934   }
935 
936 
937   /*
938    * This file uses X11 terminology for PCF data; an `encoding' in X11 speak
939    * is the same as a character code in FreeType speak.
940    */
941 #define PCF_ENC_SIZE  10
942 
943   static
944   const FT_Frame_Field  pcf_enc_header[] =
945   {
946 #undef  FT_STRUCTURE
947 #define FT_STRUCTURE  PCF_EncRec
948 
949     FT_FRAME_START( PCF_ENC_SIZE ),
950       FT_FRAME_USHORT_LE( firstCol ),
951       FT_FRAME_USHORT_LE( lastCol ),
952       FT_FRAME_USHORT_LE( firstRow ),
953       FT_FRAME_USHORT_LE( lastRow ),
954       FT_FRAME_USHORT_LE( defaultChar ),
955     FT_FRAME_END
956   };
957 
958 
959   static
960   const FT_Frame_Field  pcf_enc_msb_header[] =
961   {
962 #undef  FT_STRUCTURE
963 #define FT_STRUCTURE  PCF_EncRec
964 
965     FT_FRAME_START( PCF_ENC_SIZE ),
966       FT_FRAME_USHORT( firstCol ),
967       FT_FRAME_USHORT( lastCol ),
968       FT_FRAME_USHORT( firstRow ),
969       FT_FRAME_USHORT( lastRow ),
970       FT_FRAME_USHORT( defaultChar ),
971     FT_FRAME_END
972   };
973 
974 
975   static FT_Error
pcf_get_encodings(FT_Stream stream,PCF_Face face)976   pcf_get_encodings( FT_Stream  stream,
977                      PCF_Face   face )
978   {
979     FT_Error    error;
980     FT_Memory   memory = FT_FACE( face )->memory;
981     FT_ULong    format, size;
982     PCF_Enc     enc = &face->enc;
983     FT_ULong    nencoding;
984     FT_UShort*  offset;
985     FT_UShort   defaultCharRow, defaultCharCol;
986     FT_UShort   encodingOffset, defaultCharEncodingOffset;
987     FT_UShort   i, j;
988     FT_Byte*    pos;
989 
990 
991     error = pcf_seek_to_table_type( stream,
992                                     face->toc.tables,
993                                     face->toc.count,
994                                     PCF_BDF_ENCODINGS,
995                                     &format,
996                                     &size );
997     if ( error )
998       goto Bail;
999 
1000     if ( FT_READ_ULONG_LE( format ) )
1001       goto Bail;
1002 
1003     FT_TRACE4(( "pcf_get_encodings:\n" ));
1004     FT_TRACE4(( "  format: 0x%lX (%s)\n",
1005                 format,
1006                 PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB" ));
1007 
1008     if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
1009          !PCF_FORMAT_MATCH( format, PCF_BDF_ENCODINGS )  )
1010       return FT_THROW( Invalid_File_Format );
1011 
1012     if ( PCF_BYTE_ORDER( format ) == MSBFirst )
1013     {
1014       if ( FT_STREAM_READ_FIELDS( pcf_enc_msb_header, enc ) )
1015         goto Bail;
1016     }
1017     else
1018     {
1019       if ( FT_STREAM_READ_FIELDS( pcf_enc_header, enc ) )
1020         goto Bail;
1021     }
1022 
1023     FT_TRACE4(( "  firstCol 0x%X, lastCol 0x%X\n",
1024                 enc->firstCol, enc->lastCol ));
1025     FT_TRACE4(( "  firstRow 0x%X, lastRow 0x%X\n",
1026                 enc->firstRow, enc->lastRow ));
1027     FT_TRACE4(( "  defaultChar 0x%X\n",
1028                 enc->defaultChar ));
1029 
1030     /* sanity checks; we limit numbers of rows and columns to 256 */
1031     if ( enc->firstCol > enc->lastCol ||
1032          enc->lastCol  > 0xFF         ||
1033          enc->firstRow > enc->lastRow ||
1034          enc->lastRow  > 0xFF         )
1035       return FT_THROW( Invalid_Table );
1036 
1037     FT_TRACE5(( "\n" ));
1038 
1039     defaultCharRow = enc->defaultChar >> 8;
1040     defaultCharCol = enc->defaultChar & 0xFF;
1041 
1042     /* validate default character */
1043     if ( defaultCharRow < enc->firstRow ||
1044          defaultCharRow > enc->lastRow  ||
1045          defaultCharCol < enc->firstCol ||
1046          defaultCharCol > enc->lastCol  )
1047     {
1048       enc->defaultChar = enc->firstRow * 256U + enc->firstCol;
1049       FT_TRACE0(( "pcf_get_encodings:"
1050                   " Invalid default character set to %u\n",
1051                   enc->defaultChar ));
1052 
1053       defaultCharRow = enc->firstRow;
1054       defaultCharCol = enc->firstCol;
1055     }
1056 
1057     nencoding = (FT_ULong)( enc->lastCol - enc->firstCol + 1 ) *
1058                 (FT_ULong)( enc->lastRow - enc->firstRow + 1 );
1059 
1060     error = FT_Stream_EnterFrame( stream, 2 * nencoding );
1061     if ( error )
1062       goto Bail;
1063 
1064     /*
1065      * FreeType mandates that glyph index 0 is the `undefined glyph', which
1066      * PCF calls the `default character'.  However, FreeType needs glyph
1067      * index 0 to be used for the undefined glyph only, which is is not the
1068      * case for PCF.  For this reason, we add one slot for glyph index 0 and
1069      * simply copy the default character to it.
1070      *
1071      * `stream->cursor' still points to the beginning of the frame; we can
1072      * thus easily get the offset to the default character.
1073      */
1074     pos = stream->cursor +
1075             2 * ( ( defaultCharRow - enc->firstRow ) *
1076                     ( enc->lastCol - enc->firstCol + 1 ) +
1077                   defaultCharCol - enc->firstCol );
1078 
1079     if ( PCF_BYTE_ORDER( format ) == MSBFirst )
1080       defaultCharEncodingOffset = FT_PEEK_USHORT( pos );
1081     else
1082       defaultCharEncodingOffset = FT_PEEK_USHORT_LE( pos );
1083 
1084     if ( defaultCharEncodingOffset == 0xFFFF )
1085     {
1086       FT_TRACE0(( "pcf_get_encodings:"
1087                   " No glyph for default character,\n" ));
1088       FT_TRACE0(( "                  "
1089                   " setting it to the first glyph of the font\n" ));
1090       defaultCharEncodingOffset = 1;
1091     }
1092     else
1093     {
1094       defaultCharEncodingOffset++;
1095 
1096       if ( defaultCharEncodingOffset >= face->nmetrics )
1097       {
1098         FT_TRACE0(( "pcf_get_encodings:"
1099                     " Invalid glyph index for default character,\n" ));
1100         FT_TRACE0(( "                  "
1101                     " setting it to the first glyph of the font\n" ));
1102         defaultCharEncodingOffset = 1;
1103       }
1104     }
1105 
1106     /* copy metrics of default character to index 0 */
1107     face->metrics[0] = face->metrics[defaultCharEncodingOffset];
1108 
1109     if ( FT_QNEW_ARRAY( enc->offset, nencoding ) )
1110       goto Bail;
1111 
1112     /* now loop over all values */
1113     offset = enc->offset;
1114     for ( i = enc->firstRow; i <= enc->lastRow; i++ )
1115     {
1116       for ( j = enc->firstCol; j <= enc->lastCol; j++ )
1117       {
1118         /* X11's reference implementation uses the equivalent to  */
1119         /* `FT_GET_SHORT', however PCF fonts with more than 32768 */
1120         /* characters (e.g., `unifont.pcf') clearly show that an  */
1121         /* unsigned value is needed.                              */
1122         if ( PCF_BYTE_ORDER( format ) == MSBFirst )
1123           encodingOffset = FT_GET_USHORT();
1124         else
1125           encodingOffset = FT_GET_USHORT_LE();
1126 
1127         /* everything is off by 1 due to the artificial glyph 0 */
1128         *offset++ = encodingOffset == 0xFFFF ? 0xFFFF
1129                                              : encodingOffset + 1;
1130       }
1131     }
1132     FT_Stream_ExitFrame( stream );
1133 
1134   Bail:
1135     return error;
1136   }
1137 
1138 
1139   static
1140   const FT_Frame_Field  pcf_accel_header[] =
1141   {
1142 #undef  FT_STRUCTURE
1143 #define FT_STRUCTURE  PCF_AccelRec
1144 
1145     FT_FRAME_START( 20 ),
1146       FT_FRAME_BYTE      ( noOverlap ),
1147       FT_FRAME_BYTE      ( constantMetrics ),
1148       FT_FRAME_BYTE      ( terminalFont ),
1149       FT_FRAME_BYTE      ( constantWidth ),
1150       FT_FRAME_BYTE      ( inkInside ),
1151       FT_FRAME_BYTE      ( inkMetrics ),
1152       FT_FRAME_BYTE      ( drawDirection ),
1153       FT_FRAME_SKIP_BYTES( 1 ),
1154       FT_FRAME_LONG_LE   ( fontAscent ),
1155       FT_FRAME_LONG_LE   ( fontDescent ),
1156       FT_FRAME_LONG_LE   ( maxOverlap ),
1157     FT_FRAME_END
1158   };
1159 
1160 
1161   static
1162   const FT_Frame_Field  pcf_accel_msb_header[] =
1163   {
1164 #undef  FT_STRUCTURE
1165 #define FT_STRUCTURE  PCF_AccelRec
1166 
1167     FT_FRAME_START( 20 ),
1168       FT_FRAME_BYTE      ( noOverlap ),
1169       FT_FRAME_BYTE      ( constantMetrics ),
1170       FT_FRAME_BYTE      ( terminalFont ),
1171       FT_FRAME_BYTE      ( constantWidth ),
1172       FT_FRAME_BYTE      ( inkInside ),
1173       FT_FRAME_BYTE      ( inkMetrics ),
1174       FT_FRAME_BYTE      ( drawDirection ),
1175       FT_FRAME_SKIP_BYTES( 1 ),
1176       FT_FRAME_LONG      ( fontAscent ),
1177       FT_FRAME_LONG      ( fontDescent ),
1178       FT_FRAME_LONG      ( maxOverlap ),
1179     FT_FRAME_END
1180   };
1181 
1182 
1183   static FT_Error
pcf_get_accel(FT_Stream stream,PCF_Face face,FT_ULong type)1184   pcf_get_accel( FT_Stream  stream,
1185                  PCF_Face   face,
1186                  FT_ULong   type )
1187   {
1188     FT_ULong   format, size;
1189     FT_Error   error;
1190     PCF_Accel  accel = &face->accel;
1191 
1192 
1193     error = pcf_seek_to_table_type( stream,
1194                                     face->toc.tables,
1195                                     face->toc.count,
1196                                     type,
1197                                     &format,
1198                                     &size );
1199     if ( error )
1200       goto Bail;
1201 
1202     if ( FT_READ_ULONG_LE( format ) )
1203       goto Bail;
1204 
1205     FT_TRACE4(( "pcf_get_accel%s:\n",
1206                 type == PCF_BDF_ACCELERATORS ? " (getting BDF accelerators)"
1207                                              : "" ));
1208     FT_TRACE4(( "  format: 0x%lX (%s, %s)\n",
1209                 format,
1210                 PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB",
1211                 PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ?
1212                   "accelerated" : "not accelerated" ));
1213 
1214     if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )    &&
1215          !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
1216       goto Bail;
1217 
1218     if ( PCF_BYTE_ORDER( format ) == MSBFirst )
1219     {
1220       if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
1221         goto Bail;
1222     }
1223     else
1224     {
1225       if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
1226         goto Bail;
1227     }
1228 
1229     FT_TRACE5(( "  noOverlap=%s, constantMetrics=%s,"
1230                 " terminalFont=%s, constantWidth=%s\n",
1231                 accel->noOverlap ? "yes" : "no",
1232                 accel->constantMetrics ? "yes" : "no",
1233                 accel->terminalFont ? "yes" : "no",
1234                 accel->constantWidth ? "yes" : "no" ));
1235     FT_TRACE5(( "  inkInside=%s, inkMetrics=%s, drawDirection=%s\n",
1236                 accel->inkInside ? "yes" : "no",
1237                 accel->inkMetrics ? "yes" : "no",
1238                 accel->drawDirection ? "RTL" : "LTR" ));
1239     FT_TRACE5(( "  fontAscent=%ld, fontDescent=%ld, maxOverlap=%ld\n",
1240                 accel->fontAscent,
1241                 accel->fontDescent,
1242                 accel->maxOverlap ));
1243 
1244     /* sanity checks */
1245     if ( FT_ABS( accel->fontAscent ) > 0x7FFF )
1246     {
1247       accel->fontAscent = accel->fontAscent < 0 ? -0x7FFF : 0x7FFF;
1248       FT_TRACE0(( "pfc_get_accel: clamping font ascent to value %ld\n",
1249                   accel->fontAscent ));
1250     }
1251     if ( FT_ABS( accel->fontDescent ) > 0x7FFF )
1252     {
1253       accel->fontDescent = accel->fontDescent < 0 ? -0x7FFF : 0x7FFF;
1254       FT_TRACE0(( "pfc_get_accel: clamping font descent to value %ld\n",
1255                   accel->fontDescent ));
1256     }
1257 
1258     FT_TRACE5(( "  minbounds:" ));
1259     error = pcf_get_metric( stream,
1260                             format & ( ~PCF_FORMAT_MASK ),
1261                             &(accel->minbounds) );
1262     if ( error )
1263       goto Bail;
1264 
1265     FT_TRACE5(( "  maxbounds:" ));
1266     error = pcf_get_metric( stream,
1267                             format & ( ~PCF_FORMAT_MASK ),
1268                             &(accel->maxbounds) );
1269     if ( error )
1270       goto Bail;
1271 
1272     if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
1273     {
1274       FT_TRACE5(( "  ink minbounds:" ));
1275       error = pcf_get_metric( stream,
1276                               format & ( ~PCF_FORMAT_MASK ),
1277                               &(accel->ink_minbounds) );
1278       if ( error )
1279         goto Bail;
1280 
1281       FT_TRACE5(( "  ink maxbounds:" ));
1282       error = pcf_get_metric( stream,
1283                               format & ( ~PCF_FORMAT_MASK ),
1284                               &(accel->ink_maxbounds) );
1285       if ( error )
1286         goto Bail;
1287     }
1288     else
1289     {
1290       accel->ink_minbounds = accel->minbounds;
1291       accel->ink_maxbounds = accel->maxbounds;
1292     }
1293 
1294   Bail:
1295     return error;
1296   }
1297 
1298 
1299   static FT_Error
pcf_interpret_style(PCF_Face pcf)1300   pcf_interpret_style( PCF_Face  pcf )
1301   {
1302     FT_Error   error  = FT_Err_Ok;
1303     FT_Face    face   = FT_FACE( pcf );
1304     FT_Memory  memory = face->memory;
1305 
1306     PCF_Property  prop;
1307 
1308     const char*  strings[4] = { NULL, NULL, NULL, NULL };
1309     size_t       lengths[4], nn, len;
1310 
1311 
1312     face->style_flags = 0;
1313 
1314     prop = pcf_find_property( pcf, "SLANT" );
1315     if ( prop && prop->isString                                       &&
1316          ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ||
1317            *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) )
1318     {
1319       face->style_flags |= FT_STYLE_FLAG_ITALIC;
1320       strings[2] = ( *(prop->value.atom) == 'O' ||
1321                      *(prop->value.atom) == 'o' ) ? "Oblique"
1322                                                   : "Italic";
1323     }
1324 
1325     prop = pcf_find_property( pcf, "WEIGHT_NAME" );
1326     if ( prop && prop->isString                                       &&
1327          ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) )
1328     {
1329       face->style_flags |= FT_STYLE_FLAG_BOLD;
1330       strings[1] = "Bold";
1331     }
1332 
1333     prop = pcf_find_property( pcf, "SETWIDTH_NAME" );
1334     if ( prop && prop->isString                                        &&
1335          *(prop->value.atom)                                           &&
1336          !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1337       strings[3] = (const char*)( prop->value.atom );
1338 
1339     prop = pcf_find_property( pcf, "ADD_STYLE_NAME" );
1340     if ( prop && prop->isString                                        &&
1341          *(prop->value.atom)                                           &&
1342          !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) )
1343       strings[0] = (const char*)( prop->value.atom );
1344 
1345     for ( len = 0, nn = 0; nn < 4; nn++ )
1346     {
1347       lengths[nn] = 0;
1348       if ( strings[nn] )
1349       {
1350         lengths[nn] = ft_strlen( strings[nn] );
1351         len        += lengths[nn] + 1;
1352       }
1353     }
1354 
1355     if ( len == 0 )
1356     {
1357       strings[0] = "Regular";
1358       lengths[0] = ft_strlen( strings[0] );
1359       len        = lengths[0] + 1;
1360     }
1361 
1362     {
1363       char*  s;
1364 
1365 
1366       if ( FT_QALLOC( face->style_name, len ) )
1367         return error;
1368 
1369       s = face->style_name;
1370 
1371       for ( nn = 0; nn < 4; nn++ )
1372       {
1373         const char*  src = strings[nn];
1374 
1375 
1376         len = lengths[nn];
1377 
1378         if ( !src )
1379           continue;
1380 
1381         /* separate elements with a space */
1382         if ( s != face->style_name )
1383           *s++ = ' ';
1384 
1385         ft_memcpy( s, src, len );
1386 
1387         /* need to convert spaces to dashes for */
1388         /* add_style_name and setwidth_name     */
1389         if ( nn == 0 || nn == 3 )
1390         {
1391           size_t  mm;
1392 
1393 
1394           for ( mm = 0; mm < len; mm++ )
1395             if ( s[mm] == ' ' )
1396               s[mm] = '-';
1397         }
1398 
1399         s += len;
1400       }
1401       *s = 0;
1402     }
1403 
1404     return error;
1405   }
1406 
1407 
1408   FT_LOCAL_DEF( FT_Error )
pcf_load_font(FT_Stream stream,PCF_Face face,FT_Long face_index)1409   pcf_load_font( FT_Stream  stream,
1410                  PCF_Face   face,
1411                  FT_Long    face_index )
1412   {
1413     FT_Face    root   = FT_FACE( face );
1414     FT_Error   error;
1415     FT_Memory  memory = FT_FACE( face )->memory;
1416     FT_Bool    hasBDFAccelerators;
1417 
1418 
1419     error = pcf_read_TOC( stream, face );
1420     if ( error )
1421       goto Exit;
1422 
1423     root->num_faces  = 1;
1424     root->face_index = 0;
1425 
1426     /* If we are performing a simple font format check, exit immediately. */
1427     if ( face_index < 0 )
1428       return FT_Err_Ok;
1429 
1430     error = pcf_get_properties( stream, face );
1431     if ( error )
1432       goto Exit;
1433 
1434     /* Use the old accelerators if no BDF accelerators are in the file. */
1435     hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
1436                                              face->toc.count,
1437                                              PCF_BDF_ACCELERATORS );
1438     if ( !hasBDFAccelerators )
1439     {
1440       error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
1441       if ( error )
1442         goto Exit;
1443     }
1444 
1445     /* metrics */
1446     error = pcf_get_metrics( stream, face );
1447     if ( error )
1448       goto Exit;
1449 
1450     /* bitmaps */
1451     error = pcf_get_bitmaps( stream, face );
1452     if ( error )
1453       goto Exit;
1454 
1455     /* encodings */
1456     error = pcf_get_encodings( stream, face );
1457     if ( error )
1458       goto Exit;
1459 
1460     /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
1461     if ( hasBDFAccelerators )
1462     {
1463       error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
1464       if ( error )
1465         goto Exit;
1466     }
1467 
1468     /* XXX: TO DO: inkmetrics and glyph_names are missing */
1469 
1470     /* now construct the face object */
1471     {
1472       PCF_Property  prop;
1473 
1474 
1475       root->face_flags |= FT_FACE_FLAG_FIXED_SIZES |
1476                           FT_FACE_FLAG_HORIZONTAL;
1477 
1478       if ( face->accel.constantWidth )
1479         root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
1480 
1481       if ( FT_SET_ERROR( pcf_interpret_style( face ) ) )
1482         goto Exit;
1483 
1484       prop = pcf_find_property( face, "FAMILY_NAME" );
1485       if ( prop && prop->isString )
1486       {
1487 
1488 #ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
1489 
1490         PCF_Driver  driver = (PCF_Driver)FT_FACE_DRIVER( face );
1491 
1492 
1493         if ( !driver->no_long_family_names )
1494         {
1495           /* Prepend the foundry name plus a space to the family name.     */
1496           /* There are many fonts just called `Fixed' which look           */
1497           /* completely different, and which have nothing to do with each  */
1498           /* other.  When selecting `Fixed' in KDE or Gnome one gets       */
1499           /* results that appear rather random, the style changes often if */
1500           /* one changes the size and one cannot select some fonts at all. */
1501           /*                                                               */
1502           /* We also check whether we have `wide' characters; all put      */
1503           /* together, we get family names like `Sony Fixed' or `Misc      */
1504           /* Fixed Wide'.                                                  */
1505 
1506           PCF_Property  foundry_prop, point_size_prop, average_width_prop;
1507 
1508           int  l    = ft_strlen( prop->value.atom ) + 1;
1509           int  wide = 0;
1510 
1511 
1512           foundry_prop       = pcf_find_property( face, "FOUNDRY" );
1513           point_size_prop    = pcf_find_property( face, "POINT_SIZE" );
1514           average_width_prop = pcf_find_property( face, "AVERAGE_WIDTH" );
1515 
1516           if ( point_size_prop && average_width_prop )
1517           {
1518             if ( average_width_prop->value.l >= point_size_prop->value.l )
1519             {
1520               /* This font is at least square shaped or even wider */
1521               wide = 1;
1522               l   += ft_strlen( " Wide" );
1523             }
1524           }
1525 
1526           if ( foundry_prop && foundry_prop->isString )
1527           {
1528             l += ft_strlen( foundry_prop->value.atom ) + 1;
1529 
1530             if ( FT_QALLOC( root->family_name, l ) )
1531               goto Exit;
1532 
1533             ft_strcpy( root->family_name, foundry_prop->value.atom );
1534             ft_strcat( root->family_name, " " );
1535             ft_strcat( root->family_name, prop->value.atom );
1536           }
1537           else
1538           {
1539             if ( FT_QALLOC( root->family_name, l ) )
1540               goto Exit;
1541 
1542             ft_strcpy( root->family_name, prop->value.atom );
1543           }
1544 
1545           if ( wide )
1546             ft_strcat( root->family_name, " Wide" );
1547         }
1548         else
1549 
1550 #endif /* PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */
1551 
1552         {
1553           if ( FT_STRDUP( root->family_name, prop->value.atom ) )
1554             goto Exit;
1555         }
1556       }
1557       else
1558         root->family_name = NULL;
1559 
1560       root->num_glyphs = (FT_Long)face->nmetrics;
1561 
1562       root->num_fixed_sizes = 1;
1563       if ( FT_NEW( root->available_sizes ) )
1564         goto Exit;
1565 
1566       {
1567         FT_Bitmap_Size*  bsize = root->available_sizes;
1568         FT_Short         resolution_x = 0, resolution_y = 0;
1569 
1570 
1571         /* for simplicity, we take absolute values of integer properties */
1572 
1573 #if 0
1574         bsize->height = face->accel.maxbounds.ascent << 6;
1575 #endif
1576 
1577 #ifdef FT_DEBUG_LEVEL_TRACE
1578         if ( face->accel.fontAscent + face->accel.fontDescent < 0 )
1579           FT_TRACE0(( "pcf_load_font: negative height\n" ));
1580 #endif
1581         if ( FT_ABS( face->accel.fontAscent +
1582                      face->accel.fontDescent ) > 0x7FFF )
1583         {
1584           bsize->height = 0x7FFF;
1585           FT_TRACE0(( "pcf_load_font: clamping height to value %d\n",
1586                       bsize->height ));
1587         }
1588         else
1589           bsize->height = FT_ABS( (FT_Short)( face->accel.fontAscent +
1590                                               face->accel.fontDescent ) );
1591 
1592         prop = pcf_find_property( face, "AVERAGE_WIDTH" );
1593         if ( prop )
1594         {
1595 #ifdef FT_DEBUG_LEVEL_TRACE
1596           if ( prop->value.l < 0 )
1597             FT_TRACE0(( "pcf_load_font: negative average width\n" ));
1598 #endif
1599           if ( ( FT_ABS( prop->value.l ) > 0x7FFFL * 10 - 5 ) )
1600           {
1601             bsize->width = 0x7FFF;
1602             FT_TRACE0(( "pcf_load_font: clamping average width to value %d\n",
1603                         bsize->width ));
1604           }
1605           else
1606             bsize->width = FT_ABS( (FT_Short)( ( prop->value.l + 5 ) / 10 ) );
1607         }
1608         else
1609         {
1610           /* this is a heuristical value */
1611           bsize->width = ( bsize->height * 2 + 1 ) / 3;
1612         }
1613 
1614         prop = pcf_find_property( face, "POINT_SIZE" );
1615         if ( prop )
1616         {
1617 #ifdef FT_DEBUG_LEVEL_TRACE
1618           if ( prop->value.l < 0 )
1619             FT_TRACE0(( "pcf_load_font: negative point size\n" ));
1620 #endif
1621           /* convert from 722.7 decipoints to 72 points per inch */
1622           if ( FT_ABS( prop->value.l ) > 0x504C2L ) /* 0x7FFF * 72270/7200 */
1623           {
1624             bsize->size = 0x7FFF;
1625             FT_TRACE0(( "pcf_load_font: clamping point size to value %ld\n",
1626                         bsize->size ));
1627           }
1628           else
1629             bsize->size = FT_MulDiv( FT_ABS( prop->value.l ),
1630                                      64 * 7200,
1631                                      72270L );
1632         }
1633 
1634         prop = pcf_find_property( face, "PIXEL_SIZE" );
1635         if ( prop )
1636         {
1637 #ifdef FT_DEBUG_LEVEL_TRACE
1638           if ( prop->value.l < 0 )
1639             FT_TRACE0(( "pcf_load_font: negative pixel size\n" ));
1640 #endif
1641           if ( FT_ABS( prop->value.l ) > 0x7FFF )
1642           {
1643             bsize->y_ppem = 0x7FFF << 6;
1644             FT_TRACE0(( "pcf_load_font: clamping pixel size to value %ld\n",
1645                         bsize->y_ppem ));
1646           }
1647           else
1648             bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6;
1649         }
1650 
1651         prop = pcf_find_property( face, "RESOLUTION_X" );
1652         if ( prop )
1653         {
1654 #ifdef FT_DEBUG_LEVEL_TRACE
1655           if ( prop->value.l < 0 )
1656             FT_TRACE0(( "pcf_load_font: negative X resolution\n" ));
1657 #endif
1658           if ( FT_ABS( prop->value.l ) > 0x7FFF )
1659           {
1660             resolution_x = 0x7FFF;
1661             FT_TRACE0(( "pcf_load_font: clamping X resolution to value %d\n",
1662                         resolution_x ));
1663           }
1664           else
1665             resolution_x = FT_ABS( (FT_Short)prop->value.l );
1666         }
1667 
1668         prop = pcf_find_property( face, "RESOLUTION_Y" );
1669         if ( prop )
1670         {
1671 #ifdef FT_DEBUG_LEVEL_TRACE
1672           if ( prop->value.l < 0 )
1673             FT_TRACE0(( "pcf_load_font: negative Y resolution\n" ));
1674 #endif
1675           if ( FT_ABS( prop->value.l ) > 0x7FFF )
1676           {
1677             resolution_y = 0x7FFF;
1678             FT_TRACE0(( "pcf_load_font: clamping Y resolution to value %d\n",
1679                         resolution_y ));
1680           }
1681           else
1682             resolution_y = FT_ABS( (FT_Short)prop->value.l );
1683         }
1684 
1685         if ( bsize->y_ppem == 0 )
1686         {
1687           bsize->y_ppem = bsize->size;
1688           if ( resolution_y )
1689             bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 );
1690         }
1691         if ( resolution_x && resolution_y )
1692           bsize->x_ppem = FT_MulDiv( bsize->y_ppem,
1693                                      resolution_x,
1694                                      resolution_y );
1695         else
1696           bsize->x_ppem = bsize->y_ppem;
1697       }
1698 
1699       /* set up charset */
1700       {
1701         PCF_Property  charset_registry, charset_encoding;
1702 
1703 
1704         charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
1705         charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
1706 
1707         if ( charset_registry && charset_registry->isString &&
1708              charset_encoding && charset_encoding->isString )
1709         {
1710           if ( FT_STRDUP( face->charset_encoding,
1711                           charset_encoding->value.atom ) ||
1712                FT_STRDUP( face->charset_registry,
1713                           charset_registry->value.atom ) )
1714             goto Exit;
1715         }
1716       }
1717     }
1718 
1719   Exit:
1720     if ( error )
1721     {
1722       /* This is done to respect the behaviour of the original */
1723       /* PCF font driver.                                      */
1724       error = FT_THROW( Invalid_File_Format );
1725     }
1726 
1727     return error;
1728   }
1729 
1730 
1731 /* END */
1732