1 /***************************************************************************/ |
|
2 /* */ |
|
3 /* psobjs.c */ |
|
4 /* */ |
|
5 /* Auxiliary functions for PostScript fonts (body). */ |
|
6 /* */ |
|
7 /* Copyright 1996-2011 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 <ft2build.h> |
|
20 #include FT_INTERNAL_POSTSCRIPT_AUX_H |
|
21 #include FT_INTERNAL_DEBUG_H |
|
22 #include FT_INTERNAL_CALC_H |
|
23 |
|
24 #include "psobjs.h" |
|
25 #include "psconv.h" |
|
26 |
|
27 #include "psauxerr.h" |
|
28 |
|
29 |
|
30 /*************************************************************************/ |
|
31 /* */ |
|
32 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ |
|
33 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ |
|
34 /* messages during execution. */ |
|
35 /* */ |
|
36 #undef FT_COMPONENT |
|
37 #define FT_COMPONENT trace_psobjs |
|
38 |
|
39 |
|
40 /*************************************************************************/ |
|
41 /*************************************************************************/ |
|
42 /***** *****/ |
|
43 /***** PS_TABLE *****/ |
|
44 /***** *****/ |
|
45 /*************************************************************************/ |
|
46 /*************************************************************************/ |
|
47 |
|
48 /*************************************************************************/ |
|
49 /* */ |
|
50 /* <Function> */ |
|
51 /* ps_table_new */ |
|
52 /* */ |
|
53 /* <Description> */ |
|
54 /* Initializes a PS_Table. */ |
|
55 /* */ |
|
56 /* <InOut> */ |
|
57 /* table :: The address of the target table. */ |
|
58 /* */ |
|
59 /* <Input> */ |
|
60 /* count :: The table size = the maximum number of elements. */ |
|
61 /* */ |
|
62 /* memory :: The memory object to use for all subsequent */ |
|
63 /* reallocations. */ |
|
64 /* */ |
|
65 /* <Return> */ |
|
66 /* FreeType error code. 0 means success. */ |
|
67 /* */ |
|
68 FT_LOCAL_DEF( FT_Error ) |
|
69 ps_table_new( PS_Table table, |
|
70 FT_Int count, |
|
71 FT_Memory memory ) |
|
72 { |
|
73 FT_Error error; |
|
74 |
|
75 |
|
76 table->memory = memory; |
|
77 if ( FT_NEW_ARRAY( table->elements, count ) || |
|
78 FT_NEW_ARRAY( table->lengths, count ) ) |
|
79 goto Exit; |
|
80 |
|
81 table->max_elems = count; |
|
82 table->init = 0xDEADBEEFUL; |
|
83 table->num_elems = 0; |
|
84 table->block = 0; |
|
85 table->capacity = 0; |
|
86 table->cursor = 0; |
|
87 |
|
88 *(PS_Table_FuncsRec*)&table->funcs = ps_table_funcs; |
|
89 |
|
90 Exit: |
|
91 if ( error ) |
|
92 FT_FREE( table->elements ); |
|
93 |
|
94 return error; |
|
95 } |
|
96 |
|
97 |
|
98 static void |
|
99 shift_elements( PS_Table table, |
|
100 FT_Byte* old_base ) |
|
101 { |
|
102 FT_PtrDist delta = table->block - old_base; |
|
103 FT_Byte** offset = table->elements; |
|
104 FT_Byte** limit = offset + table->max_elems; |
|
105 |
|
106 |
|
107 for ( ; offset < limit; offset++ ) |
|
108 { |
|
109 if ( offset[0] ) |
|
110 offset[0] += delta; |
|
111 } |
|
112 } |
|
113 |
|
114 |
|
115 static FT_Error |
|
116 reallocate_t1_table( PS_Table table, |
|
117 FT_Long new_size ) |
|
118 { |
|
119 FT_Memory memory = table->memory; |
|
120 FT_Byte* old_base = table->block; |
|
121 FT_Error error; |
|
122 |
|
123 |
|
124 /* allocate new base block */ |
|
125 if ( FT_ALLOC( table->block, new_size ) ) |
|
126 { |
|
127 table->block = old_base; |
|
128 return error; |
|
129 } |
|
130 |
|
131 /* copy elements and shift offsets */ |
|
132 if ( old_base ) |
|
133 { |
|
134 FT_MEM_COPY( table->block, old_base, table->capacity ); |
|
135 shift_elements( table, old_base ); |
|
136 FT_FREE( old_base ); |
|
137 } |
|
138 |
|
139 table->capacity = new_size; |
|
140 |
|
141 return PSaux_Err_Ok; |
|
142 } |
|
143 |
|
144 |
|
145 /*************************************************************************/ |
|
146 /* */ |
|
147 /* <Function> */ |
|
148 /* ps_table_add */ |
|
149 /* */ |
|
150 /* <Description> */ |
|
151 /* Adds an object to a PS_Table, possibly growing its memory block. */ |
|
152 /* */ |
|
153 /* <InOut> */ |
|
154 /* table :: The target table. */ |
|
155 /* */ |
|
156 /* <Input> */ |
|
157 /* idx :: The index of the object in the table. */ |
|
158 /* */ |
|
159 /* object :: The address of the object to copy in memory. */ |
|
160 /* */ |
|
161 /* length :: The length in bytes of the source object. */ |
|
162 /* */ |
|
163 /* <Return> */ |
|
164 /* FreeType error code. 0 means success. An error is returned if a */ |
|
165 /* reallocation fails. */ |
|
166 /* */ |
|
167 FT_LOCAL_DEF( FT_Error ) |
|
168 ps_table_add( PS_Table table, |
|
169 FT_Int idx, |
|
170 void* object, |
|
171 FT_PtrDist length ) |
|
172 { |
|
173 if ( idx < 0 || idx >= table->max_elems ) |
|
174 { |
|
175 FT_ERROR(( "ps_table_add: invalid index\n" )); |
|
176 return PSaux_Err_Invalid_Argument; |
|
177 } |
|
178 |
|
179 if ( length < 0 ) |
|
180 { |
|
181 FT_ERROR(( "ps_table_add: invalid length\n" )); |
|
182 return PSaux_Err_Invalid_Argument; |
|
183 } |
|
184 |
|
185 /* grow the base block if needed */ |
|
186 if ( table->cursor + length > table->capacity ) |
|
187 { |
|
188 FT_Error error; |
|
189 FT_Offset new_size = table->capacity; |
|
190 FT_PtrDist in_offset; |
|
191 |
|
192 |
|
193 in_offset = (FT_Byte*)object - table->block; |
|
194 if ( in_offset < 0 || (FT_Offset)in_offset >= table->capacity ) |
|
195 in_offset = -1; |
|
196 |
|
197 while ( new_size < table->cursor + length ) |
|
198 { |
|
199 /* increase size by 25% and round up to the nearest multiple |
|
200 of 1024 */ |
|
201 new_size += ( new_size >> 2 ) + 1; |
|
202 new_size = FT_PAD_CEIL( new_size, 1024 ); |
|
203 } |
|
204 |
|
205 error = reallocate_t1_table( table, new_size ); |
|
206 if ( error ) |
|
207 return error; |
|
208 |
|
209 if ( in_offset >= 0 ) |
|
210 object = table->block + in_offset; |
|
211 } |
|
212 |
|
213 /* add the object to the base block and adjust offset */ |
|
214 table->elements[idx] = table->block + table->cursor; |
|
215 table->lengths [idx] = length; |
|
216 FT_MEM_COPY( table->block + table->cursor, object, length ); |
|
217 |
|
218 table->cursor += length; |
|
219 return PSaux_Err_Ok; |
|
220 } |
|
221 |
|
222 |
|
223 /*************************************************************************/ |
|
224 /* */ |
|
225 /* <Function> */ |
|
226 /* ps_table_done */ |
|
227 /* */ |
|
228 /* <Description> */ |
|
229 /* Finalizes a PS_TableRec (i.e., reallocate it to its current */ |
|
230 /* cursor). */ |
|
231 /* */ |
|
232 /* <InOut> */ |
|
233 /* table :: The target table. */ |
|
234 /* */ |
|
235 /* <Note> */ |
|
236 /* This function does NOT release the heap's memory block. It is up */ |
|
237 /* to the caller to clean it, or reference it in its own structures. */ |
|
238 /* */ |
|
239 FT_LOCAL_DEF( void ) |
|
240 ps_table_done( PS_Table table ) |
|
241 { |
|
242 FT_Memory memory = table->memory; |
|
243 FT_Error error; |
|
244 FT_Byte* old_base = table->block; |
|
245 |
|
246 |
|
247 /* should never fail, because rec.cursor <= rec.size */ |
|
248 if ( !old_base ) |
|
249 return; |
|
250 |
|
251 if ( FT_ALLOC( table->block, table->cursor ) ) |
|
252 return; |
|
253 FT_MEM_COPY( table->block, old_base, table->cursor ); |
|
254 shift_elements( table, old_base ); |
|
255 |
|
256 table->capacity = table->cursor; |
|
257 FT_FREE( old_base ); |
|
258 |
|
259 FT_UNUSED( error ); |
|
260 } |
|
261 |
|
262 |
|
263 FT_LOCAL_DEF( void ) |
|
264 ps_table_release( PS_Table table ) |
|
265 { |
|
266 FT_Memory memory = table->memory; |
|
267 |
|
268 |
|
269 if ( (FT_ULong)table->init == 0xDEADBEEFUL ) |
|
270 { |
|
271 FT_FREE( table->block ); |
|
272 FT_FREE( table->elements ); |
|
273 FT_FREE( table->lengths ); |
|
274 table->init = 0; |
|
275 } |
|
276 } |
|
277 |
|
278 |
|
279 /*************************************************************************/ |
|
280 /*************************************************************************/ |
|
281 /***** *****/ |
|
282 /***** T1 PARSER *****/ |
|
283 /***** *****/ |
|
284 /*************************************************************************/ |
|
285 /*************************************************************************/ |
|
286 |
|
287 |
|
288 /* first character must be already part of the comment */ |
|
289 |
|
290 static void |
|
291 skip_comment( FT_Byte* *acur, |
|
292 FT_Byte* limit ) |
|
293 { |
|
294 FT_Byte* cur = *acur; |
|
295 |
|
296 |
|
297 while ( cur < limit ) |
|
298 { |
|
299 if ( IS_PS_NEWLINE( *cur ) ) |
|
300 break; |
|
301 cur++; |
|
302 } |
|
303 |
|
304 *acur = cur; |
|
305 } |
|
306 |
|
307 |
|
308 static void |
|
309 skip_spaces( FT_Byte* *acur, |
|
310 FT_Byte* limit ) |
|
311 { |
|
312 FT_Byte* cur = *acur; |
|
313 |
|
314 |
|
315 while ( cur < limit ) |
|
316 { |
|
317 if ( !IS_PS_SPACE( *cur ) ) |
|
318 { |
|
319 if ( *cur == '%' ) |
|
320 /* According to the PLRM, a comment is equal to a space. */ |
|
321 skip_comment( &cur, limit ); |
|
322 else |
|
323 break; |
|
324 } |
|
325 cur++; |
|
326 } |
|
327 |
|
328 *acur = cur; |
|
329 } |
|
330 |
|
331 |
|
332 #define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' ) |
|
333 |
|
334 |
|
335 /* first character must be `('; */ |
|
336 /* *acur is positioned at the character after the closing `)' */ |
|
337 |
|
338 static FT_Error |
|
339 skip_literal_string( FT_Byte* *acur, |
|
340 FT_Byte* limit ) |
|
341 { |
|
342 FT_Byte* cur = *acur; |
|
343 FT_Int embed = 0; |
|
344 FT_Error error = PSaux_Err_Invalid_File_Format; |
|
345 unsigned int i; |
|
346 |
|
347 |
|
348 while ( cur < limit ) |
|
349 { |
|
350 FT_Byte c = *cur; |
|
351 |
|
352 |
|
353 ++cur; |
|
354 |
|
355 if ( c == '\\' ) |
|
356 { |
|
357 /* Red Book 3rd ed., section `Literal Text Strings', p. 29: */ |
|
358 /* A backslash can introduce three different types */ |
|
359 /* of escape sequences: */ |
|
360 /* - a special escaped char like \r, \n, etc. */ |
|
361 /* - a one-, two-, or three-digit octal number */ |
|
362 /* - none of the above in which case the backslash is ignored */ |
|
363 |
|
364 if ( cur == limit ) |
|
365 /* error (or to be ignored?) */ |
|
366 break; |
|
367 |
|
368 switch ( *cur ) |
|
369 { |
|
370 /* skip `special' escape */ |
|
371 case 'n': |
|
372 case 'r': |
|
373 case 't': |
|
374 case 'b': |
|
375 case 'f': |
|
376 case '\\': |
|
377 case '(': |
|
378 case ')': |
|
379 ++cur; |
|
380 break; |
|
381 |
|
382 default: |
|
383 /* skip octal escape or ignore backslash */ |
|
384 for ( i = 0; i < 3 && cur < limit; ++i ) |
|
385 { |
|
386 if ( !IS_OCTAL_DIGIT( *cur ) ) |
|
387 break; |
|
388 |
|
389 ++cur; |
|
390 } |
|
391 } |
|
392 } |
|
393 else if ( c == '(' ) |
|
394 embed++; |
|
395 else if ( c == ')' ) |
|
396 { |
|
397 embed--; |
|
398 if ( embed == 0 ) |
|
399 { |
|
400 error = PSaux_Err_Ok; |
|
401 break; |
|
402 } |
|
403 } |
|
404 } |
|
405 |
|
406 *acur = cur; |
|
407 |
|
408 return error; |
|
409 } |
|
410 |
|
411 |
|
412 /* first character must be `<' */ |
|
413 |
|
414 static FT_Error |
|
415 skip_string( FT_Byte* *acur, |
|
416 FT_Byte* limit ) |
|
417 { |
|
418 FT_Byte* cur = *acur; |
|
419 FT_Error err = PSaux_Err_Ok; |
|
420 |
|
421 |
|
422 while ( ++cur < limit ) |
|
423 { |
|
424 /* All whitespace characters are ignored. */ |
|
425 skip_spaces( &cur, limit ); |
|
426 if ( cur >= limit ) |
|
427 break; |
|
428 |
|
429 if ( !IS_PS_XDIGIT( *cur ) ) |
|
430 break; |
|
431 } |
|
432 |
|
433 if ( cur < limit && *cur != '>' ) |
|
434 { |
|
435 FT_ERROR(( "skip_string: missing closing delimiter `>'\n" )); |
|
436 err = PSaux_Err_Invalid_File_Format; |
|
437 } |
|
438 else |
|
439 cur++; |
|
440 |
|
441 *acur = cur; |
|
442 return err; |
|
443 } |
|
444 |
|
445 |
|
446 /* first character must be the opening brace that */ |
|
447 /* starts the procedure */ |
|
448 |
|
449 /* NB: [ and ] need not match: */ |
|
450 /* `/foo {[} def' is a valid PostScript fragment, */ |
|
451 /* even within a Type1 font */ |
|
452 |
|
453 static FT_Error |
|
454 skip_procedure( FT_Byte* *acur, |
|
455 FT_Byte* limit ) |
|
456 { |
|
457 FT_Byte* cur; |
|
458 FT_Int embed = 0; |
|
459 FT_Error error = PSaux_Err_Ok; |
|
460 |
|
461 |
|
462 FT_ASSERT( **acur == '{' ); |
|
463 |
|
464 for ( cur = *acur; cur < limit && error == PSaux_Err_Ok; ++cur ) |
|
465 { |
|
466 switch ( *cur ) |
|
467 { |
|
468 case '{': |
|
469 ++embed; |
|
470 break; |
|
471 |
|
472 case '}': |
|
473 --embed; |
|
474 if ( embed == 0 ) |
|
475 { |
|
476 ++cur; |
|
477 goto end; |
|
478 } |
|
479 break; |
|
480 |
|
481 case '(': |
|
482 error = skip_literal_string( &cur, limit ); |
|
483 break; |
|
484 |
|
485 case '<': |
|
486 error = skip_string( &cur, limit ); |
|
487 break; |
|
488 |
|
489 case '%': |
|
490 skip_comment( &cur, limit ); |
|
491 break; |
|
492 } |
|
493 } |
|
494 |
|
495 end: |
|
496 if ( embed != 0 ) |
|
497 error = PSaux_Err_Invalid_File_Format; |
|
498 |
|
499 *acur = cur; |
|
500 |
|
501 return error; |
|
502 } |
|
503 |
|
504 |
|
505 /***********************************************************************/ |
|
506 /* */ |
|
507 /* All exported parsing routines handle leading whitespace and stop at */ |
|
508 /* the first character which isn't part of the just handled token. */ |
|
509 /* */ |
|
510 /***********************************************************************/ |
|
511 |
|
512 |
|
513 FT_LOCAL_DEF( void ) |
|
514 ps_parser_skip_PS_token( PS_Parser parser ) |
|
515 { |
|
516 /* Note: PostScript allows any non-delimiting, non-whitespace */ |
|
517 /* character in a name (PS Ref Manual, 3rd ed, p31). */ |
|
518 /* PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */ |
|
519 |
|
520 FT_Byte* cur = parser->cursor; |
|
521 FT_Byte* limit = parser->limit; |
|
522 FT_Error error = PSaux_Err_Ok; |
|
523 |
|
524 |
|
525 skip_spaces( &cur, limit ); /* this also skips comments */ |
|
526 if ( cur >= limit ) |
|
527 goto Exit; |
|
528 |
|
529 /* self-delimiting, single-character tokens */ |
|
530 if ( *cur == '[' || *cur == ']' ) |
|
531 { |
|
532 cur++; |
|
533 goto Exit; |
|
534 } |
|
535 |
|
536 /* skip balanced expressions (procedures and strings) */ |
|
537 |
|
538 if ( *cur == '{' ) /* {...} */ |
|
539 { |
|
540 error = skip_procedure( &cur, limit ); |
|
541 goto Exit; |
|
542 } |
|
543 |
|
544 if ( *cur == '(' ) /* (...) */ |
|
545 { |
|
546 error = skip_literal_string( &cur, limit ); |
|
547 goto Exit; |
|
548 } |
|
549 |
|
550 if ( *cur == '<' ) /* <...> */ |
|
551 { |
|
552 if ( cur + 1 < limit && *(cur + 1) == '<' ) /* << */ |
|
553 { |
|
554 cur++; |
|
555 cur++; |
|
556 } |
|
557 else |
|
558 error = skip_string( &cur, limit ); |
|
559 |
|
560 goto Exit; |
|
561 } |
|
562 |
|
563 if ( *cur == '>' ) |
|
564 { |
|
565 cur++; |
|
566 if ( cur >= limit || *cur != '>' ) /* >> */ |
|
567 { |
|
568 FT_ERROR(( "ps_parser_skip_PS_token:" |
|
569 " unexpected closing delimiter `>'\n" )); |
|
570 error = PSaux_Err_Invalid_File_Format; |
|
571 goto Exit; |
|
572 } |
|
573 cur++; |
|
574 goto Exit; |
|
575 } |
|
576 |
|
577 if ( *cur == '/' ) |
|
578 cur++; |
|
579 |
|
580 /* anything else */ |
|
581 while ( cur < limit ) |
|
582 { |
|
583 /* *cur might be invalid (e.g., ')' or '}'), but this */ |
|
584 /* is handled by the test `cur == parser->cursor' below */ |
|
585 if ( IS_PS_DELIM( *cur ) ) |
|
586 break; |
|
587 |
|
588 cur++; |
|
589 } |
|
590 |
|
591 Exit: |
|
592 if ( cur == parser->cursor ) |
|
593 { |
|
594 FT_ERROR(( "ps_parser_skip_PS_token:" |
|
595 " current token is `%c' which is self-delimiting\n" |
|
596 " " |
|
597 " but invalid at this point\n", |
|
598 *cur )); |
|
599 |
|
600 error = PSaux_Err_Invalid_File_Format; |
|
601 } |
|
602 |
|
603 parser->error = error; |
|
604 parser->cursor = cur; |
|
605 } |
|
606 |
|
607 |
|
608 FT_LOCAL_DEF( void ) |
|
609 ps_parser_skip_spaces( PS_Parser parser ) |
|
610 { |
|
611 skip_spaces( &parser->cursor, parser->limit ); |
|
612 } |
|
613 |
|
614 |
|
615 /* `token' here means either something between balanced delimiters */ |
|
616 /* or the next token; the delimiters are not removed. */ |
|
617 |
|
618 FT_LOCAL_DEF( void ) |
|
619 ps_parser_to_token( PS_Parser parser, |
|
620 T1_Token token ) |
|
621 { |
|
622 FT_Byte* cur; |
|
623 FT_Byte* limit; |
|
624 FT_Int embed; |
|
625 |
|
626 |
|
627 token->type = T1_TOKEN_TYPE_NONE; |
|
628 token->start = 0; |
|
629 token->limit = 0; |
|
630 |
|
631 /* first of all, skip leading whitespace */ |
|
632 ps_parser_skip_spaces( parser ); |
|
633 |
|
634 cur = parser->cursor; |
|
635 limit = parser->limit; |
|
636 |
|
637 if ( cur >= limit ) |
|
638 return; |
|
639 |
|
640 switch ( *cur ) |
|
641 { |
|
642 /************* check for literal string *****************/ |
|
643 case '(': |
|
644 token->type = T1_TOKEN_TYPE_STRING; |
|
645 token->start = cur; |
|
646 |
|
647 if ( skip_literal_string( &cur, limit ) == PSaux_Err_Ok ) |
|
648 token->limit = cur; |
|
649 break; |
|
650 |
|
651 /************* check for programs/array *****************/ |
|
652 case '{': |
|
653 token->type = T1_TOKEN_TYPE_ARRAY; |
|
654 token->start = cur; |
|
655 |
|
656 if ( skip_procedure( &cur, limit ) == PSaux_Err_Ok ) |
|
657 token->limit = cur; |
|
658 break; |
|
659 |
|
660 /************* check for table/array ********************/ |
|
661 /* XXX: in theory we should also look for "<<" */ |
|
662 /* since this is semantically equivalent to "["; */ |
|
663 /* in practice it doesn't matter (?) */ |
|
664 case '[': |
|
665 token->type = T1_TOKEN_TYPE_ARRAY; |
|
666 embed = 1; |
|
667 token->start = cur++; |
|
668 |
|
669 /* we need this to catch `[ ]' */ |
|
670 parser->cursor = cur; |
|
671 ps_parser_skip_spaces( parser ); |
|
672 cur = parser->cursor; |
|
673 |
|
674 while ( cur < limit && !parser->error ) |
|
675 { |
|
676 /* XXX: this is wrong because it does not */ |
|
677 /* skip comments, procedures, and strings */ |
|
678 if ( *cur == '[' ) |
|
679 embed++; |
|
680 else if ( *cur == ']' ) |
|
681 { |
|
682 embed--; |
|
683 if ( embed <= 0 ) |
|
684 { |
|
685 token->limit = ++cur; |
|
686 break; |
|
687 } |
|
688 } |
|
689 |
|
690 parser->cursor = cur; |
|
691 ps_parser_skip_PS_token( parser ); |
|
692 /* we need this to catch `[XXX ]' */ |
|
693 ps_parser_skip_spaces ( parser ); |
|
694 cur = parser->cursor; |
|
695 } |
|
696 break; |
|
697 |
|
698 /* ************ otherwise, it is any token **************/ |
|
699 default: |
|
700 token->start = cur; |
|
701 token->type = ( *cur == '/' ? T1_TOKEN_TYPE_KEY : T1_TOKEN_TYPE_ANY ); |
|
702 ps_parser_skip_PS_token( parser ); |
|
703 cur = parser->cursor; |
|
704 if ( !parser->error ) |
|
705 token->limit = cur; |
|
706 } |
|
707 |
|
708 if ( !token->limit ) |
|
709 { |
|
710 token->start = 0; |
|
711 token->type = T1_TOKEN_TYPE_NONE; |
|
712 } |
|
713 |
|
714 parser->cursor = cur; |
|
715 } |
|
716 |
|
717 |
|
718 /* NB: `tokens' can be NULL if we only want to count */ |
|
719 /* the number of array elements */ |
|
720 |
|
721 FT_LOCAL_DEF( void ) |
|
722 ps_parser_to_token_array( PS_Parser parser, |
|
723 T1_Token tokens, |
|
724 FT_UInt max_tokens, |
|
725 FT_Int* pnum_tokens ) |
|
726 { |
|
727 T1_TokenRec master; |
|
728 |
|
729 |
|
730 *pnum_tokens = -1; |
|
731 |
|
732 /* this also handles leading whitespace */ |
|
733 ps_parser_to_token( parser, &master ); |
|
734 |
|
735 if ( master.type == T1_TOKEN_TYPE_ARRAY ) |
|
736 { |
|
737 FT_Byte* old_cursor = parser->cursor; |
|
738 FT_Byte* old_limit = parser->limit; |
|
739 T1_Token cur = tokens; |
|
740 T1_Token limit = cur + max_tokens; |
|
741 |
|
742 |
|
743 /* don't include outermost delimiters */ |
|
744 parser->cursor = master.start + 1; |
|
745 parser->limit = master.limit - 1; |
|
746 |
|
747 while ( parser->cursor < parser->limit ) |
|
748 { |
|
749 T1_TokenRec token; |
|
750 |
|
751 |
|
752 ps_parser_to_token( parser, &token ); |
|
753 if ( !token.type ) |
|
754 break; |
|
755 |
|
756 if ( tokens != NULL && cur < limit ) |
|
757 *cur = token; |
|
758 |
|
759 cur++; |
|
760 } |
|
761 |
|
762 *pnum_tokens = (FT_Int)( cur - tokens ); |
|
763 |
|
764 parser->cursor = old_cursor; |
|
765 parser->limit = old_limit; |
|
766 } |
|
767 } |
|
768 |
|
769 |
|
770 /* first character must be a delimiter or a part of a number */ |
|
771 /* NB: `coords' can be NULL if we just want to skip the */ |
|
772 /* array; in this case we ignore `max_coords' */ |
|
773 |
|
774 static FT_Int |
|
775 ps_tocoordarray( FT_Byte* *acur, |
|
776 FT_Byte* limit, |
|
777 FT_Int max_coords, |
|
778 FT_Short* coords ) |
|
779 { |
|
780 FT_Byte* cur = *acur; |
|
781 FT_Int count = 0; |
|
782 FT_Byte c, ender; |
|
783 |
|
784 |
|
785 if ( cur >= limit ) |
|
786 goto Exit; |
|
787 |
|
788 /* check for the beginning of an array; otherwise, only one number */ |
|
789 /* will be read */ |
|
790 c = *cur; |
|
791 ender = 0; |
|
792 |
|
793 if ( c == '[' ) |
|
794 ender = ']'; |
|
795 else if ( c == '{' ) |
|
796 ender = '}'; |
|
797 |
|
798 if ( ender ) |
|
799 cur++; |
|
800 |
|
801 /* now, read the coordinates */ |
|
802 while ( cur < limit ) |
|
803 { |
|
804 FT_Short dummy; |
|
805 FT_Byte* old_cur; |
|
806 |
|
807 |
|
808 /* skip whitespace in front of data */ |
|
809 skip_spaces( &cur, limit ); |
|
810 if ( cur >= limit ) |
|
811 goto Exit; |
|
812 |
|
813 if ( *cur == ender ) |
|
814 { |
|
815 cur++; |
|
816 break; |
|
817 } |
|
818 |
|
819 old_cur = cur; |
|
820 |
|
821 if ( coords != NULL && count >= max_coords ) |
|
822 break; |
|
823 |
|
824 /* call PS_Conv_ToFixed() even if coords == NULL */ |
|
825 /* to properly parse number at `cur' */ |
|
826 *( coords != NULL ? &coords[count] : &dummy ) = |
|
827 (FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 ); |
|
828 |
|
829 if ( old_cur == cur ) |
|
830 { |
|
831 count = -1; |
|
832 goto Exit; |
|
833 } |
|
834 else |
|
835 count++; |
|
836 |
|
837 if ( !ender ) |
|
838 break; |
|
839 } |
|
840 |
|
841 Exit: |
|
842 *acur = cur; |
|
843 return count; |
|
844 } |
|
845 |
|
846 |
|
847 /* first character must be a delimiter or a part of a number */ |
|
848 /* NB: `values' can be NULL if we just want to skip the */ |
|
849 /* array; in this case we ignore `max_values' */ |
|
850 |
|
851 static FT_Int |
|
852 ps_tofixedarray( FT_Byte* *acur, |
|
853 FT_Byte* limit, |
|
854 FT_Int max_values, |
|
855 FT_Fixed* values, |
|
856 FT_Int power_ten ) |
|
857 { |
|
858 FT_Byte* cur = *acur; |
|
859 FT_Int count = 0; |
|
860 FT_Byte c, ender; |
|
861 |
|
862 |
|
863 if ( cur >= limit ) |
|
864 goto Exit; |
|
865 |
|
866 /* Check for the beginning of an array. Otherwise, only one number */ |
|
867 /* will be read. */ |
|
868 c = *cur; |
|
869 ender = 0; |
|
870 |
|
871 if ( c == '[' ) |
|
872 ender = ']'; |
|
873 else if ( c == '{' ) |
|
874 ender = '}'; |
|
875 |
|
876 if ( ender ) |
|
877 cur++; |
|
878 |
|
879 /* now, read the values */ |
|
880 while ( cur < limit ) |
|
881 { |
|
882 FT_Fixed dummy; |
|
883 FT_Byte* old_cur; |
|
884 |
|
885 |
|
886 /* skip whitespace in front of data */ |
|
887 skip_spaces( &cur, limit ); |
|
888 if ( cur >= limit ) |
|
889 goto Exit; |
|
890 |
|
891 if ( *cur == ender ) |
|
892 { |
|
893 cur++; |
|
894 break; |
|
895 } |
|
896 |
|
897 old_cur = cur; |
|
898 |
|
899 if ( values != NULL && count >= max_values ) |
|
900 break; |
|
901 |
|
902 /* call PS_Conv_ToFixed() even if coords == NULL */ |
|
903 /* to properly parse number at `cur' */ |
|
904 *( values != NULL ? &values[count] : &dummy ) = |
|
905 PS_Conv_ToFixed( &cur, limit, power_ten ); |
|
906 |
|
907 if ( old_cur == cur ) |
|
908 { |
|
909 count = -1; |
|
910 goto Exit; |
|
911 } |
|
912 else |
|
913 count++; |
|
914 |
|
915 if ( !ender ) |
|
916 break; |
|
917 } |
|
918 |
|
919 Exit: |
|
920 *acur = cur; |
|
921 return count; |
|
922 } |
|
923 |
|
924 |
|
925 #if 0 |
|
926 |
|
927 static FT_String* |
|
928 ps_tostring( FT_Byte** cursor, |
|
929 FT_Byte* limit, |
|
930 FT_Memory memory ) |
|
931 { |
|
932 FT_Byte* cur = *cursor; |
|
933 FT_PtrDist len = 0; |
|
934 FT_Int count; |
|
935 FT_String* result; |
|
936 FT_Error error; |
|
937 |
|
938 |
|
939 /* XXX: some stupid fonts have a `Notice' or `Copyright' string */ |
|
940 /* that simply doesn't begin with an opening parenthesis, even */ |
|
941 /* though they have a closing one! E.g. "amuncial.pfb" */ |
|
942 /* */ |
|
943 /* We must deal with these ill-fated cases there. Note that */ |
|
944 /* these fonts didn't work with the old Type 1 driver as the */ |
|
945 /* notice/copyright was not recognized as a valid string token */ |
|
946 /* and made the old token parser commit errors. */ |
|
947 |
|
948 while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) ) |
|
949 cur++; |
|
950 if ( cur + 1 >= limit ) |
|
951 return 0; |
|
952 |
|
953 if ( *cur == '(' ) |
|
954 cur++; /* skip the opening parenthesis, if there is one */ |
|
955 |
|
956 *cursor = cur; |
|
957 count = 0; |
|
958 |
|
959 /* then, count its length */ |
|
960 for ( ; cur < limit; cur++ ) |
|
961 { |
|
962 if ( *cur == '(' ) |
|
963 count++; |
|
964 |
|
965 else if ( *cur == ')' ) |
|
966 { |
|
967 count--; |
|
968 if ( count < 0 ) |
|
969 break; |
|
970 } |
|
971 } |
|
972 |
|
973 len = cur - *cursor; |
|
974 if ( cur >= limit || FT_ALLOC( result, len + 1 ) ) |
|
975 return 0; |
|
976 |
|
977 /* now copy the string */ |
|
978 FT_MEM_COPY( result, *cursor, len ); |
|
979 result[len] = '\0'; |
|
980 *cursor = cur; |
|
981 return result; |
|
982 } |
|
983 |
|
984 #endif /* 0 */ |
|
985 |
|
986 |
|
987 static int |
|
988 ps_tobool( FT_Byte* *acur, |
|
989 FT_Byte* limit ) |
|
990 { |
|
991 FT_Byte* cur = *acur; |
|
992 FT_Bool result = 0; |
|
993 |
|
994 |
|
995 /* return 1 if we find `true', 0 otherwise */ |
|
996 if ( cur + 3 < limit && |
|
997 cur[0] == 't' && |
|
998 cur[1] == 'r' && |
|
999 cur[2] == 'u' && |
|
1000 cur[3] == 'e' ) |
|
1001 { |
|
1002 result = 1; |
|
1003 cur += 5; |
|
1004 } |
|
1005 else if ( cur + 4 < limit && |
|
1006 cur[0] == 'f' && |
|
1007 cur[1] == 'a' && |
|
1008 cur[2] == 'l' && |
|
1009 cur[3] == 's' && |
|
1010 cur[4] == 'e' ) |
|
1011 { |
|
1012 result = 0; |
|
1013 cur += 6; |
|
1014 } |
|
1015 |
|
1016 *acur = cur; |
|
1017 return result; |
|
1018 } |
|
1019 |
|
1020 |
|
1021 /* load a simple field (i.e. non-table) into the current list of objects */ |
|
1022 |
|
1023 FT_LOCAL_DEF( FT_Error ) |
|
1024 ps_parser_load_field( PS_Parser parser, |
|
1025 const T1_Field field, |
|
1026 void** objects, |
|
1027 FT_UInt max_objects, |
|
1028 FT_ULong* pflags ) |
|
1029 { |
|
1030 T1_TokenRec token; |
|
1031 FT_Byte* cur; |
|
1032 FT_Byte* limit; |
|
1033 FT_UInt count; |
|
1034 FT_UInt idx; |
|
1035 FT_Error error; |
|
1036 |
|
1037 |
|
1038 /* this also skips leading whitespace */ |
|
1039 ps_parser_to_token( parser, &token ); |
|
1040 if ( !token.type ) |
|
1041 goto Fail; |
|
1042 |
|
1043 count = 1; |
|
1044 idx = 0; |
|
1045 cur = token.start; |
|
1046 limit = token.limit; |
|
1047 |
|
1048 /* we must detect arrays in /FontBBox */ |
|
1049 if ( field->type == T1_FIELD_TYPE_BBOX ) |
|
1050 { |
|
1051 T1_TokenRec token2; |
|
1052 FT_Byte* old_cur = parser->cursor; |
|
1053 FT_Byte* old_limit = parser->limit; |
|
1054 |
|
1055 |
|
1056 /* don't include delimiters */ |
|
1057 parser->cursor = token.start + 1; |
|
1058 parser->limit = token.limit - 1; |
|
1059 |
|
1060 ps_parser_to_token( parser, &token2 ); |
|
1061 parser->cursor = old_cur; |
|
1062 parser->limit = old_limit; |
|
1063 |
|
1064 if ( token2.type == T1_TOKEN_TYPE_ARRAY ) |
|
1065 goto FieldArray; |
|
1066 } |
|
1067 else if ( token.type == T1_TOKEN_TYPE_ARRAY ) |
|
1068 { |
|
1069 FieldArray: |
|
1070 /* if this is an array and we have no blend, an error occurs */ |
|
1071 if ( max_objects == 0 ) |
|
1072 goto Fail; |
|
1073 |
|
1074 count = max_objects; |
|
1075 idx = 1; |
|
1076 |
|
1077 /* don't include delimiters */ |
|
1078 cur++; |
|
1079 limit--; |
|
1080 } |
|
1081 |
|
1082 for ( ; count > 0; count--, idx++ ) |
|
1083 { |
|
1084 FT_Byte* q = (FT_Byte*)objects[idx] + field->offset; |
|
1085 FT_Long val; |
|
1086 FT_String* string; |
|
1087 |
|
1088 |
|
1089 skip_spaces( &cur, limit ); |
|
1090 |
|
1091 switch ( field->type ) |
|
1092 { |
|
1093 case T1_FIELD_TYPE_BOOL: |
|
1094 val = ps_tobool( &cur, limit ); |
|
1095 goto Store_Integer; |
|
1096 |
|
1097 case T1_FIELD_TYPE_FIXED: |
|
1098 val = PS_Conv_ToFixed( &cur, limit, 0 ); |
|
1099 goto Store_Integer; |
|
1100 |
|
1101 case T1_FIELD_TYPE_FIXED_1000: |
|
1102 val = PS_Conv_ToFixed( &cur, limit, 3 ); |
|
1103 goto Store_Integer; |
|
1104 |
|
1105 case T1_FIELD_TYPE_INTEGER: |
|
1106 val = PS_Conv_ToInt( &cur, limit ); |
|
1107 /* fall through */ |
|
1108 |
|
1109 Store_Integer: |
|
1110 switch ( field->size ) |
|
1111 { |
|
1112 case (8 / FT_CHAR_BIT): |
|
1113 *(FT_Byte*)q = (FT_Byte)val; |
|
1114 break; |
|
1115 |
|
1116 case (16 / FT_CHAR_BIT): |
|
1117 *(FT_UShort*)q = (FT_UShort)val; |
|
1118 break; |
|
1119 |
|
1120 case (32 / FT_CHAR_BIT): |
|
1121 *(FT_UInt32*)q = (FT_UInt32)val; |
|
1122 break; |
|
1123 |
|
1124 default: /* for 64-bit systems */ |
|
1125 *(FT_Long*)q = val; |
|
1126 } |
|
1127 break; |
|
1128 |
|
1129 case T1_FIELD_TYPE_STRING: |
|
1130 case T1_FIELD_TYPE_KEY: |
|
1131 { |
|
1132 FT_Memory memory = parser->memory; |
|
1133 FT_UInt len = (FT_UInt)( limit - cur ); |
|
1134 |
|
1135 |
|
1136 if ( cur >= limit ) |
|
1137 break; |
|
1138 |
|
1139 /* we allow both a string or a name */ |
|
1140 /* for cases like /FontName (foo) def */ |
|
1141 if ( token.type == T1_TOKEN_TYPE_KEY ) |
|
1142 { |
|
1143 /* don't include leading `/' */ |
|
1144 len--; |
|
1145 cur++; |
|
1146 } |
|
1147 else if ( token.type == T1_TOKEN_TYPE_STRING ) |
|
1148 { |
|
1149 /* don't include delimiting parentheses */ |
|
1150 /* XXX we don't handle <<...>> here */ |
|
1151 /* XXX should we convert octal escapes? */ |
|
1152 /* if so, what encoding should we use? */ |
|
1153 cur++; |
|
1154 len -= 2; |
|
1155 } |
|
1156 else |
|
1157 { |
|
1158 FT_ERROR(( "ps_parser_load_field:" |
|
1159 " expected a name or string\n" |
|
1160 " " |
|
1161 " but found token of type %d instead\n", |
|
1162 token.type )); |
|
1163 error = PSaux_Err_Invalid_File_Format; |
|
1164 goto Exit; |
|
1165 } |
|
1166 |
|
1167 /* for this to work (FT_String**)q must have been */ |
|
1168 /* initialized to NULL */ |
|
1169 if ( *(FT_String**)q != NULL ) |
|
1170 { |
|
1171 FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n", |
|
1172 field->ident )); |
|
1173 FT_FREE( *(FT_String**)q ); |
|
1174 *(FT_String**)q = NULL; |
|
1175 } |
|
1176 |
|
1177 if ( FT_ALLOC( string, len + 1 ) ) |
|
1178 goto Exit; |
|
1179 |
|
1180 FT_MEM_COPY( string, cur, len ); |
|
1181 string[len] = 0; |
|
1182 |
|
1183 *(FT_String**)q = string; |
|
1184 } |
|
1185 break; |
|
1186 |
|
1187 case T1_FIELD_TYPE_BBOX: |
|
1188 { |
|
1189 FT_Fixed temp[4]; |
|
1190 FT_BBox* bbox = (FT_BBox*)q; |
|
1191 FT_Int result; |
|
1192 |
|
1193 |
|
1194 result = ps_tofixedarray( &cur, limit, 4, temp, 0 ); |
|
1195 |
|
1196 if ( result < 0 ) |
|
1197 { |
|
1198 FT_ERROR(( "ps_parser_load_field:" |
|
1199 " expected four integers in bounding box\n" )); |
|
1200 error = PSaux_Err_Invalid_File_Format; |
|
1201 goto Exit; |
|
1202 } |
|
1203 |
|
1204 bbox->xMin = FT_RoundFix( temp[0] ); |
|
1205 bbox->yMin = FT_RoundFix( temp[1] ); |
|
1206 bbox->xMax = FT_RoundFix( temp[2] ); |
|
1207 bbox->yMax = FT_RoundFix( temp[3] ); |
|
1208 } |
|
1209 break; |
|
1210 |
|
1211 default: |
|
1212 /* an error occurred */ |
|
1213 goto Fail; |
|
1214 } |
|
1215 } |
|
1216 |
|
1217 #if 0 /* obsolete -- keep for reference */ |
|
1218 if ( pflags ) |
|
1219 *pflags |= 1L << field->flag_bit; |
|
1220 #else |
|
1221 FT_UNUSED( pflags ); |
|
1222 #endif |
|
1223 |
|
1224 error = PSaux_Err_Ok; |
|
1225 |
|
1226 Exit: |
|
1227 return error; |
|
1228 |
|
1229 Fail: |
|
1230 error = PSaux_Err_Invalid_File_Format; |
|
1231 goto Exit; |
|
1232 } |
|
1233 |
|
1234 |
|
1235 #define T1_MAX_TABLE_ELEMENTS 32 |
|
1236 |
|
1237 |
|
1238 FT_LOCAL_DEF( FT_Error ) |
|
1239 ps_parser_load_field_table( PS_Parser parser, |
|
1240 const T1_Field field, |
|
1241 void** objects, |
|
1242 FT_UInt max_objects, |
|
1243 FT_ULong* pflags ) |
|
1244 { |
|
1245 T1_TokenRec elements[T1_MAX_TABLE_ELEMENTS]; |
|
1246 T1_Token token; |
|
1247 FT_Int num_elements; |
|
1248 FT_Error error = PSaux_Err_Ok; |
|
1249 FT_Byte* old_cursor; |
|
1250 FT_Byte* old_limit; |
|
1251 T1_FieldRec fieldrec = *(T1_Field)field; |
|
1252 |
|
1253 |
|
1254 fieldrec.type = T1_FIELD_TYPE_INTEGER; |
|
1255 if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY || |
|
1256 field->type == T1_FIELD_TYPE_BBOX ) |
|
1257 fieldrec.type = T1_FIELD_TYPE_FIXED; |
|
1258 |
|
1259 ps_parser_to_token_array( parser, elements, |
|
1260 T1_MAX_TABLE_ELEMENTS, &num_elements ); |
|
1261 if ( num_elements < 0 ) |
|
1262 { |
|
1263 error = PSaux_Err_Ignore; |
|
1264 goto Exit; |
|
1265 } |
|
1266 if ( (FT_UInt)num_elements > field->array_max ) |
|
1267 num_elements = field->array_max; |
|
1268 |
|
1269 old_cursor = parser->cursor; |
|
1270 old_limit = parser->limit; |
|
1271 |
|
1272 /* we store the elements count if necessary; */ |
|
1273 /* we further assume that `count_offset' can't be zero */ |
|
1274 if ( field->type != T1_FIELD_TYPE_BBOX && field->count_offset != 0 ) |
|
1275 *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) = |
|
1276 (FT_Byte)num_elements; |
|
1277 |
|
1278 /* we now load each element, adjusting the field.offset on each one */ |
|
1279 token = elements; |
|
1280 for ( ; num_elements > 0; num_elements--, token++ ) |
|
1281 { |
|
1282 parser->cursor = token->start; |
|
1283 parser->limit = token->limit; |
|
1284 ps_parser_load_field( parser, &fieldrec, objects, max_objects, 0 ); |
|
1285 fieldrec.offset += fieldrec.size; |
|
1286 } |
|
1287 |
|
1288 #if 0 /* obsolete -- keep for reference */ |
|
1289 if ( pflags ) |
|
1290 *pflags |= 1L << field->flag_bit; |
|
1291 #else |
|
1292 FT_UNUSED( pflags ); |
|
1293 #endif |
|
1294 |
|
1295 parser->cursor = old_cursor; |
|
1296 parser->limit = old_limit; |
|
1297 |
|
1298 Exit: |
|
1299 return error; |
|
1300 } |
|
1301 |
|
1302 |
|
1303 FT_LOCAL_DEF( FT_Long ) |
|
1304 ps_parser_to_int( PS_Parser parser ) |
|
1305 { |
|
1306 ps_parser_skip_spaces( parser ); |
|
1307 return PS_Conv_ToInt( &parser->cursor, parser->limit ); |
|
1308 } |
|
1309 |
|
1310 |
|
1311 /* first character must be `<' if `delimiters' is non-zero */ |
|
1312 |
|
1313 FT_LOCAL_DEF( FT_Error ) |
|
1314 ps_parser_to_bytes( PS_Parser parser, |
|
1315 FT_Byte* bytes, |
|
1316 FT_Offset max_bytes, |
|
1317 FT_Long* pnum_bytes, |
|
1318 FT_Bool delimiters ) |
|
1319 { |
|
1320 FT_Error error = PSaux_Err_Ok; |
|
1321 FT_Byte* cur; |
|
1322 |
|
1323 |
|
1324 ps_parser_skip_spaces( parser ); |
|
1325 cur = parser->cursor; |
|
1326 |
|
1327 if ( cur >= parser->limit ) |
|
1328 goto Exit; |
|
1329 |
|
1330 if ( delimiters ) |
|
1331 { |
|
1332 if ( *cur != '<' ) |
|
1333 { |
|
1334 FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" )); |
|
1335 error = PSaux_Err_Invalid_File_Format; |
|
1336 goto Exit; |
|
1337 } |
|
1338 |
|
1339 cur++; |
|
1340 } |
|
1341 |
|
1342 *pnum_bytes = PS_Conv_ASCIIHexDecode( &cur, |
|
1343 parser->limit, |
|
1344 bytes, |
|
1345 max_bytes ); |
|
1346 |
|
1347 if ( delimiters ) |
|
1348 { |
|
1349 if ( cur < parser->limit && *cur != '>' ) |
|
1350 { |
|
1351 FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" )); |
|
1352 error = PSaux_Err_Invalid_File_Format; |
|
1353 goto Exit; |
|
1354 } |
|
1355 |
|
1356 cur++; |
|
1357 } |
|
1358 |
|
1359 parser->cursor = cur; |
|
1360 |
|
1361 Exit: |
|
1362 return error; |
|
1363 } |
|
1364 |
|
1365 |
|
1366 FT_LOCAL_DEF( FT_Fixed ) |
|
1367 ps_parser_to_fixed( PS_Parser parser, |
|
1368 FT_Int power_ten ) |
|
1369 { |
|
1370 ps_parser_skip_spaces( parser ); |
|
1371 return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten ); |
|
1372 } |
|
1373 |
|
1374 |
|
1375 FT_LOCAL_DEF( FT_Int ) |
|
1376 ps_parser_to_coord_array( PS_Parser parser, |
|
1377 FT_Int max_coords, |
|
1378 FT_Short* coords ) |
|
1379 { |
|
1380 ps_parser_skip_spaces( parser ); |
|
1381 return ps_tocoordarray( &parser->cursor, parser->limit, |
|
1382 max_coords, coords ); |
|
1383 } |
|
1384 |
|
1385 |
|
1386 FT_LOCAL_DEF( FT_Int ) |
|
1387 ps_parser_to_fixed_array( PS_Parser parser, |
|
1388 FT_Int max_values, |
|
1389 FT_Fixed* values, |
|
1390 FT_Int power_ten ) |
|
1391 { |
|
1392 ps_parser_skip_spaces( parser ); |
|
1393 return ps_tofixedarray( &parser->cursor, parser->limit, |
|
1394 max_values, values, power_ten ); |
|
1395 } |
|
1396 |
|
1397 |
|
1398 #if 0 |
|
1399 |
|
1400 FT_LOCAL_DEF( FT_String* ) |
|
1401 T1_ToString( PS_Parser parser ) |
|
1402 { |
|
1403 return ps_tostring( &parser->cursor, parser->limit, parser->memory ); |
|
1404 } |
|
1405 |
|
1406 |
|
1407 FT_LOCAL_DEF( FT_Bool ) |
|
1408 T1_ToBool( PS_Parser parser ) |
|
1409 { |
|
1410 return ps_tobool( &parser->cursor, parser->limit ); |
|
1411 } |
|
1412 |
|
1413 #endif /* 0 */ |
|
1414 |
|
1415 |
|
1416 FT_LOCAL_DEF( void ) |
|
1417 ps_parser_init( PS_Parser parser, |
|
1418 FT_Byte* base, |
|
1419 FT_Byte* limit, |
|
1420 FT_Memory memory ) |
|
1421 { |
|
1422 parser->error = PSaux_Err_Ok; |
|
1423 parser->base = base; |
|
1424 parser->limit = limit; |
|
1425 parser->cursor = base; |
|
1426 parser->memory = memory; |
|
1427 parser->funcs = ps_parser_funcs; |
|
1428 } |
|
1429 |
|
1430 |
|
1431 FT_LOCAL_DEF( void ) |
|
1432 ps_parser_done( PS_Parser parser ) |
|
1433 { |
|
1434 FT_UNUSED( parser ); |
|
1435 } |
|
1436 |
|
1437 |
|
1438 /*************************************************************************/ |
|
1439 /*************************************************************************/ |
|
1440 /***** *****/ |
|
1441 /***** T1 BUILDER *****/ |
|
1442 /***** *****/ |
|
1443 /*************************************************************************/ |
|
1444 /*************************************************************************/ |
|
1445 |
|
1446 /*************************************************************************/ |
|
1447 /* */ |
|
1448 /* <Function> */ |
|
1449 /* t1_builder_init */ |
|
1450 /* */ |
|
1451 /* <Description> */ |
|
1452 /* Initializes a given glyph builder. */ |
|
1453 /* */ |
|
1454 /* <InOut> */ |
|
1455 /* builder :: A pointer to the glyph builder to initialize. */ |
|
1456 /* */ |
|
1457 /* <Input> */ |
|
1458 /* face :: The current face object. */ |
|
1459 /* */ |
|
1460 /* size :: The current size object. */ |
|
1461 /* */ |
|
1462 /* glyph :: The current glyph object. */ |
|
1463 /* */ |
|
1464 /* hinting :: Whether hinting should be applied. */ |
|
1465 /* */ |
|
1466 FT_LOCAL_DEF( void ) |
|
1467 t1_builder_init( T1_Builder builder, |
|
1468 FT_Face face, |
|
1469 FT_Size size, |
|
1470 FT_GlyphSlot glyph, |
|
1471 FT_Bool hinting ) |
|
1472 { |
|
1473 builder->parse_state = T1_Parse_Start; |
|
1474 builder->load_points = 1; |
|
1475 |
|
1476 builder->face = face; |
|
1477 builder->glyph = glyph; |
|
1478 builder->memory = face->memory; |
|
1479 |
|
1480 if ( glyph ) |
|
1481 { |
|
1482 FT_GlyphLoader loader = glyph->internal->loader; |
|
1483 |
|
1484 |
|
1485 builder->loader = loader; |
|
1486 builder->base = &loader->base.outline; |
|
1487 builder->current = &loader->current.outline; |
|
1488 FT_GlyphLoader_Rewind( loader ); |
|
1489 |
|
1490 builder->hints_globals = size->internal; |
|
1491 builder->hints_funcs = 0; |
|
1492 |
|
1493 if ( hinting ) |
|
1494 builder->hints_funcs = glyph->internal->glyph_hints; |
|
1495 } |
|
1496 |
|
1497 builder->pos_x = 0; |
|
1498 builder->pos_y = 0; |
|
1499 |
|
1500 builder->left_bearing.x = 0; |
|
1501 builder->left_bearing.y = 0; |
|
1502 builder->advance.x = 0; |
|
1503 builder->advance.y = 0; |
|
1504 |
|
1505 builder->funcs = t1_builder_funcs; |
|
1506 } |
|
1507 |
|
1508 |
|
1509 /*************************************************************************/ |
|
1510 /* */ |
|
1511 /* <Function> */ |
|
1512 /* t1_builder_done */ |
|
1513 /* */ |
|
1514 /* <Description> */ |
|
1515 /* Finalizes a given glyph builder. Its contents can still be used */ |
|
1516 /* after the call, but the function saves important information */ |
|
1517 /* within the corresponding glyph slot. */ |
|
1518 /* */ |
|
1519 /* <Input> */ |
|
1520 /* builder :: A pointer to the glyph builder to finalize. */ |
|
1521 /* */ |
|
1522 FT_LOCAL_DEF( void ) |
|
1523 t1_builder_done( T1_Builder builder ) |
|
1524 { |
|
1525 FT_GlyphSlot glyph = builder->glyph; |
|
1526 |
|
1527 |
|
1528 if ( glyph ) |
|
1529 glyph->outline = *builder->base; |
|
1530 } |
|
1531 |
|
1532 |
|
1533 /* check that there is enough space for `count' more points */ |
|
1534 FT_LOCAL_DEF( FT_Error ) |
|
1535 t1_builder_check_points( T1_Builder builder, |
|
1536 FT_Int count ) |
|
1537 { |
|
1538 return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 ); |
|
1539 } |
|
1540 |
|
1541 |
|
1542 /* add a new point, do not check space */ |
|
1543 FT_LOCAL_DEF( void ) |
|
1544 t1_builder_add_point( T1_Builder builder, |
|
1545 FT_Pos x, |
|
1546 FT_Pos y, |
|
1547 FT_Byte flag ) |
|
1548 { |
|
1549 FT_Outline* outline = builder->current; |
|
1550 |
|
1551 |
|
1552 if ( builder->load_points ) |
|
1553 { |
|
1554 FT_Vector* point = outline->points + outline->n_points; |
|
1555 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points; |
|
1556 |
|
1557 |
|
1558 point->x = FIXED_TO_INT( x ); |
|
1559 point->y = FIXED_TO_INT( y ); |
|
1560 *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC ); |
|
1561 } |
|
1562 outline->n_points++; |
|
1563 } |
|
1564 |
|
1565 |
|
1566 /* check space for a new on-curve point, then add it */ |
|
1567 FT_LOCAL_DEF( FT_Error ) |
|
1568 t1_builder_add_point1( T1_Builder builder, |
|
1569 FT_Pos x, |
|
1570 FT_Pos y ) |
|
1571 { |
|
1572 FT_Error error; |
|
1573 |
|
1574 |
|
1575 error = t1_builder_check_points( builder, 1 ); |
|
1576 if ( !error ) |
|
1577 t1_builder_add_point( builder, x, y, 1 ); |
|
1578 |
|
1579 return error; |
|
1580 } |
|
1581 |
|
1582 |
|
1583 /* check space for a new contour, then add it */ |
|
1584 FT_LOCAL_DEF( FT_Error ) |
|
1585 t1_builder_add_contour( T1_Builder builder ) |
|
1586 { |
|
1587 FT_Outline* outline = builder->current; |
|
1588 FT_Error error; |
|
1589 |
|
1590 |
|
1591 /* this might happen in invalid fonts */ |
|
1592 if ( !outline ) |
|
1593 { |
|
1594 FT_ERROR(( "t1_builder_add_contour: no outline to add points to\n" )); |
|
1595 return PSaux_Err_Invalid_File_Format; |
|
1596 } |
|
1597 |
|
1598 if ( !builder->load_points ) |
|
1599 { |
|
1600 outline->n_contours++; |
|
1601 return PSaux_Err_Ok; |
|
1602 } |
|
1603 |
|
1604 error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 ); |
|
1605 if ( !error ) |
|
1606 { |
|
1607 if ( outline->n_contours > 0 ) |
|
1608 outline->contours[outline->n_contours - 1] = |
|
1609 (short)( outline->n_points - 1 ); |
|
1610 |
|
1611 outline->n_contours++; |
|
1612 } |
|
1613 |
|
1614 return error; |
|
1615 } |
|
1616 |
|
1617 |
|
1618 /* if a path was begun, add its first on-curve point */ |
|
1619 FT_LOCAL_DEF( FT_Error ) |
|
1620 t1_builder_start_point( T1_Builder builder, |
|
1621 FT_Pos x, |
|
1622 FT_Pos y ) |
|
1623 { |
|
1624 FT_Error error = PSaux_Err_Invalid_File_Format; |
|
1625 |
|
1626 |
|
1627 /* test whether we are building a new contour */ |
|
1628 |
|
1629 if ( builder->parse_state == T1_Parse_Have_Path ) |
|
1630 error = PSaux_Err_Ok; |
|
1631 else |
|
1632 { |
|
1633 builder->parse_state = T1_Parse_Have_Path; |
|
1634 error = t1_builder_add_contour( builder ); |
|
1635 if ( !error ) |
|
1636 error = t1_builder_add_point1( builder, x, y ); |
|
1637 } |
|
1638 |
|
1639 return error; |
|
1640 } |
|
1641 |
|
1642 |
|
1643 /* close the current contour */ |
|
1644 FT_LOCAL_DEF( void ) |
|
1645 t1_builder_close_contour( T1_Builder builder ) |
|
1646 { |
|
1647 FT_Outline* outline = builder->current; |
|
1648 FT_Int first; |
|
1649 |
|
1650 |
|
1651 if ( !outline ) |
|
1652 return; |
|
1653 |
|
1654 first = outline->n_contours <= 1 |
|
1655 ? 0 : outline->contours[outline->n_contours - 2] + 1; |
|
1656 |
|
1657 /* We must not include the last point in the path if it */ |
|
1658 /* is located on the first point. */ |
|
1659 if ( outline->n_points > 1 ) |
|
1660 { |
|
1661 FT_Vector* p1 = outline->points + first; |
|
1662 FT_Vector* p2 = outline->points + outline->n_points - 1; |
|
1663 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1; |
|
1664 |
|
1665 |
|
1666 /* `delete' last point only if it coincides with the first */ |
|
1667 /* point and it is not a control point (which can happen). */ |
|
1668 if ( p1->x == p2->x && p1->y == p2->y ) |
|
1669 if ( *control == FT_CURVE_TAG_ON ) |
|
1670 outline->n_points--; |
|
1671 } |
|
1672 |
|
1673 if ( outline->n_contours > 0 ) |
|
1674 { |
|
1675 /* Don't add contours only consisting of one point, i.e., */ |
|
1676 /* check whether the first and the last point is the same. */ |
|
1677 if ( first == outline->n_points - 1 ) |
|
1678 { |
|
1679 outline->n_contours--; |
|
1680 outline->n_points--; |
|
1681 } |
|
1682 else |
|
1683 outline->contours[outline->n_contours - 1] = |
|
1684 (short)( outline->n_points - 1 ); |
|
1685 } |
|
1686 } |
|
1687 |
|
1688 |
|
1689 /*************************************************************************/ |
|
1690 /*************************************************************************/ |
|
1691 /***** *****/ |
|
1692 /***** OTHER *****/ |
|
1693 /***** *****/ |
|
1694 /*************************************************************************/ |
|
1695 /*************************************************************************/ |
|
1696 |
|
1697 FT_LOCAL_DEF( void ) |
|
1698 t1_decrypt( FT_Byte* buffer, |
|
1699 FT_Offset length, |
|
1700 FT_UShort seed ) |
|
1701 { |
|
1702 PS_Conv_EexecDecode( &buffer, |
|
1703 buffer + length, |
|
1704 buffer, |
|
1705 length, |
|
1706 &seed ); |
|
1707 } |
|
1708 |
|
1709 |
|
1710 /* END */ |
|