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

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

PDF plugin: freetype library updated to version 2.3.5

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