PageRenderTime 100ms CodeModel.GetById 33ms app.highlight 57ms RepoModel.GetById 1ms app.codeStats 1ms

/src/compiler/android-ndk/jni/freetype/src/psaux/psobjs.c

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