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