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