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