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