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

Last change on this file since 262 was 262, checked in by Eugene Romanenko, 12 years ago

PDF plugin: freetype library updated to version 2.3.8

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