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