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