t42parse.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  t42parse.c                                                             */
00004 /*                                                                         */
00005 /*    Type 42 font parser (body).                                          */
00006 /*                                                                         */
00007 /*  Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by            */
00008 /*  Roberto Alameda.                                                       */
00009 /*                                                                         */
00010 /*  This file is part of the FreeType project, and may only be used,       */
00011 /*  modified, and distributed under the terms of the FreeType project      */
00012 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00013 /*  this file you indicate that you have read the license and              */
00014 /*  understand and accept it fully.                                        */
00015 /*                                                                         */
00016 /***************************************************************************/
00017 
00018 
00019 #include "t42parse.h"
00020 #include "t42error.h"
00021 #include FT_INTERNAL_DEBUG_H
00022 #include FT_INTERNAL_STREAM_H
00023 #include FT_INTERNAL_POSTSCRIPT_AUX_H
00024 
00025 
00026   /*************************************************************************/
00027   /*                                                                       */
00028   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
00029   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
00030   /* messages during execution.                                            */
00031   /*                                                                       */
00032 #undef  FT_COMPONENT
00033 #define FT_COMPONENT  trace_t42
00034 
00035 
00036   static void
00037   t42_parse_font_matrix( T42_Face    face,
00038                          T42_Loader  loader );
00039   static void
00040   t42_parse_encoding( T42_Face    face,
00041                       T42_Loader  loader );
00042 
00043   static void
00044   t42_parse_charstrings( T42_Face    face,
00045                          T42_Loader  loader );
00046 
00047   static void
00048   t42_parse_sfnts( T42_Face    face,
00049                    T42_Loader  loader );
00050 
00051 
00052   /* as Type42 fonts have no Private dict,         */
00053   /* we set the last argument of T1_FIELD_XXX to 0 */
00054   static const
00055   T1_FieldRec  t42_keywords[] = {
00056 
00057 #undef  FT_STRUCTURE
00058 #define FT_STRUCTURE  T1_FontInfo
00059 #undef  T1CODE
00060 #define T1CODE        T1_FIELD_LOCATION_FONT_INFO
00061 
00062     T1_FIELD_STRING( "version",            version,             0 )
00063     T1_FIELD_STRING( "Notice",             notice,              0 )
00064     T1_FIELD_STRING( "FullName",           full_name,           0 )
00065     T1_FIELD_STRING( "FamilyName",         family_name,         0 )
00066     T1_FIELD_STRING( "Weight",             weight,              0 )
00067     T1_FIELD_NUM   ( "ItalicAngle",        italic_angle,        0 )
00068     T1_FIELD_BOOL  ( "isFixedPitch",       is_fixed_pitch,      0 )
00069     T1_FIELD_NUM   ( "UnderlinePosition",  underline_position,  0 )
00070     T1_FIELD_NUM   ( "UnderlineThickness", underline_thickness, 0 )
00071 
00072 #undef  FT_STRUCTURE
00073 #define FT_STRUCTURE  PS_FontExtraRec
00074 #undef  T1CODE
00075 #define T1CODE        T1_FIELD_LOCATION_FONT_EXTRA
00076 
00077     T1_FIELD_NUM   ( "FSType",             fs_type,             0 )
00078 
00079 #undef  FT_STRUCTURE
00080 #define FT_STRUCTURE  T1_FontRec
00081 #undef  T1CODE
00082 #define T1CODE        T1_FIELD_LOCATION_FONT_DICT
00083 
00084     T1_FIELD_KEY  ( "FontName",    font_name,    0 )
00085     T1_FIELD_NUM  ( "PaintType",   paint_type,   0 )
00086     T1_FIELD_NUM  ( "FontType",    font_type,    0 )
00087     T1_FIELD_FIXED( "StrokeWidth", stroke_width, 0 )
00088 
00089 #undef  FT_STRUCTURE
00090 #define FT_STRUCTURE  FT_BBox
00091 #undef  T1CODE
00092 #define T1CODE        T1_FIELD_LOCATION_BBOX
00093 
00094     T1_FIELD_BBOX("FontBBox", xMin, 0 )
00095 
00096     T1_FIELD_CALLBACK( "FontMatrix",  t42_parse_font_matrix, 0 )
00097     T1_FIELD_CALLBACK( "Encoding",    t42_parse_encoding,    0 )
00098     T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings, 0 )
00099     T1_FIELD_CALLBACK( "sfnts",       t42_parse_sfnts,       0 )
00100 
00101     { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 }
00102   };
00103 
00104 
00105 #define T1_Add_Table( p, i, o, l )  (p)->funcs.add( (p), i, o, l )
00106 #define T1_Done_Table( p )          \
00107           do                        \
00108           {                         \
00109             if ( (p)->funcs.done )  \
00110               (p)->funcs.done( p ); \
00111           } while ( 0 )
00112 #define T1_Release_Table( p )          \
00113           do                           \
00114           {                            \
00115             if ( (p)->funcs.release )  \
00116               (p)->funcs.release( p ); \
00117           } while ( 0 )
00118 
00119 #define T1_Skip_Spaces( p )    (p)->root.funcs.skip_spaces( &(p)->root )
00120 #define T1_Skip_PS_Token( p )  (p)->root.funcs.skip_PS_token( &(p)->root )
00121 
00122 #define T1_ToInt( p )                          \
00123           (p)->root.funcs.to_int( &(p)->root )
00124 #define T1_ToBytes( p, b, m, n, d )                          \
00125           (p)->root.funcs.to_bytes( &(p)->root, b, m, n, d )
00126 
00127 #define T1_ToFixedArray( p, m, f, t )                           \
00128           (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
00129 #define T1_ToToken( p, t )                          \
00130           (p)->root.funcs.to_token( &(p)->root, t )
00131 
00132 #define T1_Load_Field( p, f, o, m, pf )                         \
00133           (p)->root.funcs.load_field( &(p)->root, f, o, m, pf )
00134 #define T1_Load_Field_Table( p, f, o, m, pf )                         \
00135           (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf )
00136 
00137 
00138   /********************* Parsing Functions ******************/
00139 
00140   FT_LOCAL_DEF( FT_Error )
00141   t42_parser_init( T42_Parser     parser,
00142                    FT_Stream      stream,
00143                    FT_Memory      memory,
00144                    PSAux_Service  psaux )
00145   {
00146     FT_Error  error = T42_Err_Ok;
00147     FT_Long   size;
00148 
00149 
00150     psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory );
00151 
00152     parser->stream    = stream;
00153     parser->base_len  = 0;
00154     parser->base_dict = 0;
00155     parser->in_memory = 0;
00156 
00157     /*******************************************************************/
00158     /*                                                                 */
00159     /* Here a short summary of what is going on:                       */
00160     /*                                                                 */
00161     /*   When creating a new Type 42 parser, we try to locate and load */
00162     /*   the base dictionary, loading the whole font into memory.      */
00163     /*                                                                 */
00164     /*   When `loading' the base dictionary, we only set up pointers   */
00165     /*   in the case of a memory-based stream.  Otherwise, we allocate */
00166     /*   and load the base dictionary in it.                           */
00167     /*                                                                 */
00168     /*   parser->in_memory is set if we have a memory stream.          */
00169     /*                                                                 */
00170 
00171     if ( FT_STREAM_SEEK( 0L ) ||
00172          FT_FRAME_ENTER( 17 ) )
00173       goto Exit;
00174 
00175     if ( ft_memcmp( stream->cursor, "%!PS-TrueTypeFont", 17 ) != 0 )
00176     {
00177       FT_TRACE2(( "not a Type42 font\n" ));
00178       error = T42_Err_Unknown_File_Format;
00179     }
00180 
00181     FT_FRAME_EXIT();
00182 
00183     if ( error || FT_STREAM_SEEK( 0 ) )
00184       goto Exit;
00185 
00186     size = stream->size;
00187 
00188     /* now, try to load `size' bytes of the `base' dictionary we */
00189     /* found previously                                          */
00190 
00191     /* if it is a memory-based resource, set up pointers */
00192     if ( !stream->read )
00193     {
00194       parser->base_dict = (FT_Byte*)stream->base + stream->pos;
00195       parser->base_len  = size;
00196       parser->in_memory = 1;
00197 
00198       /* check that the `size' field is valid */
00199       if ( FT_STREAM_SKIP( size ) )
00200         goto Exit;
00201     }
00202     else
00203     {
00204       /* read segment in memory */
00205       if ( FT_ALLOC( parser->base_dict, size )       ||
00206            FT_STREAM_READ( parser->base_dict, size ) )
00207         goto Exit;
00208 
00209       parser->base_len = size;
00210     }
00211 
00212     parser->root.base   = parser->base_dict;
00213     parser->root.cursor = parser->base_dict;
00214     parser->root.limit  = parser->root.cursor + parser->base_len;
00215 
00216   Exit:
00217     if ( error && !parser->in_memory )
00218       FT_FREE( parser->base_dict );
00219 
00220     return error;
00221   }
00222 
00223 
00224   FT_LOCAL_DEF( void )
00225   t42_parser_done( T42_Parser  parser )
00226   {
00227     FT_Memory  memory = parser->root.memory;
00228 
00229 
00230     /* free the base dictionary only when we have a disk stream */
00231     if ( !parser->in_memory )
00232       FT_FREE( parser->base_dict );
00233 
00234     parser->root.funcs.done( &parser->root );
00235   }
00236 
00237 
00238   static int
00239   t42_is_space( FT_Byte  c )
00240   {
00241     return ( c == ' '  || c == '\t'              ||
00242              c == '\r' || c == '\n' || c == '\f' ||
00243              c == '\0'                           );
00244   }
00245 
00246 
00247   static void
00248   t42_parse_font_matrix( T42_Face    face,
00249                          T42_Loader  loader )
00250   {
00251     T42_Parser  parser = &loader->parser;
00252     FT_Matrix*  matrix = &face->type1.font_matrix;
00253     FT_Vector*  offset = &face->type1.font_offset;
00254     FT_Face     root   = (FT_Face)&face->root;
00255     FT_Fixed    temp[6];
00256     FT_Fixed    temp_scale;
00257 
00258 
00259     (void)T1_ToFixedArray( parser, 6, temp, 3 );
00260 
00261     temp_scale = FT_ABS( temp[3] );
00262 
00263     /* Set Units per EM based on FontMatrix values.  We set the value to */
00264     /* 1000 / temp_scale, because temp_scale was already multiplied by   */
00265     /* 1000 (in t1_tofixed, from psobjs.c).                              */
00266 
00267     root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L,
00268                                                  temp_scale ) >> 16 );
00269 
00270     /* we need to scale the values by 1.0/temp_scale */
00271     if ( temp_scale != 0x10000L ) {
00272       temp[0] = FT_DivFix( temp[0], temp_scale );
00273       temp[1] = FT_DivFix( temp[1], temp_scale );
00274       temp[2] = FT_DivFix( temp[2], temp_scale );
00275       temp[4] = FT_DivFix( temp[4], temp_scale );
00276       temp[5] = FT_DivFix( temp[5], temp_scale );
00277       temp[3] = 0x10000L;
00278     }
00279 
00280     matrix->xx = temp[0];
00281     matrix->yx = temp[1];
00282     matrix->xy = temp[2];
00283     matrix->yy = temp[3];
00284 
00285     /* note that the offsets must be expressed in integer font units */
00286     offset->x = temp[4] >> 16;
00287     offset->y = temp[5] >> 16;
00288   }
00289 
00290 
00291   static void
00292   t42_parse_encoding( T42_Face    face,
00293                       T42_Loader  loader )
00294   {
00295     T42_Parser  parser = &loader->parser;
00296     FT_Byte*    cur;
00297     FT_Byte*    limit  = parser->root.limit;
00298 
00299     PSAux_Service  psaux  = (PSAux_Service)face->psaux;
00300 
00301 
00302     T1_Skip_Spaces( parser );
00303     cur = parser->root.cursor;
00304     if ( cur >= limit )
00305     {
00306       FT_ERROR(( "t42_parse_encoding: out of bounds\n" ));
00307       parser->root.error = T42_Err_Invalid_File_Format;
00308       return;
00309     }
00310 
00311     /* if we have a number or `[', the encoding is an array, */
00312     /* and we must load it now                               */
00313     if ( ft_isdigit( *cur ) || *cur == '[' )
00314     {
00315       T1_Encoding  encode          = &face->type1.encoding;
00316       FT_UInt      count, n;
00317       PS_Table     char_table      = &loader->encoding_table;
00318       FT_Memory    memory          = parser->root.memory;
00319       FT_Error     error;
00320       FT_Bool      only_immediates = 0;
00321 
00322 
00323       /* read the number of entries in the encoding; should be 256 */
00324       if ( *cur == '[' )
00325       {
00326         count           = 256;
00327         only_immediates = 1;
00328         parser->root.cursor++;
00329       }
00330       else
00331         count = (FT_UInt)T1_ToInt( parser );
00332 
00333       T1_Skip_Spaces( parser );
00334       if ( parser->root.cursor >= limit )
00335         return;
00336 
00337       /* we use a T1_Table to store our charnames */
00338       loader->num_chars = encode->num_chars = count;
00339       if ( FT_NEW_ARRAY( encode->char_index, count )     ||
00340            FT_NEW_ARRAY( encode->char_name,  count )     ||
00341            FT_SET_ERROR( psaux->ps_table_funcs->init(
00342                            char_table, count, memory ) ) )
00343       {
00344         parser->root.error = error;
00345         return;
00346       }
00347 
00348       /* We need to `zero' out encoding_table.elements */
00349       for ( n = 0; n < count; n++ )
00350       {
00351         char*  notdef = (char *)".notdef";
00352 
00353 
00354         T1_Add_Table( char_table, n, notdef, 8 );
00355       }
00356 
00357       /* Now we need to read records of the form                */
00358       /*                                                        */
00359       /*   ... charcode /charname ...                           */
00360       /*                                                        */
00361       /* for each entry in our table.                           */
00362       /*                                                        */
00363       /* We simply look for a number followed by an immediate   */
00364       /* name.  Note that this ignores correctly the sequence   */
00365       /* that is often seen in type42 fonts:                    */
00366       /*                                                        */
00367       /*   0 1 255 { 1 index exch /.notdef put } for dup        */
00368       /*                                                        */
00369       /* used to clean the encoding array before anything else. */
00370       /*                                                        */
00371       /* Alternatively, if the array is directly given as       */
00372       /*                                                        */
00373       /*   /Encoding [ ... ]                                    */
00374       /*                                                        */
00375       /* we only read immediates.                               */
00376 
00377       n = 0;
00378       T1_Skip_Spaces( parser );
00379 
00380       while ( parser->root.cursor < limit )
00381       {
00382         cur = parser->root.cursor;
00383 
00384         /* we stop when we encounter `def' or `]' */
00385         if ( *cur == 'd' && cur + 3 < limit )
00386         {
00387           if ( cur[1] == 'e'          &&
00388                cur[2] == 'f'          &&
00389                t42_is_space( cur[3] ) )
00390           {
00391             FT_TRACE6(( "encoding end\n" ));
00392             cur += 3;
00393             break;
00394           }
00395         }
00396         if ( *cur == ']' )
00397         {
00398           FT_TRACE6(( "encoding end\n" ));
00399           cur++;
00400           break;
00401         }
00402 
00403         /* check whether we have found an entry */
00404         if ( ft_isdigit( *cur ) || only_immediates )
00405         {
00406           FT_Int  charcode;
00407 
00408 
00409           if ( only_immediates )
00410             charcode = n;
00411           else
00412           {
00413             charcode = (FT_Int)T1_ToInt( parser );
00414             T1_Skip_Spaces( parser );
00415           }
00416 
00417           cur = parser->root.cursor;
00418 
00419           if ( *cur == '/' && cur + 2 < limit && n < count )
00420           {
00421             FT_PtrDist  len;
00422 
00423 
00424             cur++;
00425 
00426             parser->root.cursor = cur;
00427             T1_Skip_PS_Token( parser );
00428             if ( parser->root.error )
00429               return;
00430 
00431             len = parser->root.cursor - cur;
00432 
00433             parser->root.error = T1_Add_Table( char_table, charcode,
00434                                                cur, len + 1 );
00435             if ( parser->root.error )
00436               return;
00437             char_table->elements[charcode][len] = '\0';
00438 
00439             n++;
00440           }
00441         }
00442         else
00443         {
00444           T1_Skip_PS_Token( parser );
00445           if ( parser->root.error )
00446             return;
00447         }
00448 
00449         T1_Skip_Spaces( parser );
00450       }
00451 
00452       face->type1.encoding_type  = T1_ENCODING_TYPE_ARRAY;
00453       parser->root.cursor        = cur;
00454     }
00455 
00456     /* Otherwise, we should have either `StandardEncoding', */
00457     /* `ExpertEncoding', or `ISOLatin1Encoding'             */
00458     else
00459     {
00460       if ( cur + 17 < limit                                            &&
00461            ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
00462         face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
00463 
00464       else if ( cur + 15 < limit                                          &&
00465                 ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
00466         face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
00467 
00468       else if ( cur + 18 < limit                                             &&
00469                 ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
00470         face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
00471 
00472       else
00473       {
00474         FT_ERROR(( "t42_parse_encoding: invalid token\n" ));
00475         parser->root.error = T42_Err_Invalid_File_Format;
00476       }
00477     }
00478   }
00479 
00480 
00481   typedef enum  T42_Load_Status_
00482   {
00483     BEFORE_START,
00484     BEFORE_TABLE_DIR,
00485     OTHER_TABLES
00486 
00487   } T42_Load_Status;
00488 
00489 
00490   static void
00491   t42_parse_sfnts( T42_Face    face,
00492                    T42_Loader  loader )
00493   {
00494     T42_Parser  parser = &loader->parser;
00495     FT_Memory   memory = parser->root.memory;
00496     FT_Byte*    cur;
00497     FT_Byte*    limit  = parser->root.limit;
00498     FT_Error    error;
00499     FT_Int      num_tables = 0;
00500     FT_ULong    count, ttf_size = 0;
00501 
00502     FT_Long     n, string_size, old_string_size, real_size;
00503     FT_Byte*    string_buf = NULL;
00504     FT_Bool     allocated  = 0;
00505 
00506     T42_Load_Status  status;
00507 
00508 
00509     /* The format is                                */
00510     /*                                              */
00511     /*   /sfnts [ <hexstring> <hexstring> ... ] def */
00512     /*                                              */
00513     /* or                                           */
00514     /*                                              */
00515     /*   /sfnts [                                   */
00516     /*      <num_bin_bytes> RD <binary data>        */
00517     /*      <num_bin_bytes> RD <binary data>        */
00518     /*      ...                                     */
00519     /*   ] def                                      */
00520     /*                                              */
00521     /* with exactly one space after the `RD' token. */
00522 
00523     T1_Skip_Spaces( parser );
00524 
00525     if ( parser->root.cursor >= limit || *parser->root.cursor++ != '[' )
00526     {
00527       FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector\n" ));
00528       error = T42_Err_Invalid_File_Format;
00529       goto Fail;
00530     }
00531 
00532     T1_Skip_Spaces( parser );
00533     status          = BEFORE_START;
00534     string_size     = 0;
00535     old_string_size = 0;
00536     count           = 0;
00537 
00538     while ( parser->root.cursor < limit )
00539     {
00540       cur = parser->root.cursor;
00541 
00542       if ( *cur == ']' )
00543       {
00544         parser->root.cursor++;
00545         goto Exit;
00546       }
00547 
00548       else if ( *cur == '<' )
00549       {
00550         T1_Skip_PS_Token( parser );
00551         if ( parser->root.error )
00552           goto Exit;
00553 
00554         /* don't include delimiters */
00555         string_size = (FT_Long)( ( parser->root.cursor - cur - 2 + 1 ) / 2 );
00556         if ( FT_REALLOC( string_buf, old_string_size, string_size ) )
00557           goto Fail;
00558 
00559         allocated = 1;
00560 
00561         parser->root.cursor = cur;
00562         (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 );
00563         old_string_size = string_size;
00564         string_size = real_size;
00565       }
00566 
00567       else if ( ft_isdigit( *cur ) )
00568       {
00569         if ( allocated )
00570         {
00571           FT_ERROR(( "t42_parse_sfnts: "
00572                      "can't handle mixed binary and hex strings\n" ));
00573           error = T42_Err_Invalid_File_Format;
00574           goto Fail;
00575         }
00576 
00577         string_size = T1_ToInt( parser );
00578 
00579         T1_Skip_PS_Token( parser );             /* `RD' */
00580         if ( parser->root.error )
00581           return;
00582 
00583         string_buf = parser->root.cursor + 1;   /* one space after `RD' */
00584 
00585         parser->root.cursor += string_size + 1;
00586         if ( parser->root.cursor >= limit )
00587         {
00588           FT_ERROR(( "t42_parse_sfnts: too many binary data\n" ));
00589           error = T42_Err_Invalid_File_Format;
00590           goto Fail;
00591         }
00592       }
00593 
00594       if ( !string_buf )
00595       {
00596         FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
00597         error = T42_Err_Invalid_File_Format;
00598         goto Fail;
00599       }
00600 
00601       /* A string can have a trailing zero byte for padding.  Ignore it. */
00602       if ( string_buf[string_size - 1] == 0 && ( string_size % 2 == 1 ) )
00603         string_size--;
00604 
00605       if ( !string_size )
00606       {
00607         FT_ERROR(( "t42_parse_sfnts: invalid string\n" ));
00608         error = T42_Err_Invalid_File_Format;
00609         goto Fail;
00610       }
00611 
00612       for ( n = 0; n < string_size; n++ )
00613       {
00614         switch ( status )
00615         {
00616         case BEFORE_START:
00617           /* load offset table, 12 bytes */
00618           if ( count < 12 )
00619           {
00620             face->ttf_data[count++] = string_buf[n];
00621             continue;
00622           }
00623           else
00624           {
00625             num_tables = 16 * face->ttf_data[4] + face->ttf_data[5];
00626             status     = BEFORE_TABLE_DIR;
00627             ttf_size   = 12 + 16 * num_tables;
00628 
00629             if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) )
00630               goto Fail;
00631           }
00632           /* fall through */
00633 
00634         case BEFORE_TABLE_DIR:
00635           /* the offset table is read; read the table directory */
00636           if ( count < ttf_size )
00637           {
00638             face->ttf_data[count++] = string_buf[n];
00639             continue;
00640           }
00641           else
00642           {
00643             int       i;
00644             FT_ULong  len;
00645 
00646 
00647             for ( i = 0; i < num_tables; i++ )
00648             {
00649               FT_Byte*  p = face->ttf_data + 12 + 16 * i + 12;
00650 
00651 
00652               len = FT_PEEK_ULONG( p );
00653 
00654               /* Pad to a 4-byte boundary length */
00655               ttf_size += ( len + 3 ) & ~3;
00656             }
00657 
00658             status         = OTHER_TABLES;
00659             face->ttf_size = ttf_size;
00660 
00661             /* there are no more than 256 tables, so no size check here */
00662             if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables,
00663                              ttf_size + 1 ) )
00664               goto Fail;
00665           }
00666           /* fall through */
00667 
00668         case OTHER_TABLES:
00669           /* all other tables are just copied */
00670           if ( count >= ttf_size )
00671           {
00672             FT_ERROR(( "t42_parse_sfnts: too many binary data\n" ));
00673             error = T42_Err_Invalid_File_Format;
00674             goto Fail;
00675           }
00676           face->ttf_data[count++] = string_buf[n];
00677         }
00678       }
00679 
00680       T1_Skip_Spaces( parser );
00681     }
00682 
00683     /* if control reaches this point, the format was not valid */
00684     error = T42_Err_Invalid_File_Format;
00685 
00686   Fail:
00687     parser->root.error = error;
00688 
00689   Exit:
00690     if ( allocated )
00691       FT_FREE( string_buf );
00692   }
00693 
00694 
00695   static void
00696   t42_parse_charstrings( T42_Face    face,
00697                          T42_Loader  loader )
00698   {
00699     T42_Parser     parser       = &loader->parser;
00700     PS_Table       code_table   = &loader->charstrings;
00701     PS_Table       name_table   = &loader->glyph_names;
00702     PS_Table       swap_table   = &loader->swap_table;
00703     FT_Memory      memory       = parser->root.memory;
00704     FT_Error       error;
00705 
00706     PSAux_Service  psaux        = (PSAux_Service)face->psaux;
00707 
00708     FT_Byte*       cur;
00709     FT_Byte*       limit        = parser->root.limit;
00710     FT_UInt        n;
00711     FT_UInt        notdef_index = 0;
00712     FT_Byte        notdef_found = 0;
00713 
00714 
00715     T1_Skip_Spaces( parser );
00716 
00717     if ( parser->root.cursor >= limit )
00718     {
00719       FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
00720       error = T42_Err_Invalid_File_Format;
00721       goto Fail;
00722     }
00723 
00724     if ( ft_isdigit( *parser->root.cursor ) )
00725     {
00726       loader->num_glyphs = (FT_UInt)T1_ToInt( parser );
00727       if ( parser->root.error )
00728         return;
00729     }
00730     else if ( *parser->root.cursor == '<' )
00731     {
00732       /* We have `<< ... >>'.  Count the number of `/' in the dictionary */
00733       /* to get its size.                                                */
00734       FT_UInt  count = 0;
00735 
00736 
00737       T1_Skip_PS_Token( parser );
00738       if ( parser->root.error )
00739         return;
00740       T1_Skip_Spaces( parser );
00741       cur = parser->root.cursor;
00742 
00743       while ( parser->root.cursor < limit )
00744       {
00745         if ( *parser->root.cursor == '/' )
00746           count++;
00747         else if ( *parser->root.cursor == '>' )
00748         {
00749           loader->num_glyphs  = count;
00750           parser->root.cursor = cur;        /* rewind */
00751           break;
00752         }
00753         T1_Skip_PS_Token( parser );
00754         if ( parser->root.error )
00755           return;
00756         T1_Skip_Spaces( parser );
00757       }
00758     }
00759     else
00760     {
00761       FT_ERROR(( "t42_parse_charstrings: invalid token\n" ));
00762       error = T42_Err_Invalid_File_Format;
00763       goto Fail;
00764     }
00765 
00766     if ( parser->root.cursor >= limit )
00767     {
00768       FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
00769       error = T42_Err_Invalid_File_Format;
00770       goto Fail;
00771     }
00772 
00773     /* initialize tables */
00774 
00775     error = psaux->ps_table_funcs->init( code_table,
00776                                          loader->num_glyphs,
00777                                          memory );
00778     if ( error )
00779       goto Fail;
00780 
00781     error = psaux->ps_table_funcs->init( name_table,
00782                                          loader->num_glyphs,
00783                                          memory );
00784     if ( error )
00785       goto Fail;
00786 
00787     /* Initialize table for swapping index notdef_index and */
00788     /* index 0 names and codes (if necessary).              */
00789 
00790     error = psaux->ps_table_funcs->init( swap_table, 4, memory );
00791     if ( error )
00792       goto Fail;
00793 
00794     n = 0;
00795 
00796     for (;;)
00797     {
00798       /* The format is simple:                   */
00799       /*   `/glyphname' + index [+ def]          */
00800 
00801       T1_Skip_Spaces( parser );
00802 
00803       cur = parser->root.cursor;
00804       if ( cur >= limit )
00805         break;
00806 
00807       /* We stop when we find an `end' keyword or '>' */
00808       if ( *cur   == 'e'          &&
00809            cur + 3 < limit        &&
00810            cur[1] == 'n'          &&
00811            cur[2] == 'd'          &&
00812            t42_is_space( cur[3] ) )
00813         break;
00814       if ( *cur == '>' )
00815         break;
00816 
00817       T1_Skip_PS_Token( parser );
00818       if ( parser->root.error )
00819         return;
00820 
00821       if ( *cur == '/' )
00822       {
00823         FT_PtrDist  len;
00824 
00825 
00826         if ( cur + 1 >= limit )
00827         {
00828           FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
00829           error = T42_Err_Invalid_File_Format;
00830           goto Fail;
00831         }
00832 
00833         cur++;                              /* skip `/' */
00834         len = parser->root.cursor - cur;
00835 
00836         error = T1_Add_Table( name_table, n, cur, len + 1 );
00837         if ( error )
00838           goto Fail;
00839 
00840         /* add a trailing zero to the name table */
00841         name_table->elements[n][len] = '\0';
00842 
00843         /* record index of /.notdef */
00844         if ( *cur == '.'                                              &&
00845              ft_strcmp( ".notdef",
00846                         (const char*)(name_table->elements[n]) ) == 0 )
00847         {
00848           notdef_index = n;
00849           notdef_found = 1;
00850         }
00851 
00852         T1_Skip_Spaces( parser );
00853 
00854         cur = parser->root.cursor;
00855 
00856         (void)T1_ToInt( parser );
00857         if ( parser->root.cursor >= limit )
00858         {
00859           FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
00860           error = T42_Err_Invalid_File_Format;
00861           goto Fail;
00862         }
00863 
00864         len = parser->root.cursor - cur;
00865 
00866         error = T1_Add_Table( code_table, n, cur, len + 1 );
00867         if ( error )
00868           goto Fail;
00869 
00870         code_table->elements[n][len] = '\0';
00871 
00872         n++;
00873         if ( n >= loader->num_glyphs )
00874           break;
00875       }
00876     }
00877 
00878     loader->num_glyphs = n;
00879 
00880     if ( !notdef_found )
00881     {
00882       FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph\n" ));
00883       error = T42_Err_Invalid_File_Format;
00884       goto Fail;
00885     }
00886 
00887     /* if /.notdef does not occupy index 0, do our magic. */
00888     if ( ft_strcmp( (const char*)".notdef",
00889                     (const char*)name_table->elements[0] ) )
00890     {
00891       /* Swap glyph in index 0 with /.notdef glyph.  First, add index 0  */
00892       /* name and code entries to swap_table.  Then place notdef_index   */
00893       /* name and code entries into swap_table.  Then swap name and code */
00894       /* entries at indices notdef_index and 0 using values stored in    */
00895       /* swap_table.                                                     */
00896 
00897       /* Index 0 name */
00898       error = T1_Add_Table( swap_table, 0,
00899                             name_table->elements[0],
00900                             name_table->lengths [0] );
00901       if ( error )
00902         goto Fail;
00903 
00904       /* Index 0 code */
00905       error = T1_Add_Table( swap_table, 1,
00906                             code_table->elements[0],
00907                             code_table->lengths [0] );
00908       if ( error )
00909         goto Fail;
00910 
00911       /* Index notdef_index name */
00912       error = T1_Add_Table( swap_table, 2,
00913                             name_table->elements[notdef_index],
00914                             name_table->lengths [notdef_index] );
00915       if ( error )
00916         goto Fail;
00917 
00918       /* Index notdef_index code */
00919       error = T1_Add_Table( swap_table, 3,
00920                             code_table->elements[notdef_index],
00921                             code_table->lengths [notdef_index] );
00922       if ( error )
00923         goto Fail;
00924 
00925       error = T1_Add_Table( name_table, notdef_index,
00926                             swap_table->elements[0],
00927                             swap_table->lengths [0] );
00928       if ( error )
00929         goto Fail;
00930 
00931       error = T1_Add_Table( code_table, notdef_index,
00932                             swap_table->elements[1],
00933                             swap_table->lengths [1] );
00934       if ( error )
00935         goto Fail;
00936 
00937       error = T1_Add_Table( name_table, 0,
00938                             swap_table->elements[2],
00939                             swap_table->lengths [2] );
00940       if ( error )
00941         goto Fail;
00942 
00943       error = T1_Add_Table( code_table, 0,
00944                             swap_table->elements[3],
00945                             swap_table->lengths [3] );
00946       if ( error )
00947         goto Fail;
00948 
00949     }
00950 
00951     return;
00952 
00953   Fail:
00954     parser->root.error = error;
00955   }
00956 
00957 
00958   static FT_Error
00959   t42_load_keyword( T42_Face    face,
00960                     T42_Loader  loader,
00961                     T1_Field    field )
00962   {
00963     FT_Error  error;
00964     void*     dummy_object;
00965     void**    objects;
00966     FT_UInt   max_objects = 0;
00967 
00968 
00969     /* if the keyword has a dedicated callback, call it */
00970     if ( field->type == T1_FIELD_TYPE_CALLBACK )
00971     {
00972       field->reader( (FT_Face)face, loader );
00973       error = loader->parser.root.error;
00974       goto Exit;
00975     }
00976 
00977     /* now the keyword is either a simple field or a table of fields; */
00978     /* we are now going to take care of it                            */
00979 
00980     switch ( field->location )
00981     {
00982     case T1_FIELD_LOCATION_FONT_INFO:
00983       dummy_object = &face->type1.font_info;
00984       break;
00985 
00986     case T1_FIELD_LOCATION_FONT_EXTRA:
00987       dummy_object = &face->type1.font_extra;
00988       break;
00989 
00990     case T1_FIELD_LOCATION_BBOX:
00991       dummy_object = &face->type1.font_bbox;
00992       break;
00993 
00994     default:
00995       dummy_object = &face->type1;
00996     }
00997 
00998     objects = &dummy_object;
00999 
01000     if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
01001          field->type == T1_FIELD_TYPE_FIXED_ARRAY   )
01002       error = T1_Load_Field_Table( &loader->parser, field,
01003                                    objects, max_objects, 0 );
01004     else
01005       error = T1_Load_Field( &loader->parser, field,
01006                              objects, max_objects, 0 );
01007 
01008    Exit:
01009     return error;
01010   }
01011 
01012 
01013   FT_LOCAL_DEF( FT_Error )
01014   t42_parse_dict( T42_Face    face,
01015                   T42_Loader  loader,
01016                   FT_Byte*    base,
01017                   FT_Long     size )
01018   {
01019     T42_Parser  parser     = &loader->parser;
01020     FT_Byte*    limit;
01021     FT_Int      n_keywords = (FT_Int)( sizeof ( t42_keywords ) /
01022                                          sizeof ( t42_keywords[0] ) );
01023 
01024 
01025     parser->root.cursor = base;
01026     parser->root.limit  = base + size;
01027     parser->root.error  = T42_Err_Ok;
01028 
01029     limit = parser->root.limit;
01030 
01031     T1_Skip_Spaces( parser );
01032 
01033     while ( parser->root.cursor < limit )
01034     {
01035       FT_Byte*  cur;
01036 
01037 
01038       cur = parser->root.cursor;
01039 
01040       /* look for `FontDirectory' which causes problems for some fonts */
01041       if ( *cur == 'F' && cur + 25 < limit                    &&
01042            ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
01043       {
01044         FT_Byte*  cur2;
01045 
01046 
01047         /* skip the `FontDirectory' keyword */
01048         T1_Skip_PS_Token( parser );
01049         T1_Skip_Spaces  ( parser );
01050         cur = cur2 = parser->root.cursor;
01051 
01052         /* look up the `known' keyword */
01053         while ( cur < limit )
01054         {
01055           if ( *cur == 'k' && cur + 5 < limit             &&
01056                 ft_strncmp( (char*)cur, "known", 5 ) == 0 )
01057             break;
01058 
01059           T1_Skip_PS_Token( parser );
01060           if ( parser->root.error )
01061             goto Exit;
01062           T1_Skip_Spaces  ( parser );
01063           cur = parser->root.cursor;
01064         }
01065 
01066         if ( cur < limit )
01067         {
01068           T1_TokenRec  token;
01069 
01070 
01071           /* skip the `known' keyword and the token following it */
01072           T1_Skip_PS_Token( parser );
01073           T1_ToToken( parser, &token );
01074 
01075           /* if the last token was an array, skip it! */
01076           if ( token.type == T1_TOKEN_TYPE_ARRAY )
01077             cur2 = parser->root.cursor;
01078         }
01079         parser->root.cursor = cur2;
01080       }
01081 
01082       /* look for immediates */
01083       else if ( *cur == '/' && cur + 2 < limit )
01084       {
01085         FT_PtrDist  len;
01086 
01087 
01088         cur++;
01089 
01090         parser->root.cursor = cur;
01091         T1_Skip_PS_Token( parser );
01092         if ( parser->root.error )
01093           goto Exit;
01094 
01095         len = parser->root.cursor - cur;
01096 
01097         if ( len > 0 && len < 22 && parser->root.cursor < limit )
01098         {
01099           int  i;
01100 
01101 
01102           /* now compare the immediate name to the keyword table */
01103 
01104           /* loop through all known keywords */
01105           for ( i = 0; i < n_keywords; i++ )
01106           {
01107             T1_Field  keyword = (T1_Field)&t42_keywords[i];
01108             FT_Byte   *name   = (FT_Byte*)keyword->ident;
01109 
01110 
01111             if ( !name )
01112               continue;
01113 
01114             if ( cur[0] == name[0]                                  &&
01115                  len == (FT_PtrDist)ft_strlen( (const char *)name ) &&
01116                  ft_memcmp( cur, name, len ) == 0                   )
01117             {
01118               /* we found it -- run the parsing callback! */
01119               parser->root.error = t42_load_keyword( face,
01120                                                      loader,
01121                                                      keyword );
01122               if ( parser->root.error )
01123                 return parser->root.error;
01124               break;
01125             }
01126           }
01127         }
01128       }
01129       else
01130       {
01131         T1_Skip_PS_Token( parser );
01132         if ( parser->root.error )
01133           goto Exit;
01134       }
01135 
01136       T1_Skip_Spaces( parser );
01137     }
01138 
01139   Exit:
01140     return parser->root.error;
01141   }
01142 
01143 
01144   FT_LOCAL_DEF( void )
01145   t42_loader_init( T42_Loader  loader,
01146                    T42_Face    face )
01147   {
01148     FT_UNUSED( face );
01149 
01150     FT_MEM_ZERO( loader, sizeof ( *loader ) );
01151     loader->num_glyphs = 0;
01152     loader->num_chars  = 0;
01153 
01154     /* initialize the tables -- simply set their `init' field to 0 */
01155     loader->encoding_table.init = 0;
01156     loader->charstrings.init    = 0;
01157     loader->glyph_names.init    = 0;
01158   }
01159 
01160 
01161   FT_LOCAL_DEF( void )
01162   t42_loader_done( T42_Loader  loader )
01163   {
01164     T42_Parser  parser = &loader->parser;
01165 
01166 
01167     /* finalize tables */
01168     T1_Release_Table( &loader->encoding_table );
01169     T1_Release_Table( &loader->charstrings );
01170     T1_Release_Table( &loader->glyph_names );
01171     T1_Release_Table( &loader->swap_table );
01172 
01173     /* finalize parser */
01174     t42_parser_done( parser );
01175   }
01176 
01177 
01178 /* END */

Generated on Tue Jul 5 14:13:54 2011 for ROOT_528-00b_version by  doxygen 1.5.1