Sync with trunk r63383 .
[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-2014 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_Offset 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 FT_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 FT_THROW( Invalid_Argument );
177 }
178
179 if ( length < 0 )
180 {
181 FT_ERROR(( "ps_table_add: invalid length\n" ));
182 return FT_THROW( 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 FT_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 = FT_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 = FT_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 = FT_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 = FT_THROW( 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 = FT_Err_Ok;
460
461
462 FT_ASSERT( **acur == '{' );
463
464 for ( cur = *acur; cur < limit && error == FT_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 = FT_THROW( 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 = FT_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 = FT_THROW( 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 < limit && 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 = FT_THROW( 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 ) == FT_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 ) == FT_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 /* return number of successfully parsed values */
852
853 static FT_Int
854 ps_tofixedarray( FT_Byte* *acur,
855 FT_Byte* limit,
856 FT_Int max_values,
857 FT_Fixed* values,
858 FT_Int power_ten )
859 {
860 FT_Byte* cur = *acur;
861 FT_Int count = 0;
862 FT_Byte c, ender;
863
864
865 if ( cur >= limit )
866 goto Exit;
867
868 /* Check for the beginning of an array. Otherwise, only one number */
869 /* will be read. */
870 c = *cur;
871 ender = 0;
872
873 if ( c == '[' )
874 ender = ']';
875 else if ( c == '{' )
876 ender = '}';
877
878 if ( ender )
879 cur++;
880
881 /* now, read the values */
882 while ( cur < limit )
883 {
884 FT_Fixed dummy;
885 FT_Byte* old_cur;
886
887
888 /* skip whitespace in front of data */
889 skip_spaces( &cur, limit );
890 if ( cur >= limit )
891 goto Exit;
892
893 if ( *cur == ender )
894 {
895 cur++;
896 break;
897 }
898
899 old_cur = cur;
900
901 if ( values != NULL && count >= max_values )
902 break;
903
904 /* call PS_Conv_ToFixed() even if coords == NULL */
905 /* to properly parse number at `cur' */
906 *( values != NULL ? &values[count] : &dummy ) =
907 PS_Conv_ToFixed( &cur, limit, power_ten );
908
909 if ( old_cur == cur )
910 {
911 count = -1;
912 goto Exit;
913 }
914 else
915 count++;
916
917 if ( !ender )
918 break;
919 }
920
921 Exit:
922 *acur = cur;
923 return count;
924 }
925
926
927 #if 0
928
929 static FT_String*
930 ps_tostring( FT_Byte** cursor,
931 FT_Byte* limit,
932 FT_Memory memory )
933 {
934 FT_Byte* cur = *cursor;
935 FT_PtrDist len = 0;
936 FT_Int count;
937 FT_String* result;
938 FT_Error error;
939
940
941 /* XXX: some stupid fonts have a `Notice' or `Copyright' string */
942 /* that simply doesn't begin with an opening parenthesis, even */
943 /* though they have a closing one! E.g. "amuncial.pfb" */
944 /* */
945 /* We must deal with these ill-fated cases there. Note that */
946 /* these fonts didn't work with the old Type 1 driver as the */
947 /* notice/copyright was not recognized as a valid string token */
948 /* and made the old token parser commit errors. */
949
950 while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) )
951 cur++;
952 if ( cur + 1 >= limit )
953 return 0;
954
955 if ( *cur == '(' )
956 cur++; /* skip the opening parenthesis, if there is one */
957
958 *cursor = cur;
959 count = 0;
960
961 /* then, count its length */
962 for ( ; cur < limit; cur++ )
963 {
964 if ( *cur == '(' )
965 count++;
966
967 else if ( *cur == ')' )
968 {
969 count--;
970 if ( count < 0 )
971 break;
972 }
973 }
974
975 len = cur - *cursor;
976 if ( cur >= limit || FT_ALLOC( result, len + 1 ) )
977 return 0;
978
979 /* now copy the string */
980 FT_MEM_COPY( result, *cursor, len );
981 result[len] = '\0';
982 *cursor = cur;
983 return result;
984 }
985
986 #endif /* 0 */
987
988
989 static int
990 ps_tobool( FT_Byte* *acur,
991 FT_Byte* limit )
992 {
993 FT_Byte* cur = *acur;
994 FT_Bool result = 0;
995
996
997 /* return 1 if we find `true', 0 otherwise */
998 if ( cur + 3 < limit &&
999 cur[0] == 't' &&
1000 cur[1] == 'r' &&
1001 cur[2] == 'u' &&
1002 cur[3] == 'e' )
1003 {
1004 result = 1;
1005 cur += 5;
1006 }
1007 else if ( cur + 4 < limit &&
1008 cur[0] == 'f' &&
1009 cur[1] == 'a' &&
1010 cur[2] == 'l' &&
1011 cur[3] == 's' &&
1012 cur[4] == 'e' )
1013 {
1014 result = 0;
1015 cur += 6;
1016 }
1017
1018 *acur = cur;
1019 return result;
1020 }
1021
1022
1023 /* load a simple field (i.e. non-table) into the current list of objects */
1024
1025 FT_LOCAL_DEF( FT_Error )
1026 ps_parser_load_field( PS_Parser parser,
1027 const T1_Field field,
1028 void** objects,
1029 FT_UInt max_objects,
1030 FT_ULong* pflags )
1031 {
1032 T1_TokenRec token;
1033 FT_Byte* cur;
1034 FT_Byte* limit;
1035 FT_UInt count;
1036 FT_UInt idx;
1037 FT_Error error;
1038 T1_FieldType type;
1039
1040
1041 /* this also skips leading whitespace */
1042 ps_parser_to_token( parser, &token );
1043 if ( !token.type )
1044 goto Fail;
1045
1046 count = 1;
1047 idx = 0;
1048 cur = token.start;
1049 limit = token.limit;
1050
1051 type = field->type;
1052
1053 /* we must detect arrays in /FontBBox */
1054 if ( type == T1_FIELD_TYPE_BBOX )
1055 {
1056 T1_TokenRec token2;
1057 FT_Byte* old_cur = parser->cursor;
1058 FT_Byte* old_limit = parser->limit;
1059
1060
1061 /* don't include delimiters */
1062 parser->cursor = token.start + 1;
1063 parser->limit = token.limit - 1;
1064
1065 ps_parser_to_token( parser, &token2 );
1066 parser->cursor = old_cur;
1067 parser->limit = old_limit;
1068
1069 if ( token2.type == T1_TOKEN_TYPE_ARRAY )
1070 {
1071 type = T1_FIELD_TYPE_MM_BBOX;
1072 goto FieldArray;
1073 }
1074 }
1075 else if ( token.type == T1_TOKEN_TYPE_ARRAY )
1076 {
1077 count = max_objects;
1078
1079 FieldArray:
1080 /* if this is an array and we have no blend, an error occurs */
1081 if ( max_objects == 0 )
1082 goto Fail;
1083
1084 idx = 1;
1085
1086 /* don't include delimiters */
1087 cur++;
1088 limit--;
1089 }
1090
1091 for ( ; count > 0; count--, idx++ )
1092 {
1093 FT_Byte* q = (FT_Byte*)objects[idx] + field->offset;
1094 FT_Long val;
1095 FT_String* string;
1096
1097
1098 skip_spaces( &cur, limit );
1099
1100 switch ( type )
1101 {
1102 case T1_FIELD_TYPE_BOOL:
1103 val = ps_tobool( &cur, limit );
1104 goto Store_Integer;
1105
1106 case T1_FIELD_TYPE_FIXED:
1107 val = PS_Conv_ToFixed( &cur, limit, 0 );
1108 goto Store_Integer;
1109
1110 case T1_FIELD_TYPE_FIXED_1000:
1111 val = PS_Conv_ToFixed( &cur, limit, 3 );
1112 goto Store_Integer;
1113
1114 case T1_FIELD_TYPE_INTEGER:
1115 val = PS_Conv_ToInt( &cur, limit );
1116 /* fall through */
1117
1118 Store_Integer:
1119 switch ( field->size )
1120 {
1121 case (8 / FT_CHAR_BIT):
1122 *(FT_Byte*)q = (FT_Byte)val;
1123 break;
1124
1125 case (16 / FT_CHAR_BIT):
1126 *(FT_UShort*)q = (FT_UShort)val;
1127 break;
1128
1129 case (32 / FT_CHAR_BIT):
1130 *(FT_UInt32*)q = (FT_UInt32)val;
1131 break;
1132
1133 default: /* for 64-bit systems */
1134 *(FT_Long*)q = val;
1135 }
1136 break;
1137
1138 case T1_FIELD_TYPE_STRING:
1139 case T1_FIELD_TYPE_KEY:
1140 {
1141 FT_Memory memory = parser->memory;
1142 FT_UInt len = (FT_UInt)( limit - cur );
1143
1144
1145 if ( cur >= limit )
1146 break;
1147
1148 /* we allow both a string or a name */
1149 /* for cases like /FontName (foo) def */
1150 if ( token.type == T1_TOKEN_TYPE_KEY )
1151 {
1152 /* don't include leading `/' */
1153 len--;
1154 cur++;
1155 }
1156 else if ( token.type == T1_TOKEN_TYPE_STRING )
1157 {
1158 /* don't include delimiting parentheses */
1159 /* XXX we don't handle <<...>> here */
1160 /* XXX should we convert octal escapes? */
1161 /* if so, what encoding should we use? */
1162 cur++;
1163 len -= 2;
1164 }
1165 else
1166 {
1167 FT_ERROR(( "ps_parser_load_field:"
1168 " expected a name or string\n"
1169 " "
1170 " but found token of type %d instead\n",
1171 token.type ));
1172 error = FT_THROW( Invalid_File_Format );
1173 goto Exit;
1174 }
1175
1176 /* for this to work (FT_String**)q must have been */
1177 /* initialized to NULL */
1178 if ( *(FT_String**)q != NULL )
1179 {
1180 FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n",
1181 field->ident ));
1182 FT_FREE( *(FT_String**)q );
1183 *(FT_String**)q = NULL;
1184 }
1185
1186 if ( FT_ALLOC( string, len + 1 ) )
1187 goto Exit;
1188
1189 FT_MEM_COPY( string, cur, len );
1190 string[len] = 0;
1191
1192 *(FT_String**)q = string;
1193 }
1194 break;
1195
1196 case T1_FIELD_TYPE_BBOX:
1197 {
1198 FT_Fixed temp[4];
1199 FT_BBox* bbox = (FT_BBox*)q;
1200 FT_Int result;
1201
1202
1203 result = ps_tofixedarray( &cur, limit, 4, temp, 0 );
1204
1205 if ( result < 4 )
1206 {
1207 FT_ERROR(( "ps_parser_load_field:"
1208 " expected four integers in bounding box\n" ));
1209 error = FT_THROW( Invalid_File_Format );
1210 goto Exit;
1211 }
1212
1213 bbox->xMin = FT_RoundFix( temp[0] );
1214 bbox->yMin = FT_RoundFix( temp[1] );
1215 bbox->xMax = FT_RoundFix( temp[2] );
1216 bbox->yMax = FT_RoundFix( temp[3] );
1217 }
1218 break;
1219
1220 case T1_FIELD_TYPE_MM_BBOX:
1221 {
1222 FT_Memory memory = parser->memory;
1223 FT_Fixed* temp;
1224 FT_Int result;
1225 FT_UInt i;
1226
1227
1228 if ( FT_NEW_ARRAY( temp, max_objects * 4 ) )
1229 goto Exit;
1230
1231 for ( i = 0; i < 4; i++ )
1232 {
1233 result = ps_tofixedarray( &cur, limit, max_objects,
1234 temp + i * max_objects, 0 );
1235 if ( result < 0 || (FT_UInt)result < max_objects )
1236 {
1237 FT_ERROR(( "ps_parser_load_field:"
1238 " expected %d integers in the %s subarray\n"
1239 " "
1240 " of /FontBBox in the /Blend dictionary\n",
1241 max_objects,
1242 i == 0 ? "first"
1243 : ( i == 1 ? "second"
1244 : ( i == 2 ? "third"
1245 : "fourth" ) ) ));
1246 error = FT_THROW( Invalid_File_Format );
1247 goto Exit;
1248 }
1249
1250 skip_spaces( &cur, limit );
1251 }
1252
1253 for ( i = 0; i < max_objects; i++ )
1254 {
1255 FT_BBox* bbox = (FT_BBox*)objects[i];
1256
1257
1258 bbox->xMin = FT_RoundFix( temp[i ] );
1259 bbox->yMin = FT_RoundFix( temp[i + max_objects] );
1260 bbox->xMax = FT_RoundFix( temp[i + 2 * max_objects] );
1261 bbox->yMax = FT_RoundFix( temp[i + 3 * max_objects] );
1262 }
1263
1264 FT_FREE( temp );
1265 }
1266 break;
1267
1268 default:
1269 /* an error occurred */
1270 goto Fail;
1271 }
1272 }
1273
1274 #if 0 /* obsolete -- keep for reference */
1275 if ( pflags )
1276 *pflags |= 1L << field->flag_bit;
1277 #else
1278 FT_UNUSED( pflags );
1279 #endif
1280
1281 error = FT_Err_Ok;
1282
1283 Exit:
1284 return error;
1285
1286 Fail:
1287 error = FT_THROW( Invalid_File_Format );
1288 goto Exit;
1289 }
1290
1291
1292 #define T1_MAX_TABLE_ELEMENTS 32
1293
1294
1295 FT_LOCAL_DEF( FT_Error )
1296 ps_parser_load_field_table( PS_Parser parser,
1297 const T1_Field field,
1298 void** objects,
1299 FT_UInt max_objects,
1300 FT_ULong* pflags )
1301 {
1302 T1_TokenRec elements[T1_MAX_TABLE_ELEMENTS];
1303 T1_Token token;
1304 FT_Int num_elements;
1305 FT_Error error = FT_Err_Ok;
1306 FT_Byte* old_cursor;
1307 FT_Byte* old_limit;
1308 T1_FieldRec fieldrec = *(T1_Field)field;
1309
1310
1311 fieldrec.type = T1_FIELD_TYPE_INTEGER;
1312 if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY ||
1313 field->type == T1_FIELD_TYPE_BBOX )
1314 fieldrec.type = T1_FIELD_TYPE_FIXED;
1315
1316 ps_parser_to_token_array( parser, elements,
1317 T1_MAX_TABLE_ELEMENTS, &num_elements );
1318 if ( num_elements < 0 )
1319 {
1320 error = FT_ERR( Ignore );
1321 goto Exit;
1322 }
1323 if ( (FT_UInt)num_elements > field->array_max )
1324 num_elements = field->array_max;
1325
1326 old_cursor = parser->cursor;
1327 old_limit = parser->limit;
1328
1329 /* we store the elements count if necessary; */
1330 /* we further assume that `count_offset' can't be zero */
1331 if ( field->type != T1_FIELD_TYPE_BBOX && field->count_offset != 0 )
1332 *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
1333 (FT_Byte)num_elements;
1334
1335 /* we now load each element, adjusting the field.offset on each one */
1336 token = elements;
1337 for ( ; num_elements > 0; num_elements--, token++ )
1338 {
1339 parser->cursor = token->start;
1340 parser->limit = token->limit;
1341 ps_parser_load_field( parser, &fieldrec, objects, max_objects, 0 );
1342 fieldrec.offset += fieldrec.size;
1343 }
1344
1345 #if 0 /* obsolete -- keep for reference */
1346 if ( pflags )
1347 *pflags |= 1L << field->flag_bit;
1348 #else
1349 FT_UNUSED( pflags );
1350 #endif
1351
1352 parser->cursor = old_cursor;
1353 parser->limit = old_limit;
1354
1355 Exit:
1356 return error;
1357 }
1358
1359
1360 FT_LOCAL_DEF( FT_Long )
1361 ps_parser_to_int( PS_Parser parser )
1362 {
1363 ps_parser_skip_spaces( parser );
1364 return PS_Conv_ToInt( &parser->cursor, parser->limit );
1365 }
1366
1367
1368 /* first character must be `<' if `delimiters' is non-zero */
1369
1370 FT_LOCAL_DEF( FT_Error )
1371 ps_parser_to_bytes( PS_Parser parser,
1372 FT_Byte* bytes,
1373 FT_Offset max_bytes,
1374 FT_Long* pnum_bytes,
1375 FT_Bool delimiters )
1376 {
1377 FT_Error error = FT_Err_Ok;
1378 FT_Byte* cur;
1379
1380
1381 ps_parser_skip_spaces( parser );
1382 cur = parser->cursor;
1383
1384 if ( cur >= parser->limit )
1385 goto Exit;
1386
1387 if ( delimiters )
1388 {
1389 if ( *cur != '<' )
1390 {
1391 FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" ));
1392 error = FT_THROW( Invalid_File_Format );
1393 goto Exit;
1394 }
1395
1396 cur++;
1397 }
1398
1399 *pnum_bytes = PS_Conv_ASCIIHexDecode( &cur,
1400 parser->limit,
1401 bytes,
1402 max_bytes );
1403
1404 if ( delimiters )
1405 {
1406 if ( cur < parser->limit && *cur != '>' )
1407 {
1408 FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" ));
1409 error = FT_THROW( Invalid_File_Format );
1410 goto Exit;
1411 }
1412
1413 cur++;
1414 }
1415
1416 parser->cursor = cur;
1417
1418 Exit:
1419 return error;
1420 }
1421
1422
1423 FT_LOCAL_DEF( FT_Fixed )
1424 ps_parser_to_fixed( PS_Parser parser,
1425 FT_Int power_ten )
1426 {
1427 ps_parser_skip_spaces( parser );
1428 return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten );
1429 }
1430
1431
1432 FT_LOCAL_DEF( FT_Int )
1433 ps_parser_to_coord_array( PS_Parser parser,
1434 FT_Int max_coords,
1435 FT_Short* coords )
1436 {
1437 ps_parser_skip_spaces( parser );
1438 return ps_tocoordarray( &parser->cursor, parser->limit,
1439 max_coords, coords );
1440 }
1441
1442
1443 FT_LOCAL_DEF( FT_Int )
1444 ps_parser_to_fixed_array( PS_Parser parser,
1445 FT_Int max_values,
1446 FT_Fixed* values,
1447 FT_Int power_ten )
1448 {
1449 ps_parser_skip_spaces( parser );
1450 return ps_tofixedarray( &parser->cursor, parser->limit,
1451 max_values, values, power_ten );
1452 }
1453
1454
1455 #if 0
1456
1457 FT_LOCAL_DEF( FT_String* )
1458 T1_ToString( PS_Parser parser )
1459 {
1460 return ps_tostring( &parser->cursor, parser->limit, parser->memory );
1461 }
1462
1463
1464 FT_LOCAL_DEF( FT_Bool )
1465 T1_ToBool( PS_Parser parser )
1466 {
1467 return ps_tobool( &parser->cursor, parser->limit );
1468 }
1469
1470 #endif /* 0 */
1471
1472
1473 FT_LOCAL_DEF( void )
1474 ps_parser_init( PS_Parser parser,
1475 FT_Byte* base,
1476 FT_Byte* limit,
1477 FT_Memory memory )
1478 {
1479 parser->error = FT_Err_Ok;
1480 parser->base = base;
1481 parser->limit = limit;
1482 parser->cursor = base;
1483 parser->memory = memory;
1484 parser->funcs = ps_parser_funcs;
1485 }
1486
1487
1488 FT_LOCAL_DEF( void )
1489 ps_parser_done( PS_Parser parser )
1490 {
1491 FT_UNUSED( parser );
1492 }
1493
1494
1495 /*************************************************************************/
1496 /*************************************************************************/
1497 /***** *****/
1498 /***** T1 BUILDER *****/
1499 /***** *****/
1500 /*************************************************************************/
1501 /*************************************************************************/
1502
1503 /*************************************************************************/
1504 /* */
1505 /* <Function> */
1506 /* t1_builder_init */
1507 /* */
1508 /* <Description> */
1509 /* Initializes a given glyph builder. */
1510 /* */
1511 /* <InOut> */
1512 /* builder :: A pointer to the glyph builder to initialize. */
1513 /* */
1514 /* <Input> */
1515 /* face :: The current face object. */
1516 /* */
1517 /* size :: The current size object. */
1518 /* */
1519 /* glyph :: The current glyph object. */
1520 /* */
1521 /* hinting :: Whether hinting should be applied. */
1522 /* */
1523 FT_LOCAL_DEF( void )
1524 t1_builder_init( T1_Builder builder,
1525 FT_Face face,
1526 FT_Size size,
1527 FT_GlyphSlot glyph,
1528 FT_Bool hinting )
1529 {
1530 builder->parse_state = T1_Parse_Start;
1531 builder->load_points = 1;
1532
1533 builder->face = face;
1534 builder->glyph = glyph;
1535 builder->memory = face->memory;
1536
1537 if ( glyph )
1538 {
1539 FT_GlyphLoader loader = glyph->internal->loader;
1540
1541
1542 builder->loader = loader;
1543 builder->base = &loader->base.outline;
1544 builder->current = &loader->current.outline;
1545 FT_GlyphLoader_Rewind( loader );
1546
1547 builder->hints_globals = size->internal;
1548 builder->hints_funcs = 0;
1549
1550 if ( hinting )
1551 builder->hints_funcs = glyph->internal->glyph_hints;
1552 }
1553
1554 builder->pos_x = 0;
1555 builder->pos_y = 0;
1556
1557 builder->left_bearing.x = 0;
1558 builder->left_bearing.y = 0;
1559 builder->advance.x = 0;
1560 builder->advance.y = 0;
1561
1562 builder->funcs = t1_builder_funcs;
1563 }
1564
1565
1566 /*************************************************************************/
1567 /* */
1568 /* <Function> */
1569 /* t1_builder_done */
1570 /* */
1571 /* <Description> */
1572 /* Finalizes a given glyph builder. Its contents can still be used */
1573 /* after the call, but the function saves important information */
1574 /* within the corresponding glyph slot. */
1575 /* */
1576 /* <Input> */
1577 /* builder :: A pointer to the glyph builder to finalize. */
1578 /* */
1579 FT_LOCAL_DEF( void )
1580 t1_builder_done( T1_Builder builder )
1581 {
1582 FT_GlyphSlot glyph = builder->glyph;
1583
1584
1585 if ( glyph )
1586 glyph->outline = *builder->base;
1587 }
1588
1589
1590 /* check that there is enough space for `count' more points */
1591 FT_LOCAL_DEF( FT_Error )
1592 t1_builder_check_points( T1_Builder builder,
1593 FT_Int count )
1594 {
1595 return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 );
1596 }
1597
1598
1599 /* add a new point, do not check space */
1600 FT_LOCAL_DEF( void )
1601 t1_builder_add_point( T1_Builder builder,
1602 FT_Pos x,
1603 FT_Pos y,
1604 FT_Byte flag )
1605 {
1606 FT_Outline* outline = builder->current;
1607
1608
1609 if ( builder->load_points )
1610 {
1611 FT_Vector* point = outline->points + outline->n_points;
1612 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points;
1613
1614
1615 point->x = FIXED_TO_INT( x );
1616 point->y = FIXED_TO_INT( y );
1617 *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
1618 }
1619 outline->n_points++;
1620 }
1621
1622
1623 /* check space for a new on-curve point, then add it */
1624 FT_LOCAL_DEF( FT_Error )
1625 t1_builder_add_point1( T1_Builder builder,
1626 FT_Pos x,
1627 FT_Pos y )
1628 {
1629 FT_Error error;
1630
1631
1632 error = t1_builder_check_points( builder, 1 );
1633 if ( !error )
1634 t1_builder_add_point( builder, x, y, 1 );
1635
1636 return error;
1637 }
1638
1639
1640 /* check space for a new contour, then add it */
1641 FT_LOCAL_DEF( FT_Error )
1642 t1_builder_add_contour( T1_Builder builder )
1643 {
1644 FT_Outline* outline = builder->current;
1645 FT_Error error;
1646
1647
1648 /* this might happen in invalid fonts */
1649 if ( !outline )
1650 {
1651 FT_ERROR(( "t1_builder_add_contour: no outline to add points to\n" ));
1652 return FT_THROW( Invalid_File_Format );
1653 }
1654
1655 if ( !builder->load_points )
1656 {
1657 outline->n_contours++;
1658 return FT_Err_Ok;
1659 }
1660
1661 error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 );
1662 if ( !error )
1663 {
1664 if ( outline->n_contours > 0 )
1665 outline->contours[outline->n_contours - 1] =
1666 (short)( outline->n_points - 1 );
1667
1668 outline->n_contours++;
1669 }
1670
1671 return error;
1672 }
1673
1674
1675 /* if a path was begun, add its first on-curve point */
1676 FT_LOCAL_DEF( FT_Error )
1677 t1_builder_start_point( T1_Builder builder,
1678 FT_Pos x,
1679 FT_Pos y )
1680 {
1681 FT_Error error = FT_ERR( Invalid_File_Format );
1682
1683
1684 /* test whether we are building a new contour */
1685
1686 if ( builder->parse_state == T1_Parse_Have_Path )
1687 error = FT_Err_Ok;
1688 else
1689 {
1690 builder->parse_state = T1_Parse_Have_Path;
1691 error = t1_builder_add_contour( builder );
1692 if ( !error )
1693 error = t1_builder_add_point1( builder, x, y );
1694 }
1695
1696 return error;
1697 }
1698
1699
1700 /* close the current contour */
1701 FT_LOCAL_DEF( void )
1702 t1_builder_close_contour( T1_Builder builder )
1703 {
1704 FT_Outline* outline = builder->current;
1705 FT_Int first;
1706
1707
1708 if ( !outline )
1709 return;
1710
1711 first = outline->n_contours <= 1
1712 ? 0 : outline->contours[outline->n_contours - 2] + 1;
1713
1714 /* We must not include the last point in the path if it */
1715 /* is located on the first point. */
1716 if ( outline->n_points > 1 )
1717 {
1718 FT_Vector* p1 = outline->points + first;
1719 FT_Vector* p2 = outline->points + outline->n_points - 1;
1720 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1;
1721
1722
1723 /* `delete' last point only if it coincides with the first */
1724 /* point and it is not a control point (which can happen). */
1725 if ( p1->x == p2->x && p1->y == p2->y )
1726 if ( *control == FT_CURVE_TAG_ON )
1727 outline->n_points--;
1728 }
1729
1730 if ( outline->n_contours > 0 )
1731 {
1732 /* Don't add contours only consisting of one point, i.e., */
1733 /* check whether the first and the last point is the same. */
1734 if ( first == outline->n_points - 1 )
1735 {
1736 outline->n_contours--;
1737 outline->n_points--;
1738 }
1739 else
1740 outline->contours[outline->n_contours - 1] =
1741 (short)( outline->n_points - 1 );
1742 }
1743 }
1744
1745
1746 /*************************************************************************/
1747 /*************************************************************************/
1748 /***** *****/
1749 /***** OTHER *****/
1750 /***** *****/
1751 /*************************************************************************/
1752 /*************************************************************************/
1753
1754 FT_LOCAL_DEF( void )
1755 t1_decrypt( FT_Byte* buffer,
1756 FT_Offset length,
1757 FT_UShort seed )
1758 {
1759 PS_Conv_EexecDecode( &buffer,
1760 buffer + length,
1761 buffer,
1762 length,
1763 &seed );
1764 }
1765
1766
1767 /* END */