source: trunk/poppler/freetype-2.1.10/src/type1/t1parse.c @ 2

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 15 years ago

First import

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