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