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