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