OLD | NEW |
| (Empty) |
1 /***************************************************************************/ | |
2 /* */ | |
3 /* cidload.c */ | |
4 /* */ | |
5 /* CID-keyed Type1 font loader (body). */ | |
6 /* */ | |
7 /* Copyright 1996-2006, 2009, 2011-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 #include "../../include/ft2build.h" | |
20 #include "../../include/freetype/internal/ftdebug.h" | |
21 #include "../../include/freetype/config/ftconfig.h" | |
22 #include "../../include/freetype/ftmm.h" | |
23 #include "../../include/freetype/internal/t1types.h" | |
24 | |
25 #include "cidload.h" | |
26 | |
27 #include "ciderrs.h" | |
28 | |
29 | |
30 /*************************************************************************/ | |
31 /* */ | |
32 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ | |
33 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ | |
34 /* messages during execution. */ | |
35 /* */ | |
36 #undef FT_COMPONENT | |
37 #define FT_COMPONENT trace_cidload | |
38 | |
39 | |
40 /* read a single offset */ | |
41 FT_LOCAL_DEF( FT_Long ) | |
42 cid_get_offset( FT_Byte* *start, | |
43 FT_Byte offsize ) | |
44 { | |
45 FT_ULong result; | |
46 FT_Byte* p = *start; | |
47 | |
48 | |
49 for ( result = 0; offsize > 0; offsize-- ) | |
50 { | |
51 result <<= 8; | |
52 result |= *p++; | |
53 } | |
54 | |
55 *start = p; | |
56 return (FT_Long)result; | |
57 } | |
58 | |
59 | |
60 /*************************************************************************/ | |
61 /*************************************************************************/ | |
62 /***** *****/ | |
63 /***** TYPE 1 SYMBOL PARSING *****/ | |
64 /***** *****/ | |
65 /*************************************************************************/ | |
66 /*************************************************************************/ | |
67 | |
68 | |
69 static FT_Error | |
70 cid_load_keyword( CID_Face face, | |
71 CID_Loader* loader, | |
72 const T1_Field keyword ) | |
73 { | |
74 FT_Error error; | |
75 CID_Parser* parser = &loader->parser; | |
76 FT_Byte* object; | |
77 void* dummy_object; | |
78 CID_FaceInfo cid = &face->cid; | |
79 | |
80 | |
81 /* if the keyword has a dedicated callback, call it */ | |
82 if ( keyword->type == T1_FIELD_TYPE_CALLBACK ) | |
83 { | |
84 keyword->reader( (FT_Face)face, parser ); | |
85 error = parser->root.error; | |
86 goto Exit; | |
87 } | |
88 | |
89 /* we must now compute the address of our target object */ | |
90 switch ( keyword->location ) | |
91 { | |
92 case T1_FIELD_LOCATION_CID_INFO: | |
93 object = (FT_Byte*)cid; | |
94 break; | |
95 | |
96 case T1_FIELD_LOCATION_FONT_INFO: | |
97 object = (FT_Byte*)&cid->font_info; | |
98 break; | |
99 | |
100 case T1_FIELD_LOCATION_FONT_EXTRA: | |
101 object = (FT_Byte*)&face->font_extra; | |
102 break; | |
103 | |
104 case T1_FIELD_LOCATION_BBOX: | |
105 object = (FT_Byte*)&cid->font_bbox; | |
106 break; | |
107 | |
108 default: | |
109 { | |
110 CID_FaceDict dict; | |
111 | |
112 | |
113 if ( parser->num_dict < 0 || parser->num_dict >= cid->num_dicts ) | |
114 { | |
115 FT_ERROR(( "cid_load_keyword: invalid use of `%s'\n", | |
116 keyword->ident )); | |
117 error = FT_THROW( Syntax_Error ); | |
118 goto Exit; | |
119 } | |
120 | |
121 dict = cid->font_dicts + parser->num_dict; | |
122 switch ( keyword->location ) | |
123 { | |
124 case T1_FIELD_LOCATION_PRIVATE: | |
125 object = (FT_Byte*)&dict->private_dict; | |
126 break; | |
127 | |
128 default: | |
129 object = (FT_Byte*)dict; | |
130 } | |
131 } | |
132 } | |
133 | |
134 dummy_object = object; | |
135 | |
136 /* now, load the keyword data in the object's field(s) */ | |
137 if ( keyword->type == T1_FIELD_TYPE_INTEGER_ARRAY || | |
138 keyword->type == T1_FIELD_TYPE_FIXED_ARRAY ) | |
139 error = cid_parser_load_field_table( &loader->parser, keyword, | |
140 &dummy_object ); | |
141 else | |
142 error = cid_parser_load_field( &loader->parser, | |
143 keyword, &dummy_object ); | |
144 Exit: | |
145 return error; | |
146 } | |
147 | |
148 | |
149 FT_CALLBACK_DEF( FT_Error ) | |
150 cid_parse_font_matrix( CID_Face face, | |
151 CID_Parser* parser ) | |
152 { | |
153 FT_Matrix* matrix; | |
154 FT_Vector* offset; | |
155 CID_FaceDict dict; | |
156 FT_Face root = (FT_Face)&face->root; | |
157 FT_Fixed temp[6]; | |
158 FT_Fixed temp_scale; | |
159 | |
160 | |
161 if ( parser->num_dict >= 0 && parser->num_dict < face->cid.num_dicts ) | |
162 { | |
163 dict = face->cid.font_dicts + parser->num_dict; | |
164 matrix = &dict->font_matrix; | |
165 offset = &dict->font_offset; | |
166 | |
167 (void)cid_parser_to_fixed_array( parser, 6, temp, 3 ); | |
168 | |
169 temp_scale = FT_ABS( temp[3] ); | |
170 | |
171 /* Set Units per EM based on FontMatrix values. We set the value to */ | |
172 /* 1000 / temp_scale, because temp_scale was already multiplied by */ | |
173 /* 1000 (in t1_tofixed, from psobjs.c). */ | |
174 | |
175 root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale ); | |
176 | |
177 /* we need to scale the values by 1.0/temp[3] */ | |
178 if ( temp_scale != 0x10000L ) | |
179 { | |
180 temp[0] = FT_DivFix( temp[0], temp_scale ); | |
181 temp[1] = FT_DivFix( temp[1], temp_scale ); | |
182 temp[2] = FT_DivFix( temp[2], temp_scale ); | |
183 temp[4] = FT_DivFix( temp[4], temp_scale ); | |
184 temp[5] = FT_DivFix( temp[5], temp_scale ); | |
185 temp[3] = 0x10000L; | |
186 } | |
187 | |
188 matrix->xx = temp[0]; | |
189 matrix->yx = temp[1]; | |
190 matrix->xy = temp[2]; | |
191 matrix->yy = temp[3]; | |
192 | |
193 /* note that the font offsets are expressed in integer font units */ | |
194 offset->x = temp[4] >> 16; | |
195 offset->y = temp[5] >> 16; | |
196 } | |
197 | |
198 return FT_Err_Ok; /* this is a callback function; */ | |
199 /* we must return an error code */ | |
200 } | |
201 | |
202 | |
203 FT_CALLBACK_DEF( FT_Error ) | |
204 parse_fd_array( CID_Face face, | |
205 CID_Parser* parser ) | |
206 { | |
207 CID_FaceInfo cid = &face->cid; | |
208 FT_Memory memory = face->root.memory; | |
209 FT_Error error = FT_Err_Ok; | |
210 FT_Long num_dicts; | |
211 | |
212 | |
213 num_dicts = cid_parser_to_int( parser ); | |
214 | |
215 if ( !cid->font_dicts ) | |
216 { | |
217 FT_Int n; | |
218 | |
219 | |
220 if ( FT_NEW_ARRAY( cid->font_dicts, num_dicts ) ) | |
221 goto Exit; | |
222 | |
223 cid->num_dicts = (FT_UInt)num_dicts; | |
224 | |
225 /* don't forget to set a few defaults */ | |
226 for ( n = 0; n < cid->num_dicts; n++ ) | |
227 { | |
228 CID_FaceDict dict = cid->font_dicts + n; | |
229 | |
230 | |
231 /* default value for lenIV */ | |
232 dict->private_dict.lenIV = 4; | |
233 } | |
234 } | |
235 | |
236 Exit: | |
237 return error; | |
238 } | |
239 | |
240 | |
241 /* by mistake, `expansion_factor' appears both in PS_PrivateRec */ | |
242 /* and CID_FaceDictRec (both are public header files and can't */ | |
243 /* changed); we simply copy the value */ | |
244 | |
245 FT_CALLBACK_DEF( FT_Error ) | |
246 parse_expansion_factor( CID_Face face, | |
247 CID_Parser* parser ) | |
248 { | |
249 CID_FaceDict dict; | |
250 | |
251 | |
252 if ( parser->num_dict >= 0 && parser->num_dict < face->cid.num_dicts ) | |
253 { | |
254 dict = face->cid.font_dicts + parser->num_dict; | |
255 | |
256 dict->expansion_factor = cid_parser_to_fixed( parser, 0 ); | |
257 dict->private_dict.expansion_factor = dict->expansion_factor; | |
258 } | |
259 | |
260 return FT_Err_Ok; | |
261 } | |
262 | |
263 | |
264 static | |
265 const T1_FieldRec cid_field_records[] = | |
266 { | |
267 | |
268 #include "cidtoken.h" | |
269 | |
270 T1_FIELD_CALLBACK( "FDArray", parse_fd_array, 0 ) | |
271 T1_FIELD_CALLBACK( "FontMatrix", cid_parse_font_matrix, 0 ) | |
272 T1_FIELD_CALLBACK( "ExpansionFactor", parse_expansion_factor, 0 ) | |
273 | |
274 { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 } | |
275 }; | |
276 | |
277 | |
278 static FT_Error | |
279 cid_parse_dict( CID_Face face, | |
280 CID_Loader* loader, | |
281 FT_Byte* base, | |
282 FT_Long size ) | |
283 { | |
284 CID_Parser* parser = &loader->parser; | |
285 | |
286 | |
287 parser->root.cursor = base; | |
288 parser->root.limit = base + size; | |
289 parser->root.error = FT_Err_Ok; | |
290 | |
291 { | |
292 FT_Byte* cur = base; | |
293 FT_Byte* limit = cur + size; | |
294 | |
295 | |
296 for (;;) | |
297 { | |
298 FT_Byte* newlimit; | |
299 | |
300 | |
301 parser->root.cursor = cur; | |
302 cid_parser_skip_spaces( parser ); | |
303 | |
304 if ( parser->root.cursor >= limit ) | |
305 newlimit = limit - 1 - 17; | |
306 else | |
307 newlimit = parser->root.cursor - 17; | |
308 | |
309 /* look for `%ADOBeginFontDict' */ | |
310 for ( ; cur < newlimit; cur++ ) | |
311 { | |
312 if ( *cur == '%' && | |
313 ft_strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 ) | |
314 { | |
315 /* if /FDArray was found, then cid->num_dicts is > 0, and */ | |
316 /* we can start increasing parser->num_dict */ | |
317 if ( face->cid.num_dicts > 0 ) | |
318 parser->num_dict++; | |
319 } | |
320 } | |
321 | |
322 cur = parser->root.cursor; | |
323 /* no error can occur in cid_parser_skip_spaces */ | |
324 if ( cur >= limit ) | |
325 break; | |
326 | |
327 cid_parser_skip_PS_token( parser ); | |
328 if ( parser->root.cursor >= limit || parser->root.error ) | |
329 break; | |
330 | |
331 /* look for immediates */ | |
332 if ( *cur == '/' && cur + 2 < limit ) | |
333 { | |
334 FT_PtrDist len; | |
335 | |
336 | |
337 cur++; | |
338 len = parser->root.cursor - cur; | |
339 | |
340 if ( len > 0 && len < 22 ) | |
341 { | |
342 /* now compare the immediate name to the keyword table */ | |
343 T1_Field keyword = (T1_Field)cid_field_records; | |
344 | |
345 | |
346 for (;;) | |
347 { | |
348 FT_Byte* name; | |
349 | |
350 | |
351 name = (FT_Byte*)keyword->ident; | |
352 if ( !name ) | |
353 break; | |
354 | |
355 if ( cur[0] == name[0] && | |
356 len == (FT_PtrDist)ft_strlen( (const char*)name ) ) | |
357 { | |
358 FT_PtrDist n; | |
359 | |
360 | |
361 for ( n = 1; n < len; n++ ) | |
362 if ( cur[n] != name[n] ) | |
363 break; | |
364 | |
365 if ( n >= len ) | |
366 { | |
367 /* we found it - run the parsing callback */ | |
368 parser->root.error = cid_load_keyword( face, | |
369 loader, | |
370 keyword ); | |
371 if ( parser->root.error ) | |
372 return parser->root.error; | |
373 break; | |
374 } | |
375 } | |
376 keyword++; | |
377 } | |
378 } | |
379 } | |
380 | |
381 cur = parser->root.cursor; | |
382 } | |
383 } | |
384 return parser->root.error; | |
385 } | |
386 | |
387 | |
388 /* read the subrmap and the subrs of each font dict */ | |
389 static FT_Error | |
390 cid_read_subrs( CID_Face face ) | |
391 { | |
392 CID_FaceInfo cid = &face->cid; | |
393 FT_Memory memory = face->root.memory; | |
394 FT_Stream stream = face->cid_stream; | |
395 FT_Error error; | |
396 FT_Int n; | |
397 CID_Subrs subr; | |
398 FT_UInt max_offsets = 0; | |
399 FT_ULong* offsets = 0; | |
400 PSAux_Service psaux = (PSAux_Service)face->psaux; | |
401 | |
402 | |
403 if ( FT_NEW_ARRAY( face->subrs, cid->num_dicts ) ) | |
404 goto Exit; | |
405 | |
406 subr = face->subrs; | |
407 for ( n = 0; n < cid->num_dicts; n++, subr++ ) | |
408 { | |
409 CID_FaceDict dict = cid->font_dicts + n; | |
410 FT_Int lenIV = dict->private_dict.lenIV; | |
411 FT_UInt count, num_subrs = dict->num_subrs; | |
412 FT_ULong data_len; | |
413 FT_Byte* p; | |
414 | |
415 | |
416 /* Check for possible overflow. */ | |
417 if ( num_subrs == FT_UINT_MAX ) | |
418 { | |
419 error = FT_THROW( Syntax_Error ); | |
420 goto Fail; | |
421 } | |
422 | |
423 /* reallocate offsets array if needed */ | |
424 if ( num_subrs + 1 > max_offsets ) | |
425 { | |
426 FT_UInt new_max = FT_PAD_CEIL( num_subrs + 1, 4 ); | |
427 | |
428 | |
429 if ( new_max <= max_offsets ) | |
430 { | |
431 error = FT_THROW( Syntax_Error ); | |
432 goto Fail; | |
433 } | |
434 | |
435 if ( FT_RENEW_ARRAY( offsets, max_offsets, new_max ) ) | |
436 goto Fail; | |
437 | |
438 max_offsets = new_max; | |
439 } | |
440 | |
441 /* read the subrmap's offsets */ | |
442 if ( FT_STREAM_SEEK( cid->data_offset + dict->subrmap_offset ) || | |
443 FT_FRAME_ENTER( ( num_subrs + 1 ) * dict->sd_bytes ) ) | |
444 goto Fail; | |
445 | |
446 p = (FT_Byte*)stream->cursor; | |
447 for ( count = 0; count <= num_subrs; count++ ) | |
448 offsets[count] = cid_get_offset( &p, (FT_Byte)dict->sd_bytes ); | |
449 | |
450 FT_FRAME_EXIT(); | |
451 | |
452 /* offsets must be ordered */ | |
453 for ( count = 1; count <= num_subrs; count++ ) | |
454 if ( offsets[count - 1] > offsets[count] ) | |
455 goto Fail; | |
456 | |
457 /* now, compute the size of subrs charstrings, */ | |
458 /* allocate, and read them */ | |
459 data_len = offsets[num_subrs] - offsets[0]; | |
460 | |
461 if ( FT_NEW_ARRAY( subr->code, num_subrs + 1 ) || | |
462 FT_ALLOC( subr->code[0], data_len ) ) | |
463 goto Fail; | |
464 | |
465 if ( FT_STREAM_SEEK( cid->data_offset + offsets[0] ) || | |
466 FT_STREAM_READ( subr->code[0], data_len ) ) | |
467 goto Fail; | |
468 | |
469 /* set up pointers */ | |
470 for ( count = 1; count <= num_subrs; count++ ) | |
471 { | |
472 FT_ULong len; | |
473 | |
474 | |
475 len = offsets[count] - offsets[count - 1]; | |
476 subr->code[count] = subr->code[count - 1] + len; | |
477 } | |
478 | |
479 /* decrypt subroutines, but only if lenIV >= 0 */ | |
480 if ( lenIV >= 0 ) | |
481 { | |
482 for ( count = 0; count < num_subrs; count++ ) | |
483 { | |
484 FT_ULong len; | |
485 | |
486 | |
487 len = offsets[count + 1] - offsets[count]; | |
488 psaux->t1_decrypt( subr->code[count], len, 4330 ); | |
489 } | |
490 } | |
491 | |
492 subr->num_subrs = num_subrs; | |
493 } | |
494 | |
495 Exit: | |
496 FT_FREE( offsets ); | |
497 return error; | |
498 | |
499 Fail: | |
500 if ( face->subrs ) | |
501 { | |
502 for ( n = 0; n < cid->num_dicts; n++ ) | |
503 { | |
504 if ( face->subrs[n].code ) | |
505 FT_FREE( face->subrs[n].code[0] ); | |
506 | |
507 FT_FREE( face->subrs[n].code ); | |
508 } | |
509 FT_FREE( face->subrs ); | |
510 } | |
511 goto Exit; | |
512 } | |
513 | |
514 | |
515 static void | |
516 cid_init_loader( CID_Loader* loader, | |
517 CID_Face face ) | |
518 { | |
519 FT_UNUSED( face ); | |
520 | |
521 FT_MEM_ZERO( loader, sizeof ( *loader ) ); | |
522 } | |
523 | |
524 | |
525 static void | |
526 cid_done_loader( CID_Loader* loader ) | |
527 { | |
528 CID_Parser* parser = &loader->parser; | |
529 | |
530 | |
531 /* finalize parser */ | |
532 cid_parser_done( parser ); | |
533 } | |
534 | |
535 | |
536 static FT_Error | |
537 cid_hex_to_binary( FT_Byte* data, | |
538 FT_Long data_len, | |
539 FT_ULong offset, | |
540 CID_Face face ) | |
541 { | |
542 FT_Stream stream = face->root.stream; | |
543 FT_Error error; | |
544 | |
545 FT_Byte buffer[256]; | |
546 FT_Byte *p, *plimit; | |
547 FT_Byte *d, *dlimit; | |
548 FT_Byte val; | |
549 | |
550 FT_Bool upper_nibble, done; | |
551 | |
552 | |
553 if ( FT_STREAM_SEEK( offset ) ) | |
554 goto Exit; | |
555 | |
556 d = data; | |
557 dlimit = d + data_len; | |
558 p = buffer; | |
559 plimit = p; | |
560 | |
561 upper_nibble = 1; | |
562 done = 0; | |
563 | |
564 while ( d < dlimit ) | |
565 { | |
566 if ( p >= plimit ) | |
567 { | |
568 FT_ULong oldpos = FT_STREAM_POS(); | |
569 FT_ULong size = stream->size - oldpos; | |
570 | |
571 | |
572 if ( size == 0 ) | |
573 { | |
574 error = FT_THROW( Syntax_Error ); | |
575 goto Exit; | |
576 } | |
577 | |
578 if ( FT_STREAM_READ( buffer, 256 > size ? size : 256 ) ) | |
579 goto Exit; | |
580 p = buffer; | |
581 plimit = p + FT_STREAM_POS() - oldpos; | |
582 } | |
583 | |
584 if ( ft_isdigit( *p ) ) | |
585 val = (FT_Byte)( *p - '0' ); | |
586 else if ( *p >= 'a' && *p <= 'f' ) | |
587 val = (FT_Byte)( *p - 'a' ); | |
588 else if ( *p >= 'A' && *p <= 'F' ) | |
589 val = (FT_Byte)( *p - 'A' + 10 ); | |
590 else if ( *p == ' ' || | |
591 *p == '\t' || | |
592 *p == '\r' || | |
593 *p == '\n' || | |
594 *p == '\f' || | |
595 *p == '\0' ) | |
596 { | |
597 p++; | |
598 continue; | |
599 } | |
600 else if ( *p == '>' ) | |
601 { | |
602 val = 0; | |
603 done = 1; | |
604 } | |
605 else | |
606 { | |
607 error = FT_THROW( Syntax_Error ); | |
608 goto Exit; | |
609 } | |
610 | |
611 if ( upper_nibble ) | |
612 *d = (FT_Byte)( val << 4 ); | |
613 else | |
614 { | |
615 *d = (FT_Byte)( *d + val ); | |
616 d++; | |
617 } | |
618 | |
619 upper_nibble = (FT_Byte)( 1 - upper_nibble ); | |
620 | |
621 if ( done ) | |
622 break; | |
623 | |
624 p++; | |
625 } | |
626 | |
627 error = FT_Err_Ok; | |
628 | |
629 Exit: | |
630 return error; | |
631 } | |
632 | |
633 | |
634 FT_LOCAL_DEF( FT_Error ) | |
635 cid_face_open( CID_Face face, | |
636 FT_Int face_index ) | |
637 { | |
638 CID_Loader loader; | |
639 CID_Parser* parser; | |
640 FT_Memory memory = face->root.memory; | |
641 FT_Error error; | |
642 | |
643 | |
644 cid_init_loader( &loader, face ); | |
645 | |
646 parser = &loader.parser; | |
647 error = cid_parser_new( parser, face->root.stream, face->root.memory, | |
648 (PSAux_Service)face->psaux ); | |
649 if ( error ) | |
650 goto Exit; | |
651 | |
652 error = cid_parse_dict( face, &loader, | |
653 parser->postscript, | |
654 parser->postscript_len ); | |
655 if ( error ) | |
656 goto Exit; | |
657 | |
658 if ( face_index < 0 ) | |
659 goto Exit; | |
660 | |
661 if ( FT_NEW( face->cid_stream ) ) | |
662 goto Exit; | |
663 | |
664 if ( parser->binary_length ) | |
665 { | |
666 /* we must convert the data section from hexadecimal to binary */ | |
667 if ( FT_ALLOC( face->binary_data, parser->binary_length ) || | |
668 cid_hex_to_binary( face->binary_data, parser->binary_length, | |
669 parser->data_offset, face ) ) | |
670 goto Exit; | |
671 | |
672 FT_Stream_OpenMemory( face->cid_stream, | |
673 face->binary_data, parser->binary_length ); | |
674 face->cid.data_offset = 0; | |
675 } | |
676 else | |
677 { | |
678 *face->cid_stream = *face->root.stream; | |
679 face->cid.data_offset = loader.parser.data_offset; | |
680 } | |
681 | |
682 error = cid_read_subrs( face ); | |
683 | |
684 Exit: | |
685 cid_done_loader( &loader ); | |
686 return error; | |
687 } | |
688 | |
689 | |
690 /* END */ | |
OLD | NEW |