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