xref: /aosp_15_r20/external/freetype/src/psaux/afmparse.c (revision 63949dbd25bcc50c4e1178497ff9e9574d44fc5a)
1 /****************************************************************************
2  *
3  * afmparse.c
4  *
5  *   AFM parser (body).
6  *
7  * Copyright (C) 2006-2023 by
8  * David Turner, Robert Wilhelm, and Werner Lemberg.
9  *
10  * This file is part of the FreeType project, and may only be used,
11  * modified, and distributed under the terms of the FreeType project
12  * license, LICENSE.TXT.  By continuing to use, modify, or distribute
13  * this file you indicate that you have read the license and
14  * understand and accept it fully.
15  *
16  */
17 
18 #include <freetype/freetype.h>
19 #include <freetype/internal/ftdebug.h>
20 #include <freetype/internal/psaux.h>
21 
22 #ifndef T1_CONFIG_OPTION_NO_AFM
23 
24 #include "afmparse.h"
25 #include "psconv.h"
26 
27 #include "psauxerr.h"
28 
29 
30   /**************************************************************************
31    *
32    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
33    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
34    * messages during execution.
35    */
36 #undef  FT_COMPONENT
37 #define FT_COMPONENT  afmparse
38 
39 
40   /**************************************************************************
41    *
42    * AFM_Stream
43    *
44    * The use of AFM_Stream is largely inspired by parseAFM.[ch] from t1lib.
45    *
46    */
47 
48   enum
49   {
50     AFM_STREAM_STATUS_NORMAL,
51     AFM_STREAM_STATUS_EOC,
52     AFM_STREAM_STATUS_EOL,
53     AFM_STREAM_STATUS_EOF
54   };
55 
56 
57   typedef struct  AFM_StreamRec_
58   {
59     FT_Byte*  cursor;
60     FT_Byte*  base;
61     FT_Byte*  limit;
62 
63     FT_Int    status;
64 
65   } AFM_StreamRec;
66 
67 
68 #ifndef EOF
69 #define EOF -1
70 #endif
71 
72 
73   /* this works because empty lines are ignored */
74 #define AFM_IS_NEWLINE( ch )  ( (ch) == '\r' || (ch) == '\n' )
75 
76 #define AFM_IS_EOF( ch )      ( (ch) == EOF  || (ch) == '\x1a' )
77 #define AFM_IS_SPACE( ch )    ( (ch) == ' '  || (ch) == '\t' )
78 
79   /* column separator; there is no `column' in the spec actually */
80 #define AFM_IS_SEP( ch )      ( (ch) == ';' )
81 
82 #define AFM_GETC()                                                       \
83           ( ( (stream)->cursor < (stream)->limit ) ? *(stream)->cursor++ \
84                                                    : EOF )
85 
86 #define AFM_STREAM_KEY_BEGIN( stream )    \
87           (char*)( (stream)->cursor - 1 )
88 
89 #define AFM_STREAM_KEY_LEN( stream, key )           \
90           (FT_Offset)( (char*)(stream)->cursor - key - 1 )
91 
92 #define AFM_STATUS_EOC( stream ) \
93           ( (stream)->status >= AFM_STREAM_STATUS_EOC )
94 
95 #define AFM_STATUS_EOL( stream ) \
96           ( (stream)->status >= AFM_STREAM_STATUS_EOL )
97 
98 #define AFM_STATUS_EOF( stream ) \
99           ( (stream)->status >= AFM_STREAM_STATUS_EOF )
100 
101 
102   static int
afm_stream_skip_spaces(AFM_Stream stream)103   afm_stream_skip_spaces( AFM_Stream  stream )
104   {
105     int  ch = 0;  /* make stupid compiler happy */
106 
107 
108     if ( AFM_STATUS_EOC( stream ) )
109       return ';';
110 
111     while ( 1 )
112     {
113       ch = AFM_GETC();
114       if ( !AFM_IS_SPACE( ch ) )
115         break;
116     }
117 
118     if ( AFM_IS_NEWLINE( ch ) )
119       stream->status = AFM_STREAM_STATUS_EOL;
120     else if ( AFM_IS_SEP( ch ) )
121       stream->status = AFM_STREAM_STATUS_EOC;
122     else if ( AFM_IS_EOF( ch ) )
123       stream->status = AFM_STREAM_STATUS_EOF;
124 
125     return ch;
126   }
127 
128 
129   /* read a key or value in current column */
130   static char*
afm_stream_read_one(AFM_Stream stream)131   afm_stream_read_one( AFM_Stream  stream )
132   {
133     char*  str;
134 
135 
136     afm_stream_skip_spaces( stream );
137     if ( AFM_STATUS_EOC( stream ) )
138       return NULL;
139 
140     str = AFM_STREAM_KEY_BEGIN( stream );
141 
142     while ( 1 )
143     {
144       int  ch = AFM_GETC();
145 
146 
147       if ( AFM_IS_SPACE( ch ) )
148         break;
149       else if ( AFM_IS_NEWLINE( ch ) )
150       {
151         stream->status = AFM_STREAM_STATUS_EOL;
152         break;
153       }
154       else if ( AFM_IS_SEP( ch ) )
155       {
156         stream->status = AFM_STREAM_STATUS_EOC;
157         break;
158       }
159       else if ( AFM_IS_EOF( ch ) )
160       {
161         stream->status = AFM_STREAM_STATUS_EOF;
162         break;
163       }
164     }
165 
166     return str;
167   }
168 
169 
170   /* read a string (i.e., read to EOL) */
171   static char*
afm_stream_read_string(AFM_Stream stream)172   afm_stream_read_string( AFM_Stream  stream )
173   {
174     char*  str;
175 
176 
177     afm_stream_skip_spaces( stream );
178     if ( AFM_STATUS_EOL( stream ) )
179       return NULL;
180 
181     str = AFM_STREAM_KEY_BEGIN( stream );
182 
183     /* scan to eol */
184     while ( 1 )
185     {
186       int  ch = AFM_GETC();
187 
188 
189       if ( AFM_IS_NEWLINE( ch ) )
190       {
191         stream->status = AFM_STREAM_STATUS_EOL;
192         break;
193       }
194       else if ( AFM_IS_EOF( ch ) )
195       {
196         stream->status = AFM_STREAM_STATUS_EOF;
197         break;
198       }
199     }
200 
201     return str;
202   }
203 
204 
205   /**************************************************************************
206    *
207    * AFM_Parser
208    *
209    */
210 
211   /* all keys defined in Ch. 7-10 of 5004.AFM_Spec.pdf */
212   typedef enum  AFM_Token_
213   {
214     AFM_TOKEN_ASCENDER,
215     AFM_TOKEN_AXISLABEL,
216     AFM_TOKEN_AXISTYPE,
217     AFM_TOKEN_B,
218     AFM_TOKEN_BLENDAXISTYPES,
219     AFM_TOKEN_BLENDDESIGNMAP,
220     AFM_TOKEN_BLENDDESIGNPOSITIONS,
221     AFM_TOKEN_C,
222     AFM_TOKEN_CC,
223     AFM_TOKEN_CH,
224     AFM_TOKEN_CAPHEIGHT,
225     AFM_TOKEN_CHARWIDTH,
226     AFM_TOKEN_CHARACTERSET,
227     AFM_TOKEN_CHARACTERS,
228     AFM_TOKEN_DESCENDER,
229     AFM_TOKEN_ENCODINGSCHEME,
230     AFM_TOKEN_ENDAXIS,
231     AFM_TOKEN_ENDCHARMETRICS,
232     AFM_TOKEN_ENDCOMPOSITES,
233     AFM_TOKEN_ENDDIRECTION,
234     AFM_TOKEN_ENDFONTMETRICS,
235     AFM_TOKEN_ENDKERNDATA,
236     AFM_TOKEN_ENDKERNPAIRS,
237     AFM_TOKEN_ENDTRACKKERN,
238     AFM_TOKEN_ESCCHAR,
239     AFM_TOKEN_FAMILYNAME,
240     AFM_TOKEN_FONTBBOX,
241     AFM_TOKEN_FONTNAME,
242     AFM_TOKEN_FULLNAME,
243     AFM_TOKEN_ISBASEFONT,
244     AFM_TOKEN_ISCIDFONT,
245     AFM_TOKEN_ISFIXEDPITCH,
246     AFM_TOKEN_ISFIXEDV,
247     AFM_TOKEN_ITALICANGLE,
248     AFM_TOKEN_KP,
249     AFM_TOKEN_KPH,
250     AFM_TOKEN_KPX,
251     AFM_TOKEN_KPY,
252     AFM_TOKEN_L,
253     AFM_TOKEN_MAPPINGSCHEME,
254     AFM_TOKEN_METRICSSETS,
255     AFM_TOKEN_N,
256     AFM_TOKEN_NOTICE,
257     AFM_TOKEN_PCC,
258     AFM_TOKEN_STARTAXIS,
259     AFM_TOKEN_STARTCHARMETRICS,
260     AFM_TOKEN_STARTCOMPOSITES,
261     AFM_TOKEN_STARTDIRECTION,
262     AFM_TOKEN_STARTFONTMETRICS,
263     AFM_TOKEN_STARTKERNDATA,
264     AFM_TOKEN_STARTKERNPAIRS,
265     AFM_TOKEN_STARTKERNPAIRS0,
266     AFM_TOKEN_STARTKERNPAIRS1,
267     AFM_TOKEN_STARTTRACKKERN,
268     AFM_TOKEN_STDHW,
269     AFM_TOKEN_STDVW,
270     AFM_TOKEN_TRACKKERN,
271     AFM_TOKEN_UNDERLINEPOSITION,
272     AFM_TOKEN_UNDERLINETHICKNESS,
273     AFM_TOKEN_VV,
274     AFM_TOKEN_VVECTOR,
275     AFM_TOKEN_VERSION,
276     AFM_TOKEN_W,
277     AFM_TOKEN_W0,
278     AFM_TOKEN_W0X,
279     AFM_TOKEN_W0Y,
280     AFM_TOKEN_W1,
281     AFM_TOKEN_W1X,
282     AFM_TOKEN_W1Y,
283     AFM_TOKEN_WX,
284     AFM_TOKEN_WY,
285     AFM_TOKEN_WEIGHT,
286     AFM_TOKEN_WEIGHTVECTOR,
287     AFM_TOKEN_XHEIGHT,
288     N_AFM_TOKENS,
289     AFM_TOKEN_UNKNOWN
290 
291   } AFM_Token;
292 
293 
294   static const char*  const afm_key_table[N_AFM_TOKENS] =
295   {
296     "Ascender",
297     "AxisLabel",
298     "AxisType",
299     "B",
300     "BlendAxisTypes",
301     "BlendDesignMap",
302     "BlendDesignPositions",
303     "C",
304     "CC",
305     "CH",
306     "CapHeight",
307     "CharWidth",
308     "CharacterSet",
309     "Characters",
310     "Descender",
311     "EncodingScheme",
312     "EndAxis",
313     "EndCharMetrics",
314     "EndComposites",
315     "EndDirection",
316     "EndFontMetrics",
317     "EndKernData",
318     "EndKernPairs",
319     "EndTrackKern",
320     "EscChar",
321     "FamilyName",
322     "FontBBox",
323     "FontName",
324     "FullName",
325     "IsBaseFont",
326     "IsCIDFont",
327     "IsFixedPitch",
328     "IsFixedV",
329     "ItalicAngle",
330     "KP",
331     "KPH",
332     "KPX",
333     "KPY",
334     "L",
335     "MappingScheme",
336     "MetricsSets",
337     "N",
338     "Notice",
339     "PCC",
340     "StartAxis",
341     "StartCharMetrics",
342     "StartComposites",
343     "StartDirection",
344     "StartFontMetrics",
345     "StartKernData",
346     "StartKernPairs",
347     "StartKernPairs0",
348     "StartKernPairs1",
349     "StartTrackKern",
350     "StdHW",
351     "StdVW",
352     "TrackKern",
353     "UnderlinePosition",
354     "UnderlineThickness",
355     "VV",
356     "VVector",
357     "Version",
358     "W",
359     "W0",
360     "W0X",
361     "W0Y",
362     "W1",
363     "W1X",
364     "W1Y",
365     "WX",
366     "WY",
367     "Weight",
368     "WeightVector",
369     "XHeight"
370   };
371 
372 
373   /*
374    * `afm_parser_read_vals' and `afm_parser_next_key' provide
375    * high-level operations to an AFM_Stream.  The rest of the
376    * parser functions should use them without accessing the
377    * AFM_Stream directly.
378    */
379 
380   FT_LOCAL_DEF( FT_Int )
afm_parser_read_vals(AFM_Parser parser,AFM_Value vals,FT_Int n)381   afm_parser_read_vals( AFM_Parser  parser,
382                         AFM_Value   vals,
383                         FT_Int      n )
384   {
385     AFM_Stream  stream = parser->stream;
386     char*       str;
387     FT_Int      i;
388 
389 
390     if ( n > AFM_MAX_ARGUMENTS )
391       return 0;
392 
393     for ( i = 0; i < n; i++ )
394     {
395       FT_Offset  len;
396       AFM_Value  val = vals + i;
397 
398 
399       if ( val->type == AFM_VALUE_TYPE_STRING )
400         str = afm_stream_read_string( stream );
401       else
402         str = afm_stream_read_one( stream );
403 
404       if ( !str )
405         break;
406 
407       len = AFM_STREAM_KEY_LEN( stream, str );
408 
409       switch ( val->type )
410       {
411       case AFM_VALUE_TYPE_STRING:
412       case AFM_VALUE_TYPE_NAME:
413         {
414           FT_Memory  memory = parser->memory;
415           FT_Error   error;
416 
417 
418           if ( !FT_QALLOC( val->u.s, len + 1 ) )
419           {
420             ft_memcpy( val->u.s, str, len );
421             val->u.s[len] = '\0';
422           }
423         }
424         break;
425 
426       case AFM_VALUE_TYPE_FIXED:
427         val->u.f = PS_Conv_ToFixed( (FT_Byte**)(void*)&str,
428                                     (FT_Byte*)str + len, 0 );
429         break;
430 
431       case AFM_VALUE_TYPE_INTEGER:
432         val->u.i = PS_Conv_ToInt( (FT_Byte**)(void*)&str,
433                                   (FT_Byte*)str + len );
434         break;
435 
436       case AFM_VALUE_TYPE_BOOL:
437         val->u.b = FT_BOOL( len == 4                      &&
438                             !ft_strncmp( str, "true", 4 ) );
439         break;
440 
441       case AFM_VALUE_TYPE_INDEX:
442         if ( parser->get_index )
443           val->u.i = parser->get_index( str, len, parser->user_data );
444         else
445           val->u.i = 0;
446         break;
447       }
448     }
449 
450     return i;
451   }
452 
453 
454   FT_LOCAL_DEF( char* )
afm_parser_next_key(AFM_Parser parser,FT_Bool line,FT_Offset * len)455   afm_parser_next_key( AFM_Parser  parser,
456                        FT_Bool     line,
457                        FT_Offset*  len )
458   {
459     AFM_Stream  stream = parser->stream;
460     char*       key    = NULL;  /* make stupid compiler happy */
461 
462 
463     if ( line )
464     {
465       while ( 1 )
466       {
467         /* skip current line */
468         if ( !AFM_STATUS_EOL( stream ) )
469           afm_stream_read_string( stream );
470 
471         stream->status = AFM_STREAM_STATUS_NORMAL;
472         key = afm_stream_read_one( stream );
473 
474         /* skip empty line */
475         if ( !key                      &&
476              !AFM_STATUS_EOF( stream ) &&
477              AFM_STATUS_EOL( stream )  )
478           continue;
479 
480         break;
481       }
482     }
483     else
484     {
485       while ( 1 )
486       {
487         /* skip current column */
488         while ( !AFM_STATUS_EOC( stream ) )
489           afm_stream_read_one( stream );
490 
491         stream->status = AFM_STREAM_STATUS_NORMAL;
492         key = afm_stream_read_one( stream );
493 
494         /* skip empty column */
495         if ( !key                      &&
496              !AFM_STATUS_EOF( stream ) &&
497              AFM_STATUS_EOC( stream )  )
498           continue;
499 
500         break;
501       }
502     }
503 
504     if ( len )
505       *len = ( key ) ? (FT_Offset)AFM_STREAM_KEY_LEN( stream, key )
506                      : 0;
507 
508     return key;
509   }
510 
511 
512   static AFM_Token
afm_tokenize(const char * key,FT_Offset len)513   afm_tokenize( const char*  key,
514                 FT_Offset    len )
515   {
516     int  n;
517 
518 
519     for ( n = 0; n < N_AFM_TOKENS; n++ )
520     {
521       if ( *( afm_key_table[n] ) == *key )
522       {
523         for ( ; n < N_AFM_TOKENS; n++ )
524         {
525           if ( *( afm_key_table[n] ) != *key )
526             return AFM_TOKEN_UNKNOWN;
527 
528           if ( ft_strncmp( afm_key_table[n], key, len ) == 0 )
529             return (AFM_Token) n;
530         }
531       }
532     }
533 
534     return AFM_TOKEN_UNKNOWN;
535   }
536 
537 
538   FT_LOCAL_DEF( FT_Error )
afm_parser_init(AFM_Parser parser,FT_Memory memory,FT_Byte * base,FT_Byte * limit)539   afm_parser_init( AFM_Parser  parser,
540                    FT_Memory   memory,
541                    FT_Byte*    base,
542                    FT_Byte*    limit )
543   {
544     AFM_Stream  stream = NULL;
545     FT_Error    error;
546 
547 
548     if ( FT_NEW( stream ) )
549       return error;
550 
551     stream->cursor = stream->base = base;
552     stream->limit  = limit;
553 
554     /* don't skip the first line during the first call */
555     stream->status = AFM_STREAM_STATUS_EOL;
556 
557     parser->memory    = memory;
558     parser->stream    = stream;
559     parser->FontInfo  = NULL;
560     parser->get_index = NULL;
561 
562     return FT_Err_Ok;
563   }
564 
565 
566   FT_LOCAL_DEF( void )
afm_parser_done(AFM_Parser parser)567   afm_parser_done( AFM_Parser  parser )
568   {
569     FT_Memory  memory = parser->memory;
570 
571 
572     FT_FREE( parser->stream );
573   }
574 
575 
576   static FT_Error
afm_parser_read_int(AFM_Parser parser,FT_Int * aint)577   afm_parser_read_int( AFM_Parser  parser,
578                        FT_Int*     aint )
579   {
580     AFM_ValueRec  val;
581 
582 
583     val.type = AFM_VALUE_TYPE_INTEGER;
584 
585     if ( afm_parser_read_vals( parser, &val, 1 ) == 1 )
586     {
587       *aint = val.u.i;
588 
589       return FT_Err_Ok;
590     }
591     else
592       return FT_THROW( Syntax_Error );
593   }
594 
595 
596   static FT_Error
afm_parse_track_kern(AFM_Parser parser)597   afm_parse_track_kern( AFM_Parser  parser )
598   {
599     AFM_FontInfo   fi     = parser->FontInfo;
600     AFM_Stream     stream = parser->stream;
601     AFM_TrackKern  tk;
602 
603     char*      key;
604     FT_Offset  len;
605     int        n = -1;
606     FT_Int     tmp;
607 
608 
609     if ( afm_parser_read_int( parser, &tmp ) )
610         goto Fail;
611 
612     if ( tmp < 0 )
613     {
614       FT_ERROR(( "afm_parse_track_kern: invalid number of track kerns\n" ));
615       goto Fail;
616     }
617 
618     fi->NumTrackKern = (FT_UInt)tmp;
619     FT_TRACE3(( "afm_parse_track_kern: %u track kern%s expected\n",
620                 fi->NumTrackKern,
621                 fi->NumTrackKern == 1 ? "" : "s" ));
622 
623     /* Rough sanity check: The minimum line length of the `TrackKern` */
624     /* command is 20 characters (including the EOL character).        */
625     if ( (FT_ULong)( stream->limit - stream->cursor ) / 20 <
626            fi->NumTrackKern )
627     {
628       FT_ERROR(( "afm_parse_track_kern:"
629                  " number of track kern entries exceeds stream size\n" ));
630       goto Fail;
631     }
632 
633     if ( fi->NumTrackKern )
634     {
635       FT_Memory  memory = parser->memory;
636       FT_Error   error;
637 
638 
639       if ( FT_QNEW_ARRAY( fi->TrackKerns, fi->NumTrackKern ) )
640         return error;
641     }
642 
643     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
644     {
645       AFM_ValueRec  shared_vals[5];
646 
647 
648       switch ( afm_tokenize( key, len ) )
649       {
650       case AFM_TOKEN_TRACKKERN:
651         n++;
652 
653         if ( n >= (int)fi->NumTrackKern )
654           {
655             FT_ERROR(( "afm_parse_track_kern: too many track kern data\n" ));
656             goto Fail;
657           }
658 
659         tk = fi->TrackKerns + n;
660 
661         shared_vals[0].type = AFM_VALUE_TYPE_INTEGER;
662         shared_vals[1].type = AFM_VALUE_TYPE_FIXED;
663         shared_vals[2].type = AFM_VALUE_TYPE_FIXED;
664         shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
665         shared_vals[4].type = AFM_VALUE_TYPE_FIXED;
666         if ( afm_parser_read_vals( parser, shared_vals, 5 ) != 5 )
667         {
668           FT_ERROR(( "afm_parse_track_kern:"
669                      " insufficient number of parameters for entry %d\n",
670                      n ));
671           goto Fail;
672         }
673 
674         tk->degree     = shared_vals[0].u.i;
675         tk->min_ptsize = shared_vals[1].u.f;
676         tk->min_kern   = shared_vals[2].u.f;
677         tk->max_ptsize = shared_vals[3].u.f;
678         tk->max_kern   = shared_vals[4].u.f;
679 
680         break;
681 
682       case AFM_TOKEN_ENDTRACKKERN:
683       case AFM_TOKEN_ENDKERNDATA:
684       case AFM_TOKEN_ENDFONTMETRICS:
685         tmp = n + 1;
686         if ( (FT_UInt)tmp != fi->NumTrackKern )
687         {
688           FT_TRACE1(( "afm_parse_track_kern: %s%d track kern entr%s seen\n",
689                       tmp == 0 ? "" : "only ",
690                       tmp,
691                       tmp == 1 ? "y" : "ies" ));
692           fi->NumTrackKern = (FT_UInt)tmp;
693         }
694         else
695           FT_TRACE3(( "afm_parse_track_kern: %d track kern entr%s seen\n",
696                       tmp,
697                       tmp == 1 ? "y" : "ies" ));
698         return FT_Err_Ok;
699 
700       case AFM_TOKEN_UNKNOWN:
701         break;
702 
703       default:
704         goto Fail;
705       }
706     }
707 
708   Fail:
709     return FT_THROW( Syntax_Error );
710   }
711 
712 
713 #undef  KERN_INDEX
714 #define KERN_INDEX( g1, g2 )  ( ( (FT_ULong)g1 << 16 ) | g2 )
715 
716 
717   /* compare two kerning pairs */
718   FT_COMPARE_DEF( int )
afm_compare_kern_pairs(const void * a,const void * b)719   afm_compare_kern_pairs( const void*  a,
720                           const void*  b )
721   {
722     AFM_KernPair  kp1 = (AFM_KernPair)a;
723     AFM_KernPair  kp2 = (AFM_KernPair)b;
724 
725     FT_ULong  index1 = KERN_INDEX( kp1->index1, kp1->index2 );
726     FT_ULong  index2 = KERN_INDEX( kp2->index1, kp2->index2 );
727 
728 
729     if ( index1 > index2 )
730       return 1;
731     else if ( index1 < index2 )
732       return -1;
733     else
734       return 0;
735   }
736 
737 
738   static FT_Error
afm_parse_kern_pairs(AFM_Parser parser)739   afm_parse_kern_pairs( AFM_Parser  parser )
740   {
741     AFM_FontInfo  fi     = parser->FontInfo;
742     AFM_Stream    stream = parser->stream;
743     AFM_KernPair  kp;
744     char*         key;
745     FT_Offset     len;
746     int           n = -1;
747     FT_Int        tmp;
748 
749 
750     if ( afm_parser_read_int( parser, &tmp ) )
751       goto Fail;
752 
753     if ( tmp < 0 )
754     {
755       FT_ERROR(( "afm_parse_kern_pairs: invalid number of kern pairs\n" ));
756       goto Fail;
757     }
758 
759     fi->NumKernPair = (FT_UInt)tmp;
760     FT_TRACE3(( "afm_parse_kern_pairs: %u kern pair%s expected\n",
761                 fi->NumKernPair,
762                 fi->NumKernPair == 1 ? "" : "s" ));
763 
764     /* Rough sanity check: The minimum line length of the `KP`,    */
765     /* `KPH`,`KPX`, and `KPY` commands is 10 characters (including */
766     /* the EOL character).                                         */
767     if ( (FT_ULong)( stream->limit - stream->cursor ) / 10 <
768            fi->NumKernPair )
769     {
770       FT_ERROR(( "afm_parse_kern_pairs:"
771                  " number of kern pairs exceeds stream size\n" ));
772       goto Fail;
773     }
774 
775     if ( fi->NumKernPair )
776     {
777       FT_Memory  memory = parser->memory;
778       FT_Error   error;
779 
780 
781       if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )
782         return error;
783     }
784 
785     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
786     {
787       AFM_Token  token = afm_tokenize( key, len );
788 
789 
790       switch ( token )
791       {
792       case AFM_TOKEN_KP:
793       case AFM_TOKEN_KPX:
794       case AFM_TOKEN_KPY:
795         {
796           FT_Int        r;
797           AFM_ValueRec  shared_vals[4];
798 
799 
800           n++;
801 
802           if ( n >= (int)fi->NumKernPair )
803           {
804             FT_ERROR(( "afm_parse_kern_pairs: too many kern pairs\n" ));
805             goto Fail;
806           }
807 
808           kp = fi->KernPairs + n;
809 
810           shared_vals[0].type = AFM_VALUE_TYPE_INDEX;
811           shared_vals[1].type = AFM_VALUE_TYPE_INDEX;
812           shared_vals[2].type = AFM_VALUE_TYPE_INTEGER;
813           shared_vals[3].type = AFM_VALUE_TYPE_INTEGER;
814           r = afm_parser_read_vals( parser, shared_vals, 4 );
815           if ( r < 3 )
816           {
817             FT_ERROR(( "afm_parse_kern_pairs:"
818                        " insufficient number of parameters for entry %d\n",
819                        n ));
820             goto Fail;
821           }
822 
823           /* index values can't be negative */
824           kp->index1 = shared_vals[0].u.u;
825           kp->index2 = shared_vals[1].u.u;
826           if ( token == AFM_TOKEN_KPY )
827           {
828             kp->x = 0;
829             kp->y = shared_vals[2].u.i;
830           }
831           else
832           {
833             kp->x = shared_vals[2].u.i;
834             kp->y = ( token == AFM_TOKEN_KP && r == 4 )
835                       ? shared_vals[3].u.i : 0;
836           }
837         }
838         break;
839 
840       case AFM_TOKEN_ENDKERNPAIRS:
841       case AFM_TOKEN_ENDKERNDATA:
842       case AFM_TOKEN_ENDFONTMETRICS:
843         tmp = n + 1;
844         if ( (FT_UInt)tmp != fi->NumKernPair )
845         {
846           FT_TRACE1(( "afm_parse_kern_pairs: %s%d kern pair%s seen\n",
847                       tmp == 0 ? "" : "only ",
848                       tmp,
849                       tmp == 1 ? "" : "s" ));
850           fi->NumKernPair = (FT_UInt)tmp;
851         }
852         else
853           FT_TRACE3(( "afm_parse_kern_pairs: %d kern pair%s seen\n",
854                       tmp,
855                       tmp == 1 ? "" : "s" ));
856 
857         ft_qsort( fi->KernPairs, fi->NumKernPair,
858                   sizeof ( AFM_KernPairRec ),
859                   afm_compare_kern_pairs );
860         return FT_Err_Ok;
861 
862       case AFM_TOKEN_UNKNOWN:
863         break;
864 
865       default:
866         goto Fail;
867       }
868     }
869 
870   Fail:
871     return FT_THROW( Syntax_Error );
872   }
873 
874 
875   static FT_Error
afm_parse_kern_data(AFM_Parser parser)876   afm_parse_kern_data( AFM_Parser  parser )
877   {
878     FT_Error   error;
879     char*      key;
880     FT_Offset  len;
881 
882     int  have_trackkern = 0;
883     int  have_kernpairs = 0;
884 
885 
886     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
887     {
888       switch ( afm_tokenize( key, len ) )
889       {
890       case AFM_TOKEN_STARTTRACKKERN:
891         if ( have_trackkern )
892         {
893           FT_ERROR(( "afm_parse_kern_data:"
894                      " invalid second horizontal track kern section\n" ));
895           goto Fail;
896         }
897 
898         error = afm_parse_track_kern( parser );
899         if ( error )
900           return error;
901 
902         have_trackkern = 1;
903         break;
904 
905       case AFM_TOKEN_STARTKERNPAIRS:
906       case AFM_TOKEN_STARTKERNPAIRS0:
907         if ( have_kernpairs )
908         {
909           FT_ERROR(( "afm_parse_kern_data:"
910                      " invalid second horizontal kern pair section\n" ));
911           goto Fail;
912         }
913 
914         error = afm_parse_kern_pairs( parser );
915         if ( error )
916           return error;
917 
918         have_kernpairs = 1;
919         break;
920 
921       case AFM_TOKEN_ENDKERNDATA:
922       case AFM_TOKEN_ENDFONTMETRICS:
923         return FT_Err_Ok;
924 
925       case AFM_TOKEN_UNKNOWN:
926         break;
927 
928       default:
929         goto Fail;
930       }
931     }
932 
933   Fail:
934     return FT_THROW( Syntax_Error );
935   }
936 
937 
938   static FT_Error
afm_parser_skip_section(AFM_Parser parser,FT_Int n,AFM_Token end_section)939   afm_parser_skip_section( AFM_Parser  parser,
940                            FT_Int      n,
941                            AFM_Token   end_section )
942   {
943     char*      key;
944     FT_Offset  len;
945 
946 
947     while ( n-- > 0 )
948     {
949       key = afm_parser_next_key( parser, 1, NULL );
950       if ( !key )
951         goto Fail;
952     }
953 
954     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
955     {
956       AFM_Token  token = afm_tokenize( key, len );
957 
958 
959       if ( token == end_section || token == AFM_TOKEN_ENDFONTMETRICS )
960         return FT_Err_Ok;
961     }
962 
963   Fail:
964     return FT_THROW( Syntax_Error );
965   }
966 
967 
968   FT_LOCAL_DEF( FT_Error )
afm_parser_parse(AFM_Parser parser)969   afm_parser_parse( AFM_Parser  parser )
970   {
971     FT_Memory     memory = parser->memory;
972     AFM_FontInfo  fi     = parser->FontInfo;
973     FT_Error      error  = FT_ERR( Syntax_Error );
974     char*         key;
975     FT_Offset     len;
976     FT_Int        metrics_sets = 0;
977 
978 
979     if ( !fi )
980       return FT_THROW( Invalid_Argument );
981 
982     key = afm_parser_next_key( parser, 1, &len );
983     if ( !key || len != 16                              ||
984          ft_strncmp( key, "StartFontMetrics", 16 ) != 0 )
985       return FT_THROW( Unknown_File_Format );
986 
987     while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 )
988     {
989       AFM_ValueRec  shared_vals[4];
990 
991 
992       switch ( afm_tokenize( key, len ) )
993       {
994       case AFM_TOKEN_METRICSSETS:
995         if ( afm_parser_read_int( parser, &metrics_sets ) )
996           goto Fail;
997 
998         if ( metrics_sets != 0 && metrics_sets != 2 )
999         {
1000           error = FT_THROW( Unimplemented_Feature );
1001 
1002           goto Fail;
1003         }
1004         break;
1005 
1006       case AFM_TOKEN_ISCIDFONT:
1007         shared_vals[0].type = AFM_VALUE_TYPE_BOOL;
1008         if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
1009           goto Fail;
1010 
1011         fi->IsCIDFont = shared_vals[0].u.b;
1012         break;
1013 
1014       case AFM_TOKEN_FONTBBOX:
1015         shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
1016         shared_vals[1].type = AFM_VALUE_TYPE_FIXED;
1017         shared_vals[2].type = AFM_VALUE_TYPE_FIXED;
1018         shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
1019         if ( afm_parser_read_vals( parser, shared_vals, 4 ) != 4 )
1020           goto Fail;
1021 
1022         fi->FontBBox.xMin = shared_vals[0].u.f;
1023         fi->FontBBox.yMin = shared_vals[1].u.f;
1024         fi->FontBBox.xMax = shared_vals[2].u.f;
1025         fi->FontBBox.yMax = shared_vals[3].u.f;
1026         break;
1027 
1028       case AFM_TOKEN_ASCENDER:
1029         shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
1030         if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
1031           goto Fail;
1032 
1033         fi->Ascender = shared_vals[0].u.f;
1034         break;
1035 
1036       case AFM_TOKEN_DESCENDER:
1037         shared_vals[0].type = AFM_VALUE_TYPE_FIXED;
1038         if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
1039           goto Fail;
1040 
1041         fi->Descender = shared_vals[0].u.f;
1042         break;
1043 
1044       case AFM_TOKEN_STARTCHARMETRICS:
1045         {
1046           FT_Int  n = 0;
1047 
1048 
1049           if ( afm_parser_read_int( parser, &n ) )
1050             goto Fail;
1051 
1052           error = afm_parser_skip_section( parser, n,
1053                                            AFM_TOKEN_ENDCHARMETRICS );
1054           if ( error )
1055             return error;
1056         }
1057         break;
1058 
1059       case AFM_TOKEN_STARTKERNDATA:
1060         error = afm_parse_kern_data( parser );
1061         if ( error )
1062           goto Fail;
1063         /* we only support kern data, so ... */
1064         FALL_THROUGH;
1065 
1066       case AFM_TOKEN_ENDFONTMETRICS:
1067         return FT_Err_Ok;
1068 
1069       default:
1070         break;
1071       }
1072     }
1073 
1074   Fail:
1075     FT_FREE( fi->TrackKerns );
1076     fi->NumTrackKern = 0;
1077 
1078     FT_FREE( fi->KernPairs );
1079     fi->NumKernPair = 0;
1080 
1081     fi->IsCIDFont = 0;
1082 
1083     return error;
1084   }
1085 
1086 #else /* T1_CONFIG_OPTION_NO_AFM */
1087 
1088   /* ANSI C doesn't like empty source files */
1089   typedef int  afm_parse_dummy_;
1090 
1091 #endif /* T1_CONFIG_OPTION_NO_AFM */
1092 
1093 
1094 /* END */
1095