misc/libfreetype/src/type42/t42parse.c
changeset 9431 0f5961910e27
parent 9357 a501f5ec7b34
parent 9429 7a97a554ac80
child 9433 f0a8ac191839
equal deleted inserted replaced
9357:a501f5ec7b34 9431:0f5961910e27
     1 /***************************************************************************/
       
     2 /*                                                                         */
       
     3 /*  t42parse.c                                                             */
       
     4 /*                                                                         */
       
     5 /*    Type 42 font parser (body).                                          */
       
     6 /*                                                                         */
       
     7 /*  Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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 byte for padding.  Ignore it. */
       
   611       if ( string_buf[string_size - 1] == 0 && ( string_size % 2 == 1 ) )
       
   612         string_size--;
       
   613 
       
   614       if ( !string_size )
       
   615       {
       
   616         FT_ERROR(( "t42_parse_sfnts: invalid string\n" ));
       
   617         error = T42_Err_Invalid_File_Format;
       
   618         goto Fail;
       
   619       }
       
   620 
       
   621       for ( n = 0; n < string_size; n++ )
       
   622       {
       
   623         switch ( status )
       
   624         {
       
   625         case BEFORE_START:
       
   626           /* load offset table, 12 bytes */
       
   627           if ( count < 12 )
       
   628           {
       
   629             face->ttf_data[count++] = string_buf[n];
       
   630             continue;
       
   631           }
       
   632           else
       
   633           {
       
   634             num_tables = 16 * face->ttf_data[4] + face->ttf_data[5];
       
   635             status     = BEFORE_TABLE_DIR;
       
   636             ttf_size   = 12 + 16 * num_tables;
       
   637 
       
   638             if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) )
       
   639               goto Fail;
       
   640           }
       
   641           /* fall through */
       
   642 
       
   643         case BEFORE_TABLE_DIR:
       
   644           /* the offset table is read; read the table directory */
       
   645           if ( count < ttf_size )
       
   646           {
       
   647             face->ttf_data[count++] = string_buf[n];
       
   648             continue;
       
   649           }
       
   650           else
       
   651           {
       
   652             int       i;
       
   653             FT_ULong  len;
       
   654 
       
   655 
       
   656             for ( i = 0; i < num_tables; i++ )
       
   657             {
       
   658               FT_Byte*  p = face->ttf_data + 12 + 16 * i + 12;
       
   659 
       
   660 
       
   661               len = FT_PEEK_ULONG( p );
       
   662 
       
   663               /* Pad to a 4-byte boundary length */
       
   664               ttf_size += ( len + 3 ) & ~3;
       
   665             }
       
   666 
       
   667             status         = OTHER_TABLES;
       
   668             face->ttf_size = ttf_size;
       
   669 
       
   670             /* there are no more than 256 tables, so no size check here */
       
   671             if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables,
       
   672                              ttf_size + 1 ) )
       
   673               goto Fail;
       
   674           }
       
   675           /* fall through */
       
   676 
       
   677         case OTHER_TABLES:
       
   678           /* all other tables are just copied */
       
   679           if ( count >= ttf_size )
       
   680           {
       
   681             FT_ERROR(( "t42_parse_sfnts: too many binary data\n" ));
       
   682             error = T42_Err_Invalid_File_Format;
       
   683             goto Fail;
       
   684           }
       
   685           face->ttf_data[count++] = string_buf[n];
       
   686         }
       
   687       }
       
   688 
       
   689       T1_Skip_Spaces( parser );
       
   690     }
       
   691 
       
   692     /* if control reaches this point, the format was not valid */
       
   693     error = T42_Err_Invalid_File_Format;
       
   694 
       
   695   Fail:
       
   696     parser->root.error = error;
       
   697 
       
   698   Exit:
       
   699     if ( allocated )
       
   700       FT_FREE( string_buf );
       
   701   }
       
   702 
       
   703 
       
   704   static void
       
   705   t42_parse_charstrings( T42_Face    face,
       
   706                          T42_Loader  loader )
       
   707   {
       
   708     T42_Parser     parser       = &loader->parser;
       
   709     PS_Table       code_table   = &loader->charstrings;
       
   710     PS_Table       name_table   = &loader->glyph_names;
       
   711     PS_Table       swap_table   = &loader->swap_table;
       
   712     FT_Memory      memory       = parser->root.memory;
       
   713     FT_Error       error;
       
   714 
       
   715     PSAux_Service  psaux        = (PSAux_Service)face->psaux;
       
   716 
       
   717     FT_Byte*       cur;
       
   718     FT_Byte*       limit        = parser->root.limit;
       
   719     FT_UInt        n;
       
   720     FT_UInt        notdef_index = 0;
       
   721     FT_Byte        notdef_found = 0;
       
   722 
       
   723 
       
   724     T1_Skip_Spaces( parser );
       
   725 
       
   726     if ( parser->root.cursor >= limit )
       
   727     {
       
   728       FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
       
   729       error = T42_Err_Invalid_File_Format;
       
   730       goto Fail;
       
   731     }
       
   732 
       
   733     if ( ft_isdigit( *parser->root.cursor ) )
       
   734     {
       
   735       loader->num_glyphs = (FT_UInt)T1_ToInt( parser );
       
   736       if ( parser->root.error )
       
   737         return;
       
   738     }
       
   739     else if ( *parser->root.cursor == '<' )
       
   740     {
       
   741       /* We have `<< ... >>'.  Count the number of `/' in the dictionary */
       
   742       /* to get its size.                                                */
       
   743       FT_UInt  count = 0;
       
   744 
       
   745 
       
   746       T1_Skip_PS_Token( parser );
       
   747       if ( parser->root.error )
       
   748         return;
       
   749       T1_Skip_Spaces( parser );
       
   750       cur = parser->root.cursor;
       
   751 
       
   752       while ( parser->root.cursor < limit )
       
   753       {
       
   754         if ( *parser->root.cursor == '/' )
       
   755           count++;
       
   756         else if ( *parser->root.cursor == '>' )
       
   757         {
       
   758           loader->num_glyphs  = count;
       
   759           parser->root.cursor = cur;        /* rewind */
       
   760           break;
       
   761         }
       
   762         T1_Skip_PS_Token( parser );
       
   763         if ( parser->root.error )
       
   764           return;
       
   765         T1_Skip_Spaces( parser );
       
   766       }
       
   767     }
       
   768     else
       
   769     {
       
   770       FT_ERROR(( "t42_parse_charstrings: invalid token\n" ));
       
   771       error = T42_Err_Invalid_File_Format;
       
   772       goto Fail;
       
   773     }
       
   774 
       
   775     if ( parser->root.cursor >= limit )
       
   776     {
       
   777       FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
       
   778       error = T42_Err_Invalid_File_Format;
       
   779       goto Fail;
       
   780     }
       
   781 
       
   782     /* initialize tables */
       
   783 
       
   784     error = psaux->ps_table_funcs->init( code_table,
       
   785                                          loader->num_glyphs,
       
   786                                          memory );
       
   787     if ( error )
       
   788       goto Fail;
       
   789 
       
   790     error = psaux->ps_table_funcs->init( name_table,
       
   791                                          loader->num_glyphs,
       
   792                                          memory );
       
   793     if ( error )
       
   794       goto Fail;
       
   795 
       
   796     /* Initialize table for swapping index notdef_index and */
       
   797     /* index 0 names and codes (if necessary).              */
       
   798 
       
   799     error = psaux->ps_table_funcs->init( swap_table, 4, memory );
       
   800     if ( error )
       
   801       goto Fail;
       
   802 
       
   803     n = 0;
       
   804 
       
   805     for (;;)
       
   806     {
       
   807       /* The format is simple:                   */
       
   808       /*   `/glyphname' + index [+ def]          */
       
   809 
       
   810       T1_Skip_Spaces( parser );
       
   811 
       
   812       cur = parser->root.cursor;
       
   813       if ( cur >= limit )
       
   814         break;
       
   815 
       
   816       /* We stop when we find an `end' keyword or '>' */
       
   817       if ( *cur   == 'e'          &&
       
   818            cur + 3 < limit        &&
       
   819            cur[1] == 'n'          &&
       
   820            cur[2] == 'd'          &&
       
   821            t42_is_space( cur[3] ) )
       
   822         break;
       
   823       if ( *cur == '>' )
       
   824         break;
       
   825 
       
   826       T1_Skip_PS_Token( parser );
       
   827       if ( parser->root.error )
       
   828         return;
       
   829 
       
   830       if ( *cur == '/' )
       
   831       {
       
   832         FT_PtrDist  len;
       
   833 
       
   834 
       
   835         if ( cur + 1 >= limit )
       
   836         {
       
   837           FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
       
   838           error = T42_Err_Invalid_File_Format;
       
   839           goto Fail;
       
   840         }
       
   841 
       
   842         cur++;                              /* skip `/' */
       
   843         len = parser->root.cursor - cur;
       
   844 
       
   845         error = T1_Add_Table( name_table, n, cur, len + 1 );
       
   846         if ( error )
       
   847           goto Fail;
       
   848 
       
   849         /* add a trailing zero to the name table */
       
   850         name_table->elements[n][len] = '\0';
       
   851 
       
   852         /* record index of /.notdef */
       
   853         if ( *cur == '.'                                              &&
       
   854              ft_strcmp( ".notdef",
       
   855                         (const char*)(name_table->elements[n]) ) == 0 )
       
   856         {
       
   857           notdef_index = n;
       
   858           notdef_found = 1;
       
   859         }
       
   860 
       
   861         T1_Skip_Spaces( parser );
       
   862 
       
   863         cur = parser->root.cursor;
       
   864 
       
   865         (void)T1_ToInt( parser );
       
   866         if ( parser->root.cursor >= limit )
       
   867         {
       
   868           FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
       
   869           error = T42_Err_Invalid_File_Format;
       
   870           goto Fail;
       
   871         }
       
   872 
       
   873         len = parser->root.cursor - cur;
       
   874 
       
   875         error = T1_Add_Table( code_table, n, cur, len + 1 );
       
   876         if ( error )
       
   877           goto Fail;
       
   878 
       
   879         code_table->elements[n][len] = '\0';
       
   880 
       
   881         n++;
       
   882         if ( n >= loader->num_glyphs )
       
   883           break;
       
   884       }
       
   885     }
       
   886 
       
   887     loader->num_glyphs = n;
       
   888 
       
   889     if ( !notdef_found )
       
   890     {
       
   891       FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph\n" ));
       
   892       error = T42_Err_Invalid_File_Format;
       
   893       goto Fail;
       
   894     }
       
   895 
       
   896     /* if /.notdef does not occupy index 0, do our magic. */
       
   897     if ( ft_strcmp( (const char*)".notdef",
       
   898                     (const char*)name_table->elements[0] ) )
       
   899     {
       
   900       /* Swap glyph in index 0 with /.notdef glyph.  First, add index 0  */
       
   901       /* name and code entries to swap_table.  Then place notdef_index   */
       
   902       /* name and code entries into swap_table.  Then swap name and code */
       
   903       /* entries at indices notdef_index and 0 using values stored in    */
       
   904       /* swap_table.                                                     */
       
   905 
       
   906       /* Index 0 name */
       
   907       error = T1_Add_Table( swap_table, 0,
       
   908                             name_table->elements[0],
       
   909                             name_table->lengths [0] );
       
   910       if ( error )
       
   911         goto Fail;
       
   912 
       
   913       /* Index 0 code */
       
   914       error = T1_Add_Table( swap_table, 1,
       
   915                             code_table->elements[0],
       
   916                             code_table->lengths [0] );
       
   917       if ( error )
       
   918         goto Fail;
       
   919 
       
   920       /* Index notdef_index name */
       
   921       error = T1_Add_Table( swap_table, 2,
       
   922                             name_table->elements[notdef_index],
       
   923                             name_table->lengths [notdef_index] );
       
   924       if ( error )
       
   925         goto Fail;
       
   926 
       
   927       /* Index notdef_index code */
       
   928       error = T1_Add_Table( swap_table, 3,
       
   929                             code_table->elements[notdef_index],
       
   930                             code_table->lengths [notdef_index] );
       
   931       if ( error )
       
   932         goto Fail;
       
   933 
       
   934       error = T1_Add_Table( name_table, notdef_index,
       
   935                             swap_table->elements[0],
       
   936                             swap_table->lengths [0] );
       
   937       if ( error )
       
   938         goto Fail;
       
   939 
       
   940       error = T1_Add_Table( code_table, notdef_index,
       
   941                             swap_table->elements[1],
       
   942                             swap_table->lengths [1] );
       
   943       if ( error )
       
   944         goto Fail;
       
   945 
       
   946       error = T1_Add_Table( name_table, 0,
       
   947                             swap_table->elements[2],
       
   948                             swap_table->lengths [2] );
       
   949       if ( error )
       
   950         goto Fail;
       
   951 
       
   952       error = T1_Add_Table( code_table, 0,
       
   953                             swap_table->elements[3],
       
   954                             swap_table->lengths [3] );
       
   955       if ( error )
       
   956         goto Fail;
       
   957 
       
   958     }
       
   959 
       
   960     return;
       
   961 
       
   962   Fail:
       
   963     parser->root.error = error;
       
   964   }
       
   965 
       
   966 
       
   967   static FT_Error
       
   968   t42_load_keyword( T42_Face    face,
       
   969                     T42_Loader  loader,
       
   970                     T1_Field    field )
       
   971   {
       
   972     FT_Error  error;
       
   973     void*     dummy_object;
       
   974     void**    objects;
       
   975     FT_UInt   max_objects = 0;
       
   976 
       
   977 
       
   978     /* if the keyword has a dedicated callback, call it */
       
   979     if ( field->type == T1_FIELD_TYPE_CALLBACK )
       
   980     {
       
   981       field->reader( (FT_Face)face, loader );
       
   982       error = loader->parser.root.error;
       
   983       goto Exit;
       
   984     }
       
   985 
       
   986     /* now the keyword is either a simple field or a table of fields; */
       
   987     /* we are now going to take care of it                            */
       
   988 
       
   989     switch ( field->location )
       
   990     {
       
   991     case T1_FIELD_LOCATION_FONT_INFO:
       
   992       dummy_object = &face->type1.font_info;
       
   993       break;
       
   994 
       
   995     case T1_FIELD_LOCATION_FONT_EXTRA:
       
   996       dummy_object = &face->type1.font_extra;
       
   997       break;
       
   998 
       
   999     case T1_FIELD_LOCATION_BBOX:
       
  1000       dummy_object = &face->type1.font_bbox;
       
  1001       break;
       
  1002 
       
  1003     default:
       
  1004       dummy_object = &face->type1;
       
  1005     }
       
  1006 
       
  1007     objects = &dummy_object;
       
  1008 
       
  1009     if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
       
  1010          field->type == T1_FIELD_TYPE_FIXED_ARRAY   )
       
  1011       error = T1_Load_Field_Table( &loader->parser, field,
       
  1012                                    objects, max_objects, 0 );
       
  1013     else
       
  1014       error = T1_Load_Field( &loader->parser, field,
       
  1015                              objects, max_objects, 0 );
       
  1016 
       
  1017    Exit:
       
  1018     return error;
       
  1019   }
       
  1020 
       
  1021 
       
  1022   FT_LOCAL_DEF( FT_Error )
       
  1023   t42_parse_dict( T42_Face    face,
       
  1024                   T42_Loader  loader,
       
  1025                   FT_Byte*    base,
       
  1026                   FT_Long     size )
       
  1027   {
       
  1028     T42_Parser  parser     = &loader->parser;
       
  1029     FT_Byte*    limit;
       
  1030     FT_Int      n_keywords = (FT_Int)( sizeof ( t42_keywords ) /
       
  1031                                          sizeof ( t42_keywords[0] ) );
       
  1032 
       
  1033 
       
  1034     parser->root.cursor = base;
       
  1035     parser->root.limit  = base + size;
       
  1036     parser->root.error  = T42_Err_Ok;
       
  1037 
       
  1038     limit = parser->root.limit;
       
  1039 
       
  1040     T1_Skip_Spaces( parser );
       
  1041 
       
  1042     while ( parser->root.cursor < limit )
       
  1043     {
       
  1044       FT_Byte*  cur;
       
  1045 
       
  1046 
       
  1047       cur = parser->root.cursor;
       
  1048 
       
  1049       /* look for `FontDirectory' which causes problems for some fonts */
       
  1050       if ( *cur == 'F' && cur + 25 < limit                    &&
       
  1051            ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
       
  1052       {
       
  1053         FT_Byte*  cur2;
       
  1054 
       
  1055 
       
  1056         /* skip the `FontDirectory' keyword */
       
  1057         T1_Skip_PS_Token( parser );
       
  1058         T1_Skip_Spaces  ( parser );
       
  1059         cur = cur2 = parser->root.cursor;
       
  1060 
       
  1061         /* look up the `known' keyword */
       
  1062         while ( cur < limit )
       
  1063         {
       
  1064           if ( *cur == 'k' && cur + 5 < limit             &&
       
  1065                 ft_strncmp( (char*)cur, "known", 5 ) == 0 )
       
  1066             break;
       
  1067 
       
  1068           T1_Skip_PS_Token( parser );
       
  1069           if ( parser->root.error )
       
  1070             goto Exit;
       
  1071           T1_Skip_Spaces  ( parser );
       
  1072           cur = parser->root.cursor;
       
  1073         }
       
  1074 
       
  1075         if ( cur < limit )
       
  1076         {
       
  1077           T1_TokenRec  token;
       
  1078 
       
  1079 
       
  1080           /* skip the `known' keyword and the token following it */
       
  1081           T1_Skip_PS_Token( parser );
       
  1082           T1_ToToken( parser, &token );
       
  1083 
       
  1084           /* if the last token was an array, skip it! */
       
  1085           if ( token.type == T1_TOKEN_TYPE_ARRAY )
       
  1086             cur2 = parser->root.cursor;
       
  1087         }
       
  1088         parser->root.cursor = cur2;
       
  1089       }
       
  1090 
       
  1091       /* look for immediates */
       
  1092       else if ( *cur == '/' && cur + 2 < limit )
       
  1093       {
       
  1094         FT_PtrDist  len;
       
  1095 
       
  1096 
       
  1097         cur++;
       
  1098 
       
  1099         parser->root.cursor = cur;
       
  1100         T1_Skip_PS_Token( parser );
       
  1101         if ( parser->root.error )
       
  1102           goto Exit;
       
  1103 
       
  1104         len = parser->root.cursor - cur;
       
  1105 
       
  1106         if ( len > 0 && len < 22 && parser->root.cursor < limit )
       
  1107         {
       
  1108           int  i;
       
  1109 
       
  1110 
       
  1111           /* now compare the immediate name to the keyword table */
       
  1112 
       
  1113           /* loop through all known keywords */
       
  1114           for ( i = 0; i < n_keywords; i++ )
       
  1115           {
       
  1116             T1_Field  keyword = (T1_Field)&t42_keywords[i];
       
  1117             FT_Byte   *name   = (FT_Byte*)keyword->ident;
       
  1118 
       
  1119 
       
  1120             if ( !name )
       
  1121               continue;
       
  1122 
       
  1123             if ( cur[0] == name[0]                                  &&
       
  1124                  len == (FT_PtrDist)ft_strlen( (const char *)name ) &&
       
  1125                  ft_memcmp( cur, name, len ) == 0                   )
       
  1126             {
       
  1127               /* we found it -- run the parsing callback! */
       
  1128               parser->root.error = t42_load_keyword( face,
       
  1129                                                      loader,
       
  1130                                                      keyword );
       
  1131               if ( parser->root.error )
       
  1132                 return parser->root.error;
       
  1133               break;
       
  1134             }
       
  1135           }
       
  1136         }
       
  1137       }
       
  1138       else
       
  1139       {
       
  1140         T1_Skip_PS_Token( parser );
       
  1141         if ( parser->root.error )
       
  1142           goto Exit;
       
  1143       }
       
  1144 
       
  1145       T1_Skip_Spaces( parser );
       
  1146     }
       
  1147 
       
  1148   Exit:
       
  1149     return parser->root.error;
       
  1150   }
       
  1151 
       
  1152 
       
  1153   FT_LOCAL_DEF( void )
       
  1154   t42_loader_init( T42_Loader  loader,
       
  1155                    T42_Face    face )
       
  1156   {
       
  1157     FT_UNUSED( face );
       
  1158 
       
  1159     FT_MEM_ZERO( loader, sizeof ( *loader ) );
       
  1160     loader->num_glyphs = 0;
       
  1161     loader->num_chars  = 0;
       
  1162 
       
  1163     /* initialize the tables -- simply set their `init' field to 0 */
       
  1164     loader->encoding_table.init = 0;
       
  1165     loader->charstrings.init    = 0;
       
  1166     loader->glyph_names.init    = 0;
       
  1167   }
       
  1168 
       
  1169 
       
  1170   FT_LOCAL_DEF( void )
       
  1171   t42_loader_done( T42_Loader  loader )
       
  1172   {
       
  1173     T42_Parser  parser = &loader->parser;
       
  1174 
       
  1175 
       
  1176     /* finalize tables */
       
  1177     T1_Release_Table( &loader->encoding_table );
       
  1178     T1_Release_Table( &loader->charstrings );
       
  1179     T1_Release_Table( &loader->glyph_names );
       
  1180     T1_Release_Table( &loader->swap_table );
       
  1181 
       
  1182     /* finalize parser */
       
  1183     t42_parser_done( parser );
       
  1184   }
       
  1185 
       
  1186 
       
  1187 /* END */