PageRenderTime 43ms CodeModel.GetById 16ms app.highlight 21ms RepoModel.GetById 1ms app.codeStats 0ms

/src/freetype/src/type1/t1parse.c

https://bitbucket.org/cabalistic/ogredeps/
C | 494 lines | 288 code | 94 blank | 112 comment | 71 complexity | 183ad04ee764ebeeb4da559d08b1e18d MD5 | raw file
  1/***************************************************************************/
  2/*                                                                         */
  3/*  t1parse.c                                                              */
  4/*                                                                         */
  5/*    Type 1 parser (body).                                                */
  6/*                                                                         */
  7/*  Copyright 1996-2005, 2008, 2009, 2012 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 Type 1 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    if ( parser->private_len < 4 )
471    {
472      FT_ERROR(( "T1_Get_Private_Dict:"
473                 " invalid private dictionary section\n" ));
474      error = T1_Err_Invalid_File_Format;
475      goto Fail;
476    }
477
478    /* replace the four random bytes at the beginning with whitespace */
479    parser->private_dict[0] = ' ';
480    parser->private_dict[1] = ' ';
481    parser->private_dict[2] = ' ';
482    parser->private_dict[3] = ' ';
483
484    parser->root.base   = parser->private_dict;
485    parser->root.cursor = parser->private_dict;
486    parser->root.limit  = parser->root.cursor + parser->private_len;
487
488  Fail:
489  Exit:
490    return error;
491  }
492
493
494/* END */