sdk-world v2026.11.05
PS2 SDK - world tier (copyleft-allowed, non-essential packages)
Loading...
Searching...
No Matches
cidload.c
1/****************************************************************************
2 *
3 * cidload.c
4 *
5 * CID-keyed Type1 font loader (body).
6 *
7 * Copyright (C) 1996-2025 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 <ft2build.h>
21#include FT_CONFIG_CONFIG_H
22#include <freetype/ftmm.h>
25
26#include "cidload.h"
27
28#include "ciderrs.h"
29
30
31 /**************************************************************************
32 *
33 * The macro FT_COMPONENT is used in trace mode. It is an implicit
34 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
35 * messages during execution.
36 */
37#undef FT_COMPONENT
38#define FT_COMPONENT cidload
39
40
41 /* read a single offset */
42 FT_LOCAL_DEF( FT_ULong )
43 cid_get_offset( FT_Byte* *start,
44 FT_UInt offsize )
45 {
46 FT_ULong result;
47 FT_Byte* p = *start;
48
49
50 for ( result = 0; offsize > 0; offsize-- )
51 {
52 result <<= 8;
53 result |= *p++;
54 }
55
56 *start = p;
57 return result;
58 }
59
60
61 /*************************************************************************/
62 /*************************************************************************/
63 /***** *****/
64 /***** TYPE 1 SYMBOL PARSING *****/
65 /***** *****/
66 /*************************************************************************/
67 /*************************************************************************/
68
69
70 static FT_Error
71 cid_load_keyword( CID_Face face,
72 CID_Loader* loader,
73 const T1_Field keyword )
74 {
75 FT_Error error;
76 CID_Parser* parser = &loader->parser;
77 FT_Byte* object;
78 void* dummy_object;
79 CID_FaceInfo cid = &face->cid;
80
81
82 /* if the keyword has a dedicated callback, call it */
83 if ( keyword->type == T1_FIELD_TYPE_CALLBACK )
84 {
85 FT_TRACE4(( " %s", keyword->ident ));
86
87 keyword->reader( (FT_Face)face, parser );
88 error = parser->root.error;
89 goto Exit;
90 }
91
92 /* we must now compute the address of our target object */
93 switch ( keyword->location )
94 {
95 case T1_FIELD_LOCATION_CID_INFO:
96 object = (FT_Byte*)cid;
97 break;
98
99 case T1_FIELD_LOCATION_FONT_INFO:
100 object = (FT_Byte*)&cid->font_info;
101 break;
102
103 case T1_FIELD_LOCATION_FONT_EXTRA:
104 object = (FT_Byte*)&face->font_extra;
105 break;
106
107 case T1_FIELD_LOCATION_BBOX:
108 object = (FT_Byte*)&cid->font_bbox;
109 break;
110
111 default:
112 {
113 CID_FaceDict dict;
114
115
116 if ( parser->num_dict >= cid->num_dicts )
117 {
118 FT_ERROR(( "cid_load_keyword: invalid use of `%s'\n",
119 keyword->ident ));
120 error = FT_THROW( Syntax_Error );
121 goto Exit;
122 }
123
124 dict = cid->font_dicts + parser->num_dict;
125 switch ( keyword->location )
126 {
127 case T1_FIELD_LOCATION_PRIVATE:
128 object = (FT_Byte*)&dict->private_dict;
129 break;
130
131 default:
132 object = (FT_Byte*)dict;
133 }
134 }
135 }
136
137 FT_TRACE4(( " %s", keyword->ident ));
138
139 dummy_object = object;
140
141 /* now, load the keyword data in the object's field(s) */
142 if ( keyword->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
143 keyword->type == T1_FIELD_TYPE_FIXED_ARRAY )
144 error = cid_parser_load_field_table( &loader->parser, keyword,
145 &dummy_object );
146 else
147 error = cid_parser_load_field( &loader->parser,
148 keyword, &dummy_object );
149
150 FT_TRACE4(( "\n" ));
151
152 Exit:
153 return error;
154 }
155
156
157 FT_CALLBACK_DEF( void )
158 cid_parse_font_matrix( FT_Face face, /* CID_Face */
159 void* parser_ )
160 {
161 CID_Face cidface = (CID_Face)face;
162 CID_Parser* parser = (CID_Parser*)parser_;
163 CID_FaceDict dict;
164 FT_Fixed temp[6];
165 FT_Fixed temp_scale;
166
167
168 if ( parser->num_dict < cidface->cid.num_dicts )
169 {
170 FT_Matrix* matrix;
171 FT_Vector* offset;
172 FT_Int result;
173
174
175 dict = cidface->cid.font_dicts + parser->num_dict;
176 matrix = &dict->font_matrix;
177 offset = &dict->font_offset;
178
179 /* input is scaled by 1000 to accommodate default FontMatrix */
180 result = cid_parser_to_fixed_array( parser, 6, temp, 3 );
181
182 if ( result < 6 )
183 {
184 FT_ERROR(( "cid_parse_font_matrix: not enough matrix elements\n" ));
185 goto Exit;
186 }
187
188 FT_TRACE4(( " [%f %f %f %f %f %f]\n",
189 (double)temp[0] / 65536 / 1000,
190 (double)temp[1] / 65536 / 1000,
191 (double)temp[2] / 65536 / 1000,
192 (double)temp[3] / 65536 / 1000,
193 (double)temp[4] / 65536 / 1000,
194 (double)temp[5] / 65536 / 1000 ));
195
196 temp_scale = FT_ABS( temp[3] );
197
198 if ( temp_scale == 0 )
199 {
200 FT_ERROR(( "cid_parse_font_matrix: invalid font matrix\n" ));
201 goto Exit;
202 }
203
204 /* atypical case */
205 if ( temp_scale != 0x10000L )
206 {
207 /* set units per EM based on FontMatrix values */
208 face->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale );
209
210 temp[0] = FT_DivFix( temp[0], temp_scale );
211 temp[1] = FT_DivFix( temp[1], temp_scale );
212 temp[2] = FT_DivFix( temp[2], temp_scale );
213 temp[4] = FT_DivFix( temp[4], temp_scale );
214 temp[5] = FT_DivFix( temp[5], temp_scale );
215 temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L;
216 }
217
218 matrix->xx = temp[0];
219 matrix->yx = temp[1];
220 matrix->xy = temp[2];
221 matrix->yy = temp[3];
222
223 if ( !FT_Matrix_Check( matrix ) )
224 {
225 FT_ERROR(( "t1_parse_font_matrix: invalid font matrix\n" ));
226 parser->root.error = FT_THROW( Invalid_File_Format );
227 goto Exit;
228 }
229
230 /* note that the font offsets are expressed in integer font units */
231 offset->x = temp[4] >> 16;
232 offset->y = temp[5] >> 16;
233 }
234
235 Exit:
236 return;
237 }
238
239
240 FT_CALLBACK_DEF( void )
241 parse_fd_array( FT_Face face, /* CID_Face */
242 void* parser_ )
243 {
244 CID_Face cidface = (CID_Face)face;
245 CID_Parser* parser = (CID_Parser*)parser_;
246 CID_FaceInfo cid = &cidface->cid;
247 FT_Memory memory = FT_FACE_MEMORY( face );
248 FT_Stream stream = parser->stream;
249 FT_Error error = FT_Err_Ok;
250 FT_Long num_dicts, max_dicts;
251
252
253 num_dicts = cid_parser_to_int( parser );
254 if ( num_dicts < 0 || num_dicts > FT_INT_MAX )
255 {
256 FT_ERROR(( "parse_fd_array: invalid number of dictionaries\n" ));
257 goto Exit;
258 }
259
260 FT_TRACE4(( " %ld\n", num_dicts ));
261
262 /*
263 * A single entry in the FDArray must (at least) contain the following
264 * structure elements.
265 *
266 * %ADOBeginFontDict 18
267 * X dict begin 13
268 * /FontMatrix [X X X X] 22
269 * /Private X dict begin 22
270 * end 4
271 * end 4
272 * %ADOEndFontDict 16
273 *
274 * This needs 18+13+22+22+4+4+16=99 bytes or more. Normally, you also
275 * need a `dup X' at the very beginning and a `put' at the end, so a
276 * rough guess using 100 bytes as the minimum is justified.
277 */
278 max_dicts = (FT_Long)( stream->size / 100 );
279 if ( num_dicts > max_dicts )
280 {
281 FT_TRACE0(( "parse_fd_array: adjusting FDArray size"
282 " (from %ld to %ld)\n",
283 num_dicts, max_dicts ));
284 num_dicts = max_dicts;
285 }
286
287 if ( !cid->font_dicts )
288 {
289 FT_UInt n;
290
291
292 if ( FT_NEW_ARRAY( cid->font_dicts, num_dicts ) )
293 goto Exit;
294
295 cid->num_dicts = num_dicts;
296
297 /* set some default values (the same as for Type 1 fonts) */
298 for ( n = 0; n < cid->num_dicts; n++ )
299 {
300 CID_FaceDict dict = cid->font_dicts + n;
301
302
303 dict->private_dict.blue_shift = 7;
304 dict->private_dict.blue_fuzz = 1;
305 dict->private_dict.lenIV = 4;
306 dict->private_dict.expansion_factor = (FT_Fixed)( 0.06 * 0x10000L );
307 dict->private_dict.blue_scale = (FT_Fixed)(
308 0.039625 * 0x10000L * 1000 );
309 }
310 }
311
312 Exit:
313 return;
314 }
315
316
317 /* By mistake, `expansion_factor' appears both in PS_PrivateRec */
318 /* and CID_FaceDictRec (both are public header files and can't */
319 /* be thus changed). We simply copy the value. */
320
321 FT_CALLBACK_DEF( void )
322 parse_expansion_factor( FT_Face face, /* CID_Face */
323 void* parser_ )
324 {
325 CID_Face cidface = (CID_Face)face;
326 CID_Parser* parser = (CID_Parser*)parser_;
327 CID_FaceDict dict;
328
329
330 if ( parser->num_dict < cidface->cid.num_dicts )
331 {
332 dict = cidface->cid.font_dicts + parser->num_dict;
333
334 dict->expansion_factor = cid_parser_to_fixed( parser, 0 );
335 dict->private_dict.expansion_factor = dict->expansion_factor;
336
337 FT_TRACE4(( "%ld\n", dict->expansion_factor ));
338 }
339
340 return;
341 }
342
343
344 /* By mistake, `CID_FaceDictRec' doesn't contain a field for the */
345 /* `FontName' keyword. FreeType doesn't need it, but it is nice */
346 /* to catch it for producing better trace output. */
347
348 FT_CALLBACK_DEF( void )
349 parse_font_name( FT_Face face, /* CID_Face */
350 void* parser_ )
351 {
352#ifdef FT_DEBUG_LEVEL_TRACE
353 CID_Face cidface = (CID_Face)face;
354 CID_Parser* parser = (CID_Parser*)parser_;
355
356
357 if ( parser->num_dict < cidface->cid.num_dicts )
358 {
359 T1_TokenRec token;
360 FT_UInt len;
361
362
363 cid_parser_to_token( parser, &token );
364
365 len = (FT_UInt)( token.limit - token.start );
366 if ( len )
367 FT_TRACE4(( " %.*s\n", len, token.start ));
368 else
369 FT_TRACE4(( " <no value>\n" ));
370 }
371#else
372 FT_UNUSED( face );
373 FT_UNUSED( parser_ );
374#endif
375
376 return;
377 }
378
379
380 static
381 const T1_FieldRec cid_field_records[] =
382 {
383
384#include "cidtoken.h"
385
386 T1_FIELD_CALLBACK( "FDArray", parse_fd_array, 0 )
387 T1_FIELD_CALLBACK( "FontMatrix", cid_parse_font_matrix, 0 )
388 T1_FIELD_CALLBACK( "ExpansionFactor", parse_expansion_factor, 0 )
389 T1_FIELD_CALLBACK( "FontName", parse_font_name, 0 )
390
391 T1_FIELD_ZERO
392 };
393
394
395 static FT_Error
396 cid_parse_dict( CID_Face face,
397 CID_Loader* loader,
398 FT_Byte* base,
399 FT_ULong size )
400 {
401 CID_Parser* parser = &loader->parser;
402
403
404 parser->root.cursor = base;
405 parser->root.limit = base + size;
406 parser->root.error = FT_Err_Ok;
407
408 {
409 FT_Byte* cur = base;
410 FT_Byte* limit = cur + size;
411
412
413 for (;;)
414 {
415 FT_Byte* newlimit;
416
417
418 parser->root.cursor = cur;
419 cid_parser_skip_spaces( parser );
420
421 if ( parser->root.cursor >= limit )
422 newlimit = limit - 1 - 17;
423 else
424 newlimit = parser->root.cursor - 17;
425
426 /* look for `%ADOBeginFontDict' */
427 for ( ; cur < newlimit; cur++ )
428 {
429 if ( *cur == '%' &&
430 ft_strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 )
431 {
432 /* if /FDArray was found, then cid->num_dicts is > 0, and */
433 /* we can start increasing parser->num_dict */
434 if ( face->cid.num_dicts > 0 )
435 {
436 parser->num_dict++;
437
438#ifdef FT_DEBUG_LEVEL_TRACE
439 FT_TRACE4(( " FontDict %u", parser->num_dict ));
440 if ( parser->num_dict > face->cid.num_dicts )
441 FT_TRACE4(( " (ignored)" ));
442 FT_TRACE4(( "\n" ));
443#endif
444 }
445 }
446 }
447
448 cur = parser->root.cursor;
449 /* no error can occur in cid_parser_skip_spaces */
450 if ( cur >= limit )
451 break;
452
453 cid_parser_skip_PS_token( parser );
454 if ( parser->root.cursor >= limit || parser->root.error )
455 break;
456
457 /* look for immediates */
458 if ( *cur == '/' && cur + 2 < limit )
459 {
460 FT_UInt len;
461
462
463 cur++;
464 len = (FT_UInt)( parser->root.cursor - cur );
465
466 if ( len > 0 && len < 22 )
467 {
468 /* now compare the immediate name to the keyword table */
469 T1_Field keyword = (T1_Field)cid_field_records;
470
471
472 while ( keyword->len )
473 {
474 FT_Byte* name = (FT_Byte*)keyword->ident;
475
476
477 if ( keyword->len == len &&
478 ft_memcmp( cur, name, len ) == 0 )
479 {
480 /* we found it - run the parsing callback */
481 parser->root.error = cid_load_keyword( face,
482 loader,
483 keyword );
484 if ( parser->root.error )
485 return parser->root.error;
486 break;
487 }
488
489 keyword++;
490 }
491 }
492 }
493
494 cur = parser->root.cursor;
495 }
496
497 if ( !face->cid.num_dicts )
498 {
499 FT_ERROR(( "cid_parse_dict: No font dictionary found\n" ));
500 return FT_THROW( Invalid_File_Format );
501 }
502 }
503
504 return parser->root.error;
505 }
506
507
508 /* read the subrmap and the subrs of each font dict */
509 static FT_Error
510 cid_read_subrs( CID_Face face )
511 {
512 CID_FaceInfo cid = &face->cid;
513 FT_Memory memory = face->root.memory;
514 FT_Stream stream = face->cid_stream;
515 FT_Error error;
516 FT_UInt n;
517 CID_Subrs subr;
518 FT_UInt max_offsets = 0;
519 FT_ULong* offsets = NULL;
520 PSAux_Service psaux = (PSAux_Service)face->psaux;
521
522
523 if ( FT_NEW_ARRAY( face->subrs, cid->num_dicts ) )
524 goto Exit;
525
526 subr = face->subrs;
527 for ( n = 0; n < cid->num_dicts; n++, subr++ )
528 {
529 CID_FaceDict dict = cid->font_dicts + n;
530 FT_Int lenIV = dict->private_dict.lenIV;
531 FT_UInt count, num_subrs = dict->num_subrs;
532 FT_ULong data_len;
533 FT_Byte* p;
534
535
536 if ( !num_subrs )
537 continue;
538
539 /* reallocate offsets array if needed */
540 if ( num_subrs + 1 > max_offsets )
541 {
542 FT_UInt new_max = FT_PAD_CEIL( num_subrs + 1, 4 );
543
544
545 if ( new_max <= max_offsets )
546 {
547 error = FT_THROW( Syntax_Error );
548 goto Fail;
549 }
550
551 if ( FT_QRENEW_ARRAY( offsets, max_offsets, new_max ) )
552 goto Fail;
553
554 max_offsets = new_max;
555 }
556
557 /* read the subrmap's offsets */
558 if ( FT_STREAM_SEEK( cid->data_offset + dict->subrmap_offset ) ||
559 FT_FRAME_ENTER( ( num_subrs + 1 ) * dict->sd_bytes ) )
560 goto Fail;
561
562 p = (FT_Byte*)stream->cursor;
563 for ( count = 0; count <= num_subrs; count++ )
564 offsets[count] = cid_get_offset( &p, dict->sd_bytes );
565
566 FT_FRAME_EXIT();
567
568 /* offsets must be ordered */
569 for ( count = 1; count <= num_subrs; count++ )
570 if ( offsets[count - 1] > offsets[count] )
571 {
572 FT_ERROR(( "cid_read_subrs: offsets are not ordered\n" ));
573 error = FT_THROW( Invalid_File_Format );
574 goto Fail;
575 }
576
577 if ( offsets[num_subrs] > stream->size - cid->data_offset )
578 {
579 FT_ERROR(( "cid_read_subrs: too large `subrs' offsets\n" ));
580 error = FT_THROW( Invalid_File_Format );
581 goto Fail;
582 }
583
584 /* now, compute the size of subrs charstrings, */
585 /* allocate, and read them */
586 data_len = offsets[num_subrs] - offsets[0];
587
588 if ( FT_QNEW_ARRAY( subr->code, num_subrs + 1 ) ||
589 FT_QALLOC( subr->code[0], data_len ) )
590 goto Fail;
591
592 if ( FT_STREAM_SEEK( cid->data_offset + offsets[0] ) ||
593 FT_STREAM_READ( subr->code[0], data_len ) )
594 goto Fail;
595
596 /* set up pointers */
597 for ( count = 1; count <= num_subrs; count++ )
598 {
599 FT_ULong len;
600
601
602 len = offsets[count] - offsets[count - 1];
603 subr->code[count] = subr->code[count - 1] + len;
604 }
605
606 /* decrypt subroutines, but only if lenIV >= 0 */
607 if ( lenIV >= 0 )
608 {
609 for ( count = 0; count < num_subrs; count++ )
610 {
611 FT_ULong len;
612
613
614 len = offsets[count + 1] - offsets[count];
615 psaux->t1_decrypt( subr->code[count], len, 4330 );
616 }
617 }
618
619 subr->num_subrs = (FT_Int)num_subrs;
620 }
621
622 Exit:
623 FT_FREE( offsets );
624 return error;
625
626 Fail:
627 if ( face->subrs )
628 {
629 for ( n = 0; n < cid->num_dicts; n++ )
630 {
631 if ( face->subrs[n].code )
632 FT_FREE( face->subrs[n].code[0] );
633
634 FT_FREE( face->subrs[n].code );
635 }
636 FT_FREE( face->subrs );
637 }
638 goto Exit;
639 }
640
641
642 static void
643 cid_init_loader( CID_Loader* loader,
644 CID_Face face )
645 {
646 FT_UNUSED( face );
647
648 FT_ZERO( loader );
649 }
650
651
652 static void
653 cid_done_loader( CID_Loader* loader )
654 {
655 CID_Parser* parser = &loader->parser;
656
657
658 /* finalize parser */
659 cid_parser_done( parser );
660 }
661
662
663 static FT_Error
664 cid_hex_to_binary( FT_Byte* data,
665 FT_ULong data_len,
666 FT_ULong offset,
667 CID_Face face,
668 FT_ULong* data_written )
669 {
670 FT_Stream stream = face->root.stream;
671 FT_Error error;
672
673 FT_Byte buffer[256];
674 FT_Byte *p, *plimit;
675 FT_Byte *d = data, *dlimit;
676 FT_Byte val;
677
678 FT_Bool upper_nibble, done;
679
680
681 if ( FT_STREAM_SEEK( offset ) )
682 goto Exit;
683
684 dlimit = d + data_len;
685 p = buffer;
686 plimit = p;
687
688 upper_nibble = 1;
689 done = 0;
690
691 while ( d < dlimit )
692 {
693 if ( p >= plimit )
694 {
695 FT_ULong oldpos = FT_STREAM_POS();
696 FT_ULong size = stream->size - oldpos;
697
698
699 if ( size == 0 )
700 {
701 error = FT_THROW( Syntax_Error );
702 goto Exit;
703 }
704
705 if ( FT_STREAM_READ( buffer, 256 > size ? size : 256 ) )
706 goto Exit;
707 p = buffer;
708 plimit = p + FT_STREAM_POS() - oldpos;
709 }
710
711 if ( ft_isdigit( *p ) )
712 val = (FT_Byte)( *p - '0' );
713 else if ( *p >= 'a' && *p <= 'f' )
714 val = (FT_Byte)( *p - 'a' + 10 );
715 else if ( *p >= 'A' && *p <= 'F' )
716 val = (FT_Byte)( *p - 'A' + 10 );
717 else if ( *p == ' ' ||
718 *p == '\t' ||
719 *p == '\r' ||
720 *p == '\n' ||
721 *p == '\f' ||
722 *p == '\0' )
723 {
724 p++;
725 continue;
726 }
727 else if ( *p == '>' )
728 {
729 val = 0;
730 done = 1;
731 }
732 else
733 {
734 error = FT_THROW( Syntax_Error );
735 goto Exit;
736 }
737
738 if ( upper_nibble )
739 *d = (FT_Byte)( val << 4 );
740 else
741 {
742 *d = (FT_Byte)( *d + val );
743 d++;
744 }
745
746 upper_nibble = (FT_Byte)( 1 - upper_nibble );
747
748 if ( done )
749 break;
750
751 p++;
752 }
753
754 error = FT_Err_Ok;
755
756 Exit:
757 *data_written = (FT_ULong)( d - data );
758 return error;
759 }
760
761
762 FT_LOCAL_DEF( FT_Error )
763 cid_face_open( CID_Face face,
764 FT_Int face_index )
765 {
766 CID_Loader loader;
767 CID_Parser* parser;
768 FT_Memory memory = face->root.memory;
769 FT_Error error;
770 FT_UInt n;
771
772 CID_FaceInfo cid = &face->cid;
773
774 FT_ULong binary_length;
775
776
777 cid_init_loader( &loader, face );
778
779 parser = &loader.parser;
780 error = cid_parser_new( parser, face->root.stream, face->root.memory,
781 (PSAux_Service)face->psaux );
782 if ( error )
783 goto Exit;
784
785 error = cid_parse_dict( face, &loader,
786 parser->postscript,
787 parser->postscript_len );
788 if ( error )
789 goto Exit;
790
791 if ( face_index < 0 )
792 goto Exit;
793
794 if ( FT_NEW( face->cid_stream ) )
795 goto Exit;
796
797 if ( parser->binary_length )
798 {
799 if ( parser->binary_length >
800 face->root.stream->size - parser->data_offset )
801 {
802 FT_TRACE0(( "cid_face_open: adjusting length of binary data\n" ));
803 FT_TRACE0(( " (from %lu to %lu bytes)\n",
804 parser->binary_length,
805 face->root.stream->size - parser->data_offset ));
806 parser->binary_length = face->root.stream->size -
807 parser->data_offset;
808 }
809
810 /* we must convert the data section from hexadecimal to binary */
811 if ( FT_QALLOC( face->binary_data, parser->binary_length ) ||
812 FT_SET_ERROR( cid_hex_to_binary( face->binary_data,
813 parser->binary_length,
814 parser->data_offset,
815 face,
816 &binary_length ) ) )
817 goto Exit;
818
819 FT_Stream_OpenMemory( face->cid_stream,
820 face->binary_data, binary_length );
821 cid->data_offset = 0;
822 }
823 else
824 {
825 *face->cid_stream = *face->root.stream;
826 cid->data_offset = loader.parser.data_offset;
827 }
828
829 /* sanity tests */
830
831 if ( cid->gd_bytes == 0 )
832 {
833 FT_ERROR(( "cid_face_open:"
834 " Invalid `GDBytes' value\n" ));
835 error = FT_THROW( Invalid_File_Format );
836 goto Exit;
837 }
838
839 /* allow at most 32bit offsets */
840 if ( cid->fd_bytes > 4 || cid->gd_bytes > 4 )
841 {
842 FT_ERROR(( "cid_face_open:"
843 " Values of `FDBytes' or `GDBytes' larger than 4\n" ));
844 FT_ERROR(( " "
845 " are not supported\n" ));
846 error = FT_THROW( Invalid_File_Format );
847 goto Exit;
848 }
849
850 binary_length = face->cid_stream->size - cid->data_offset;
851
852 if ( cid->cidmap_offset > binary_length )
853 {
854 FT_ERROR(( "cid_face_open: Invalid `CIDMapOffset' value\n" ));
855 error = FT_THROW( Invalid_File_Format );
856 goto Exit;
857 }
858
859 /* the initial pre-check prevents the multiplication overflow */
860 if ( cid->cid_count > FT_ULONG_MAX / 8 ||
861 cid->cid_count * ( cid->fd_bytes + cid->gd_bytes ) >
862 binary_length - cid->cidmap_offset )
863 {
864 FT_ERROR(( "cid_face_open: Invalid `CIDCount' value\n" ));
865 error = FT_THROW( Invalid_File_Format );
866 goto Exit;
867 }
868
869
870 for ( n = 0; n < cid->num_dicts; n++ )
871 {
872 CID_FaceDict dict = cid->font_dicts + n;
873
874
875 /* the upper limits are ad-hoc values */
876 if ( dict->private_dict.blue_shift > 1000 ||
877 dict->private_dict.blue_shift < 0 )
878 {
879 FT_TRACE2(( "cid_face_open:"
880 " setting unlikely BlueShift value %d to default (7)\n",
881 dict->private_dict.blue_shift ));
882 dict->private_dict.blue_shift = 7;
883 }
884
885 if ( dict->private_dict.blue_fuzz > 1000 ||
886 dict->private_dict.blue_fuzz < 0 )
887 {
888 FT_TRACE2(( "cid_face_open:"
889 " setting unlikely BlueFuzz value %d to default (1)\n",
890 dict->private_dict.blue_fuzz ));
891 dict->private_dict.blue_fuzz = 1;
892 }
893
894 if ( dict->num_subrs && dict->sd_bytes == 0 )
895 {
896 FT_ERROR(( "cid_face_open: Invalid `SDBytes' value\n" ));
897 error = FT_THROW( Invalid_File_Format );
898 goto Exit;
899 }
900
901 if ( dict->sd_bytes > 4 )
902 {
903 FT_ERROR(( "cid_face_open:"
904 " Values of `SDBytes' larger than 4"
905 " are not supported\n" ));
906 error = FT_THROW( Invalid_File_Format );
907 goto Exit;
908 }
909
910 if ( dict->subrmap_offset > binary_length )
911 {
912 FT_ERROR(( "cid_face_open: Invalid `SubrMapOffset' value\n" ));
913 error = FT_THROW( Invalid_File_Format );
914 goto Exit;
915 }
916
917 /* the initial pre-check prevents the multiplication overflow */
918 if ( dict->num_subrs > FT_UINT_MAX / 4 ||
919 dict->num_subrs * dict->sd_bytes >
920 binary_length - dict->subrmap_offset )
921 {
922 FT_ERROR(( "cid_face_open: Invalid `SubrCount' value\n" ));
923 error = FT_THROW( Invalid_File_Format );
924 goto Exit;
925 }
926 }
927
928 /* we can now safely proceed */
929 error = cid_read_subrs( face );
930
931 Exit:
932 cid_done_loader( &loader );
933 return error;
934 }
935
936
937/* END */