Visualization Library 2.0.0-b5

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
t1parse.c
Go to the documentation of this file.
1 /***************************************************************************/
2 /* */
3 /* t1parse.c */
4 /* */
5 /* Type 1 parser (body). */
6 /* */
7 /* Copyright 1996-2005, 2008, 2009, 2012, 2013 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  {
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 = FT_Err_Ok;
123 
124  if ( ft_memcmp( stream->cursor, header_string, header_length ) != 0 )
125  error = FT_THROW( Unknown_File_Format );
126 
127  FT_FRAME_EXIT();
128  }
129 
130  Exit:
131  return error;
132  }
133 
134 
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 ( FT_ERR_NEQ( error, 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 )
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 
262  PSAux_Service psaux )
263  {
264  FT_Stream stream = parser->stream;
265  FT_Memory memory = parser->root.memory;
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 = FT_THROW( 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 = FT_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  /* whitespace + 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 = FT_THROW( 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  /* set limit to `eexec' + whitespace + 4 characters */
368  parser->root.limit = cur + 10;
369 
370  cur = parser->root.cursor;
371  limit = parser->root.limit;
372 
373  while ( cur < limit )
374  {
375  if ( *cur == 'e' && ft_strncmp( (char*)cur, "eexec", 5 ) == 0 )
376  goto Found;
377 
378  T1_Skip_PS_Token( parser );
379  if ( parser->root.error )
380  break;
381  T1_Skip_Spaces ( parser );
382  cur = parser->root.cursor;
383  }
384 
385  /* we haven't found the correct `eexec'; go back and continue */
386  /* searching */
387 
388  cur = limit;
389  limit = parser->base_dict + parser->base_len;
390  goto Again;
391 
392  /* now determine where to write the _encrypted_ binary private */
393  /* dictionary. We overwrite the base dictionary for disk-based */
394  /* resources and allocate a new block otherwise */
395 
396  Found:
397  parser->root.limit = parser->base_dict + parser->base_len;
398 
399  T1_Skip_PS_Token( parser );
400  cur = parser->root.cursor;
401  limit = parser->root.limit;
402 
403  /* according to the Type1 spec, the first cipher byte must not be */
404  /* an ASCII whitespace character code (blank, tab, carriage return */
405  /* or line feed). We have seen Type 1 fonts with two line feed */
406  /* characters... So skip now all whitespace character codes. */
407  while ( cur < limit &&
408  ( *cur == ' ' ||
409  *cur == '\t' ||
410  *cur == '\r' ||
411  *cur == '\n' ) )
412  ++cur;
413  if ( cur >= limit )
414  {
415  FT_ERROR(( "T1_Get_Private_Dict:"
416  " `eexec' not properly terminated\n" ));
417  error = FT_THROW( Invalid_File_Format );
418  goto Exit;
419  }
420 
421  size = parser->base_len - ( cur - parser->base_dict );
422 
423  if ( parser->in_memory )
424  {
425  /* note that we allocate one more byte to put a terminating `0' */
426  if ( FT_ALLOC( parser->private_dict, size + 1 ) )
427  goto Fail;
428  parser->private_len = size;
429  }
430  else
431  {
432  parser->single_block = 1;
433  parser->private_dict = parser->base_dict;
434  parser->private_len = size;
435  parser->base_dict = 0;
436  parser->base_len = 0;
437  }
438 
439  /* now determine whether the private dictionary is encoded in binary */
440  /* or hexadecimal ASCII format -- decode it accordingly */
441 
442  /* we need to access the next 4 bytes (after the final whitespace */
443  /* following the `eexec' keyword); if they all are hexadecimal */
444  /* digits, then we have a case of ASCII storage */
445 
446  if ( cur + 3 < limit &&
447  ft_isxdigit( cur[0] ) && ft_isxdigit( cur[1] ) &&
448  ft_isxdigit( cur[2] ) && ft_isxdigit( cur[3] ) )
449  {
450  /* ASCII hexadecimal encoding */
451  FT_Long len;
452 
453 
454  parser->root.cursor = cur;
455  (void)psaux->ps_parser_funcs->to_bytes( &parser->root,
456  parser->private_dict,
457  parser->private_len,
458  &len,
459  0 );
460  parser->private_len = len;
461 
462  /* put a safeguard */
463  parser->private_dict[len] = '\0';
464  }
465  else
466  /* binary encoding -- copy the private dict */
467  FT_MEM_MOVE( parser->private_dict, cur, size );
468  }
469 
470  /* we now decrypt the encoded binary private dictionary */
471  psaux->t1_decrypt( parser->private_dict, parser->private_len, 55665U );
472 
473  if ( parser->private_len < 4 )
474  {
475  FT_ERROR(( "T1_Get_Private_Dict:"
476  " invalid private dictionary section\n" ));
477  error = FT_THROW( Invalid_File_Format );
478  goto Fail;
479  }
480 
481  /* replace the four random bytes at the beginning with whitespace */
482  parser->private_dict[0] = ' ';
483  parser->private_dict[1] = ' ';
484  parser->private_dict[2] = ' ';
485  parser->private_dict[3] = ' ';
486 
487  parser->root.base = parser->private_dict;
488  parser->root.cursor = parser->private_dict;
489  parser->root.limit = parser->root.cursor + parser->private_len;
490 
491  Fail:
492  Exit:
493  return error;
494  }
495 
496 
497 /* END */
unsigned char * base
Definition: ftsystem.h:323
#define FT_ALLOC(ptr, size)
Definition: ftmemory.h:260
T1_Finalize_Parser(T1_Parser parser)
Definition: t1parse.c:244
int FT_Error
Definition: fttypes.h:296
GLuint GLuint stream
signed long FT_Long
Definition: fttypes.h:238
#define ft_strncmp
Definition: ftstdlib.h:88
unsigned long FT_ULong
Definition: fttypes.h:249
unsigned long size
Definition: ftsystem.h:324
T1_New_Parser(T1_Parser parser, FT_Stream stream, FT_Memory memory, PSAux_Service psaux)
Definition: t1parse.c:136
#define T1_Skip_Spaces(p)
Definition: t1parse.h:94
unsigned char * cursor
Definition: ftsystem.h:333
return FT_THROW(Missing_Property)
#define ft_isxdigit(x)
Definition: ftobjs.h:100
return FT_Err_Ok
Definition: ftbbox.c:645
#define FT_READ_USHORT(var)
Definition: ftstream.h:309
typedef void(APIENTRY *GLDEBUGPROCARB)(GLenum source
FT_Stream_IoFunc read
Definition: ftsystem.h:329
#define FT_ERROR(varformat)
Definition: ftdebug.h:181
unsigned char FT_Byte
Definition: fttypes.h:150
FT_Memory memory
Definition: ftsystem.h:332
#define FT_FREE(ptr)
Definition: ftmemory.h:286
#define FT_STREAM_SKIP(distance)
Definition: ftstream.h:492
GLenum GLsizei len
FT_Error error
Definition: cffdrivr.c:411
#define T1_Skip_PS_Token(p)
Definition: t1parse.h:95
#define FT_TRACE2(varformat)
Definition: ftdebug.h:159
const GLubyte * c
#define FT_READ_ULONG_LE(var)
Definition: ftstream.h:318
#define FT_ERR_NEQ(x, e)
Definition: fttypes.h:589
T1_Get_Private_Dict(T1_Parser parser, PSAux_Service psaux)
Definition: t1parse.c:261
typedefFT_BEGIN_HEADER struct FT_MemoryRec_ * FT_Memory
Definition: ftsystem.h:66
#define FT_FRAME_EXIT()
Definition: ftstream.h:514
#define FT_STREAM_SEEK(position)
Definition: ftstream.h:489
if(!abbox) return FT_THROW(Invalid_Argument)
#define FT_STREAM_POS()
Definition: ftstream.h:486
#define ft_memcmp
Definition: ftstdlib.h:80
#define FT_FRAME_ENTER(size)
Definition: ftstream.h:510
FT_BEGIN_HEADER struct T1_ParserRec_ * T1_Parser
unsigned long pos
Definition: ftsystem.h:325
unsigned short FT_UShort
Definition: fttypes.h:205
#define FT_MEM_MOVE(dest, source, count)
Definition: ftmemory.h:205
#define FT_STREAM_READ(buffer, count)
Definition: ftstream.h:495
GLsizeiptr size
GLint limit
#define FT_LOCAL_DEF(x)
Definition: ftconfig.h:236