xref: /inferno-os/libfreetype/t1parse.c (revision d0e1d143ef6f03c75c008c7ec648859dd260cbab)
1 /***************************************************************************/
2 /*                                                                         */
3 /*  t1parse.c                                                              */
4 /*                                                                         */
5 /*    Type 1 parser (body).                                                */
6 /*                                                                         */
7 /*  Copyright 1996-2001, 2002 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 #define IS_T1_WHITESPACE( c )  ( (c) == ' '  || (c) == '\t' )
69 #define IS_T1_LINESPACE( c )   ( (c) == '\r' || (c) == '\n' )
70 
71 #define IS_T1_SPACE( c )  ( IS_T1_WHITESPACE( c ) || IS_T1_LINESPACE( c ) )
72 
73 
74   typedef struct  PFB_Tag_
75   {
76     FT_UShort  tag;
77     FT_Long    size;
78 
79   } PFB_Tag;
80 
81 
82 #undef  FT_STRUCTURE
83 #define FT_STRUCTURE  PFB_Tag
84 
85 
86   static
87   const FT_Frame_Field  pfb_tag_fields[] =
88   {
89     FT_FRAME_START( 6 ),
90       FT_FRAME_USHORT ( tag ),
91       FT_FRAME_LONG_LE( size ),
92     FT_FRAME_END
93   };
94 
95 
96   static FT_Error
97   read_pfb_tag( FT_Stream   stream,
98                 FT_UShort*  tag,
99                 FT_Long*    size )
100   {
101     FT_Error  error;
102     PFB_Tag   head;
103 
104 
105     *tag  = 0;
106     *size = 0;
107     if ( !FT_STREAM_READ_FIELDS( pfb_tag_fields, &head ) )
108     {
109       if ( head.tag == 0x8001U || head.tag == 0x8002U )
110       {
111         *tag  = head.tag;
112         *size = head.size;
113       }
114     }
115     return error;
116   }
117 
118 
119   FT_LOCAL_DEF( FT_Error )
120   T1_New_Parser( T1_Parser      parser,
121                  FT_Stream      stream,
122                  FT_Memory      memory,
123                  PSAux_Service  psaux )
124   {
125     FT_Error   error;
126     FT_UShort  tag;
127     FT_Long    size;
128 
129 
130     psaux->ps_parser_funcs->init( &parser->root,0, 0, memory );
131 
132     parser->stream       = stream;
133     parser->base_len     = 0;
134     parser->base_dict    = 0;
135     parser->private_len  = 0;
136     parser->private_dict = 0;
137     parser->in_pfb       = 0;
138     parser->in_memory    = 0;
139     parser->single_block = 0;
140 
141     /******************************************************************/
142     /*                                                                */
143     /* Here a short summary of what is going on:                      */
144     /*                                                                */
145     /*   When creating a new Type 1 parser, we try to locate and load */
146     /*   the base dictionary if this is possible (i.e. for PFB        */
147     /*   files).  Otherwise, we load the whole font into memory.      */
148     /*                                                                */
149     /*   When `loading' the base dictionary, we only setup pointers   */
150     /*   in the case of a memory-based stream.  Otherwise, we         */
151     /*   allocate and load the base dictionary in it.                 */
152     /*                                                                */
153     /*   parser->in_pfb is set if we are in a binary (".pfb") font.   */
154     /*   parser->in_memory is set if we have a memory stream.         */
155     /*                                                                */
156 
157     /* try to compute the size of the base dictionary;   */
158     /* look for a Postscript binary file tag, i.e 0x8001 */
159     if ( FT_STREAM_SEEK( 0L ) )
160       goto Exit;
161 
162     error = read_pfb_tag( stream, &tag, &size );
163     if ( error )
164       goto Exit;
165 
166     if ( tag != 0x8001U )
167     {
168       /* assume that this is a PFA file for now; an error will */
169       /* be produced later when more things are checked        */
170       if ( FT_STREAM_SEEK( 0L ) )
171         goto Exit;
172       size = stream->size;
173     }
174     else
175       parser->in_pfb = 1;
176 
177     /* now, try to load `size' bytes of the `base' dictionary we */
178     /* found previously                                          */
179 
180     /* if it is a memory-based resource, set up pointers */
181     if ( !stream->read )
182     {
183       parser->base_dict = (FT_Byte*)stream->base + stream->pos;
184       parser->base_len  = size;
185       parser->in_memory = 1;
186 
187       /* check that the `size' field is valid */
188       if ( FT_STREAM_SKIP( size ) )
189         goto Exit;
190     }
191     else
192     {
193       /* read segment in memory */
194       if ( FT_ALLOC( parser->base_dict, size )     ||
195            FT_STREAM_READ( parser->base_dict, size ) )
196         goto Exit;
197       parser->base_len = size;
198     }
199 
200     /* Now check font format; we must see `%!PS-AdobeFont-1' */
201     /* or `%!FontType'                                       */
202     {
203       if ( size <= 16                                       ||
204            ( ft_strncmp( (const char*)parser->base_dict,
205                          "%!PS-AdobeFont-1", 16 )        &&
206              ft_strncmp( (const char*)parser->base_dict,
207                          "%!FontType", 10 )              )  )
208       {
209         FT_TRACE2(( "[not a Type1 font]\n" ));
210         error = T1_Err_Unknown_File_Format;
211       }
212       else
213       {
214         parser->root.base   = parser->base_dict;
215         parser->root.cursor = parser->base_dict;
216         parser->root.limit  = parser->root.cursor + parser->base_len;
217       }
218     }
219 
220   Exit:
221     if ( error && !parser->in_memory )
222       FT_FREE( parser->base_dict );
223 
224     return error;
225   }
226 
227 
228   FT_LOCAL_DEF( void )
229   T1_Finalize_Parser( T1_Parser  parser )
230   {
231     FT_Memory  memory = parser->root.memory;
232 
233 
234     /* always free the private dictionary */
235     FT_FREE( parser->private_dict );
236 
237     /* free the base dictionary only when we have a disk stream */
238     if ( !parser->in_memory )
239       FT_FREE( parser->base_dict );
240 
241     parser->root.funcs.done( &parser->root );
242   }
243 
244 
245   /* return the value of an hexadecimal digit */
246   static int
247   hexa_value( char  c )
248   {
249     unsigned int  d;
250 
251 
252     d = (unsigned int)( c - '0' );
253     if ( d <= 9 )
254       return (int)d;
255 
256     d = (unsigned int)( c - 'a' );
257     if ( d <= 5 )
258       return (int)( d + 10 );
259 
260     d = (unsigned int)( c - 'A' );
261     if ( d <= 5 )
262       return (int)( d + 10 );
263 
264     return -1;
265   }
266 
267 
268   FT_LOCAL_DEF( FT_Error )
269   T1_Get_Private_Dict( T1_Parser      parser,
270                        PSAux_Service  psaux )
271   {
272     FT_Stream  stream = parser->stream;
273     FT_Memory  memory = parser->root.memory;
274     FT_Error   error  = 0;
275     FT_Long    size;
276 
277 
278     if ( parser->in_pfb )
279     {
280       /* in the case of the PFB format, the private dictionary can be  */
281       /* made of several segments.  We thus first read the number of   */
282       /* segments to compute the total size of the private dictionary  */
283       /* then re-read them into memory.                                */
284       FT_Long    start_pos = FT_STREAM_POS();
285       FT_UShort  tag;
286 
287 
288       parser->private_len = 0;
289       for (;;)
290       {
291         error = read_pfb_tag( stream, &tag, &size );
292         if ( error )
293           goto Fail;
294 
295         if ( tag != 0x8002U )
296           break;
297 
298         parser->private_len += size;
299 
300         if ( FT_STREAM_SKIP( size ) )
301           goto Fail;
302       }
303 
304       /* Check that we have a private dictionary there */
305       /* and allocate private dictionary buffer        */
306       if ( parser->private_len == 0 )
307       {
308         FT_ERROR(( "T1_Get_Private_Dict:" ));
309         FT_ERROR(( " invalid private dictionary section\n" ));
310         error = T1_Err_Invalid_File_Format;
311         goto Fail;
312       }
313 
314       if ( FT_STREAM_SEEK( start_pos )                             ||
315            FT_ALLOC( parser->private_dict, parser->private_len ) )
316         goto Fail;
317 
318       parser->private_len = 0;
319       for (;;)
320       {
321         error = read_pfb_tag( stream, &tag, &size );
322         if ( error || tag != 0x8002U )
323         {
324           error = T1_Err_Ok;
325           break;
326         }
327 
328         if ( FT_STREAM_READ( parser->private_dict + parser->private_len, size ) )
329           goto Fail;
330 
331         parser->private_len += size;
332       }
333     }
334     else
335     {
336       /* we have already `loaded' the whole PFA font file into memory; */
337       /* if this is a memory resource, allocate a new block to hold    */
338       /* the private dict. Otherwise, simply overwrite into the base   */
339       /* dictionary block in the heap.                                 */
340 
341       /* first of all, look at the `eexec' keyword */
342       FT_Byte*  cur   = parser->base_dict;
343       FT_Byte*  limit = cur + parser->base_len;
344       FT_Byte   c;
345 
346 
347       for (;;)
348       {
349         c = cur[0];
350         if ( c == 'e' && cur + 9 < limit )  /* 9 = 5 letters for `eexec' + */
351                                             /* newline + 4 chars           */
352         {
353           if ( cur[1] == 'e' && cur[2] == 'x' &&
354                cur[3] == 'e' && cur[4] == 'c' )
355           {
356             cur += 6; /* we skip the newling after the `eexec' */
357 
358             /* XXX: Some fonts use DOS-linefeeds, i.e. \r\n; we need to */
359             /*      skip the extra \n if we find it                     */
360             if ( cur[0] == '\n' )
361               cur++;
362 
363             break;
364           }
365         }
366         cur++;
367         if ( cur >= limit )
368         {
369           FT_ERROR(( "T1_Get_Private_Dict:" ));
370           FT_ERROR(( " could not find `eexec' keyword\n" ));
371           error = T1_Err_Invalid_File_Format;
372           goto Exit;
373         }
374       }
375 
376       /* now determine where to write the _encrypted_ binary private  */
377       /* dictionary.  We overwrite the base dictionary for disk-based */
378       /* resources and allocate a new block otherwise                 */
379 
380       size = (FT_Long)( parser->base_len - ( cur - parser->base_dict ) );
381 
382       if ( parser->in_memory )
383       {
384         /* note that we allocate one more byte to put a terminating `0' */
385         if ( FT_ALLOC( parser->private_dict, size + 1 ) )
386           goto Fail;
387         parser->private_len = size;
388       }
389       else
390       {
391         parser->single_block = 1;
392         parser->private_dict = parser->base_dict;
393         parser->private_len  = size;
394         parser->base_dict    = 0;
395         parser->base_len     = 0;
396       }
397 
398       /* now determine whether the private dictionary is encoded in binary */
399       /* or hexadecimal ASCII format -- decode it accordingly              */
400 
401       /* we need to access the next 4 bytes (after the final \r following */
402       /* the `eexec' keyword); if they all are hexadecimal digits, then   */
403       /* we have a case of ASCII storage                                  */
404 
405       if ( ( hexa_value( cur[0] ) | hexa_value( cur[1] ) |
406              hexa_value( cur[2] ) | hexa_value( cur[3] ) ) < 0 )
407 
408         /* binary encoding -- `simply' copy the private dict */
409         FT_MEM_COPY( parser->private_dict, cur, size );
410 
411       else
412       {
413         /* ASCII hexadecimal encoding */
414 
415         FT_Byte*  write;
416         FT_Int    count;
417 
418 
419         write = parser->private_dict;
420         count = 0;
421 
422         for ( ;cur < limit; cur++ )
423         {
424           int  hex1;
425 
426 
427           /* check for newline */
428           if ( cur[0] == '\r' || cur[0] == '\n' )
429             continue;
430 
431           /* exit if we have a non-hexadecimal digit that isn't a newline */
432           hex1 = hexa_value( cur[0] );
433           if ( hex1 < 0 || cur + 1 >= limit )
434             break;
435 
436           /* otherwise, store byte */
437           *write++ = (FT_Byte)( ( hex1 << 4 ) | hexa_value( cur[1] ) );
438           count++;
439           cur++;
440         }
441 
442         /* put a safeguard */
443         parser->private_len = write - parser->private_dict;
444         *write++ = 0;
445       }
446     }
447 
448     /* we now decrypt the encoded binary private dictionary */
449     psaux->t1_decrypt( parser->private_dict, parser->private_len, 55665U );
450     parser->root.base   = parser->private_dict;
451     parser->root.cursor = parser->private_dict;
452     parser->root.limit  = parser->root.cursor + parser->private_len;
453 
454   Fail:
455   Exit:
456     return error;
457   }
458 
459 
460 /* END */
461