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