~ubuntu-branches/ubuntu/vivid/emscripten/vivid

« back to all changes in this revision

Viewing changes to tests/freetype/src/type42/t42parse.c

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2013-05-02 13:11:51 UTC
  • Revision ID: package-import@ubuntu.com-20130502131151-q8dvteqr1ef2x7xz
Tags: upstream-1.4.1~20130504~adb56cb
ImportĀ upstreamĀ versionĀ 1.4.1~20130504~adb56cb

Show diffs side-by-side

added added

removed removed

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