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