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