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