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