~ubuntu-branches/ubuntu/wily/hedgewars/wily

« back to all changes in this revision

Viewing changes to misc/libfreetype/src/type1/t1parse.c

  • Committer: Package Import Robot
  • Author(s): Dmitry E. Oboukhov
  • Date: 2011-09-23 10:16:55 UTC
  • mfrom: (1.2.11 upstream)
  • Revision ID: package-import@ubuntu.com-20110923101655-3977th2gc5n0a3pv
Tags: 0.9.16-1
* New upstream version.
 + Downloadable content! Simply click to install any content.
   New voices, hats, maps, themes, translations, music, scripts...
   Hedgewars is now more customisable than ever before! As time goes
   by we will be soliciting community content to feature on this page,
   so remember to check it from time to time. If you decide you want
   to go back to standard Hedgewars, just remove the Data directory
   from your Hedgewars config directory.
 + 3-D rendering! Diorama-like rendering of the game in a variety
   of 3D modes. Let us know which ones work best for you, we didn't
   really have the equipment to test them all.
 + Resizable game window.
 + New utilities! The Time Box will remove one of your hedgehogs
   from the game for a while, protecting from attack until it returns,
   somewhere else on the map. Land spray will allow you to build bridges,
   seal up holes, or just make life unpleasant for your enemies.
 + New single player: Bamboo Thicket, That Sinking Feeling, Newton and
   the Tree and multi-player: The Specialists, Space Invaders,
   Racer - scripts! And a ton more script hooks for scripters
 + New twists on old weapons. Drill strike, seduction and fire have
   been adjusted. Defective mines have been added, rope can attach to
   hogs/crates/barrels again, grenades now have variable bounce (use
   precise key + 1-5). Portal gun is now more usable in flight and
   all game actions are a lot faster.
 + New theme - Golf, dozens of new community hats and a new
   localised Default voice, Ukranian.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************/
 
2
/*                                                                         */
 
3
/*  t1parse.c                                                              */
 
4
/*                                                                         */
 
5
/*    Type 1 parser (body).                                                */
 
6
/*                                                                         */
 
7
/*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2008, 2009 by             */
 
8
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 
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
  /*************************************************************************/
 
20
  /*                                                                       */
 
21
  /* The Type 1 parser is in charge of the following:                      */
 
22
  /*                                                                       */
 
23
  /*  - provide an implementation of a growing sequence of objects called  */
 
24
  /*    a `T1_Table' (used to build various tables needed by the loader).  */
 
25
  /*                                                                       */
 
26
  /*  - opening .pfb and .pfa files to extract their top-level and private */
 
27
  /*    dictionaries.                                                      */
 
28
  /*                                                                       */
 
29
  /*  - read numbers, arrays & strings from any dictionary.                */
 
30
  /*                                                                       */
 
31
  /* See `t1load.c' to see how data is loaded from the font file.          */
 
32
  /*                                                                       */
 
33
  /*************************************************************************/
 
34
 
 
35
 
 
36
#include <ft2build.h>
 
37
#include FT_INTERNAL_DEBUG_H
 
38
#include FT_INTERNAL_STREAM_H
 
39
#include FT_INTERNAL_POSTSCRIPT_AUX_H
 
40
 
 
41
#include "t1parse.h"
 
42
 
 
43
#include "t1errors.h"
 
44
 
 
45
 
 
46
  /*************************************************************************/
 
47
  /*                                                                       */
 
48
  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
 
49
  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
 
50
  /* messages during execution.                                            */
 
51
  /*                                                                       */
 
52
#undef  FT_COMPONENT
 
53
#define FT_COMPONENT  trace_t1parse
 
54
 
 
55
 
 
56
  /*************************************************************************/
 
57
  /*************************************************************************/
 
58
  /*************************************************************************/
 
59
  /*****                                                               *****/
 
60
  /*****                   INPUT STREAM PARSER                         *****/
 
61
  /*****                                                               *****/
 
62
  /*************************************************************************/
 
63
  /*************************************************************************/
 
64
  /*************************************************************************/
 
65
 
 
66
 
 
67
  /* see Adobe Technical Note 5040.Download_Fonts.pdf */
 
68
 
 
69
  static FT_Error
 
70
  read_pfb_tag( FT_Stream   stream,
 
71
                FT_UShort  *atag,
 
72
                FT_ULong   *asize )
 
73
  {
 
74
    FT_Error   error;
 
75
    FT_UShort  tag;
 
76
    FT_ULong   size;
 
77
 
 
78
 
 
79
    *atag  = 0;
 
80
    *asize = 0;
 
81
 
 
82
    if ( !FT_READ_USHORT( tag ) )
 
83
    {
 
84
      if ( tag == 0x8001U || tag == 0x8002U )
 
85
      {
 
86
        if ( !FT_READ_ULONG_LE( size ) )
 
87
          *asize = size;
 
88
      }
 
89
 
 
90
      *atag = tag;
 
91
    }
 
92
 
 
93
    return error;
 
94
  }
 
95
 
 
96
 
 
97
  static FT_Error
 
98
  check_type1_format( FT_Stream    stream,
 
99
                      const char*  header_string,
 
100
                      size_t       header_length )
 
101
  {
 
102
    FT_Error   error;
 
103
    FT_UShort  tag;
 
104
    FT_ULong   dummy;
 
105
 
 
106
 
 
107
    if ( FT_STREAM_SEEK( 0 ) )
 
108
      goto Exit;
 
109
 
 
110
    error = read_pfb_tag( stream, &tag, &dummy );
 
111
    if ( error )
 
112
      goto Exit;
 
113
 
 
114
    /* We assume that the first segment in a PFB is always encoded as   */
 
115
    /* text.  This might be wrong (and the specification doesn't insist */
 
116
    /* on that), but we have never seen a counterexample.               */
 
117
    if ( tag != 0x8001U && FT_STREAM_SEEK( 0 ) )
 
118
      goto Exit;
 
119
 
 
120
    if ( !FT_FRAME_ENTER( header_length ) )
 
121
    {
 
122
      error = T1_Err_Ok;
 
123
 
 
124
      if ( ft_memcmp( stream->cursor, header_string, header_length ) != 0 )
 
125
        error = T1_Err_Unknown_File_Format;
 
126
 
 
127
      FT_FRAME_EXIT();
 
128
    }
 
129
 
 
130
  Exit:
 
131
    return error;
 
132
  }
 
133
 
 
134
 
 
135
  FT_LOCAL_DEF( FT_Error )
 
136
  T1_New_Parser( T1_Parser      parser,
 
137
                 FT_Stream      stream,
 
138
                 FT_Memory      memory,
 
139
                 PSAux_Service  psaux )
 
140
  {
 
141
    FT_Error   error;
 
142
    FT_UShort  tag;
 
143
    FT_ULong   size;
 
144
 
 
145
 
 
146
    psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory );
 
147
 
 
148
    parser->stream       = stream;
 
149
    parser->base_len     = 0;
 
150
    parser->base_dict    = 0;
 
151
    parser->private_len  = 0;
 
152
    parser->private_dict = 0;
 
153
    parser->in_pfb       = 0;
 
154
    parser->in_memory    = 0;
 
155
    parser->single_block = 0;
 
156
 
 
157
    /* check the header format */
 
158
    error = check_type1_format( stream, "%!PS-AdobeFont", 14 );
 
159
    if ( error )
 
160
    {
 
161
      if ( error != T1_Err_Unknown_File_Format )
 
162
        goto Exit;
 
163
 
 
164
      error = check_type1_format( stream, "%!FontType", 10 );
 
165
      if ( error )
 
166
      {
 
167
        FT_TRACE2(( "[not a Type1 font]\n" ));
 
168
        goto Exit;
 
169
      }
 
170
    }
 
171
 
 
172
    /******************************************************************/
 
173
    /*                                                                */
 
174
    /* Here a short summary of what is going on:                      */
 
175
    /*                                                                */
 
176
    /*   When creating a new Type 1 parser, we try to locate and load */
 
177
    /*   the base dictionary if this is possible (i.e., for PFB       */
 
178
    /*   files).  Otherwise, we load the whole font into memory.      */
 
179
    /*                                                                */
 
180
    /*   When `loading' the base dictionary, we only setup pointers   */
 
181
    /*   in the case of a memory-based stream.  Otherwise, we         */
 
182
    /*   allocate and load the base dictionary in it.                 */
 
183
    /*                                                                */
 
184
    /*   parser->in_pfb is set if we are in a binary (`.pfb') font.   */
 
185
    /*   parser->in_memory is set if we have a memory stream.         */
 
186
    /*                                                                */
 
187
 
 
188
    /* try to compute the size of the base dictionary;     */
 
189
    /* look for a Postscript binary file tag, i.e., 0x8001 */
 
190
    if ( FT_STREAM_SEEK( 0L ) )
 
191
      goto Exit;
 
192
 
 
193
    error = read_pfb_tag( stream, &tag, &size );
 
194
    if ( error )
 
195
      goto Exit;
 
196
 
 
197
    if ( tag != 0x8001U )
 
198
    {
 
199
      /* assume that this is a PFA file for now; an error will */
 
200
      /* be produced later when more things are checked        */
 
201
      if ( FT_STREAM_SEEK( 0L ) )
 
202
        goto Exit;
 
203
      size = stream->size;
 
204
    }
 
205
    else
 
206
      parser->in_pfb = 1;
 
207
 
 
208
    /* now, try to load `size' bytes of the `base' dictionary we */
 
209
    /* found previously                                          */
 
210
 
 
211
    /* if it is a memory-based resource, set up pointers */
 
212
    if ( !stream->read )
 
213
    {
 
214
      parser->base_dict = (FT_Byte*)stream->base + stream->pos;
 
215
      parser->base_len  = size;
 
216
      parser->in_memory = 1;
 
217
 
 
218
      /* check that the `size' field is valid */
 
219
      if ( FT_STREAM_SKIP( size ) )
 
220
        goto Exit;
 
221
    }
 
222
    else
 
223
    {
 
224
      /* read segment in memory -- this is clumsy, but so does the format */
 
225
      if ( FT_ALLOC( parser->base_dict, size )       ||
 
226
           FT_STREAM_READ( parser->base_dict, size ) )
 
227
        goto Exit;
 
228
      parser->base_len = size;
 
229
    }
 
230
 
 
231
    parser->root.base   = parser->base_dict;
 
232
    parser->root.cursor = parser->base_dict;
 
233
    parser->root.limit  = parser->root.cursor + parser->base_len;
 
234
 
 
235
  Exit:
 
236
    if ( error && !parser->in_memory )
 
237
      FT_FREE( parser->base_dict );
 
238
 
 
239
    return error;
 
240
  }
 
241
 
 
242
 
 
243
  FT_LOCAL_DEF( void )
 
244
  T1_Finalize_Parser( T1_Parser  parser )
 
245
  {
 
246
    FT_Memory  memory = parser->root.memory;
 
247
 
 
248
 
 
249
    /* always free the private dictionary */
 
250
    FT_FREE( parser->private_dict );
 
251
 
 
252
    /* free the base dictionary only when we have a disk stream */
 
253
    if ( !parser->in_memory )
 
254
      FT_FREE( parser->base_dict );
 
255
 
 
256
    parser->root.funcs.done( &parser->root );
 
257
  }
 
258
 
 
259
 
 
260
  FT_LOCAL_DEF( FT_Error )
 
261
  T1_Get_Private_Dict( T1_Parser      parser,
 
262
                       PSAux_Service  psaux )
 
263
  {
 
264
    FT_Stream  stream = parser->stream;
 
265
    FT_Memory  memory = parser->root.memory;
 
266
    FT_Error   error  = T1_Err_Ok;
 
267
    FT_ULong   size;
 
268
 
 
269
 
 
270
    if ( parser->in_pfb )
 
271
    {
 
272
      /* in the case of the PFB format, the private dictionary can be  */
 
273
      /* made of several segments.  We thus first read the number of   */
 
274
      /* segments to compute the total size of the private dictionary  */
 
275
      /* then re-read them into memory.                                */
 
276
      FT_Long    start_pos = FT_STREAM_POS();
 
277
      FT_UShort  tag;
 
278
 
 
279
 
 
280
      parser->private_len = 0;
 
281
      for (;;)
 
282
      {
 
283
        error = read_pfb_tag( stream, &tag, &size );
 
284
        if ( error )
 
285
          goto Fail;
 
286
 
 
287
        if ( tag != 0x8002U )
 
288
          break;
 
289
 
 
290
        parser->private_len += size;
 
291
 
 
292
        if ( FT_STREAM_SKIP( size ) )
 
293
          goto Fail;
 
294
      }
 
295
 
 
296
      /* Check that we have a private dictionary there */
 
297
      /* and allocate private dictionary buffer        */
 
298
      if ( parser->private_len == 0 )
 
299
      {
 
300
        FT_ERROR(( "T1_Get_Private_Dict:"
 
301
                   " invalid private dictionary section\n" ));
 
302
        error = T1_Err_Invalid_File_Format;
 
303
        goto Fail;
 
304
      }
 
305
 
 
306
      if ( FT_STREAM_SEEK( start_pos )                           ||
 
307
           FT_ALLOC( parser->private_dict, parser->private_len ) )
 
308
        goto Fail;
 
309
 
 
310
      parser->private_len = 0;
 
311
      for (;;)
 
312
      {
 
313
        error = read_pfb_tag( stream, &tag, &size );
 
314
        if ( error || tag != 0x8002U )
 
315
        {
 
316
          error = T1_Err_Ok;
 
317
          break;
 
318
        }
 
319
 
 
320
        if ( FT_STREAM_READ( parser->private_dict + parser->private_len,
 
321
                             size ) )
 
322
          goto Fail;
 
323
 
 
324
        parser->private_len += size;
 
325
      }
 
326
    }
 
327
    else
 
328
    {
 
329
      /* We have already `loaded' the whole PFA font file into memory; */
 
330
      /* if this is a memory resource, allocate a new block to hold    */
 
331
      /* the private dict.  Otherwise, simply overwrite into the base  */
 
332
      /* dictionary block in the heap.                                 */
 
333
 
 
334
      /* first of all, look at the `eexec' keyword */
 
335
      FT_Byte*  cur   = parser->base_dict;
 
336
      FT_Byte*  limit = cur + parser->base_len;
 
337
      FT_Byte   c;
 
338
 
 
339
 
 
340
    Again:
 
341
      for (;;)
 
342
      {
 
343
        c = cur[0];
 
344
        if ( c == 'e' && cur + 9 < limit )  /* 9 = 5 letters for `eexec' + */
 
345
                                            /* newline + 4 chars           */
 
346
        {
 
347
          if ( cur[1] == 'e' &&
 
348
               cur[2] == 'x' &&
 
349
               cur[3] == 'e' &&
 
350
               cur[4] == 'c' )
 
351
            break;
 
352
        }
 
353
        cur++;
 
354
        if ( cur >= limit )
 
355
        {
 
356
          FT_ERROR(( "T1_Get_Private_Dict:"
 
357
                     " could not find `eexec' keyword\n" ));
 
358
          error = T1_Err_Invalid_File_Format;
 
359
          goto Exit;
 
360
        }
 
361
      }
 
362
 
 
363
      /* check whether `eexec' was real -- it could be in a comment */
 
364
      /* or string (as e.g. in u003043t.gsf from ghostscript)       */
 
365
 
 
366
      parser->root.cursor = parser->base_dict;
 
367
      parser->root.limit  = cur + 9;
 
368
 
 
369
      cur   = parser->root.cursor;
 
370
      limit = parser->root.limit;
 
371
 
 
372
      while ( cur < limit )
 
373
      {
 
374
        if ( *cur == 'e' && ft_strncmp( (char*)cur, "eexec", 5 ) == 0 )
 
375
          goto Found;
 
376
 
 
377
        T1_Skip_PS_Token( parser );
 
378
        if ( parser->root.error )
 
379
          break;
 
380
        T1_Skip_Spaces  ( parser );
 
381
        cur = parser->root.cursor;
 
382
      }
 
383
 
 
384
      /* we haven't found the correct `eexec'; go back and continue */
 
385
      /* searching                                                  */
 
386
 
 
387
      cur   = limit;
 
388
      limit = parser->base_dict + parser->base_len;
 
389
      goto Again;
 
390
 
 
391
      /* now determine where to write the _encrypted_ binary private  */
 
392
      /* dictionary.  We overwrite the base dictionary for disk-based */
 
393
      /* resources and allocate a new block otherwise                 */
 
394
 
 
395
    Found:
 
396
      parser->root.limit = parser->base_dict + parser->base_len;
 
397
 
 
398
      T1_Skip_PS_Token( parser );
 
399
      cur = parser->root.cursor;
 
400
 
 
401
      /* according to the Type1 spec, the first cipher byte must not be  */
 
402
      /* an ASCII whitespace character code (blank, tab, carriage return */
 
403
      /* or line feed).  We have seen Type 1 fonts with two line feed    */
 
404
      /* characters...  So skip now all whitespace character codes.      */
 
405
      while ( cur < limit       &&
 
406
              ( *cur == ' '  ||
 
407
                *cur == '\t' || 
 
408
                *cur == '\r' ||
 
409
                *cur == '\n' ) )
 
410
        ++cur;
 
411
      if ( cur >= limit )
 
412
      {
 
413
        FT_ERROR(( "T1_Get_Private_Dict:"
 
414
                   " `eexec' not properly terminated\n" ));
 
415
        error = T1_Err_Invalid_File_Format;
 
416
        goto Exit;
 
417
      }
 
418
 
 
419
      size = parser->base_len - ( cur - parser->base_dict );
 
420
 
 
421
      if ( parser->in_memory )
 
422
      {
 
423
        /* note that we allocate one more byte to put a terminating `0' */
 
424
        if ( FT_ALLOC( parser->private_dict, size + 1 ) )
 
425
          goto Fail;
 
426
        parser->private_len = size;
 
427
      }
 
428
      else
 
429
      {
 
430
        parser->single_block = 1;
 
431
        parser->private_dict = parser->base_dict;
 
432
        parser->private_len  = size;
 
433
        parser->base_dict    = 0;
 
434
        parser->base_len     = 0;
 
435
      }
 
436
 
 
437
      /* now determine whether the private dictionary is encoded in binary */
 
438
      /* or hexadecimal ASCII format -- decode it accordingly              */
 
439
 
 
440
      /* we need to access the next 4 bytes (after the final \r following */
 
441
      /* the `eexec' keyword); if they all are hexadecimal digits, then   */
 
442
      /* we have a case of ASCII storage                                  */
 
443
 
 
444
      if ( ft_isxdigit( cur[0] ) && ft_isxdigit( cur[1] ) &&
 
445
           ft_isxdigit( cur[2] ) && ft_isxdigit( cur[3] ) )
 
446
      {
 
447
        /* ASCII hexadecimal encoding */
 
448
        FT_Long  len;
 
449
 
 
450
 
 
451
        parser->root.cursor = cur;
 
452
        (void)psaux->ps_parser_funcs->to_bytes( &parser->root,
 
453
                                                parser->private_dict,
 
454
                                                parser->private_len,
 
455
                                                &len,
 
456
                                                0 );
 
457
        parser->private_len = len;
 
458
 
 
459
        /* put a safeguard */
 
460
        parser->private_dict[len] = '\0';
 
461
      }
 
462
      else
 
463
        /* binary encoding -- copy the private dict */
 
464
        FT_MEM_MOVE( parser->private_dict, cur, size );
 
465
    }
 
466
 
 
467
    /* we now decrypt the encoded binary private dictionary */
 
468
    psaux->t1_decrypt( parser->private_dict, parser->private_len, 55665U );
 
469
 
 
470
    /* replace the four random bytes at the beginning with whitespace */
 
471
    parser->private_dict[0] = ' ';
 
472
    parser->private_dict[1] = ' ';
 
473
    parser->private_dict[2] = ' ';
 
474
    parser->private_dict[3] = ' ';
 
475
 
 
476
    parser->root.base   = parser->private_dict;
 
477
    parser->root.cursor = parser->private_dict;
 
478
    parser->root.limit  = parser->root.cursor + parser->private_len;
 
479
 
 
480
  Fail:
 
481
  Exit:
 
482
    return error;
 
483
  }
 
484
 
 
485
 
 
486
/* END */