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 */ |
|