source: trunk/poppler/freetype2/src/type42/t42parse.c @ 269

Last change on this file since 269 was 269, checked in by Eugene Romanenko, 13 years ago

PDF plugin: freetype library updated to version 2.3.9

File size: 35.5 KB
Line 
1/***************************************************************************/
2/*                                                                         */
3/*  t42parse.c                                                             */
4/*                                                                         */
5/*    Type 42 font parser (body).                                          */
6/*                                                                         */
7/*  Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 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_LIST_H
24#include FT_INTERNAL_POSTSCRIPT_AUX_H
25
26
27  /*************************************************************************/
28  /*                                                                       */
29  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
30  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
31  /* messages during execution.                                            */
32  /*                                                                       */
33#undef  FT_COMPONENT
34#define FT_COMPONENT  trace_t42
35
36
37  static void
38  t42_parse_font_matrix( T42_Face    face,
39                         T42_Loader  loader );
40  static void
41  t42_parse_encoding( T42_Face    face,
42                      T42_Loader  loader );
43
44  static void
45  t42_parse_charstrings( T42_Face    face,
46                         T42_Loader  loader );
47
48  static void
49  t42_parse_sfnts( T42_Face    face,
50                   T42_Loader  loader );
51
52
53  /* as Type42 fonts have no Private dict,         */
54  /* we set the last argument of T1_FIELD_XXX to 0 */
55  static const
56  T1_FieldRec  t42_keywords[] = {
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      temp[0] = FT_DivFix( temp[0], temp_scale );
274      temp[1] = FT_DivFix( temp[1], temp_scale );
275      temp[2] = FT_DivFix( temp[2], temp_scale );
276      temp[4] = FT_DivFix( temp[4], temp_scale );
277      temp[5] = FT_DivFix( temp[5], temp_scale );
278      temp[3] = 0x10000L;
279    }
280
281    matrix->xx = temp[0];
282    matrix->yx = temp[1];
283    matrix->xy = temp[2];
284    matrix->yy = temp[3];
285
286    /* note that the offsets must be expressed in integer font units */
287    offset->x = temp[4] >> 16;
288    offset->y = temp[5] >> 16;
289  }
290
291
292  static void
293  t42_parse_encoding( T42_Face    face,
294                      T42_Loader  loader )
295  {
296    T42_Parser  parser = &loader->parser;
297    FT_Byte*    cur;
298    FT_Byte*    limit  = parser->root.limit;
299
300    PSAux_Service  psaux  = (PSAux_Service)face->psaux;
301
302
303    T1_Skip_Spaces( parser );
304    cur = parser->root.cursor;
305    if ( cur >= limit )
306    {
307      FT_ERROR(( "t42_parse_encoding: out of bounds!\n" ));
308      parser->root.error = T42_Err_Invalid_File_Format;
309      return;
310    }
311
312    /* if we have a number or `[', the encoding is an array, */
313    /* and we must load it now                               */
314    if ( ft_isdigit( *cur ) || *cur == '[' )
315    {
316      T1_Encoding  encode          = &face->type1.encoding;
317      FT_UInt      count, n;
318      PS_Table     char_table      = &loader->encoding_table;
319      FT_Memory    memory          = parser->root.memory;
320      FT_Error     error;
321      FT_Bool      only_immediates = 0;
322
323
324      /* read the number of entries in the encoding; should be 256 */
325      if ( *cur == '[' )
326      {
327        count           = 256;
328        only_immediates = 1;
329        parser->root.cursor++;
330      }
331      else
332        count = (FT_UInt)T1_ToInt( parser );
333
334      T1_Skip_Spaces( parser );
335      if ( parser->root.cursor >= limit )
336        return;
337
338      /* we use a T1_Table to store our charnames */
339      loader->num_chars = encode->num_chars = count;
340      if ( FT_NEW_ARRAY( encode->char_index, count )     ||
341           FT_NEW_ARRAY( encode->char_name,  count )     ||
342           FT_SET_ERROR( psaux->ps_table_funcs->init(
343                           char_table, count, memory ) ) )
344      {
345        parser->root.error = error;
346        return;
347      }
348
349      /* We need to `zero' out encoding_table.elements */
350      for ( n = 0; n < count; n++ )
351      {
352        char*  notdef = (char *)".notdef";
353
354
355        T1_Add_Table( char_table, n, notdef, 8 );
356      }
357
358      /* Now we need to read records of the form                */
359      /*                                                        */
360      /*   ... charcode /charname ...                           */
361      /*                                                        */
362      /* for each entry in our table.                           */
363      /*                                                        */
364      /* We simply look for a number followed by an immediate   */
365      /* name.  Note that this ignores correctly the sequence   */
366      /* that is often seen in type42 fonts:                    */
367      /*                                                        */
368      /*   0 1 255 { 1 index exch /.notdef put } for dup        */
369      /*                                                        */
370      /* used to clean the encoding array before anything else. */
371      /*                                                        */
372      /* Alternatively, if the array is directly given as       */
373      /*                                                        */
374      /*   /Encoding [ ... ]                                    */
375      /*                                                        */
376      /* we only read immediates.                               */
377
378      n = 0;
379      T1_Skip_Spaces( parser );
380
381      while ( parser->root.cursor < limit )
382      {
383        cur = parser->root.cursor;
384
385        /* we stop when we encounter `def' or `]' */
386        if ( *cur == 'd' && cur + 3 < limit )
387        {
388          if ( cur[1] == 'e'          &&
389               cur[2] == 'f'          &&
390               t42_is_space( cur[3] ) )
391          {
392            FT_TRACE6(( "encoding end\n" ));
393            cur += 3;
394            break;
395          }
396        }
397        if ( *cur == ']' )
398        {
399          FT_TRACE6(( "encoding end\n" ));
400          cur++;
401          break;
402        }
403
404        /* check whether we have found an entry */
405        if ( ft_isdigit( *cur ) || only_immediates )
406        {
407          FT_Int  charcode;
408
409
410          if ( only_immediates )
411            charcode = n;
412          else
413          {
414            charcode = (FT_Int)T1_ToInt( parser );
415            T1_Skip_Spaces( parser );
416          }
417
418          cur = parser->root.cursor;
419
420          if ( *cur == '/' && cur + 2 < limit && n < count )
421          {
422            FT_PtrDist  len;
423
424
425            cur++;
426
427            parser->root.cursor = cur;
428            T1_Skip_PS_Token( parser );
429            if ( parser->root.error )
430              return;
431
432            len = parser->root.cursor - cur;
433
434            parser->root.error = T1_Add_Table( char_table, charcode,
435                                               cur, len + 1 );
436            if ( parser->root.error )
437              return;
438            char_table->elements[charcode][len] = '\0';
439
440            n++;
441          }
442        }
443        else
444        {
445          T1_Skip_PS_Token( parser );
446          if ( parser->root.error )
447            return;
448        }
449
450        T1_Skip_Spaces( parser );
451      }
452
453      face->type1.encoding_type  = T1_ENCODING_TYPE_ARRAY;
454      parser->root.cursor        = cur;
455    }
456
457    /* Otherwise, we should have either `StandardEncoding', */
458    /* `ExpertEncoding', or `ISOLatin1Encoding'             */
459    else
460    {
461      if ( cur + 17 < limit                                            &&
462           ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
463        face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
464
465      else if ( cur + 15 < limit                                          &&
466                ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
467        face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
468
469      else if ( cur + 18 < limit                                             &&
470                ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
471        face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
472
473      else
474      {
475        FT_ERROR(( "t42_parse_encoding: invalid token!\n" ));
476        parser->root.error = T42_Err_Invalid_File_Format;
477      }
478    }
479  }
480
481
482  typedef enum  T42_Load_Status_
483  {
484    BEFORE_START,
485    BEFORE_TABLE_DIR,
486    OTHER_TABLES
487
488  } T42_Load_Status;
489
490
491  static void
492  t42_parse_sfnts( T42_Face    face,
493                   T42_Loader  loader )
494  {
495    T42_Parser  parser = &loader->parser;
496    FT_Memory   memory = parser->root.memory;
497    FT_Byte*    cur;
498    FT_Byte*    limit  = parser->root.limit;
499    FT_Error    error;
500    FT_Int      num_tables = 0;
501    FT_ULong    count, ttf_size = 0;
502
503    FT_Long     n, string_size, old_string_size, real_size;
504    FT_Byte*    string_buf = NULL;
505    FT_Bool     allocated  = 0;
506
507    T42_Load_Status  status;
508
509
510    /* The format is                                */
511    /*                                              */
512    /*   /sfnts [ <hexstring> <hexstring> ... ] def */
513    /*                                              */
514    /* or                                           */
515    /*                                              */
516    /*   /sfnts [                                   */
517    /*      <num_bin_bytes> RD <binary data>        */
518    /*      <num_bin_bytes> RD <binary data>        */
519    /*      ...                                     */
520    /*   ] def                                      */
521    /*                                              */
522    /* with exactly one space after the `RD' token. */
523
524    T1_Skip_Spaces( parser );
525
526    if ( parser->root.cursor >= limit || *parser->root.cursor++ != '[' )
527    {
528      FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector!\n" ));
529      error = T42_Err_Invalid_File_Format;
530      goto Fail;
531    }
532
533    T1_Skip_Spaces( parser );
534    status          = BEFORE_START;
535    string_size     = 0;
536    old_string_size = 0;
537    count           = 0;
538
539    while ( parser->root.cursor < limit )
540    {
541      cur = parser->root.cursor;
542
543      if ( *cur == ']' )
544      {
545        parser->root.cursor++;
546        goto Exit;
547      }
548
549      else if ( *cur == '<' )
550      {
551        T1_Skip_PS_Token( parser );
552        if ( parser->root.error )
553          goto Exit;
554
555        /* don't include delimiters */
556        string_size = (FT_Long)( ( parser->root.cursor - cur - 2 + 1 ) / 2 );
557        if ( FT_REALLOC( string_buf, old_string_size, string_size ) )
558          goto Fail;
559
560        allocated = 1;
561
562        parser->root.cursor = cur;
563        (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 );
564        old_string_size = string_size;
565        string_size = real_size;
566      }
567
568      else if ( ft_isdigit( *cur ) )
569      {
570        if ( allocated )
571        {
572          FT_ERROR(( "t42_parse_sfnts: "
573                     "can't handle mixed binary and hex strings!\n" ));
574          error = T42_Err_Invalid_File_Format;
575          goto Fail;
576        }
577
578        string_size = T1_ToInt( parser );
579
580        T1_Skip_PS_Token( parser );             /* `RD' */
581        if ( parser->root.error )
582          return;
583
584        string_buf = parser->root.cursor + 1;   /* one space after `RD' */
585
586        parser->root.cursor += string_size + 1;
587        if ( parser->root.cursor >= limit )
588        {
589          FT_ERROR(( "t42_parse_sfnts: too many binary data!\n" ));
590          error = T42_Err_Invalid_File_Format;
591          goto Fail;
592        }
593      }
594
595      if ( !string_buf )
596      {
597        FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array!\n" ));
598        error = T42_Err_Invalid_File_Format;
599        goto Fail;
600      }
601
602      /* A string can have a trailing zero byte for padding.  Ignore it. */
603      if ( string_buf[string_size - 1] == 0 && ( string_size % 2 == 1 ) )
604        string_size--;
605
606      if ( !string_size )
607      {
608        FT_ERROR(( "t42_parse_sfnts: invalid string!\n" ));
609        error = T42_Err_Invalid_File_Format;
610        goto Fail;
611      }
612
613      for ( n = 0; n < string_size; n++ )
614      {
615        switch ( status )
616        {
617        case BEFORE_START:
618          /* load offset table, 12 bytes */
619          if ( count < 12 )
620          {
621            face->ttf_data[count++] = string_buf[n];
622            continue;
623          }
624          else
625          {
626            num_tables = 16 * face->ttf_data[4] + face->ttf_data[5];
627            status     = BEFORE_TABLE_DIR;
628            ttf_size   = 12 + 16 * num_tables;
629
630            if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) )
631              goto Fail;
632          }
633          /* fall through */
634
635        case BEFORE_TABLE_DIR:
636          /* the offset table is read; read the table directory */
637          if ( count < ttf_size )
638          {
639            face->ttf_data[count++] = string_buf[n];
640            continue;
641          }
642          else
643          {
644            int       i;
645            FT_ULong  len;
646
647
648            for ( i = 0; i < num_tables; i++ )
649            {
650              FT_Byte*  p = face->ttf_data + 12 + 16 * i + 12;
651
652
653              len = FT_PEEK_ULONG( p );
654
655              /* Pad to a 4-byte boundary length */
656              ttf_size += ( len + 3 ) & ~3;
657            }
658
659            status         = OTHER_TABLES;
660            face->ttf_size = ttf_size;
661
662            /* there are no more than 256 tables, so no size check here */
663            if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables,
664                             ttf_size + 1 ) )
665              goto Fail;
666          }
667          /* fall through */
668
669        case OTHER_TABLES:
670          /* all other tables are just copied */
671          if ( count >= ttf_size )
672          {
673            FT_ERROR(( "t42_parse_sfnts: too many binary data!\n" ));
674            error = T42_Err_Invalid_File_Format;
675            goto Fail;
676          }
677          face->ttf_data[count++] = string_buf[n];
678        }
679      }
680
681      T1_Skip_Spaces( parser );
682    }
683
684    /* if control reaches this point, the format was not valid */
685    error = T42_Err_Invalid_File_Format;
686
687  Fail:
688    parser->root.error = error;
689
690  Exit:
691    if ( allocated )
692      FT_FREE( string_buf );
693  }
694
695
696  static void
697  t42_parse_charstrings( T42_Face    face,
698                         T42_Loader  loader )
699  {
700    T42_Parser     parser       = &loader->parser;
701    PS_Table       code_table   = &loader->charstrings;
702    PS_Table       name_table   = &loader->glyph_names;
703    PS_Table       swap_table   = &loader->swap_table;
704    FT_Memory      memory       = parser->root.memory;
705    FT_Error       error;
706
707    PSAux_Service  psaux        = (PSAux_Service)face->psaux;
708
709    FT_Byte*       cur;
710    FT_Byte*       limit        = parser->root.limit;
711    FT_UInt        n;
712    FT_UInt        notdef_index = 0;
713    FT_Byte        notdef_found = 0;
714
715
716    T1_Skip_Spaces( parser );
717
718    if ( parser->root.cursor >= limit )
719    {
720      FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" ));
721      error = T42_Err_Invalid_File_Format;
722      goto Fail;
723    }
724
725    if ( ft_isdigit( *parser->root.cursor ) )
726    {
727      loader->num_glyphs = (FT_UInt)T1_ToInt( parser );
728      if ( parser->root.error )
729        return;
730    }
731    else if ( *parser->root.cursor == '<' )
732    {
733      /* We have `<< ... >>'.  Count the number of `/' in the dictionary */
734      /* to get its size.                                                */
735      FT_UInt  count = 0;
736
737
738      T1_Skip_PS_Token( parser );
739      if ( parser->root.error )
740        return;
741      T1_Skip_Spaces( parser );
742      cur = parser->root.cursor;
743
744      while ( parser->root.cursor < limit )
745      {
746        if ( *parser->root.cursor == '/' )
747          count++;
748        else if ( *parser->root.cursor == '>' )
749        {
750          loader->num_glyphs  = count;
751          parser->root.cursor = cur;        /* rewind */
752          break;
753        }
754        T1_Skip_PS_Token( parser );
755        if ( parser->root.error )
756          return;
757        T1_Skip_Spaces( parser );
758      }
759    }
760    else
761    {
762      FT_ERROR(( "t42_parse_charstrings: invalid token!\n" ));
763      error = T42_Err_Invalid_File_Format;
764      goto Fail;
765    }
766
767    if ( parser->root.cursor >= limit )
768    {
769      FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" ));
770      error = T42_Err_Invalid_File_Format;
771      goto Fail;
772    }
773
774    /* initialize tables */
775
776    error = psaux->ps_table_funcs->init( code_table,
777                                         loader->num_glyphs,
778                                         memory );
779    if ( error )
780      goto Fail;
781
782    error = psaux->ps_table_funcs->init( name_table,
783                                         loader->num_glyphs,
784                                         memory );
785    if ( error )
786      goto Fail;
787
788    /* Initialize table for swapping index notdef_index and */
789    /* index 0 names and codes (if necessary).              */
790
791    error = psaux->ps_table_funcs->init( swap_table, 4, memory );
792    if ( error )
793      goto Fail;
794
795    n = 0;
796
797    for (;;)
798    {
799      /* The format is simple:                   */
800      /*   `/glyphname' + index [+ def]          */
801
802      T1_Skip_Spaces( parser );
803
804      cur = parser->root.cursor;
805      if ( cur >= limit )
806        break;
807
808      /* We stop when we find an `end' keyword or '>' */
809      if ( *cur   == 'e'          &&
810           cur + 3 < limit        &&
811           cur[1] == 'n'          &&
812           cur[2] == 'd'          &&
813           t42_is_space( cur[3] ) )
814        break;
815      if ( *cur == '>' )
816        break;
817
818      T1_Skip_PS_Token( parser );
819      if ( parser->root.error )
820        return;
821
822      if ( *cur == '/' )
823      {
824        FT_PtrDist  len;
825
826
827        if ( cur + 1 >= limit )
828        {
829          FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" ));
830          error = T42_Err_Invalid_File_Format;
831          goto Fail;
832        }
833
834        cur++;                              /* skip `/' */
835        len = parser->root.cursor - cur;
836
837        error = T1_Add_Table( name_table, n, cur, len + 1 );
838        if ( error )
839          goto Fail;
840
841        /* add a trailing zero to the name table */
842        name_table->elements[n][len] = '\0';
843
844        /* record index of /.notdef */
845        if ( *cur == '.'                                              &&
846             ft_strcmp( ".notdef",
847                        (const char*)(name_table->elements[n]) ) == 0 )
848        {
849          notdef_index = n;
850          notdef_found = 1;
851        }
852
853        T1_Skip_Spaces( parser );
854
855        cur = parser->root.cursor;
856
857        (void)T1_ToInt( parser );
858        if ( parser->root.cursor >= limit )
859        {
860          FT_ERROR(( "t42_parse_charstrings: out of bounds!\n" ));
861          error = T42_Err_Invalid_File_Format;
862          goto Fail;
863        }
864
865        len = parser->root.cursor - cur;
866
867        error = T1_Add_Table( code_table, n, cur, len + 1 );
868        if ( error )
869          goto Fail;
870
871        code_table->elements[n][len] = '\0';
872
873        n++;
874        if ( n >= loader->num_glyphs )
875          break;
876      }
877    }
878
879    loader->num_glyphs = n;
880
881    if ( !notdef_found )
882    {
883      FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph!\n" ));
884      error = T42_Err_Invalid_File_Format;
885      goto Fail;
886    }
887
888    /* if /.notdef does not occupy index 0, do our magic. */
889    if ( ft_strcmp( (const char*)".notdef",
890                    (const char*)name_table->elements[0] ) )
891    {
892      /* Swap glyph in index 0 with /.notdef glyph.  First, add index 0  */
893      /* name and code entries to swap_table.  Then place notdef_index   */
894      /* name and code entries into swap_table.  Then swap name and code */
895      /* entries at indices notdef_index and 0 using values stored in    */
896      /* swap_table.                                                     */
897
898      /* Index 0 name */
899      error = T1_Add_Table( swap_table, 0,
900                            name_table->elements[0],
901                            name_table->lengths [0] );
902      if ( error )
903        goto Fail;
904
905      /* Index 0 code */
906      error = T1_Add_Table( swap_table, 1,
907                            code_table->elements[0],
908                            code_table->lengths [0] );
909      if ( error )
910        goto Fail;
911
912      /* Index notdef_index name */
913      error = T1_Add_Table( swap_table, 2,
914                            name_table->elements[notdef_index],
915                            name_table->lengths [notdef_index] );
916      if ( error )
917        goto Fail;
918
919      /* Index notdef_index code */
920      error = T1_Add_Table( swap_table, 3,
921                            code_table->elements[notdef_index],
922                            code_table->lengths [notdef_index] );
923      if ( error )
924        goto Fail;
925
926      error = T1_Add_Table( name_table, notdef_index,
927                            swap_table->elements[0],
928                            swap_table->lengths [0] );
929      if ( error )
930        goto Fail;
931
932      error = T1_Add_Table( code_table, notdef_index,
933                            swap_table->elements[1],
934                            swap_table->lengths [1] );
935      if ( error )
936        goto Fail;
937
938      error = T1_Add_Table( name_table, 0,
939                            swap_table->elements[2],
940                            swap_table->lengths [2] );
941      if ( error )
942        goto Fail;
943
944      error = T1_Add_Table( code_table, 0,
945                            swap_table->elements[3],
946                            swap_table->lengths [3] );
947      if ( error )
948        goto Fail;
949
950    }
951
952    return;
953
954  Fail:
955    parser->root.error = error;
956  }
957
958
959  static FT_Error
960  t42_load_keyword( T42_Face    face,
961                    T42_Loader  loader,
962                    T1_Field    field )
963  {
964    FT_Error  error;
965    void*     dummy_object;
966    void**    objects;
967    FT_UInt   max_objects = 0;
968
969
970    /* if the keyword has a dedicated callback, call it */
971    if ( field->type == T1_FIELD_TYPE_CALLBACK )
972    {
973      field->reader( (FT_Face)face, loader );
974      error = loader->parser.root.error;
975      goto Exit;
976    }
977
978    /* now the keyword is either a simple field or a table of fields; */
979    /* we are now going to take care of it                            */
980
981    switch ( field->location )
982    {
983    case T1_FIELD_LOCATION_FONT_INFO:
984      dummy_object = &face->type1.font_info;
985      break;
986
987    case T1_FIELD_LOCATION_BBOX:
988      dummy_object = &face->type1.font_bbox;
989      break;
990
991    default:
992      dummy_object = &face->type1;
993    }
994
995    objects = &dummy_object;
996
997    if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
998         field->type == T1_FIELD_TYPE_FIXED_ARRAY   )
999      error = T1_Load_Field_Table( &loader->parser, field,
1000                                   objects, max_objects, 0 );
1001    else
1002      error = T1_Load_Field( &loader->parser, field,
1003                             objects, max_objects, 0 );
1004
1005   Exit:
1006    return error;
1007  }
1008
1009
1010  FT_LOCAL_DEF( FT_Error )
1011  t42_parse_dict( T42_Face    face,
1012                  T42_Loader  loader,
1013                  FT_Byte*    base,
1014                  FT_Long     size )
1015  {
1016    T42_Parser  parser     = &loader->parser;
1017    FT_Byte*    limit;
1018    FT_Int      n_keywords = (FT_Int)( sizeof ( t42_keywords ) /
1019                                         sizeof ( t42_keywords[0] ) );
1020
1021
1022    parser->root.cursor = base;
1023    parser->root.limit  = base + size;
1024    parser->root.error  = T42_Err_Ok;
1025
1026    limit = parser->root.limit;
1027
1028    T1_Skip_Spaces( parser );
1029
1030    while ( parser->root.cursor < limit )
1031    {
1032      FT_Byte*  cur;
1033
1034
1035      cur = parser->root.cursor;
1036
1037      /* look for `FontDirectory' which causes problems for some fonts */
1038      if ( *cur == 'F' && cur + 25 < limit                    &&
1039           ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
1040      {
1041        FT_Byte*  cur2;
1042
1043
1044        /* skip the `FontDirectory' keyword */
1045        T1_Skip_PS_Token( parser );
1046        T1_Skip_Spaces  ( parser );
1047        cur = cur2 = parser->root.cursor;
1048
1049        /* look up the `known' keyword */
1050        while ( cur < limit )
1051        {
1052          if ( *cur == 'k' && cur + 5 < limit             &&
1053                ft_strncmp( (char*)cur, "known", 5 ) == 0 )
1054            break;
1055
1056          T1_Skip_PS_Token( parser );
1057          if ( parser->root.error )
1058            goto Exit;
1059          T1_Skip_Spaces  ( parser );
1060          cur = parser->root.cursor;
1061        }
1062
1063        if ( cur < limit )
1064        {
1065          T1_TokenRec  token;
1066
1067
1068          /* skip the `known' keyword and the token following it */
1069          T1_Skip_PS_Token( parser );
1070          T1_ToToken( parser, &token );
1071
1072          /* if the last token was an array, skip it! */
1073          if ( token.type == T1_TOKEN_TYPE_ARRAY )
1074            cur2 = parser->root.cursor;
1075        }
1076        parser->root.cursor = cur2;
1077      }
1078
1079      /* look for immediates */
1080      else if ( *cur == '/' && cur + 2 < limit )
1081      {
1082        FT_PtrDist  len;
1083
1084
1085        cur++;
1086
1087        parser->root.cursor = cur;
1088        T1_Skip_PS_Token( parser );
1089        if ( parser->root.error )
1090          goto Exit;
1091
1092        len = parser->root.cursor - cur;
1093
1094        if ( len > 0 && len < 22 && parser->root.cursor < limit )
1095        {
1096          int  i;
1097
1098
1099          /* now compare the immediate name to the keyword table */
1100
1101          /* loop through all known keywords */
1102          for ( i = 0; i < n_keywords; i++ )
1103          {
1104            T1_Field  keyword = (T1_Field)&t42_keywords[i];
1105            FT_Byte   *name   = (FT_Byte*)keyword->ident;
1106
1107
1108            if ( !name )
1109              continue;
1110
1111            if ( cur[0] == name[0]                                  &&
1112                 len == (FT_PtrDist)ft_strlen( (const char *)name ) &&
1113                 ft_memcmp( cur, name, len ) == 0                   )
1114            {
1115              /* we found it -- run the parsing callback! */
1116              parser->root.error = t42_load_keyword( face,
1117                                                     loader,
1118                                                     keyword );
1119              if ( parser->root.error )
1120                return parser->root.error;
1121              break;
1122            }
1123          }
1124        }
1125      }
1126      else
1127      {
1128        T1_Skip_PS_Token( parser );
1129        if ( parser->root.error )
1130          goto Exit;
1131      }
1132
1133      T1_Skip_Spaces( parser );
1134    }
1135
1136  Exit:
1137    return parser->root.error;
1138  }
1139
1140
1141  FT_LOCAL_DEF( void )
1142  t42_loader_init( T42_Loader  loader,
1143                   T42_Face    face )
1144  {
1145    FT_UNUSED( face );
1146
1147    FT_MEM_ZERO( loader, sizeof ( *loader ) );
1148    loader->num_glyphs = 0;
1149    loader->num_chars  = 0;
1150
1151    /* initialize the tables -- simply set their `init' field to 0 */
1152    loader->encoding_table.init = 0;
1153    loader->charstrings.init    = 0;
1154    loader->glyph_names.init    = 0;
1155  }
1156
1157
1158  FT_LOCAL_DEF( void )
1159  t42_loader_done( T42_Loader  loader )
1160  {
1161    T42_Parser  parser = &loader->parser;
1162
1163
1164    /* finalize tables */
1165    T1_Release_Table( &loader->encoding_table );
1166    T1_Release_Table( &loader->charstrings );
1167    T1_Release_Table( &loader->glyph_names );
1168    T1_Release_Table( &loader->swap_table );
1169
1170    /* finalize parser */
1171    t42_parser_done( parser );
1172  }
1173
1174
1175/* END */
Note: See TracBrowser for help on using the repository browser.