Home | History | Annotate | Download | only in psaux
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  psobjs.c                                                               */
      4 /*                                                                         */
      5 /*    Auxiliary functions for PostScript fonts (body).                     */
      6 /*                                                                         */
      7 /*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */
      8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
      9 /*                                                                         */
     10 /*  This file is part of the FreeType project, and may only be used,       */
     11 /*  modified, and distributed under the terms of the FreeType project      */
     12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
     13 /*  this file you indicate that you have read the license and              */
     14 /*  understand and accept it fully.                                        */
     15 /*                                                                         */
     16 /***************************************************************************/
     17 
     18 
     19 #include <ft2build.h>
     20 #include FT_INTERNAL_POSTSCRIPT_AUX_H
     21 #include FT_INTERNAL_DEBUG_H
     22 #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     = 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_Long   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 PSaux_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 PSaux_Err_Invalid_Argument;
    177     }
    178 
    179     if ( length < 0 )
    180     {
    181       FT_ERROR(( "ps_table_add: invalid length\n" ));
    182       return PSaux_Err_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_Long    in_offset;
    191 
    192 
    193       in_offset = (FT_Long)((FT_Byte*)object - table->block);
    194       if ( (FT_ULong)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 PSaux_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 = PSaux_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 = PSaux_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 =  PSaux_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 = PSaux_Err_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 = PSaux_Err_Ok;
    460 
    461 
    462     FT_ASSERT( **acur == '{' );
    463 
    464     for ( cur = *acur; cur < limit && error == PSaux_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 = PSaux_Err_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 = PSaux_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 = PSaux_Err_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 == 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 = PSaux_Err_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 ) == PSaux_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 ) == PSaux_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 
   1037 
   1038     /* this also skips leading whitespace */
   1039     ps_parser_to_token( parser, &token );
   1040     if ( !token.type )
   1041       goto Fail;
   1042 
   1043     count = 1;
   1044     idx   = 0;
   1045     cur   = token.start;
   1046     limit = token.limit;
   1047 
   1048     /* we must detect arrays in /FontBBox */
   1049     if ( field->type == T1_FIELD_TYPE_BBOX )
   1050     {
   1051       T1_TokenRec  token2;
   1052       FT_Byte*     old_cur   = parser->cursor;
   1053       FT_Byte*     old_limit = parser->limit;
   1054 
   1055 
   1056       /* don't include delimiters */
   1057       parser->cursor = token.start + 1;
   1058       parser->limit  = token.limit - 1;
   1059 
   1060       ps_parser_to_token( parser, &token2 );
   1061       parser->cursor = old_cur;
   1062       parser->limit  = old_limit;
   1063 
   1064       if ( token2.type == T1_TOKEN_TYPE_ARRAY )
   1065         goto FieldArray;
   1066     }
   1067     else if ( token.type == T1_TOKEN_TYPE_ARRAY )
   1068     {
   1069     FieldArray:
   1070       /* if this is an array and we have no blend, an error occurs */
   1071       if ( max_objects == 0 )
   1072         goto Fail;
   1073 
   1074       count = max_objects;
   1075       idx   = 1;
   1076 
   1077       /* don't include delimiters */
   1078       cur++;
   1079       limit--;
   1080     }
   1081 
   1082     for ( ; count > 0; count--, idx++ )
   1083     {
   1084       FT_Byte*    q = (FT_Byte*)objects[idx] + field->offset;
   1085       FT_Long     val;
   1086       FT_String*  string;
   1087 
   1088 
   1089       skip_spaces( &cur, limit );
   1090 
   1091       switch ( field->type )
   1092       {
   1093       case T1_FIELD_TYPE_BOOL:
   1094         val = ps_tobool( &cur, limit );
   1095         goto Store_Integer;
   1096 
   1097       case T1_FIELD_TYPE_FIXED:
   1098         val = PS_Conv_ToFixed( &cur, limit, 0 );
   1099         goto Store_Integer;
   1100 
   1101       case T1_FIELD_TYPE_FIXED_1000:
   1102         val = PS_Conv_ToFixed( &cur, limit, 3 );
   1103         goto Store_Integer;
   1104 
   1105       case T1_FIELD_TYPE_INTEGER:
   1106         val = PS_Conv_ToInt( &cur, limit );
   1107         /* fall through */
   1108 
   1109       Store_Integer:
   1110         switch ( field->size )
   1111         {
   1112         case (8 / FT_CHAR_BIT):
   1113           *(FT_Byte*)q = (FT_Byte)val;
   1114           break;
   1115 
   1116         case (16 / FT_CHAR_BIT):
   1117           *(FT_UShort*)q = (FT_UShort)val;
   1118           break;
   1119 
   1120         case (32 / FT_CHAR_BIT):
   1121           *(FT_UInt32*)q = (FT_UInt32)val;
   1122           break;
   1123 
   1124         default:                /* for 64-bit systems */
   1125           *(FT_Long*)q = val;
   1126         }
   1127         break;
   1128 
   1129       case T1_FIELD_TYPE_STRING:
   1130       case T1_FIELD_TYPE_KEY:
   1131         {
   1132           FT_Memory  memory = parser->memory;
   1133           FT_UInt    len    = (FT_UInt)( limit - cur );
   1134 
   1135 
   1136           if ( cur >= limit )
   1137             break;
   1138 
   1139           /* we allow both a string or a name   */
   1140           /* for cases like /FontName (foo) def */
   1141           if ( token.type == T1_TOKEN_TYPE_KEY )
   1142           {
   1143             /* don't include leading `/' */
   1144             len--;
   1145             cur++;
   1146           }
   1147           else if ( token.type == T1_TOKEN_TYPE_STRING )
   1148           {
   1149             /* don't include delimiting parentheses    */
   1150             /* XXX we don't handle <<...>> here        */
   1151             /* XXX should we convert octal escapes?    */
   1152             /*     if so, what encoding should we use? */
   1153             cur++;
   1154             len -= 2;
   1155           }
   1156           else
   1157           {
   1158             FT_ERROR(( "ps_parser_load_field:"
   1159                        " expected a name or string\n"
   1160                        "                     "
   1161                        " but found token of type %d instead\n",
   1162                        token.type ));
   1163             error = PSaux_Err_Invalid_File_Format;
   1164             goto Exit;
   1165           }
   1166 
   1167           /* for this to work (FT_String**)q must have been */
   1168           /* initialized to NULL                            */
   1169           if ( *(FT_String**)q != NULL )
   1170           {
   1171             FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n",
   1172                         field->ident ));
   1173             FT_FREE( *(FT_String**)q );
   1174             *(FT_String**)q = NULL;
   1175           }
   1176 
   1177           if ( FT_ALLOC( string, len + 1 ) )
   1178             goto Exit;
   1179 
   1180           FT_MEM_COPY( string, cur, len );
   1181           string[len] = 0;
   1182 
   1183           *(FT_String**)q = string;
   1184         }
   1185         break;
   1186 
   1187       case T1_FIELD_TYPE_BBOX:
   1188         {
   1189           FT_Fixed  temp[4];
   1190           FT_BBox*  bbox = (FT_BBox*)q;
   1191           FT_Int    result;
   1192 
   1193 
   1194           result = ps_tofixedarray( &cur, limit, 4, temp, 0 );
   1195 
   1196           if ( result < 0 )
   1197           {
   1198             FT_ERROR(( "ps_parser_load_field:"
   1199                        " expected four integers in bounding box\n" ));
   1200             error = PSaux_Err_Invalid_File_Format;
   1201             goto Exit;
   1202           }
   1203 
   1204           bbox->xMin = FT_RoundFix( temp[0] );
   1205           bbox->yMin = FT_RoundFix( temp[1] );
   1206           bbox->xMax = FT_RoundFix( temp[2] );
   1207           bbox->yMax = FT_RoundFix( temp[3] );
   1208         }
   1209         break;
   1210 
   1211       default:
   1212         /* an error occurred */
   1213         goto Fail;
   1214       }
   1215     }
   1216 
   1217 #if 0  /* obsolete -- keep for reference */
   1218     if ( pflags )
   1219       *pflags |= 1L << field->flag_bit;
   1220 #else
   1221     FT_UNUSED( pflags );
   1222 #endif
   1223 
   1224     error = PSaux_Err_Ok;
   1225 
   1226   Exit:
   1227     return error;
   1228 
   1229   Fail:
   1230     error = PSaux_Err_Invalid_File_Format;
   1231     goto Exit;
   1232   }
   1233 
   1234 
   1235 #define T1_MAX_TABLE_ELEMENTS  32
   1236 
   1237 
   1238   FT_LOCAL_DEF( FT_Error )
   1239   ps_parser_load_field_table( PS_Parser       parser,
   1240                               const T1_Field  field,
   1241                               void**          objects,
   1242                               FT_UInt         max_objects,
   1243                               FT_ULong*       pflags )
   1244   {
   1245     T1_TokenRec  elements[T1_MAX_TABLE_ELEMENTS];
   1246     T1_Token     token;
   1247     FT_Int       num_elements;
   1248     FT_Error     error = PSaux_Err_Ok;
   1249     FT_Byte*     old_cursor;
   1250     FT_Byte*     old_limit;
   1251     T1_FieldRec  fieldrec = *(T1_Field)field;
   1252 
   1253 
   1254     fieldrec.type = T1_FIELD_TYPE_INTEGER;
   1255     if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY ||
   1256          field->type == T1_FIELD_TYPE_BBOX        )
   1257       fieldrec.type = T1_FIELD_TYPE_FIXED;
   1258 
   1259     ps_parser_to_token_array( parser, elements,
   1260                               T1_MAX_TABLE_ELEMENTS, &num_elements );
   1261     if ( num_elements < 0 )
   1262     {
   1263       error = PSaux_Err_Ignore;
   1264       goto Exit;
   1265     }
   1266     if ( (FT_UInt)num_elements > field->array_max )
   1267       num_elements = field->array_max;
   1268 
   1269     old_cursor = parser->cursor;
   1270     old_limit  = parser->limit;
   1271 
   1272     /* we store the elements count if necessary;           */
   1273     /* we further assume that `count_offset' can't be zero */
   1274     if ( field->type != T1_FIELD_TYPE_BBOX && field->count_offset != 0 )
   1275       *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
   1276         (FT_Byte)num_elements;
   1277 
   1278     /* we now load each element, adjusting the field.offset on each one */
   1279     token = elements;
   1280     for ( ; num_elements > 0; num_elements--, token++ )
   1281     {
   1282       parser->cursor = token->start;
   1283       parser->limit  = token->limit;
   1284       ps_parser_load_field( parser, &fieldrec, objects, max_objects, 0 );
   1285       fieldrec.offset += fieldrec.size;
   1286     }
   1287 
   1288 #if 0  /* obsolete -- keep for reference */
   1289     if ( pflags )
   1290       *pflags |= 1L << field->flag_bit;
   1291 #else
   1292     FT_UNUSED( pflags );
   1293 #endif
   1294 
   1295     parser->cursor = old_cursor;
   1296     parser->limit  = old_limit;
   1297 
   1298   Exit:
   1299     return error;
   1300   }
   1301 
   1302 
   1303   FT_LOCAL_DEF( FT_Long )
   1304   ps_parser_to_int( PS_Parser  parser )
   1305   {
   1306     ps_parser_skip_spaces( parser );
   1307     return PS_Conv_ToInt( &parser->cursor, parser->limit );
   1308   }
   1309 
   1310 
   1311   /* first character must be `<' if `delimiters' is non-zero */
   1312 
   1313   FT_LOCAL_DEF( FT_Error )
   1314   ps_parser_to_bytes( PS_Parser  parser,
   1315                       FT_Byte*   bytes,
   1316                       FT_Offset  max_bytes,
   1317                       FT_Long*   pnum_bytes,
   1318                       FT_Bool    delimiters )
   1319   {
   1320     FT_Error  error = PSaux_Err_Ok;
   1321     FT_Byte*  cur;
   1322 
   1323 
   1324     ps_parser_skip_spaces( parser );
   1325     cur = parser->cursor;
   1326 
   1327     if ( cur >= parser->limit )
   1328       goto Exit;
   1329 
   1330     if ( delimiters )
   1331     {
   1332       if ( *cur != '<' )
   1333       {
   1334         FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" ));
   1335         error = PSaux_Err_Invalid_File_Format;
   1336         goto Exit;
   1337       }
   1338 
   1339       cur++;
   1340     }
   1341 
   1342     *pnum_bytes = PS_Conv_ASCIIHexDecode( &cur,
   1343                                           parser->limit,
   1344                                           bytes,
   1345                                           max_bytes );
   1346 
   1347     if ( delimiters )
   1348     {
   1349       if ( cur < parser->limit && *cur != '>' )
   1350       {
   1351         FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" ));
   1352         error = PSaux_Err_Invalid_File_Format;
   1353         goto Exit;
   1354       }
   1355 
   1356       cur++;
   1357     }
   1358 
   1359     parser->cursor = cur;
   1360 
   1361   Exit:
   1362     return error;
   1363   }
   1364 
   1365 
   1366   FT_LOCAL_DEF( FT_Fixed )
   1367   ps_parser_to_fixed( PS_Parser  parser,
   1368                       FT_Int     power_ten )
   1369   {
   1370     ps_parser_skip_spaces( parser );
   1371     return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten );
   1372   }
   1373 
   1374 
   1375   FT_LOCAL_DEF( FT_Int )
   1376   ps_parser_to_coord_array( PS_Parser  parser,
   1377                             FT_Int     max_coords,
   1378                             FT_Short*  coords )
   1379   {
   1380     ps_parser_skip_spaces( parser );
   1381     return ps_tocoordarray( &parser->cursor, parser->limit,
   1382                             max_coords, coords );
   1383   }
   1384 
   1385 
   1386   FT_LOCAL_DEF( FT_Int )
   1387   ps_parser_to_fixed_array( PS_Parser  parser,
   1388                             FT_Int     max_values,
   1389                             FT_Fixed*  values,
   1390                             FT_Int     power_ten )
   1391   {
   1392     ps_parser_skip_spaces( parser );
   1393     return ps_tofixedarray( &parser->cursor, parser->limit,
   1394                             max_values, values, power_ten );
   1395   }
   1396 
   1397 
   1398 #if 0
   1399 
   1400   FT_LOCAL_DEF( FT_String* )
   1401   T1_ToString( PS_Parser  parser )
   1402   {
   1403     return ps_tostring( &parser->cursor, parser->limit, parser->memory );
   1404   }
   1405 
   1406 
   1407   FT_LOCAL_DEF( FT_Bool )
   1408   T1_ToBool( PS_Parser  parser )
   1409   {
   1410     return ps_tobool( &parser->cursor, parser->limit );
   1411   }
   1412 
   1413 #endif /* 0 */
   1414 
   1415 
   1416   FT_LOCAL_DEF( void )
   1417   ps_parser_init( PS_Parser  parser,
   1418                   FT_Byte*   base,
   1419                   FT_Byte*   limit,
   1420                   FT_Memory  memory )
   1421   {
   1422     parser->error  = PSaux_Err_Ok;
   1423     parser->base   = base;
   1424     parser->limit  = limit;
   1425     parser->cursor = base;
   1426     parser->memory = memory;
   1427     parser->funcs  = ps_parser_funcs;
   1428   }
   1429 
   1430 
   1431   FT_LOCAL_DEF( void )
   1432   ps_parser_done( PS_Parser  parser )
   1433   {
   1434     FT_UNUSED( parser );
   1435   }
   1436 
   1437 
   1438   /*************************************************************************/
   1439   /*************************************************************************/
   1440   /*****                                                               *****/
   1441   /*****                            T1 BUILDER                         *****/
   1442   /*****                                                               *****/
   1443   /*************************************************************************/
   1444   /*************************************************************************/
   1445 
   1446   /*************************************************************************/
   1447   /*                                                                       */
   1448   /* <Function>                                                            */
   1449   /*    t1_builder_init                                                    */
   1450   /*                                                                       */
   1451   /* <Description>                                                         */
   1452   /*    Initializes a given glyph builder.                                 */
   1453   /*                                                                       */
   1454   /* <InOut>                                                               */
   1455   /*    builder :: A pointer to the glyph builder to initialize.           */
   1456   /*                                                                       */
   1457   /* <Input>                                                               */
   1458   /*    face    :: The current face object.                                */
   1459   /*                                                                       */
   1460   /*    size    :: The current size object.                                */
   1461   /*                                                                       */
   1462   /*    glyph   :: The current glyph object.                               */
   1463   /*                                                                       */
   1464   /*    hinting :: Whether hinting should be applied.                      */
   1465   /*                                                                       */
   1466   FT_LOCAL_DEF( void )
   1467   t1_builder_init( T1_Builder    builder,
   1468                    FT_Face       face,
   1469                    FT_Size       size,
   1470                    FT_GlyphSlot  glyph,
   1471                    FT_Bool       hinting )
   1472   {
   1473     builder->parse_state = T1_Parse_Start;
   1474     builder->load_points = 1;
   1475 
   1476     builder->face   = face;
   1477     builder->glyph  = glyph;
   1478     builder->memory = face->memory;
   1479 
   1480     if ( glyph )
   1481     {
   1482       FT_GlyphLoader  loader = glyph->internal->loader;
   1483 
   1484 
   1485       builder->loader  = loader;
   1486       builder->base    = &loader->base.outline;
   1487       builder->current = &loader->current.outline;
   1488       FT_GlyphLoader_Rewind( loader );
   1489 
   1490       builder->hints_globals = size->internal;
   1491       builder->hints_funcs   = 0;
   1492 
   1493       if ( hinting )
   1494         builder->hints_funcs = glyph->internal->glyph_hints;
   1495     }
   1496 
   1497     builder->pos_x = 0;
   1498     builder->pos_y = 0;
   1499 
   1500     builder->left_bearing.x = 0;
   1501     builder->left_bearing.y = 0;
   1502     builder->advance.x      = 0;
   1503     builder->advance.y      = 0;
   1504 
   1505     builder->funcs = t1_builder_funcs;
   1506   }
   1507 
   1508 
   1509   /*************************************************************************/
   1510   /*                                                                       */
   1511   /* <Function>                                                            */
   1512   /*    t1_builder_done                                                    */
   1513   /*                                                                       */
   1514   /* <Description>                                                         */
   1515   /*    Finalizes a given glyph builder.  Its contents can still be used   */
   1516   /*    after the call, but the function saves important information       */
   1517   /*    within the corresponding glyph slot.                               */
   1518   /*                                                                       */
   1519   /* <Input>                                                               */
   1520   /*    builder :: A pointer to the glyph builder to finalize.             */
   1521   /*                                                                       */
   1522   FT_LOCAL_DEF( void )
   1523   t1_builder_done( T1_Builder  builder )
   1524   {
   1525     FT_GlyphSlot  glyph = builder->glyph;
   1526 
   1527 
   1528     if ( glyph )
   1529       glyph->outline = *builder->base;
   1530   }
   1531 
   1532 
   1533   /* check that there is enough space for `count' more points */
   1534   FT_LOCAL_DEF( FT_Error )
   1535   t1_builder_check_points( T1_Builder  builder,
   1536                            FT_Int      count )
   1537   {
   1538     return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 );
   1539   }
   1540 
   1541 
   1542   /* add a new point, do not check space */
   1543   FT_LOCAL_DEF( void )
   1544   t1_builder_add_point( T1_Builder  builder,
   1545                         FT_Pos      x,
   1546                         FT_Pos      y,
   1547                         FT_Byte     flag )
   1548   {
   1549     FT_Outline*  outline = builder->current;
   1550 
   1551 
   1552     if ( builder->load_points )
   1553     {
   1554       FT_Vector*  point   = outline->points + outline->n_points;
   1555       FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points;
   1556 
   1557 
   1558       point->x = FIXED_TO_INT( x );
   1559       point->y = FIXED_TO_INT( y );
   1560       *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
   1561     }
   1562     outline->n_points++;
   1563   }
   1564 
   1565 
   1566   /* check space for a new on-curve point, then add it */
   1567   FT_LOCAL_DEF( FT_Error )
   1568   t1_builder_add_point1( T1_Builder  builder,
   1569                          FT_Pos      x,
   1570                          FT_Pos      y )
   1571   {
   1572     FT_Error  error;
   1573 
   1574 
   1575     error = t1_builder_check_points( builder, 1 );
   1576     if ( !error )
   1577       t1_builder_add_point( builder, x, y, 1 );
   1578 
   1579     return error;
   1580   }
   1581 
   1582 
   1583   /* check space for a new contour, then add it */
   1584   FT_LOCAL_DEF( FT_Error )
   1585   t1_builder_add_contour( T1_Builder  builder )
   1586   {
   1587     FT_Outline*  outline = builder->current;
   1588     FT_Error     error;
   1589 
   1590 
   1591     if ( !builder->load_points )
   1592     {
   1593       outline->n_contours++;
   1594       return PSaux_Err_Ok;
   1595     }
   1596 
   1597     error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 );
   1598     if ( !error )
   1599     {
   1600       if ( outline->n_contours > 0 )
   1601         outline->contours[outline->n_contours - 1] =
   1602           (short)( outline->n_points - 1 );
   1603 
   1604       outline->n_contours++;
   1605     }
   1606 
   1607     return error;
   1608   }
   1609 
   1610 
   1611   /* if a path was begun, add its first on-curve point */
   1612   FT_LOCAL_DEF( FT_Error )
   1613   t1_builder_start_point( T1_Builder  builder,
   1614                           FT_Pos      x,
   1615                           FT_Pos      y )
   1616   {
   1617     FT_Error  error = PSaux_Err_Invalid_File_Format;
   1618 
   1619 
   1620     /* test whether we are building a new contour */
   1621 
   1622     if ( builder->parse_state == T1_Parse_Have_Path )
   1623       error = PSaux_Err_Ok;
   1624     else if ( builder->parse_state == T1_Parse_Have_Moveto )
   1625     {
   1626       builder->parse_state = T1_Parse_Have_Path;
   1627       error = t1_builder_add_contour( builder );
   1628       if ( !error )
   1629         error = t1_builder_add_point1( builder, x, y );
   1630     }
   1631 
   1632     return error;
   1633   }
   1634 
   1635 
   1636   /* close the current contour */
   1637   FT_LOCAL_DEF( void )
   1638   t1_builder_close_contour( T1_Builder  builder )
   1639   {
   1640     FT_Outline*  outline = builder->current;
   1641     FT_Int       first;
   1642 
   1643 
   1644     if ( !outline )
   1645       return;
   1646 
   1647     first = outline->n_contours <= 1
   1648             ? 0 : outline->contours[outline->n_contours - 2] + 1;
   1649 
   1650     /* We must not include the last point in the path if it */
   1651     /* is located on the first point.                       */
   1652     if ( outline->n_points > 1 )
   1653     {
   1654       FT_Vector*  p1      = outline->points + first;
   1655       FT_Vector*  p2      = outline->points + outline->n_points - 1;
   1656       FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points - 1;
   1657 
   1658 
   1659       /* `delete' last point only if it coincides with the first */
   1660       /* point and it is not a control point (which can happen). */
   1661       if ( p1->x == p2->x && p1->y == p2->y )
   1662         if ( *control == FT_CURVE_TAG_ON )
   1663           outline->n_points--;
   1664     }
   1665 
   1666     if ( outline->n_contours > 0 )
   1667     {
   1668       /* Don't add contours only consisting of one point, i.e.,  */
   1669       /* check whether the first and the last point is the same. */
   1670       if ( first == outline->n_points - 1 )
   1671       {
   1672         outline->n_contours--;
   1673         outline->n_points--;
   1674       }
   1675       else
   1676         outline->contours[outline->n_contours - 1] =
   1677           (short)( outline->n_points - 1 );
   1678     }
   1679   }
   1680 
   1681 
   1682   /*************************************************************************/
   1683   /*************************************************************************/
   1684   /*****                                                               *****/
   1685   /*****                            OTHER                              *****/
   1686   /*****                                                               *****/
   1687   /*************************************************************************/
   1688   /*************************************************************************/
   1689 
   1690   FT_LOCAL_DEF( void )
   1691   t1_decrypt( FT_Byte*   buffer,
   1692               FT_Offset  length,
   1693               FT_UShort  seed )
   1694   {
   1695     PS_Conv_EexecDecode( &buffer,
   1696                          buffer + length,
   1697                          buffer,
   1698                          length,
   1699                          &seed );
   1700   }
   1701 
   1702 
   1703 /* END */
   1704