]>
Commit | Line | Data |
---|---|---|
1 | /***************************************************************************/ | |
2 | /* */ | |
3 | /* t1load.c */ | |
4 | /* */ | |
5 | /* Type 1 font loader (body). */ | |
6 | /* */ | |
7 | /* Copyright 1996-2000 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 | ||
19 | #include <freetype/config/ftconfig.h> | |
20 | #include <freetype/internal/ftdebug.h> | |
21 | #include <freetype/internal/t1types.h> | |
22 | ||
23 | ||
24 | #ifdef FT_FLAT_COMPILE | |
25 | ||
26 | #include "t1tokens.h" | |
27 | #include "t1parse.h" | |
28 | ||
29 | #else | |
30 | ||
31 | #include <type1/t1tokens.h> | |
32 | #include <type1/t1parse.h> | |
33 | ||
34 | #endif | |
35 | ||
36 | ||
37 | #include <stdio.h> | |
38 | ||
39 | #include <string.h> /* for strncpy(), strncmp(), strlen() */ | |
40 | ||
41 | ||
42 | /*************************************************************************/ | |
43 | /* */ | |
44 | /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ | |
45 | /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ | |
46 | /* messages during execution. */ | |
47 | /* */ | |
48 | #undef FT_COMPONENT | |
49 | #define FT_COMPONENT trace_t1load | |
50 | ||
51 | ||
52 | typedef FT_Error (*T1_Parse_Func)( T1_Parser* parser ); | |
53 | ||
54 | ||
55 | /*************************************************************************/ | |
56 | /* */ | |
57 | /* <Function> */ | |
58 | /* Init_T1_Parser */ | |
59 | /* */ | |
60 | /* <Description> */ | |
61 | /* Initializes a given parser object to build a given T1_Face. */ | |
62 | /* */ | |
63 | /* <InOut> */ | |
64 | /* parser :: A handle to the newly built parser object. */ | |
65 | /* */ | |
66 | /* <Input> */ | |
67 | /* face :: A handle to the target Type 1 face object. */ | |
68 | /* */ | |
69 | /* tokenizer :: A handle to the target Type 1 token manager. */ | |
70 | /* */ | |
71 | LOCAL_FUNC | |
72 | void Init_T1_Parser( T1_Parser* parser, | |
73 | T1_Face face, | |
74 | T1_Tokenizer tokenizer ) | |
75 | { | |
76 | parser->error = 0; | |
77 | parser->face = face; | |
78 | parser->tokenizer = tokenizer; | |
79 | parser->top = parser->stack; | |
80 | parser->limit = parser->stack + T1_MAX_STACK_DEPTH; | |
81 | ||
82 | parser->state_index = 0; | |
83 | parser->state_stack[0] = dict_none; | |
84 | ||
85 | parser->encoding_type = t1_encoding_none; | |
86 | parser->encoding_names = 0; | |
87 | parser->encoding_offsets = 0; | |
88 | parser->encoding_lengths = 0; | |
89 | ||
90 | parser->dump_tokens = 0; | |
91 | face->type1.private_dict.lenIV = 4; /* XXX : is it sure? */ | |
92 | } | |
93 | ||
94 | ||
95 | /*************************************************************************/ | |
96 | /* */ | |
97 | /* <Function> */ | |
98 | /* Next_T1_Token */ | |
99 | /* */ | |
100 | /* <Description> */ | |
101 | /* Grabs the next significant token from a parser's input stream. */ | |
102 | /* This function ignores a number of tokens, and translates */ | |
103 | /* alternate forms into their common ones. */ | |
104 | /* */ | |
105 | /* <Input> */ | |
106 | /* parser :: A handle to the source parser. */ | |
107 | /* */ | |
108 | /* <Output> */ | |
109 | /* token :: The extracted token descriptor. */ | |
110 | /* */ | |
111 | /* <Return> */ | |
112 | /* FreeTyoe error code. 0 means success. */ | |
113 | /* */ | |
114 | LOCAL_FUNC | |
115 | FT_Error Next_T1_Token( T1_Parser* parser, | |
116 | T1_Token* token ) | |
117 | { | |
118 | FT_Error error; | |
119 | T1_Tokenizer tokzer = parser->tokenizer; | |
120 | ||
121 | ||
122 | L1: | |
123 | error = Read_Token( tokzer ); | |
124 | if ( error ) | |
125 | return error; | |
126 | ||
127 | /* we now must ignore a number of tokens like `dup', `executeonly', */ | |
128 | /* `readonly', etc. */ | |
129 | *token = tokzer->token; | |
130 | if ( token->kind == tok_keyword ) | |
131 | switch( token->kind2 ) | |
132 | { | |
133 | case key_dup: | |
134 | case key_execonly: | |
135 | case key_readonly: | |
136 | case key_noaccess: | |
137 | case key_userdict: | |
138 | /* do nothing - loop */ | |
139 | goto L1; | |
140 | ||
141 | /* we also translate some other keywords from their alternative */ | |
142 | /* to their `normal' form */ | |
143 | ||
144 | case key_NP_alternate: | |
145 | token->kind2 = key_NP; | |
146 | break; | |
147 | ||
148 | case key_RD_alternate: | |
149 | token->kind2 = key_RD; | |
150 | break; | |
151 | ||
152 | case key_ND_alternate: | |
153 | token->kind2 = key_ND; | |
154 | break; | |
155 | ||
156 | default: | |
157 | ; | |
158 | } | |
159 | ||
160 | #if defined( FT_DEBUG_LEVEL_ERROR ) || defined( FT_DEBUG_LEVEL_TRACE ) | |
161 | ||
162 | /* Dump the token when requested. This feature is only available */ | |
163 | /* in the `error' and `trace' debug levels. */ | |
164 | if ( parser->dump_tokens ) | |
165 | { | |
166 | FT_String temp_string[128]; | |
167 | FT_Int len; | |
168 | ||
169 | ||
170 | len = token->len; | |
171 | if ( len > 127 ) | |
172 | len = 127; | |
173 | strncpy( temp_string, | |
174 | (FT_String*)tokzer->base + token->start, | |
175 | len ); | |
176 | temp_string[len] = '\0'; | |
177 | FT_ERROR(( "%s\n", temp_string )); | |
178 | } | |
179 | ||
180 | #endif /* FT_DEBUG_LEVEL_ERROR or FT_DEBUG_LEVEL_TRACE */ | |
181 | ||
182 | return T1_Err_Ok; | |
183 | } | |
184 | ||
185 | ||
186 | static | |
187 | FT_Error Expect_Keyword( T1_Parser* parser, | |
188 | T1_TokenType keyword ) | |
189 | { | |
190 | T1_Token token; | |
191 | FT_Error error; | |
192 | ||
193 | ||
194 | error = Next_T1_Token( parser, &token ); | |
195 | if ( error ) | |
196 | goto Exit; | |
197 | ||
198 | if ( token.kind != tok_keyword || | |
199 | token.kind2 != keyword ) | |
200 | { | |
201 | error = T1_Err_Syntax_Error; | |
202 | FT_ERROR(( "Expect_Keyword: keyword `%s' expected.\n", | |
203 | t1_keywords[keyword - key_first_] )); | |
204 | } | |
205 | ||
206 | Exit: | |
207 | return error; | |
208 | } | |
209 | ||
210 | ||
211 | static | |
212 | FT_Error Expect_Keyword2( T1_Parser* parser, | |
213 | T1_TokenType keyword1, | |
214 | T1_TokenType keyword2 ) | |
215 | { | |
216 | T1_Token token; | |
217 | FT_Error error; | |
218 | ||
219 | ||
220 | error = Next_T1_Token( parser, &token ); | |
221 | if ( error ) | |
222 | goto Exit; | |
223 | ||
224 | if ( token.kind != tok_keyword || | |
225 | ( token.kind2 != keyword1 && | |
226 | token.kind2 != keyword2 ) ) | |
227 | { | |
228 | error = T1_Err_Syntax_Error; | |
229 | FT_ERROR(( "Expect_Keyword2: keyword `%s' or `%s' expected.\n", | |
230 | t1_keywords[keyword1 - key_first_], | |
231 | t1_keywords[keyword2 - key_first_] )); | |
232 | } | |
233 | ||
234 | Exit: | |
235 | return error; | |
236 | } | |
237 | ||
238 | ||
239 | static | |
240 | void Parse_Encoding( T1_Parser* parser ) | |
241 | { | |
242 | T1_Token* token = parser->top+1; | |
243 | FT_Memory memory = parser->face->root.memory; | |
244 | T1_Encoding* encode = &parser->face->type1.encoding; | |
245 | FT_Error error = 0; | |
246 | ||
247 | ||
248 | if ( token->kind == tok_keyword && | |
249 | ( token->kind2 == key_StandardEncoding || | |
250 | token->kind2 == key_ExpertEncoding ) ) | |
251 | { | |
252 | encode->num_chars = 256; | |
253 | encode->code_first = 32; | |
254 | encode->code_last = 255; | |
255 | ||
256 | if ( ALLOC_ARRAY( encode->char_index, 256, FT_Short ) ) | |
257 | goto Exit; | |
258 | ||
259 | encode->char_name = 0; /* no need to store glyph names */ | |
260 | ||
261 | /* Now copy the encoding */ | |
262 | switch ( token->kind2 ) | |
263 | { | |
264 | case key_ExpertEncoding: | |
265 | parser->encoding_type = t1_encoding_expert; | |
266 | break; | |
267 | ||
268 | default: | |
269 | parser->encoding_type = t1_encoding_standard; | |
270 | break; | |
271 | } | |
272 | } | |
273 | else | |
274 | { | |
275 | FT_ERROR(( "Parse_Encoding: invalid encoding type\n" )); | |
276 | error = T1_Err_Syntax_Error; | |
277 | } | |
278 | ||
279 | Exit: | |
280 | parser->error = error; | |
281 | } | |
282 | ||
283 | ||
284 | /*************************************************************************/ | |
285 | /* */ | |
286 | /* */ | |
287 | /* IMPLEMENTATION OF THE `DEF' KEYWORD DEPENDING ON */ | |
288 | /* CURRENT DICTIONARY STATE */ | |
289 | /* */ | |
290 | /* */ | |
291 | /*************************************************************************/ | |
292 | ||
293 | ||
294 | /*************************************************************************/ | |
295 | /* */ | |
296 | /* <Function> */ | |
297 | /* Do_Def_Font */ | |
298 | /* */ | |
299 | /* <Description> */ | |
300 | /* This function performs a `def' if in the Font dictionary. Its */ | |
301 | /* purpose is to build the T1_Face attributes directly from the */ | |
302 | /* stream. */ | |
303 | /* */ | |
304 | /* <InOut> */ | |
305 | /* parser :: A handle to the current parser. */ | |
306 | /* */ | |
307 | /* <Return> */ | |
308 | /* FreeType error code. 0 means success. */ | |
309 | /* */ | |
310 | static | |
311 | FT_Error Do_Def_Font( T1_Parser* parser ) | |
312 | { | |
313 | T1_Token* top = parser->top; | |
314 | T1_Face face = parser->face; | |
315 | T1_Font* type1 = &face->type1; | |
316 | ||
317 | ||
318 | switch ( top[0].kind2 ) | |
319 | { | |
320 | case imm_FontName: | |
321 | /* in some cases, the /FontName is an immediate like */ | |
322 | /* /TimesNewRoman. In this case, we simply copy the */ | |
323 | /* token string (without the /). */ | |
324 | if ( top[1].kind == tok_immediate ) | |
325 | { | |
326 | FT_Memory memory = parser->tokenizer->memory; | |
327 | FT_Error error; | |
328 | FT_Int len = top[1].len; | |
329 | ||
330 | ||
331 | if ( ALLOC( type1->font_name, len + 1 ) ) | |
332 | { | |
333 | parser->error = error; | |
334 | return error; | |
335 | } | |
336 | ||
337 | MEM_Copy( type1->font_name, | |
338 | parser->tokenizer->base + top[1].start, | |
339 | len ); | |
340 | type1->font_name[len] = '\0'; | |
341 | } | |
342 | else | |
343 | type1->font_name = CopyString( parser ); | |
344 | break; | |
345 | ||
346 | case imm_Encoding: | |
347 | Parse_Encoding( parser ); | |
348 | break; | |
349 | ||
350 | case imm_PaintType: | |
351 | type1->paint_type = (FT_Byte)CopyInteger( parser ); | |
352 | break; | |
353 | ||
354 | case imm_FontType: | |
355 | type1->font_type = (FT_Byte)CopyInteger( parser ); | |
356 | break; | |
357 | ||
358 | case imm_FontMatrix: | |
359 | CopyMatrix( parser, &type1->font_matrix ); | |
360 | break; | |
361 | ||
362 | case imm_FontBBox: | |
363 | CopyBBox( parser, &type1->font_bbox ); | |
364 | break; | |
365 | ||
366 | case imm_UniqueID: | |
367 | type1->private_dict.unique_id = CopyInteger( parser ); | |
368 | break; | |
369 | ||
370 | case imm_StrokeWidth: | |
371 | type1->stroke_width = CopyInteger( parser ); | |
372 | break; | |
373 | ||
374 | case imm_FontID: | |
375 | type1->font_id = CopyInteger( parser ); | |
376 | break; | |
377 | ||
378 | default: | |
379 | /* ignore all other things */ | |
380 | parser->error = T1_Err_Ok; | |
381 | } | |
382 | ||
383 | return parser->error; | |
384 | } | |
385 | ||
386 | ||
387 | /*************************************************************************/ | |
388 | /* */ | |
389 | /* <Function> */ | |
390 | /* Do_Def_FontInfo */ | |
391 | /* */ | |
392 | /* <Description> */ | |
393 | /* This function performs a `def' if in the FontInfo dictionary. Its */ | |
394 | /* purpose is to build the T1_FontInfo structure directly from the */ | |
395 | /* stream. */ | |
396 | /* */ | |
397 | /* <InOut> */ | |
398 | /* parser :: A handle to the current parser. */ | |
399 | /* */ | |
400 | /* <Return> */ | |
401 | /* FreeTyoe error code. 0 means success. */ | |
402 | /* */ | |
403 | static | |
404 | FT_Error Do_Def_FontInfo( T1_Parser* parser ) | |
405 | { | |
406 | T1_Token* top = parser->top; | |
407 | T1_FontInfo* info = &parser->face->type1.font_info; | |
408 | ||
409 | ||
410 | switch ( top[0].kind2 ) | |
411 | { | |
412 | case imm_version: | |
413 | info->version = CopyString( parser ); | |
414 | break; | |
415 | ||
416 | case imm_Notice: | |
417 | info->notice = CopyString( parser ); | |
418 | break; | |
419 | ||
420 | case imm_FullName: | |
421 | info->full_name = CopyString( parser ); | |
422 | break; | |
423 | ||
424 | case imm_FamilyName: | |
425 | info->family_name = CopyString( parser ); | |
426 | break; | |
427 | ||
428 | case imm_Weight: | |
429 | info->weight = CopyString( parser ); | |
430 | break; | |
431 | ||
432 | case imm_ItalicAngle: | |
433 | info->italic_angle = CopyInteger( parser ); | |
434 | break; | |
435 | ||
436 | case imm_isFixedPitch: | |
437 | info->is_fixed_pitch = CopyBoolean( parser ); | |
438 | break; | |
439 | ||
440 | case imm_UnderlinePosition: | |
441 | info->underline_position = (FT_Short)CopyInteger( parser ); | |
442 | break; | |
443 | ||
444 | case imm_UnderlineThickness: | |
445 | info->underline_thickness = (FT_Short)CopyInteger( parser ); | |
446 | break; | |
447 | ||
448 | default: | |
449 | /* ignore all other things */ | |
450 | parser->error = T1_Err_Ok; | |
451 | } | |
452 | ||
453 | return parser->error; | |
454 | } | |
455 | ||
456 | ||
457 | /*************************************************************************/ | |
458 | /* */ | |
459 | /* <Function> */ | |
460 | /* Do_Def_Private */ | |
461 | /* */ | |
462 | /* <Description> */ | |
463 | /* This function performs a `def' if in the Private dictionary. Its */ | |
464 | /* purpose is to build the T1_Private structure directly from the */ | |
465 | /* stream. */ | |
466 | /* */ | |
467 | /* <InOut> */ | |
468 | /* parser :: A handle to the current parser. */ | |
469 | /* */ | |
470 | /* <Return> */ | |
471 | /* FreeTyoe error code. 0 means success. */ | |
472 | /* */ | |
473 | static | |
474 | FT_Error Do_Def_Private( T1_Parser* parser ) | |
475 | { | |
476 | T1_Token* top = parser->top; | |
477 | T1_Private* priv = &parser->face->type1.private_dict; | |
478 | ||
479 | ||
480 | switch ( top[0].kind2 ) | |
481 | { | |
482 | /* Ignore the definitions of RD, NP, ND, and their alternate forms */ | |
483 | case imm_RD: | |
484 | case imm_RD_alternate: | |
485 | case imm_ND: | |
486 | case imm_ND_alternate: | |
487 | case imm_NP: | |
488 | case imm_NP_alternate: | |
489 | parser->error = T1_Err_Ok; | |
490 | break; | |
491 | ||
492 | case imm_BlueValues: | |
493 | CopyArray( parser, &priv->num_blue_values, | |
494 | priv->blue_values, 14 ); | |
495 | break; | |
496 | ||
497 | case imm_OtherBlues: | |
498 | CopyArray( parser, &priv->num_other_blues, | |
499 | priv->other_blues, 10 ); | |
500 | break; | |
501 | ||
502 | case imm_FamilyBlues: | |
503 | CopyArray( parser, &priv->num_family_blues, | |
504 | priv->family_blues, 14 ); | |
505 | break; | |
506 | ||
507 | case imm_FamilyOtherBlues: | |
508 | CopyArray( parser, &priv->num_family_other_blues, | |
509 | priv->family_other_blues, 10 ); | |
510 | break; | |
511 | ||
512 | case imm_BlueScale: | |
513 | priv->blue_scale = CopyFloat( parser, 0x10000L ); | |
514 | break; | |
515 | ||
516 | case imm_BlueShift: | |
517 | priv->blue_shift = CopyInteger( parser ); | |
518 | break; | |
519 | ||
520 | case imm_BlueFuzz: | |
521 | priv->blue_fuzz = CopyInteger( parser ); | |
522 | break; | |
523 | ||
524 | case imm_StdHW: | |
525 | CopyArray( parser, 0, (FT_Short*)&priv->standard_width, 1 ); | |
526 | break; | |
527 | ||
528 | case imm_StdVW: | |
529 | CopyArray( parser, 0, (FT_Short*)&priv->standard_height, 1 ); | |
530 | break; | |
531 | ||
532 | case imm_StemSnapH: | |
533 | CopyArray( parser, &priv->num_snap_widths, | |
534 | priv->snap_widths, 12 ); | |
535 | break; | |
536 | ||
537 | case imm_StemSnapV: | |
538 | CopyArray( parser, &priv->num_snap_heights, | |
539 | priv->snap_heights, 12 ); | |
540 | break; | |
541 | ||
542 | case imm_ForceBold: | |
543 | priv->force_bold = CopyBoolean( parser ); | |
544 | break; | |
545 | ||
546 | case imm_LanguageGroup: | |
547 | priv->language_group = CopyInteger( parser ); | |
548 | break; | |
549 | ||
550 | case imm_password: | |
551 | priv->password = CopyInteger( parser ); | |
552 | break; | |
553 | ||
554 | case imm_UniqueID: | |
555 | priv->unique_id = CopyInteger( parser ); | |
556 | break; | |
557 | ||
558 | case imm_lenIV: | |
559 | priv->lenIV = CopyInteger( parser ); | |
560 | break; | |
561 | ||
562 | case imm_MinFeature: | |
563 | CopyArray( parser, 0, priv->min_feature, 2 ); | |
564 | break; | |
565 | ||
566 | default: | |
567 | /* ignore all other things */ | |
568 | parser->error = T1_Err_Ok; | |
569 | } | |
570 | ||
571 | return parser->error; | |
572 | } | |
573 | ||
574 | ||
575 | /*************************************************************************/ | |
576 | /* */ | |
577 | /* <Function> */ | |
578 | /* Do_Def_Error */ | |
579 | /* */ | |
580 | /* <Description> */ | |
581 | /* This function returns a simple syntax error when invoked. It is */ | |
582 | /* used for the `def' keyword if in the `encoding', `subrs', */ | |
583 | /* `othersubrs', and `charstrings' dictionary states. */ | |
584 | /* */ | |
585 | /* <InOut> */ | |
586 | /* parser :: A handle to the current parser. */ | |
587 | /* */ | |
588 | /* <Return> */ | |
589 | /* FreeType error code. 0 means success. */ | |
590 | /* */ | |
591 | static | |
592 | FT_Error Do_Def_Error( T1_Parser* parser ) | |
593 | { | |
594 | FT_ERROR(( "Do_Def_Error:" )); | |
595 | FT_ERROR(( " `def' keyword encountered in bad dictionary/array\n" )); | |
596 | ||
597 | parser->error = T1_Err_Syntax_Error; | |
598 | ||
599 | return parser->error; | |
600 | } | |
601 | ||
602 | ||
603 | static | |
604 | FT_Error Do_Def_Ignore( T1_Parser* parser ) | |
605 | { | |
606 | FT_UNUSED( parser ); | |
607 | return T1_Err_Ok; | |
608 | } | |
609 | ||
610 | ||
611 | static | |
612 | T1_Parse_Func def_funcs[dict_max] = | |
613 | { | |
614 | Do_Def_Error, | |
615 | Do_Def_Font, | |
616 | Do_Def_FontInfo, | |
617 | Do_Def_Ignore, | |
618 | Do_Def_Private, | |
619 | Do_Def_Ignore, | |
620 | Do_Def_Ignore, | |
621 | Do_Def_Ignore, | |
622 | Do_Def_Ignore, | |
623 | Do_Def_Ignore, | |
624 | Do_Def_Ignore, | |
625 | }; | |
626 | ||
627 | ||
628 | /*************************************************************************/ | |
629 | /* */ | |
630 | /* */ | |
631 | /* IMPLEMENTATION OF THE `PUT' KEYWORD DEPENDING ON */ | |
632 | /* CURRENT DICTIONARY STATE */ | |
633 | /* */ | |
634 | /* */ | |
635 | /*************************************************************************/ | |
636 | ||
637 | ||
638 | /*************************************************************************/ | |
639 | /* */ | |
640 | /* <Function> */ | |
641 | /* Do_Put_Encoding */ | |
642 | /* */ | |
643 | /* <Description> */ | |
644 | /* This function performs a `put' if in the Encoding array. The */ | |
645 | /* glyph name is copied into the T1 recorder, and the charcode and */ | |
646 | /* glyph name pointer are written into the face object encoding. */ | |
647 | /* */ | |
648 | /* <InOut> */ | |
649 | /* parser :: A handle to the current parser. */ | |
650 | /* */ | |
651 | /* <Return> */ | |
652 | /* FreeType error code. 0 means success. */ | |
653 | /* */ | |
654 | static | |
655 | FT_Error Do_Put_Encoding( T1_Parser* parser ) | |
656 | { | |
657 | FT_Error error = T1_Err_Ok; | |
658 | T1_Face face = parser->face; | |
659 | T1_Token* top = parser->top; | |
660 | T1_Encoding* encode = &face->type1.encoding; | |
661 | FT_Int index; | |
662 | ||
663 | ||
664 | /* record and check the character code */ | |
665 | if ( top[0].kind != tok_number ) | |
666 | { | |
667 | FT_TRACE4(( "Do_Put_Encoding: number expected\n" )); | |
668 | goto Syntax_Error; | |
669 | } | |
670 | index = (FT_Int)CopyInteger( parser ); | |
671 | if ( parser->error ) | |
672 | return parser->error; | |
673 | ||
674 | if ( index < 0 || index >= encode->num_chars ) | |
675 | { | |
676 | FT_TRACE4(( "Do_Put_Encoding: invalid character code\n" )); | |
677 | goto Syntax_Error; | |
678 | } | |
679 | ||
680 | /* record the immediate name */ | |
681 | if ( top[1].kind != tok_immediate ) | |
682 | { | |
683 | FT_TRACE4(( "Do_Put_Encoding: immediate name expected\n" )); | |
684 | goto Syntax_Error; | |
685 | } | |
686 | ||
687 | /* if the glyph name is `.notdef', store a NULL char name; */ | |
688 | /* otherwise, record the glyph name */ | |
689 | if ( top[1].kind == imm_notdef ) | |
690 | { | |
691 | parser->table.elements[index] = 0; | |
692 | parser->table.lengths [index] = 0; | |
693 | } | |
694 | else | |
695 | { | |
696 | FT_String temp_name[128]; | |
697 | T1_Token* token = top + 1; | |
698 | FT_Int len = token->len - 1; | |
699 | ||
700 | ||
701 | /* copy immediate name */ | |
702 | if ( len > 127 ) | |
703 | len = 127; | |
704 | MEM_Copy( temp_name, parser->tokenizer->base + token->start + 1, len ); | |
705 | temp_name[len] = '\0'; | |
706 | ||
707 | error = T1_Add_Table( &parser->table, index, | |
708 | (FT_Byte*)temp_name, len + 1 ); | |
709 | ||
710 | /* adjust code_first and code_last */ | |
711 | if ( index < encode->code_first ) encode->code_first = index; | |
712 | if ( index > encode->code_last ) encode->code_last = index; | |
713 | } | |
714 | return error; | |
715 | ||
716 | Syntax_Error: | |
717 | /* ignore the error, and simply clear the stack */ | |
718 | FT_TRACE4(( "Do_Put_Encoding: invalid syntax encountered\n" )); | |
719 | parser->top = parser->stack; | |
720 | ||
721 | return T1_Err_Ok; | |
722 | } | |
723 | ||
724 | ||
725 | /*************************************************************************/ | |
726 | /* */ | |
727 | /* */ | |
728 | /* IMPLEMENTATION OF THE "RD" KEYWORD DEPENDING ON */ | |
729 | /* CURRENT DICTIONARY STATE */ | |
730 | /* */ | |
731 | /* */ | |
732 | /*************************************************************************/ | |
733 | ||
734 | ||
735 | /*************************************************************************/ | |
736 | /* */ | |
737 | /* <Function> */ | |
738 | /* Do_RD_Subrs */ | |
739 | /* */ | |
740 | /* <Description> */ | |
741 | /* This function performs an `RD' if in the Subrs dictionary. It */ | |
742 | /* simply records the array of bytecodes/charstrings corresponding to */ | |
743 | /* the sub-routine. */ | |
744 | /* */ | |
745 | /* <InOut> */ | |
746 | /* parser :: A handle to the current parser. */ | |
747 | /* */ | |
748 | /* <Return> */ | |
749 | /* FreeType error code. 0 means success. */ | |
750 | /* */ | |
751 | static | |
752 | FT_Error Do_RD_Subrs( T1_Parser* parser ) | |
753 | { | |
754 | FT_Error error = T1_Err_Ok; | |
755 | T1_Face face = parser->face; | |
756 | T1_Token* top = parser->top; | |
757 | T1_Tokenizer tokzer = parser->tokenizer; | |
758 | FT_Int index, count; | |
759 | ||
760 | ||
761 | /* record and check the character code */ | |
762 | if ( top[0].kind != tok_number || | |
763 | top[1].kind != tok_number ) | |
764 | { | |
765 | FT_ERROR(( "Do_RD_Subrs: number expected\n" )); | |
766 | goto Syntax_Error; | |
767 | } | |
768 | index = (FT_Int)CopyInteger( parser ); | |
769 | error = parser->error; | |
770 | if ( error ) | |
771 | goto Exit; | |
772 | ||
773 | count = (FT_Int)CopyInteger( parser ); | |
774 | error = parser->error; | |
775 | if ( error ) | |
776 | goto Exit; | |
777 | ||
778 | if ( index < 0 || index >= face->type1.num_subrs ) | |
779 | { | |
780 | FT_ERROR(( "Do_RD_Subrs: invalid character code\n" )); | |
781 | goto Syntax_Error; | |
782 | } | |
783 | ||
784 | /* decrypt charstring and skip it */ | |
785 | { | |
786 | FT_Byte* base = tokzer->base + tokzer->cursor; | |
787 | ||
788 | ||
789 | tokzer->cursor += count; | |
790 | ||
791 | /* some fonts use a value of -1 for lenIV to indicate that */ | |
792 | /* the charstrings are unencoded. */ | |
793 | /* */ | |
794 | /* Thanks to Tom Kacvinsky for pointing this out. */ | |
795 | /* */ | |
796 | if ( face->type1.private_dict.lenIV >= 0 ) | |
797 | { | |
798 | t1_decrypt( base, count, 4330 ); | |
799 | ||
800 | base += face->type1.private_dict.lenIV; | |
801 | count -= face->type1.private_dict.lenIV; | |
802 | } | |
803 | ||
804 | error = T1_Add_Table( &parser->table, index, base, count ); | |
805 | } | |
806 | ||
807 | /* consume the closing NP or `put' */ | |
808 | error = Expect_Keyword2( parser, key_NP, key_put ); | |
809 | ||
810 | Exit: | |
811 | return error; | |
812 | ||
813 | Syntax_Error: | |
814 | return T1_Err_Syntax_Error; | |
815 | } | |
816 | ||
817 | ||
818 | /*************************************************************************/ | |
819 | /* */ | |
820 | /* <Function> */ | |
821 | /* Do_RD_CharStrings */ | |
822 | /* */ | |
823 | /* <Description> */ | |
824 | /* This function performs an `RD' if in the CharStrings dictionary. */ | |
825 | /* It simply records the array of bytecodes/charstrings corresponding */ | |
826 | /* to the glyph program string. */ | |
827 | /* */ | |
828 | /* <InOut> */ | |
829 | /* parser :: A handle to the current parser. */ | |
830 | /* */ | |
831 | /* <Return> */ | |
832 | /* FreeType error code. 0 means success. */ | |
833 | /* */ | |
834 | static | |
835 | FT_Error Do_RD_Charstrings( T1_Parser* parser ) | |
836 | { | |
837 | FT_Error error = T1_Err_Ok; | |
838 | T1_Face face = parser->face; | |
839 | T1_Token* top = parser->top; | |
840 | T1_Tokenizer tokzer = parser->tokenizer; | |
841 | FT_Int index, count; | |
842 | ||
843 | ||
844 | /* check the character name argument */ | |
845 | if ( top[0].kind != tok_immediate ) | |
846 | { | |
847 | FT_ERROR(( "Do_RD_Charstrings: immediate character name expected\n" )); | |
848 | goto Syntax_Error; | |
849 | } | |
850 | ||
851 | /* check the count argument */ | |
852 | if ( top[1].kind != tok_number ) | |
853 | { | |
854 | FT_ERROR(( "Do_RD_Charstrings: number expected\n" )); | |
855 | goto Syntax_Error; | |
856 | } | |
857 | ||
858 | parser->args++; | |
859 | count = (FT_Int)CopyInteger( parser ); | |
860 | error = parser->error; | |
861 | if ( error ) | |
862 | goto Exit; | |
863 | ||
864 | /* record the glyph name and get the corresponding glyph index */ | |
865 | if ( top[0].kind2 == imm_notdef ) | |
866 | index = 0; | |
867 | else | |
868 | { | |
869 | FT_String temp_name[128]; | |
870 | T1_Token* token = top; | |
871 | FT_Int len = token->len - 1; | |
872 | ||
873 | ||
874 | /* copy immediate name */ | |
875 | if ( len > 127 ) | |
876 | len = 127; | |
877 | MEM_Copy( temp_name, parser->tokenizer->base + token->start + 1, len ); | |
878 | temp_name[len] = '\0'; | |
879 | ||
880 | index = parser->cur_name++; | |
881 | error = T1_Add_Table( &parser->table, index * 2, | |
882 | (FT_Byte*)temp_name, len + 1 ); | |
883 | if ( error ) | |
884 | goto Exit; | |
885 | } | |
886 | ||
887 | /* decrypt and record charstring, then skip them */ | |
888 | { | |
889 | FT_Byte* base = tokzer->base + tokzer->cursor; | |
890 | ||
891 | ||
892 | tokzer->cursor += count; /* skip */ | |
893 | ||
894 | if ( face->type1.private_dict.lenIV >= 0 ) | |
895 | { | |
896 | t1_decrypt( base, count, 4330 ); | |
897 | ||
898 | base += face->type1.private_dict.lenIV; | |
899 | count -= face->type1.private_dict.lenIV; | |
900 | } | |
901 | ||
902 | error = T1_Add_Table( &parser->table, index * 2 + 1, base, count ); | |
903 | } | |
904 | ||
905 | /* consume the closing `ND' */ | |
906 | if ( !error ) | |
907 | error = Expect_Keyword( parser, key_ND ); | |
908 | ||
909 | Exit: | |
910 | return error; | |
911 | ||
912 | Syntax_Error: | |
913 | return T1_Err_Syntax_Error; | |
914 | } | |
915 | ||
916 | ||
917 | static | |
918 | FT_Error Expect_Dict_Arguments( T1_Parser* parser, | |
919 | FT_Int num_args, | |
920 | T1_TokenType immediate, | |
921 | T1_DictState new_state, | |
922 | FT_Int* count ) | |
923 | { | |
924 | /* check that we have enough arguments in the stack, including */ | |
925 | /* the `dict' keyword */ | |
926 | if ( parser->top - parser->stack < num_args ) | |
927 | { | |
928 | FT_ERROR(( "Expect_Dict_Arguments: expecting at least %d arguments", | |
929 | num_args )); | |
930 | goto Syntax_Error; | |
931 | } | |
932 | ||
933 | /* check that we have the correct immediate, if needed */ | |
934 | if ( num_args == 2 ) | |
935 | { | |
936 | if ( parser->top[-2].kind != tok_immediate || | |
937 | parser->top[-2].kind2 != immediate ) | |
938 | { | |
939 | FT_ERROR(( "Expect_Dict_Arguments: expecting `/%s' dictionary\n", | |
940 | t1_immediates[immediate - imm_first_] )); | |
941 | goto Syntax_Error; | |
942 | } | |
943 | } | |
944 | ||
945 | parser->args = parser->top-1; | |
946 | ||
947 | /* check that the count argument is a number */ | |
948 | if ( parser->args->kind != tok_number ) | |
949 | { | |
950 | FT_ERROR(( "Expect_Dict_Arguments:" )); | |
951 | FT_ERROR(( " expecting numerical count argument for `dict'\n" )); | |
952 | goto Syntax_Error; | |
953 | } | |
954 | ||
955 | if ( count ) | |
956 | { | |
957 | *count = CopyInteger( parser ); | |
958 | if ( parser->error ) | |
959 | return parser->error; | |
960 | } | |
961 | ||
962 | /* save the dictionary state */ | |
963 | parser->state_stack[++parser->state_index] = new_state; | |
964 | ||
965 | /* consume the `begin' keyword and clear the stack */ | |
966 | parser->top -= num_args; | |
967 | return Expect_Keyword( parser, key_begin ); | |
968 | ||
969 | Syntax_Error: | |
970 | return T1_Err_Syntax_Error; | |
971 | } | |
972 | ||
973 | ||
974 | static | |
975 | FT_Error Expect_Array_Arguments( T1_Parser* parser ) | |
976 | { | |
977 | T1_Token* top = parser->top; | |
978 | FT_Error error = T1_Err_Ok; | |
979 | T1_DictState new_state; | |
980 | FT_Int count; | |
981 | T1_Face face = parser->face; | |
982 | FT_Memory memory = face->root.memory; | |
983 | ||
984 | ||
985 | /* Check arguments format */ | |
986 | if ( top - parser->stack < 2 ) | |
987 | { | |
988 | FT_ERROR(( "Expect_Array_Arguments: two arguments expected\n" )); | |
989 | error = T1_Err_Stack_Underflow; | |
990 | goto Exit; | |
991 | } | |
992 | ||
993 | parser->top -= 2; | |
994 | top -= 2; | |
995 | parser->args = top + 1; | |
996 | ||
997 | if ( top[0].kind != tok_immediate ) | |
998 | { | |
999 | FT_ERROR(( "Expect_Array_Arguments:" )); | |
1000 | FT_ERROR(( " first argument must be an immediate name\n" )); | |
1001 | goto Syntax_Error; | |
1002 | } | |
1003 | ||
1004 | if ( top[1].kind != tok_number ) | |
1005 | { | |
1006 | FT_ERROR(( "Expect_Array_Arguments:" )); | |
1007 | FT_ERROR(( " second argument must be a number\n" )); | |
1008 | goto Syntax_Error; | |
1009 | } | |
1010 | ||
1011 | count = (FT_Int)CopyInteger( parser ); | |
1012 | ||
1013 | /* Is this an array we know about? */ | |
1014 | switch ( top[0].kind2 ) | |
1015 | { | |
1016 | case imm_Encoding: | |
1017 | { | |
1018 | T1_Encoding* encode = &face->type1.encoding; | |
1019 | ||
1020 | ||
1021 | new_state = dict_encoding; | |
1022 | ||
1023 | encode->code_first = count; | |
1024 | encode->code_last = 0; | |
1025 | encode->num_chars = count; | |
1026 | ||
1027 | /* Allocate the table of character indices. The table of */ | |
1028 | /* character names is allocated through init_t1_recorder(). */ | |
1029 | if ( ALLOC_ARRAY( encode->char_index, count, FT_Short ) ) | |
1030 | return error; | |
1031 | ||
1032 | error = T1_New_Table( &parser->table, count, memory ); | |
1033 | if ( error ) | |
1034 | goto Exit; | |
1035 | ||
1036 | parser->encoding_type = t1_encoding_array; | |
1037 | } | |
1038 | break; | |
1039 | ||
1040 | case imm_Subrs: | |
1041 | new_state = dict_subrs; | |
1042 | face->type1.num_subrs = count; | |
1043 | ||
1044 | error = T1_New_Table( &parser->table, count, memory ); | |
1045 | if ( error ) | |
1046 | goto Exit; | |
1047 | break; | |
1048 | ||
1049 | case imm_CharStrings: | |
1050 | new_state = dict_charstrings; | |
1051 | break; | |
1052 | ||
1053 | default: | |
1054 | new_state = dict_unknown_array; | |
1055 | } | |
1056 | ||
1057 | parser->state_stack[++parser->state_index] = new_state; | |
1058 | ||
1059 | Exit: | |
1060 | return error; | |
1061 | ||
1062 | Syntax_Error: | |
1063 | return T1_Err_Syntax_Error; | |
1064 | } | |
1065 | ||
1066 | ||
1067 | static | |
1068 | FT_Error Finalize_Parsing( T1_Parser* parser ) | |
1069 | { | |
1070 | T1_Face face = parser->face; | |
1071 | T1_Font* type1 = &face->type1; | |
1072 | FT_Memory memory = face->root.memory; | |
1073 | T1_Table* strings = &parser->table; | |
1074 | PSNames_Interface* psnames = (PSNames_Interface*)face->psnames; | |
1075 | ||
1076 | FT_Int num_glyphs; | |
1077 | FT_Int n; | |
1078 | FT_Error error; | |
1079 | ||
1080 | ||
1081 | num_glyphs = type1->num_glyphs = parser->cur_name; | |
1082 | ||
1083 | /* allocate glyph names and charstrings arrays */ | |
1084 | if ( ALLOC_ARRAY( type1->glyph_names, num_glyphs, FT_String* ) || | |
1085 | ALLOC_ARRAY( type1->charstrings, num_glyphs, FT_Byte* ) || | |
1086 | ALLOC_ARRAY( type1->charstrings_len, num_glyphs, FT_Int* ) ) | |
1087 | return error; | |
1088 | ||
1089 | /* copy glyph names and charstrings offsets and lengths */ | |
1090 | type1->charstrings_block = strings->block; | |
1091 | for ( n = 0; n < num_glyphs; n++ ) | |
1092 | { | |
1093 | type1->glyph_names[n] = (FT_String*)strings->elements[2 * n]; | |
1094 | type1->charstrings[n] = strings->elements[2 * n + 1]; | |
1095 | type1->charstrings_len[n] = strings->lengths [2 * n + 1]; | |
1096 | } | |
1097 | ||
1098 | /* now free the old tables */ | |
1099 | FREE( strings->elements ); | |
1100 | FREE( strings->lengths ); | |
1101 | ||
1102 | if ( !psnames ) | |
1103 | { | |
1104 | FT_ERROR(( "Finalize_Parsing: `PSNames' module missing!\n" )); | |
1105 | return T1_Err_Unimplemented_Feature; | |
1106 | } | |
1107 | ||
1108 | /* compute encoding if required */ | |
1109 | if ( parser->encoding_type == t1_encoding_none ) | |
1110 | { | |
1111 | FT_ERROR(( "Finalize_Parsing: no encoding specified in font file\n" )); | |
1112 | return T1_Err_Syntax_Error; | |
1113 | } | |
1114 | ||
1115 | { | |
1116 | FT_Int n; | |
1117 | T1_Encoding* encode = &type1->encoding; | |
1118 | ||
1119 | ||
1120 | encode->code_first = encode->num_chars - 1; | |
1121 | encode->code_last = 0; | |
1122 | ||
1123 | for ( n = 0; n < encode->num_chars; n++ ) | |
1124 | { | |
1125 | FT_String** names; | |
1126 | FT_Int index; | |
1127 | FT_Int m; | |
1128 | ||
1129 | ||
1130 | switch ( parser->encoding_type ) | |
1131 | { | |
1132 | case t1_encoding_standard: | |
1133 | index = psnames->adobe_std_encoding[n]; | |
1134 | names = 0; | |
1135 | break; | |
1136 | ||
1137 | case t1_encoding_expert: | |
1138 | index = psnames->adobe_expert_encoding[n]; | |
1139 | names = 0; | |
1140 | break; | |
1141 | ||
1142 | default: | |
1143 | index = n; | |
1144 | names = (FT_String**)parser->encoding_offsets; | |
1145 | } | |
1146 | ||
1147 | encode->char_index[n] = 0; | |
1148 | ||
1149 | if ( index ) | |
1150 | { | |
1151 | FT_String* name; | |
1152 | ||
1153 | ||
1154 | if ( names ) | |
1155 | name = names[index]; | |
1156 | else | |
1157 | name = (FT_String*)psnames->adobe_std_strings(index); | |
1158 | ||
1159 | if ( name ) | |
1160 | { | |
1161 | FT_Int len = strlen( name ); | |
1162 | ||
1163 | ||
1164 | /* lookup glyph index from name */ | |
1165 | for ( m = 0; m < num_glyphs; m++ ) | |
1166 | { | |
1167 | if ( strncmp( type1->glyph_names[m], name, len ) == 0 ) | |
1168 | { | |
1169 | encode->char_index[n] = m; | |
1170 | break; | |
1171 | } | |
1172 | } | |
1173 | ||
1174 | if ( n < encode->code_first ) encode->code_first = n; | |
1175 | if ( n > encode->code_last ) encode->code_last = n; | |
1176 | } | |
1177 | } | |
1178 | } | |
1179 | ||
1180 | parser->encoding_type = t1_encoding_none; | |
1181 | ||
1182 | FREE( parser->encoding_names ); | |
1183 | FREE( parser->encoding_lengths ); | |
1184 | FREE( parser->encoding_offsets ); | |
1185 | } | |
1186 | ||
1187 | return T1_Err_Ok; | |
1188 | } | |
1189 | ||
1190 | ||
1191 | /*************************************************************************/ | |
1192 | /* */ | |
1193 | /* <Function> */ | |
1194 | /* Parse_T1_FontProgram */ | |
1195 | /* */ | |
1196 | /* <Description> */ | |
1197 | /* Parses a given Type 1 font file and builds its face object. */ | |
1198 | /* */ | |
1199 | /* <InOut> */ | |
1200 | /* parser :: A handle to the target parser object. */ | |
1201 | /* */ | |
1202 | /* <Return> */ | |
1203 | /* FreeType error code. 0 means success. */ | |
1204 | /* */ | |
1205 | /* <Note> */ | |
1206 | /* The parser contains a handle to the target face object. */ | |
1207 | /* */ | |
1208 | LOCAL_FUNC | |
1209 | FT_Error Parse_T1_FontProgram( T1_Parser* parser ) | |
1210 | { | |
1211 | FT_Error error; | |
1212 | T1_Font* type1 = &parser->face->type1; | |
1213 | ||
1214 | ||
1215 | for (;;) | |
1216 | { | |
1217 | T1_Token token; | |
1218 | T1_Token* top; | |
1219 | T1_DictState dict_state; | |
1220 | FT_Int dict_index; | |
1221 | ||
1222 | ||
1223 | error = Next_T1_Token( parser, &token ); | |
1224 | top = parser->top; | |
1225 | dict_index = parser->state_index; | |
1226 | dict_state = parser->state_stack[dict_index]; | |
1227 | ||
1228 | switch ( token.kind ) | |
1229 | { | |
1230 | /* a keyword has been detected */ | |
1231 | case tok_keyword: | |
1232 | switch ( token.kind2 ) | |
1233 | { | |
1234 | case key_dict: | |
1235 | switch ( dict_state ) | |
1236 | { | |
1237 | case dict_none: | |
1238 | /* All right, we are beginning the font dictionary. */ | |
1239 | /* Check that we only have one number argument, then */ | |
1240 | /* consume the `begin' and change to `dict_font' */ | |
1241 | /* state. */ | |
1242 | error = Expect_Dict_Arguments( parser, 1, tok_error, | |
1243 | dict_font, 0 ); | |
1244 | if ( error ) | |
1245 | goto Exit; | |
1246 | ||
1247 | /* clear stack from all the previous content. This */ | |
1248 | /* could be some stupid Postscript code. */ | |
1249 | parser->top = parser->stack; | |
1250 | break; | |
1251 | ||
1252 | case dict_font: | |
1253 | /* This must be the /FontInfo dictionary, so check */ | |
1254 | /* that we have at least two arguments, that they */ | |
1255 | /* are `/FontInfo' and a number, then change the */ | |
1256 | /* dictionary state. */ | |
1257 | error = Expect_Dict_Arguments( parser, 2, imm_FontInfo, | |
1258 | dict_fontinfo, 0 ); | |
1259 | if ( error ) | |
1260 | goto Exit; | |
1261 | break; | |
1262 | ||
1263 | case dict_none2: | |
1264 | error = Expect_Dict_Arguments( parser, 2, imm_Private, | |
1265 | dict_private, 0 ); | |
1266 | if ( error ) | |
1267 | goto Exit; | |
1268 | break; | |
1269 | ||
1270 | case dict_private: | |
1271 | { | |
1272 | T1_Face face = parser->face; | |
1273 | FT_Int count; | |
1274 | ||
1275 | ||
1276 | error = Expect_Dict_Arguments( parser, 2, imm_CharStrings, | |
1277 | dict_charstrings, &count ); | |
1278 | if ( error ) | |
1279 | goto Exit; | |
1280 | ||
1281 | type1->num_glyphs = count; | |
1282 | error = T1_New_Table( &parser->table, count * 2, | |
1283 | face->root.memory ); | |
1284 | if ( error ) | |
1285 | goto Exit; | |
1286 | ||
1287 | /* record `.notdef' as the first glyph in the font */ | |
1288 | error = T1_Add_Table( &parser->table, 0, | |
1289 | (FT_Byte*)".notdef", 8 ); | |
1290 | parser->cur_name = 1; | |
1291 | /* XXX: DO SOMETHING HERE */ | |
1292 | } | |
1293 | break; | |
1294 | ||
1295 | default: | |
1296 | /* All other uses are invalid */ | |
1297 | FT_ERROR(( "Parse_T1_FontProgram:" )); | |
1298 | FT_ERROR(( " invalid use of `dict' keyword\n" )); | |
1299 | goto Syntax_Error; | |
1300 | } | |
1301 | break; | |
1302 | ||
1303 | case key_array: | |
1304 | /* Are we in an array yet? If so, raise an error */ | |
1305 | switch ( dict_state ) | |
1306 | { | |
1307 | case dict_encoding: | |
1308 | case dict_subrs: | |
1309 | case dict_othersubrs: | |
1310 | case dict_charstrings: | |
1311 | case dict_unknown_array: | |
1312 | FT_ERROR(( "Parse_T1_FontProgram: nested array definitions\n" )); | |
1313 | goto Syntax_Error; | |
1314 | ||
1315 | default: | |
1316 | ; | |
1317 | } | |
1318 | error = Expect_Array_Arguments( parser ); | |
1319 | if ( error ) | |
1320 | goto Exit; | |
1321 | break; | |
1322 | ||
1323 | case key_ND: | |
1324 | case key_NP: | |
1325 | case key_def: | |
1326 | /* Are we in an array? If so, finalize it. */ | |
1327 | switch ( dict_state ) | |
1328 | { | |
1329 | case dict_encoding: /* finish encoding array */ | |
1330 | /* copy table names to the face object */ | |
1331 | T1_Done_Table( &parser->table ); | |
1332 | ||
1333 | parser->encoding_names = parser->table.block; | |
1334 | parser->encoding_lengths = parser->table.lengths; | |
1335 | parser->encoding_offsets = parser->table.elements; | |
1336 | ||
1337 | parser->state_index--; | |
1338 | break; | |
1339 | ||
1340 | case dict_subrs: | |
1341 | /* copy recorder sub-routines */ | |
1342 | T1_Done_Table( &parser->table ); | |
1343 | ||
1344 | parser->subrs = parser->table.block; | |
1345 | type1->subrs = parser->table.elements; | |
1346 | type1->subrs_len = parser->table.lengths; | |
1347 | type1->subrs_block = parser->table.block; | |
1348 | ||
1349 | parser->state_index--; | |
1350 | break; | |
1351 | ||
1352 | case dict_charstrings: | |
1353 | case dict_othersubrs: | |
1354 | case dict_unknown_array: | |
1355 | FT_ERROR(( "Parse_T1_FontProgram: unsupported array\n" )); | |
1356 | goto Syntax_Error; | |
1357 | break; | |
1358 | ||
1359 | default: /* normal `def' processing */ | |
1360 | /* Check that we have sufficient operands in the stack */ | |
1361 | if ( top >= parser->stack + 2 ) | |
1362 | { | |
1363 | /* Now check that the first operand is an immediate. */ | |
1364 | /* If so, call the appropriate `def' routine based */ | |
1365 | /* on the current parser state. */ | |
1366 | if ( top[-2].kind == tok_immediate ) | |
1367 | { | |
1368 | parser->top -= 2; | |
1369 | parser->args = parser->top + 1; | |
1370 | error = def_funcs[dict_state](parser); | |
1371 | } | |
1372 | else | |
1373 | { | |
1374 | /* This is an error, but some fonts contain */ | |
1375 | /* stupid Postscript code. We simply ignore */ | |
1376 | /* an invalid `def' by clearing the stack. */ | |
1377 | #if 0 | |
1378 | FT_ERROR(( "Parse_T1_FontProgram: immediate expected\n" )); | |
1379 | goto Syntax_Error; | |
1380 | #else | |
1381 | parser->top = parser->stack; | |
1382 | #endif | |
1383 | } | |
1384 | } | |
1385 | else | |
1386 | { | |
1387 | FT_ERROR(( "Parse_T1_FontProgram: not enough arguments\n" )); | |
1388 | goto Stack_Underflow; | |
1389 | } | |
1390 | } | |
1391 | break; | |
1392 | ||
1393 | case key_index: | |
1394 | if ( top <= parser->stack ) | |
1395 | { | |
1396 | FT_ERROR(( "Parse_T1_FontProgram: not enough arguments\n" )); | |
1397 | goto Stack_Underflow; | |
1398 | } | |
1399 | ||
1400 | /* simply ignore? */ | |
1401 | parser->top --; | |
1402 | break; | |
1403 | ||
1404 | case key_put: | |
1405 | /* Check that we have sufficient operands in stack */ | |
1406 | if ( top < parser->stack + 2 ) | |
1407 | { | |
1408 | FT_ERROR(( "Parse_T1_FontProgram: not enough arguments\n" )); | |
1409 | goto Stack_Underflow; | |
1410 | } | |
1411 | ||
1412 | parser->top -= 2; | |
1413 | parser->args = parser->top; | |
1414 | ||
1415 | switch ( dict_state ) | |
1416 | { | |
1417 | case dict_encoding: | |
1418 | error = Do_Put_Encoding( parser ); | |
1419 | if ( error ) | |
1420 | goto Exit; | |
1421 | break; | |
1422 | ||
1423 | case dict_unknown_array: /* ignore the `put' */ | |
1424 | break; | |
1425 | ||
1426 | default: | |
1427 | #if 0 | |
1428 | FT_ERROR(( "Parse_T1_FontProgram: invalid context\n" )); | |
1429 | goto Syntax_Error; | |
1430 | #else | |
1431 | /* invalid context; simply ignore the `put' and */ | |
1432 | /* clear the stack (stupid Postscript code) */ | |
1433 | FT_TRACE4(( "Parse_T1_FontProgram: invalid context ignored.\n" )); | |
1434 | parser->top = parser->stack; | |
1435 | #endif | |
1436 | } | |
1437 | break; | |
1438 | ||
1439 | case key_RD: | |
1440 | /* Check that we have sufficient operands in stack */ | |
1441 | if ( top < parser->stack + 2 ) | |
1442 | { | |
1443 | FT_ERROR(( "Parse_T1_FontProgram: not enough arguments\n" )); | |
1444 | goto Stack_Underflow; | |
1445 | } | |
1446 | ||
1447 | parser->top -= 2; | |
1448 | parser->args = parser->top; | |
1449 | switch ( dict_state ) | |
1450 | { | |
1451 | case dict_subrs: | |
1452 | error = Do_RD_Subrs( parser ); | |
1453 | if ( error ) | |
1454 | goto Exit; | |
1455 | break; | |
1456 | ||
1457 | case dict_charstrings: | |
1458 | error = Do_RD_Charstrings( parser ); | |
1459 | if ( error ) | |
1460 | goto Exit; | |
1461 | break; | |
1462 | ||
1463 | default: | |
1464 | FT_ERROR(( "Parse_T1_FontProgram: invalid context\n" )); | |
1465 | goto Syntax_Error; | |
1466 | } | |
1467 | break; | |
1468 | ||
1469 | case key_end: | |
1470 | /* Were we in a dictionary or in an array? */ | |
1471 | if ( dict_index <= 0 ) | |
1472 | { | |
1473 | FT_ERROR(( "Parse_T1_FontProgram: no dictionary defined\n" )); | |
1474 | goto Syntax_Error; | |
1475 | } | |
1476 | ||
1477 | switch ( dict_state ) | |
1478 | { | |
1479 | /* jump to the private dictionary if we are closing the */ | |
1480 | /* `/Font' dictionary */ | |
1481 | case dict_font: | |
1482 | goto Open_Private; | |
1483 | ||
1484 | /* exit the parser when closing the CharStrings dictionary */ | |
1485 | case dict_charstrings: | |
1486 | return Finalize_Parsing( parser ); | |
1487 | ||
1488 | default: | |
1489 | /* Pop the current dictionary state and return to previous */ | |
1490 | /* one. Consume the `def'. */ | |
1491 | ||
1492 | /* Because some buggy fonts (BitStream) have incorrect */ | |
1493 | /* syntax, we never escape from the private dictionary */ | |
1494 | if ( dict_state != dict_private ) | |
1495 | parser->state_index--; | |
1496 | ||
1497 | /* many fonts use `NP' instead of `def' or `put', so */ | |
1498 | /* we simply ignore the next token */ | |
1499 | #if 0 | |
1500 | error = Expect_Keyword2( parser, key_def, key_put ); | |
1501 | if ( error ) | |
1502 | goto Exit; | |
1503 | #else | |
1504 | (void)Expect_Keyword2( parser, key_def, key_put ); | |
1505 | #endif | |
1506 | } | |
1507 | break; | |
1508 | ||
1509 | case key_for: | |
1510 | /* check that we have four arguments and simply */ | |
1511 | /* ignore them */ | |
1512 | if ( top - parser->stack < 4 ) | |
1513 | { | |
1514 | FT_ERROR(( "Parse_T1_FontProgram: not enough arguments\n" )); | |
1515 | goto Stack_Underflow; | |
1516 | } | |
1517 | ||
1518 | parser->top -= 4; | |
1519 | break; | |
1520 | ||
1521 | case key_currentdict: | |
1522 | Open_Private: | |
1523 | parser->state_index = 0; | |
1524 | parser->state_stack[0] = dict_none2; | |
1525 | error = Open_PrivateDict( parser->tokenizer ); | |
1526 | if ( error ) | |
1527 | goto Exit; | |
1528 | break; | |
1529 | ||
1530 | case key_true: | |
1531 | case key_false: | |
1532 | case key_StandardEncoding: | |
1533 | case key_ExpertEncoding: | |
1534 | goto Push_Element; | |
1535 | ||
1536 | default: | |
1537 | FT_ERROR(( "Parse_T1_FontProgram:" )); | |
1538 | FT_ERROR(( " invalid keyword in context\n" )); | |
1539 | error = T1_Err_Syntax_Error; | |
1540 | } | |
1541 | break; | |
1542 | ||
1543 | /* check for the presence of `/BlendAxisTypes' -- we cannot deal */ | |
1544 | /* with multiple master fonts, so we must return a correct error */ | |
1545 | /* code to allow another driver to load them */ | |
1546 | case tok_immediate: | |
1547 | if ( token.kind2 == imm_BlendAxisTypes ) | |
1548 | { | |
1549 | error = FT_Err_Unknown_File_Format; | |
1550 | goto Exit; | |
1551 | } | |
1552 | /* fallthrough */ | |
1553 | ||
1554 | /* A number was detected */ | |
1555 | case tok_string: | |
1556 | case tok_program: | |
1557 | case tok_array: | |
1558 | case tok_hexarray: | |
1559 | case tok_any: | |
1560 | case tok_number: /* push number on stack */ | |
1561 | ||
1562 | Push_Element: | |
1563 | if ( top >= parser->limit ) | |
1564 | { | |
1565 | error = T1_Err_Stack_Overflow; | |
1566 | goto Exit; | |
1567 | } | |
1568 | else | |
1569 | *parser->top++ = token; | |
1570 | break; | |
1571 | ||
1572 | /* anything else is an error per se the spec, but we */ | |
1573 | /* frequently encounter stupid postscript code in fonts, */ | |
1574 | /* so just ignore them */ | |
1575 | default: | |
1576 | error = T1_Err_Ok; /* ignore token */ | |
1577 | } | |
1578 | ||
1579 | if ( error ) | |
1580 | return error; | |
1581 | } | |
1582 | ||
1583 | Exit: | |
1584 | return error; | |
1585 | ||
1586 | Syntax_Error: | |
1587 | return T1_Err_Syntax_Error; | |
1588 | ||
1589 | Stack_Underflow: | |
1590 | return T1_Err_Stack_Underflow; | |
1591 | } | |
1592 | ||
1593 | ||
1594 | /* END */ |