PageRenderTime 61ms CodeModel.GetById 7ms app.highlight 46ms RepoModel.GetById 1ms app.codeStats 0ms

/src/freetype/src/type42/t42parse.c

https://bitbucket.org/cabalistic/ogredeps/
C | 1188 lines | 808 code | 243 blank | 137 comment | 176 complexity | 28658c5723a32a4b0af312672c0b066d MD5 | raw file
   1/***************************************************************************/
   2/*                                                                         */
   3/*  t42parse.c                                                             */
   4/*                                                                         */
   5/*    Type 42 font parser (body).                                          */
   6/*                                                                         */
   7/*  Copyright 2002-2012 by                                                 */
   8/*  Roberto Alameda.                                                       */
   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 "t42parse.h"
  20#include "t42error.h"
  21#include FT_INTERNAL_DEBUG_H
  22#include FT_INTERNAL_STREAM_H
  23#include FT_INTERNAL_POSTSCRIPT_AUX_H
  24
  25
  26  /*************************************************************************/
  27  /*                                                                       */
  28  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  29  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  30  /* messages during execution.                                            */
  31  /*                                                                       */
  32#undef  FT_COMPONENT
  33#define FT_COMPONENT  trace_t42
  34
  35
  36  static void
  37  t42_parse_font_matrix( T42_Face    face,
  38                         T42_Loader  loader );
  39  static void
  40  t42_parse_encoding( T42_Face    face,
  41                      T42_Loader  loader );
  42
  43  static void
  44  t42_parse_charstrings( T42_Face    face,
  45                         T42_Loader  loader );
  46
  47  static void
  48  t42_parse_sfnts( T42_Face    face,
  49                   T42_Loader  loader );
  50
  51
  52  /* as Type42 fonts have no Private dict,         */
  53  /* we set the last argument of T1_FIELD_XXX to 0 */
  54  static const
  55  T1_FieldRec  t42_keywords[] =
  56  {
  57
  58#undef  FT_STRUCTURE
  59#define FT_STRUCTURE  T1_FontInfo
  60#undef  T1CODE
  61#define T1CODE        T1_FIELD_LOCATION_FONT_INFO
  62
  63    T1_FIELD_STRING( "version",            version,             0 )
  64    T1_FIELD_STRING( "Notice",             notice,              0 )
  65    T1_FIELD_STRING( "FullName",           full_name,           0 )
  66    T1_FIELD_STRING( "FamilyName",         family_name,         0 )
  67    T1_FIELD_STRING( "Weight",             weight,              0 )
  68    T1_FIELD_NUM   ( "ItalicAngle",        italic_angle,        0 )
  69    T1_FIELD_BOOL  ( "isFixedPitch",       is_fixed_pitch,      0 )
  70    T1_FIELD_NUM   ( "UnderlinePosition",  underline_position,  0 )
  71    T1_FIELD_NUM   ( "UnderlineThickness", underline_thickness, 0 )
  72
  73#undef  FT_STRUCTURE
  74#define FT_STRUCTURE  PS_FontExtraRec
  75#undef  T1CODE
  76#define T1CODE        T1_FIELD_LOCATION_FONT_EXTRA
  77
  78    T1_FIELD_NUM   ( "FSType",             fs_type,             0 )
  79
  80#undef  FT_STRUCTURE
  81#define FT_STRUCTURE  T1_FontRec
  82#undef  T1CODE
  83#define T1CODE        T1_FIELD_LOCATION_FONT_DICT
  84
  85    T1_FIELD_KEY  ( "FontName",    font_name,    0 )
  86    T1_FIELD_NUM  ( "PaintType",   paint_type,   0 )
  87    T1_FIELD_NUM  ( "FontType",    font_type,    0 )
  88    T1_FIELD_FIXED( "StrokeWidth", stroke_width, 0 )
  89
  90#undef  FT_STRUCTURE
  91#define FT_STRUCTURE  FT_BBox
  92#undef  T1CODE
  93#define T1CODE        T1_FIELD_LOCATION_BBOX
  94
  95    T1_FIELD_BBOX("FontBBox", xMin, 0 )
  96
  97    T1_FIELD_CALLBACK( "FontMatrix",  t42_parse_font_matrix, 0 )
  98    T1_FIELD_CALLBACK( "Encoding",    t42_parse_encoding,    0 )
  99    T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings, 0 )
 100    T1_FIELD_CALLBACK( "sfnts",       t42_parse_sfnts,       0 )
 101
 102    { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 }
 103  };
 104
 105
 106#define T1_Add_Table( p, i, o, l )  (p)->funcs.add( (p), i, o, l )
 107#define T1_Done_Table( p )          \
 108          do                        \
 109          {                         \
 110            if ( (p)->funcs.done )  \
 111              (p)->funcs.done( p ); \
 112          } while ( 0 )
 113#define T1_Release_Table( p )          \
 114          do                           \
 115          {                            \
 116            if ( (p)->funcs.release )  \
 117              (p)->funcs.release( p ); \
 118          } while ( 0 )
 119
 120#define T1_Skip_Spaces( p )    (p)->root.funcs.skip_spaces( &(p)->root )
 121#define T1_Skip_PS_Token( p )  (p)->root.funcs.skip_PS_token( &(p)->root )
 122
 123#define T1_ToInt( p )                          \
 124          (p)->root.funcs.to_int( &(p)->root )
 125#define T1_ToBytes( p, b, m, n, d )                          \
 126          (p)->root.funcs.to_bytes( &(p)->root, b, m, n, d )
 127
 128#define T1_ToFixedArray( p, m, f, t )                           \
 129          (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
 130#define T1_ToToken( p, t )                          \
 131          (p)->root.funcs.to_token( &(p)->root, t )
 132
 133#define T1_Load_Field( p, f, o, m, pf )                         \
 134          (p)->root.funcs.load_field( &(p)->root, f, o, m, pf )
 135#define T1_Load_Field_Table( p, f, o, m, pf )                         \
 136          (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf )
 137
 138
 139  /********************* Parsing Functions ******************/
 140
 141  FT_LOCAL_DEF( FT_Error )
 142  t42_parser_init( T42_Parser     parser,
 143                   FT_Stream      stream,
 144                   FT_Memory      memory,
 145                   PSAux_Service  psaux )
 146  {
 147    FT_Error  error = T42_Err_Ok;
 148    FT_Long   size;
 149
 150
 151    psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory );
 152
 153    parser->stream    = stream;
 154    parser->base_len  = 0;
 155    parser->base_dict = 0;
 156    parser->in_memory = 0;
 157
 158    /*******************************************************************/
 159    /*                                                                 */
 160    /* Here a short summary of what is going on:                       */
 161    /*                                                                 */
 162    /*   When creating a new Type 42 parser, we try to locate and load */
 163    /*   the base dictionary, loading the whole font into memory.      */
 164    /*                                                                 */
 165    /*   When `loading' the base dictionary, we only set up pointers   */
 166    /*   in the case of a memory-based stream.  Otherwise, we allocate */
 167    /*   and load the base dictionary in it.                           */
 168    /*                                                                 */
 169    /*   parser->in_memory is set if we have a memory stream.          */
 170    /*                                                                 */
 171
 172    if ( FT_STREAM_SEEK( 0L ) ||
 173         FT_FRAME_ENTER( 17 ) )
 174      goto Exit;
 175
 176    if ( ft_memcmp( stream->cursor, "%!PS-TrueTypeFont", 17 ) != 0 )
 177    {
 178      FT_TRACE2(( "  not a Type42 font\n" ));
 179      error = T42_Err_Unknown_File_Format;
 180    }
 181
 182    FT_FRAME_EXIT();
 183
 184    if ( error || FT_STREAM_SEEK( 0 ) )
 185      goto Exit;
 186
 187    size = stream->size;
 188
 189    /* now, try to load `size' bytes of the `base' dictionary we */
 190    /* found previously                                          */
 191
 192    /* if it is a memory-based resource, set up pointers */
 193    if ( !stream->read )
 194    {
 195      parser->base_dict = (FT_Byte*)stream->base + stream->pos;
 196      parser->base_len  = size;
 197      parser->in_memory = 1;
 198
 199      /* check that the `size' field is valid */
 200      if ( FT_STREAM_SKIP( size ) )
 201        goto Exit;
 202    }
 203    else
 204    {
 205      /* read segment in memory */
 206      if ( FT_ALLOC( parser->base_dict, size )       ||
 207           FT_STREAM_READ( parser->base_dict, size ) )
 208        goto Exit;
 209
 210      parser->base_len = size;
 211    }
 212
 213    parser->root.base   = parser->base_dict;
 214    parser->root.cursor = parser->base_dict;
 215    parser->root.limit  = parser->root.cursor + parser->base_len;
 216
 217  Exit:
 218    if ( error && !parser->in_memory )
 219      FT_FREE( parser->base_dict );
 220
 221    return error;
 222  }
 223
 224
 225  FT_LOCAL_DEF( void )
 226  t42_parser_done( T42_Parser  parser )
 227  {
 228    FT_Memory  memory = parser->root.memory;
 229
 230
 231    /* free the base dictionary only when we have a disk stream */
 232    if ( !parser->in_memory )
 233      FT_FREE( parser->base_dict );
 234
 235    parser->root.funcs.done( &parser->root );
 236  }
 237
 238
 239  static int
 240  t42_is_space( FT_Byte  c )
 241  {
 242    return ( c == ' '  || c == '\t'              ||
 243             c == '\r' || c == '\n' || c == '\f' ||
 244             c == '\0'                           );
 245  }
 246
 247
 248  static void
 249  t42_parse_font_matrix( T42_Face    face,
 250                         T42_Loader  loader )
 251  {
 252    T42_Parser  parser = &loader->parser;
 253    FT_Matrix*  matrix = &face->type1.font_matrix;
 254    FT_Vector*  offset = &face->type1.font_offset;
 255    FT_Face     root   = (FT_Face)&face->root;
 256    FT_Fixed    temp[6];
 257    FT_Fixed    temp_scale;
 258
 259
 260    (void)T1_ToFixedArray( parser, 6, temp, 3 );
 261
 262    temp_scale = FT_ABS( temp[3] );
 263
 264    /* Set Units per EM based on FontMatrix values.  We set the value to */
 265    /* 1000 / temp_scale, because temp_scale was already multiplied by   */
 266    /* 1000 (in t1_tofixed, from psobjs.c).                              */
 267
 268    root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L,
 269                                                 temp_scale ) >> 16 );
 270
 271    /* we need to scale the values by 1.0/temp_scale */
 272    if ( temp_scale != 0x10000L )
 273    {
 274      temp[0] = FT_DivFix( temp[0], temp_scale );
 275      temp[1] = FT_DivFix( temp[1], temp_scale );
 276      temp[2] = FT_DivFix( temp[2], temp_scale );
 277      temp[4] = FT_DivFix( temp[4], temp_scale );
 278      temp[5] = FT_DivFix( temp[5], temp_scale );
 279      temp[3] = 0x10000L;
 280    }
 281
 282    matrix->xx = temp[0];
 283    matrix->yx = temp[1];
 284    matrix->xy = temp[2];
 285    matrix->yy = temp[3];
 286
 287    /* note that the offsets must be expressed in integer font units */
 288    offset->x = temp[4] >> 16;
 289    offset->y = temp[5] >> 16;
 290  }
 291
 292
 293  static void
 294  t42_parse_encoding( T42_Face    face,
 295                      T42_Loader  loader )
 296  {
 297    T42_Parser  parser = &loader->parser;
 298    FT_Byte*    cur;
 299    FT_Byte*    limit  = parser->root.limit;
 300
 301    PSAux_Service  psaux  = (PSAux_Service)face->psaux;
 302
 303
 304    T1_Skip_Spaces( parser );
 305    cur = parser->root.cursor;
 306    if ( cur >= limit )
 307    {
 308      FT_ERROR(( "t42_parse_encoding: out of bounds\n" ));
 309      parser->root.error = T42_Err_Invalid_File_Format;
 310      return;
 311    }
 312
 313    /* if we have a number or `[', the encoding is an array, */
 314    /* and we must load it now                               */
 315    if ( ft_isdigit( *cur ) || *cur == '[' )
 316    {
 317      T1_Encoding  encode          = &face->type1.encoding;
 318      FT_UInt      count, n;
 319      PS_Table     char_table      = &loader->encoding_table;
 320      FT_Memory    memory          = parser->root.memory;
 321      FT_Error     error;
 322      FT_Bool      only_immediates = 0;
 323
 324
 325      /* read the number of entries in the encoding; should be 256 */
 326      if ( *cur == '[' )
 327      {
 328        count           = 256;
 329        only_immediates = 1;
 330        parser->root.cursor++;
 331      }
 332      else
 333        count = (FT_UInt)T1_ToInt( parser );
 334
 335      T1_Skip_Spaces( parser );
 336      if ( parser->root.cursor >= limit )
 337        return;
 338
 339      /* we use a T1_Table to store our charnames */
 340      loader->num_chars = encode->num_chars = count;
 341      if ( FT_NEW_ARRAY( encode->char_index, count )     ||
 342           FT_NEW_ARRAY( encode->char_name,  count )     ||
 343           FT_SET_ERROR( psaux->ps_table_funcs->init(
 344                           char_table, count, memory ) ) )
 345      {
 346        parser->root.error = error;
 347        return;
 348      }
 349
 350      /* We need to `zero' out encoding_table.elements */
 351      for ( n = 0; n < count; n++ )
 352      {
 353        char*  notdef = (char *)".notdef";
 354
 355
 356        T1_Add_Table( char_table, n, notdef, 8 );
 357      }
 358
 359      /* Now we need to read records of the form                */
 360      /*                                                        */
 361      /*   ... charcode /charname ...                           */
 362      /*                                                        */
 363      /* for each entry in our table.                           */
 364      /*                                                        */
 365      /* We simply look for a number followed by an immediate   */
 366      /* name.  Note that this ignores correctly the sequence   */
 367      /* that is often seen in type42 fonts:                    */
 368      /*                                                        */
 369      /*   0 1 255 { 1 index exch /.notdef put } for dup        */
 370      /*                                                        */
 371      /* used to clean the encoding array before anything else. */
 372      /*                                                        */
 373      /* Alternatively, if the array is directly given as       */
 374      /*                                                        */
 375      /*   /Encoding [ ... ]                                    */
 376      /*                                                        */
 377      /* we only read immediates.                               */
 378
 379      n = 0;
 380      T1_Skip_Spaces( parser );
 381
 382      while ( parser->root.cursor < limit )
 383      {
 384        cur = parser->root.cursor;
 385
 386        /* we stop when we encounter `def' or `]' */
 387        if ( *cur == 'd' && cur + 3 < limit )
 388        {
 389          if ( cur[1] == 'e'          &&
 390               cur[2] == 'f'          &&
 391               t42_is_space( cur[3] ) )
 392          {
 393            FT_TRACE6(( "encoding end\n" ));
 394            cur += 3;
 395            break;
 396          }
 397        }
 398        if ( *cur == ']' )
 399        {
 400          FT_TRACE6(( "encoding end\n" ));
 401          cur++;
 402          break;
 403        }
 404
 405        /* check whether we have found an entry */
 406        if ( ft_isdigit( *cur ) || only_immediates )
 407        {
 408          FT_Int  charcode;
 409
 410
 411          if ( only_immediates )
 412            charcode = n;
 413          else
 414          {
 415            charcode = (FT_Int)T1_ToInt( parser );
 416            T1_Skip_Spaces( parser );
 417          }
 418
 419          cur = parser->root.cursor;
 420
 421          if ( *cur == '/' && cur + 2 < limit && n < count )
 422          {
 423            FT_PtrDist  len;
 424
 425
 426            cur++;
 427
 428            parser->root.cursor = cur;
 429            T1_Skip_PS_Token( parser );
 430            if ( parser->root.error )
 431              return;
 432
 433            len = parser->root.cursor - cur;
 434
 435            parser->root.error = T1_Add_Table( char_table, charcode,
 436                                               cur, len + 1 );
 437            if ( parser->root.error )
 438              return;
 439            char_table->elements[charcode][len] = '\0';
 440
 441            n++;
 442          }
 443        }
 444        else
 445        {
 446          T1_Skip_PS_Token( parser );
 447          if ( parser->root.error )
 448            return;
 449        }
 450
 451        T1_Skip_Spaces( parser );
 452      }
 453
 454      face->type1.encoding_type  = T1_ENCODING_TYPE_ARRAY;
 455      parser->root.cursor        = cur;
 456    }
 457
 458    /* Otherwise, we should have either `StandardEncoding', */
 459    /* `ExpertEncoding', or `ISOLatin1Encoding'             */
 460    else
 461    {
 462      if ( cur + 17 < limit                                            &&
 463           ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
 464        face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
 465
 466      else if ( cur + 15 < limit                                          &&
 467                ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
 468        face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
 469
 470      else if ( cur + 18 < limit                                             &&
 471                ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
 472        face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
 473
 474      else
 475      {
 476        FT_ERROR(( "t42_parse_encoding: invalid token\n" ));
 477        parser->root.error = T42_Err_Invalid_File_Format;
 478      }
 479    }
 480  }
 481
 482
 483  typedef enum  T42_Load_Status_
 484  {
 485    BEFORE_START,
 486    BEFORE_TABLE_DIR,
 487    OTHER_TABLES
 488
 489  } T42_Load_Status;
 490
 491
 492  static void
 493  t42_parse_sfnts( T42_Face    face,
 494                   T42_Loader  loader )
 495  {
 496    T42_Parser  parser = &loader->parser;
 497    FT_Memory   memory = parser->root.memory;
 498    FT_Byte*    cur;
 499    FT_Byte*    limit  = parser->root.limit;
 500    FT_Error    error;
 501    FT_Int      num_tables = 0;
 502    FT_ULong    count, ttf_size = 0;
 503
 504    FT_Long     n, string_size, old_string_size, real_size;
 505    FT_Byte*    string_buf = NULL;
 506    FT_Bool     allocated  = 0;
 507
 508    T42_Load_Status  status;
 509
 510
 511    /* The format is                                */
 512    /*                                              */
 513    /*   /sfnts [ <hexstring> <hexstring> ... ] def */
 514    /*                                              */
 515    /* or                                           */
 516    /*                                              */
 517    /*   /sfnts [                                   */
 518    /*      <num_bin_bytes> RD <binary data>        */
 519    /*      <num_bin_bytes> RD <binary data>        */
 520    /*      ...                                     */
 521    /*   ] def                                      */
 522    /*                                              */
 523    /* with exactly one space after the `RD' token. */
 524
 525    T1_Skip_Spaces( parser );
 526
 527    if ( parser->root.cursor >= limit || *parser->root.cursor++ != '[' )
 528    {
 529      FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector\n" ));
 530      error = T42_Err_Invalid_File_Format;
 531      goto Fail;
 532    }
 533
 534    T1_Skip_Spaces( parser );
 535    status          = BEFORE_START;
 536    string_size     = 0;
 537    old_string_size = 0;
 538    count           = 0;
 539
 540    while ( parser->root.cursor < limit )
 541    {
 542      cur = parser->root.cursor;
 543
 544      if ( *cur == ']' )
 545      {
 546        parser->root.cursor++;
 547        goto Exit;
 548      }
 549
 550      else if ( *cur == '<' )
 551      {
 552        T1_Skip_PS_Token( parser );
 553        if ( parser->root.error )
 554          goto Exit;
 555
 556        /* don't include delimiters */
 557        string_size = (FT_Long)( ( parser->root.cursor - cur - 2 + 1 ) / 2 );
 558        if ( FT_REALLOC( string_buf, old_string_size, string_size ) )
 559          goto Fail;
 560
 561        allocated = 1;
 562
 563        parser->root.cursor = cur;
 564        (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 );
 565        old_string_size = string_size;
 566        string_size = real_size;
 567      }
 568
 569      else if ( ft_isdigit( *cur ) )
 570      {
 571        if ( allocated )
 572        {
 573          FT_ERROR(( "t42_parse_sfnts: "
 574                     "can't handle mixed binary and hex strings\n" ));
 575          error = T42_Err_Invalid_File_Format;
 576          goto Fail;
 577        }
 578
 579        string_size = T1_ToInt( parser );
 580        if ( string_size < 0 )
 581        {
 582          FT_ERROR(( "t42_parse_sfnts: invalid string size\n" ));
 583          error = T42_Err_Invalid_File_Format;
 584          goto Fail;
 585        }
 586
 587        T1_Skip_PS_Token( parser );             /* `RD' */
 588        if ( parser->root.error )
 589          return;
 590
 591        string_buf = parser->root.cursor + 1;   /* one space after `RD' */
 592
 593        if ( limit - parser->root.cursor < string_size )
 594        {
 595          FT_ERROR(( "t42_parse_sfnts: too many binary data\n" ));
 596          error = T42_Err_Invalid_File_Format;
 597          goto Fail;
 598        }
 599        else
 600          parser->root.cursor += string_size + 1;
 601      }
 602
 603      if ( !string_buf )
 604      {
 605        FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
 606        error = T42_Err_Invalid_File_Format;
 607        goto Fail;
 608      }
 609
 610      /* A string can have a trailing zero (odd) byte for padding. */
 611      /* Ignore it.                                                */
 612      if ( ( string_size & 1 ) && string_buf[string_size - 1] == 0 )
 613        string_size--;
 614
 615      if ( !string_size )
 616      {
 617        FT_ERROR(( "t42_parse_sfnts: invalid string\n" ));
 618        error = T42_Err_Invalid_File_Format;
 619        goto Fail;
 620      }
 621
 622      for ( n = 0; n < string_size; n++ )
 623      {
 624        switch ( status )
 625        {
 626        case BEFORE_START:
 627          /* load offset table, 12 bytes */
 628          if ( count < 12 )
 629          {
 630            face->ttf_data[count++] = string_buf[n];
 631            continue;
 632          }
 633          else
 634          {
 635            num_tables = 16 * face->ttf_data[4] + face->ttf_data[5];
 636            status     = BEFORE_TABLE_DIR;
 637            ttf_size   = 12 + 16 * num_tables;
 638
 639            if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) )
 640              goto Fail;
 641          }
 642          /* fall through */
 643
 644        case BEFORE_TABLE_DIR:
 645          /* the offset table is read; read the table directory */
 646          if ( count < ttf_size )
 647          {
 648            face->ttf_data[count++] = string_buf[n];
 649            continue;
 650          }
 651          else
 652          {
 653            int       i;
 654            FT_ULong  len;
 655
 656
 657            for ( i = 0; i < num_tables; i++ )
 658            {
 659              FT_Byte*  p = face->ttf_data + 12 + 16 * i + 12;
 660
 661
 662              len = FT_PEEK_ULONG( p );
 663
 664              /* Pad to a 4-byte boundary length */
 665              ttf_size += ( len + 3 ) & ~3;
 666            }
 667
 668            status         = OTHER_TABLES;
 669            face->ttf_size = ttf_size;
 670
 671            /* there are no more than 256 tables, so no size check here */
 672            if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables,
 673                             ttf_size + 1 ) )
 674              goto Fail;
 675          }
 676          /* fall through */
 677
 678        case OTHER_TABLES:
 679          /* all other tables are just copied */
 680          if ( count >= ttf_size )
 681          {
 682            FT_ERROR(( "t42_parse_sfnts: too many binary data\n" ));
 683            error = T42_Err_Invalid_File_Format;
 684            goto Fail;
 685          }
 686          face->ttf_data[count++] = string_buf[n];
 687        }
 688      }
 689
 690      T1_Skip_Spaces( parser );
 691    }
 692
 693    /* if control reaches this point, the format was not valid */
 694    error = T42_Err_Invalid_File_Format;
 695
 696  Fail:
 697    parser->root.error = error;
 698
 699  Exit:
 700    if ( allocated )
 701      FT_FREE( string_buf );
 702  }
 703
 704
 705  static void
 706  t42_parse_charstrings( T42_Face    face,
 707                         T42_Loader  loader )
 708  {
 709    T42_Parser     parser       = &loader->parser;
 710    PS_Table       code_table   = &loader->charstrings;
 711    PS_Table       name_table   = &loader->glyph_names;
 712    PS_Table       swap_table   = &loader->swap_table;
 713    FT_Memory      memory       = parser->root.memory;
 714    FT_Error       error;
 715
 716    PSAux_Service  psaux        = (PSAux_Service)face->psaux;
 717
 718    FT_Byte*       cur;
 719    FT_Byte*       limit        = parser->root.limit;
 720    FT_UInt        n;
 721    FT_UInt        notdef_index = 0;
 722    FT_Byte        notdef_found = 0;
 723
 724
 725    T1_Skip_Spaces( parser );
 726
 727    if ( parser->root.cursor >= limit )
 728    {
 729      FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
 730      error = T42_Err_Invalid_File_Format;
 731      goto Fail;
 732    }
 733
 734    if ( ft_isdigit( *parser->root.cursor ) )
 735    {
 736      loader->num_glyphs = (FT_UInt)T1_ToInt( parser );
 737      if ( parser->root.error )
 738        return;
 739    }
 740    else if ( *parser->root.cursor == '<' )
 741    {
 742      /* We have `<< ... >>'.  Count the number of `/' in the dictionary */
 743      /* to get its size.                                                */
 744      FT_UInt  count = 0;
 745
 746
 747      T1_Skip_PS_Token( parser );
 748      if ( parser->root.error )
 749        return;
 750      T1_Skip_Spaces( parser );
 751      cur = parser->root.cursor;
 752
 753      while ( parser->root.cursor < limit )
 754      {
 755        if ( *parser->root.cursor == '/' )
 756          count++;
 757        else if ( *parser->root.cursor == '>' )
 758        {
 759          loader->num_glyphs  = count;
 760          parser->root.cursor = cur;        /* rewind */
 761          break;
 762        }
 763        T1_Skip_PS_Token( parser );
 764        if ( parser->root.error )
 765          return;
 766        T1_Skip_Spaces( parser );
 767      }
 768    }
 769    else
 770    {
 771      FT_ERROR(( "t42_parse_charstrings: invalid token\n" ));
 772      error = T42_Err_Invalid_File_Format;
 773      goto Fail;
 774    }
 775
 776    if ( parser->root.cursor >= limit )
 777    {
 778      FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
 779      error = T42_Err_Invalid_File_Format;
 780      goto Fail;
 781    }
 782
 783    /* initialize tables */
 784
 785    error = psaux->ps_table_funcs->init( code_table,
 786                                         loader->num_glyphs,
 787                                         memory );
 788    if ( error )
 789      goto Fail;
 790
 791    error = psaux->ps_table_funcs->init( name_table,
 792                                         loader->num_glyphs,
 793                                         memory );
 794    if ( error )
 795      goto Fail;
 796
 797    /* Initialize table for swapping index notdef_index and */
 798    /* index 0 names and codes (if necessary).              */
 799
 800    error = psaux->ps_table_funcs->init( swap_table, 4, memory );
 801    if ( error )
 802      goto Fail;
 803
 804    n = 0;
 805
 806    for (;;)
 807    {
 808      /* The format is simple:                   */
 809      /*   `/glyphname' + index [+ def]          */
 810
 811      T1_Skip_Spaces( parser );
 812
 813      cur = parser->root.cursor;
 814      if ( cur >= limit )
 815        break;
 816
 817      /* We stop when we find an `end' keyword or '>' */
 818      if ( *cur   == 'e'          &&
 819           cur + 3 < limit        &&
 820           cur[1] == 'n'          &&
 821           cur[2] == 'd'          &&
 822           t42_is_space( cur[3] ) )
 823        break;
 824      if ( *cur == '>' )
 825        break;
 826
 827      T1_Skip_PS_Token( parser );
 828      if ( parser->root.error )
 829        return;
 830
 831      if ( *cur == '/' )
 832      {
 833        FT_PtrDist  len;
 834
 835
 836        if ( cur + 1 >= limit )
 837        {
 838          FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
 839          error = T42_Err_Invalid_File_Format;
 840          goto Fail;
 841        }
 842
 843        cur++;                              /* skip `/' */
 844        len = parser->root.cursor - cur;
 845
 846        error = T1_Add_Table( name_table, n, cur, len + 1 );
 847        if ( error )
 848          goto Fail;
 849
 850        /* add a trailing zero to the name table */
 851        name_table->elements[n][len] = '\0';
 852
 853        /* record index of /.notdef */
 854        if ( *cur == '.'                                              &&
 855             ft_strcmp( ".notdef",
 856                        (const char*)(name_table->elements[n]) ) == 0 )
 857        {
 858          notdef_index = n;
 859          notdef_found = 1;
 860        }
 861
 862        T1_Skip_Spaces( parser );
 863
 864        cur = parser->root.cursor;
 865
 866        (void)T1_ToInt( parser );
 867        if ( parser->root.cursor >= limit )
 868        {
 869          FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
 870          error = T42_Err_Invalid_File_Format;
 871          goto Fail;
 872        }
 873
 874        len = parser->root.cursor - cur;
 875
 876        error = T1_Add_Table( code_table, n, cur, len + 1 );
 877        if ( error )
 878          goto Fail;
 879
 880        code_table->elements[n][len] = '\0';
 881
 882        n++;
 883        if ( n >= loader->num_glyphs )
 884          break;
 885      }
 886    }
 887
 888    loader->num_glyphs = n;
 889
 890    if ( !notdef_found )
 891    {
 892      FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph\n" ));
 893      error = T42_Err_Invalid_File_Format;
 894      goto Fail;
 895    }
 896
 897    /* if /.notdef does not occupy index 0, do our magic. */
 898    if ( ft_strcmp( (const char*)".notdef",
 899                    (const char*)name_table->elements[0] ) )
 900    {
 901      /* Swap glyph in index 0 with /.notdef glyph.  First, add index 0  */
 902      /* name and code entries to swap_table.  Then place notdef_index   */
 903      /* name and code entries into swap_table.  Then swap name and code */
 904      /* entries at indices notdef_index and 0 using values stored in    */
 905      /* swap_table.                                                     */
 906
 907      /* Index 0 name */
 908      error = T1_Add_Table( swap_table, 0,
 909                            name_table->elements[0],
 910                            name_table->lengths [0] );
 911      if ( error )
 912        goto Fail;
 913
 914      /* Index 0 code */
 915      error = T1_Add_Table( swap_table, 1,
 916                            code_table->elements[0],
 917                            code_table->lengths [0] );
 918      if ( error )
 919        goto Fail;
 920
 921      /* Index notdef_index name */
 922      error = T1_Add_Table( swap_table, 2,
 923                            name_table->elements[notdef_index],
 924                            name_table->lengths [notdef_index] );
 925      if ( error )
 926        goto Fail;
 927
 928      /* Index notdef_index code */
 929      error = T1_Add_Table( swap_table, 3,
 930                            code_table->elements[notdef_index],
 931                            code_table->lengths [notdef_index] );
 932      if ( error )
 933        goto Fail;
 934
 935      error = T1_Add_Table( name_table, notdef_index,
 936                            swap_table->elements[0],
 937                            swap_table->lengths [0] );
 938      if ( error )
 939        goto Fail;
 940
 941      error = T1_Add_Table( code_table, notdef_index,
 942                            swap_table->elements[1],
 943                            swap_table->lengths [1] );
 944      if ( error )
 945        goto Fail;
 946
 947      error = T1_Add_Table( name_table, 0,
 948                            swap_table->elements[2],
 949                            swap_table->lengths [2] );
 950      if ( error )
 951        goto Fail;
 952
 953      error = T1_Add_Table( code_table, 0,
 954                            swap_table->elements[3],
 955                            swap_table->lengths [3] );
 956      if ( error )
 957        goto Fail;
 958
 959    }
 960
 961    return;
 962
 963  Fail:
 964    parser->root.error = error;
 965  }
 966
 967
 968  static FT_Error
 969  t42_load_keyword( T42_Face    face,
 970                    T42_Loader  loader,
 971                    T1_Field    field )
 972  {
 973    FT_Error  error;
 974    void*     dummy_object;
 975    void**    objects;
 976    FT_UInt   max_objects = 0;
 977
 978
 979    /* if the keyword has a dedicated callback, call it */
 980    if ( field->type == T1_FIELD_TYPE_CALLBACK )
 981    {
 982      field->reader( (FT_Face)face, loader );
 983      error = loader->parser.root.error;
 984      goto Exit;
 985    }
 986
 987    /* now the keyword is either a simple field or a table of fields; */
 988    /* we are now going to take care of it                            */
 989
 990    switch ( field->location )
 991    {
 992    case T1_FIELD_LOCATION_FONT_INFO:
 993      dummy_object = &face->type1.font_info;
 994      break;
 995
 996    case T1_FIELD_LOCATION_FONT_EXTRA:
 997      dummy_object = &face->type1.font_extra;
 998      break;
 999
1000    case T1_FIELD_LOCATION_BBOX:
1001      dummy_object = &face->type1.font_bbox;
1002      break;
1003
1004    default:
1005      dummy_object = &face->type1;
1006    }
1007
1008    objects = &dummy_object;
1009
1010    if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
1011         field->type == T1_FIELD_TYPE_FIXED_ARRAY   )
1012      error = T1_Load_Field_Table( &loader->parser, field,
1013                                   objects, max_objects, 0 );
1014    else
1015      error = T1_Load_Field( &loader->parser, field,
1016                             objects, max_objects, 0 );
1017
1018   Exit:
1019    return error;
1020  }
1021
1022
1023  FT_LOCAL_DEF( FT_Error )
1024  t42_parse_dict( T42_Face    face,
1025                  T42_Loader  loader,
1026                  FT_Byte*    base,
1027                  FT_Long     size )
1028  {
1029    T42_Parser  parser     = &loader->parser;
1030    FT_Byte*    limit;
1031    FT_Int      n_keywords = (FT_Int)( sizeof ( t42_keywords ) /
1032                                         sizeof ( t42_keywords[0] ) );
1033
1034
1035    parser->root.cursor = base;
1036    parser->root.limit  = base + size;
1037    parser->root.error  = T42_Err_Ok;
1038
1039    limit = parser->root.limit;
1040
1041    T1_Skip_Spaces( parser );
1042
1043    while ( parser->root.cursor < limit )
1044    {
1045      FT_Byte*  cur;
1046
1047
1048      cur = parser->root.cursor;
1049
1050      /* look for `FontDirectory' which causes problems for some fonts */
1051      if ( *cur == 'F' && cur + 25 < limit                    &&
1052           ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
1053      {
1054        FT_Byte*  cur2;
1055
1056
1057        /* skip the `FontDirectory' keyword */
1058        T1_Skip_PS_Token( parser );
1059        T1_Skip_Spaces  ( parser );
1060        cur = cur2 = parser->root.cursor;
1061
1062        /* look up the `known' keyword */
1063        while ( cur < limit )
1064        {
1065          if ( *cur == 'k' && cur + 5 < limit             &&
1066                ft_strncmp( (char*)cur, "known", 5 ) == 0 )
1067            break;
1068
1069          T1_Skip_PS_Token( parser );
1070          if ( parser->root.error )
1071            goto Exit;
1072          T1_Skip_Spaces  ( parser );
1073          cur = parser->root.cursor;
1074        }
1075
1076        if ( cur < limit )
1077        {
1078          T1_TokenRec  token;
1079
1080
1081          /* skip the `known' keyword and the token following it */
1082          T1_Skip_PS_Token( parser );
1083          T1_ToToken( parser, &token );
1084
1085          /* if the last token was an array, skip it! */
1086          if ( token.type == T1_TOKEN_TYPE_ARRAY )
1087            cur2 = parser->root.cursor;
1088        }
1089        parser->root.cursor = cur2;
1090      }
1091
1092      /* look for immediates */
1093      else if ( *cur == '/' && cur + 2 < limit )
1094      {
1095        FT_PtrDist  len;
1096
1097
1098        cur++;
1099
1100        parser->root.cursor = cur;
1101        T1_Skip_PS_Token( parser );
1102        if ( parser->root.error )
1103          goto Exit;
1104
1105        len = parser->root.cursor - cur;
1106
1107        if ( len > 0 && len < 22 && parser->root.cursor < limit )
1108        {
1109          int  i;
1110
1111
1112          /* now compare the immediate name to the keyword table */
1113
1114          /* loop through all known keywords */
1115          for ( i = 0; i < n_keywords; i++ )
1116          {
1117            T1_Field  keyword = (T1_Field)&t42_keywords[i];
1118            FT_Byte   *name   = (FT_Byte*)keyword->ident;
1119
1120
1121            if ( !name )
1122              continue;
1123
1124            if ( cur[0] == name[0]                                  &&
1125                 len == (FT_PtrDist)ft_strlen( (const char *)name ) &&
1126                 ft_memcmp( cur, name, len ) == 0                   )
1127            {
1128              /* we found it -- run the parsing callback! */
1129              parser->root.error = t42_load_keyword( face,
1130                                                     loader,
1131                                                     keyword );
1132              if ( parser->root.error )
1133                return parser->root.error;
1134              break;
1135            }
1136          }
1137        }
1138      }
1139      else
1140      {
1141        T1_Skip_PS_Token( parser );
1142        if ( parser->root.error )
1143          goto Exit;
1144      }
1145
1146      T1_Skip_Spaces( parser );
1147    }
1148
1149  Exit:
1150    return parser->root.error;
1151  }
1152
1153
1154  FT_LOCAL_DEF( void )
1155  t42_loader_init( T42_Loader  loader,
1156                   T42_Face    face )
1157  {
1158    FT_UNUSED( face );
1159
1160    FT_MEM_ZERO( loader, sizeof ( *loader ) );
1161    loader->num_glyphs = 0;
1162    loader->num_chars  = 0;
1163
1164    /* initialize the tables -- simply set their `init' field to 0 */
1165    loader->encoding_table.init = 0;
1166    loader->charstrings.init    = 0;
1167    loader->glyph_names.init    = 0;
1168  }
1169
1170
1171  FT_LOCAL_DEF( void )
1172  t42_loader_done( T42_Loader  loader )
1173  {
1174    T42_Parser  parser = &loader->parser;
1175
1176
1177    /* finalize tables */
1178    T1_Release_Table( &loader->encoding_table );
1179    T1_Release_Table( &loader->charstrings );
1180    T1_Release_Table( &loader->glyph_names );
1181    T1_Release_Table( &loader->swap_table );
1182
1183    /* finalize parser */
1184    t42_parser_done( parser );
1185  }
1186
1187
1188/* END */