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
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*
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*
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 )
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* )
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
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 )
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 )
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
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
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 )
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
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
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
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 )
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