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