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