1/****************************************************************************
2 *
3 * cidload.c
4 *
5 * CID-keyed Type1 font loader (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#include <ft2build.h>
20#include <freetype/internal/ftdebug.h>
21#include FT_CONFIG_CONFIG_H
22#include <freetype/ftmm.h>
23#include <freetype/internal/t1types.h>
24#include <freetype/internal/psaux.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 { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 }
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 for (;;)
473 {
474 FT_Byte* name;
475
476
477 name = (FT_Byte*)keyword->ident;
478 if ( !name )
479 break;
480
481 if ( cur[0] == name[0] &&
482 len == ft_strlen( (const char*)name ) )
483 {
484 FT_UInt n;
485
486
487 for ( n = 1; n < len; n++ )
488 if ( cur[n] != name[n] )
489 break;
490
491 if ( n >= len )
492 {
493 /* we found it - run the parsing callback */
494 parser->root.error = cid_load_keyword( face,
495 loader,
496 keyword );
497 if ( parser->root.error )
498 return parser->root.error;
499 break;
500 }
501 }
502 keyword++;
503 }
504 }
505 }
506
507 cur = parser->root.cursor;
508 }
509
510 if ( !face->cid.num_dicts )
511 {
512 FT_ERROR(( "cid_parse_dict: No font dictionary found\n" ));
513 return FT_THROW( Invalid_File_Format );
514 }
515 }
516
517 return parser->root.error;
518 }
519
520
521 /* read the subrmap and the subrs of each font dict */
522 static FT_Error
523 cid_read_subrs( CID_Face face )
524 {
525 CID_FaceInfo cid = &face->cid;
526 FT_Memory memory = face->root.memory;
527 FT_Stream stream = face->cid_stream;
528 FT_Error error;
529 FT_UInt n;
530 CID_Subrs subr;
531 FT_UInt max_offsets = 0;
532 FT_ULong* offsets = NULL;
533 PSAux_Service psaux = (PSAux_Service)face->psaux;
534
535
536 if ( FT_NEW_ARRAY( face->subrs, cid->num_dicts ) )
537 goto Exit;
538
539 subr = face->subrs;
540 for ( n = 0; n < cid->num_dicts; n++, subr++ )
541 {
542 CID_FaceDict dict = cid->font_dicts + n;
543 FT_Int lenIV = dict->private_dict.lenIV;
544 FT_UInt count, num_subrs = dict->num_subrs;
545 FT_ULong data_len;
546 FT_Byte* p;
547
548
549 if ( !num_subrs )
550 continue;
551
552 /* reallocate offsets array if needed */
553 if ( num_subrs + 1 > max_offsets )
554 {
555 FT_UInt new_max = FT_PAD_CEIL( num_subrs + 1, 4 );
556
557
558 if ( new_max <= max_offsets )
559 {
560 error = FT_THROW( Syntax_Error );
561 goto Fail;
562 }
563
564 if ( FT_QRENEW_ARRAY( offsets, max_offsets, new_max ) )
565 goto Fail;
566
567 max_offsets = new_max;
568 }
569
570 /* read the subrmap's offsets */
571 if ( FT_STREAM_SEEK( cid->data_offset + dict->subrmap_offset ) ||
572 FT_FRAME_ENTER( ( num_subrs + 1 ) * dict->sd_bytes ) )
573 goto Fail;
574
575 p = (FT_Byte*)stream->cursor;
576 for ( count = 0; count <= num_subrs; count++ )
577 offsets[count] = cid_get_offset( &p, dict->sd_bytes );
578
579 FT_FRAME_EXIT();
580
581 /* offsets must be ordered */
582 for ( count = 1; count <= num_subrs; count++ )
583 if ( offsets[count - 1] > offsets[count] )
584 {
585 FT_ERROR(( "cid_read_subrs: offsets are not ordered\n" ));
586 error = FT_THROW( Invalid_File_Format );
587 goto Fail;
588 }
589
590 if ( offsets[num_subrs] > stream->size - cid->data_offset )
591 {
592 FT_ERROR(( "cid_read_subrs: too large `subrs' offsets\n" ));
593 error = FT_THROW( Invalid_File_Format );
594 goto Fail;
595 }
596
597 /* now, compute the size of subrs charstrings, */
598 /* allocate, and read them */
599 data_len = offsets[num_subrs] - offsets[0];
600
601 if ( FT_QNEW_ARRAY( subr->code, num_subrs + 1 ) ||
602 FT_QALLOC( subr->code[0], data_len ) )
603 goto Fail;
604
605 if ( FT_STREAM_SEEK( cid->data_offset + offsets[0] ) ||
606 FT_STREAM_READ( subr->code[0], data_len ) )
607 goto Fail;
608
609 /* set up pointers */
610 for ( count = 1; count <= num_subrs; count++ )
611 {
612 FT_ULong len;
613
614
615 len = offsets[count] - offsets[count - 1];
616 subr->code[count] = subr->code[count - 1] + len;
617 }
618
619 /* decrypt subroutines, but only if lenIV >= 0 */
620 if ( lenIV >= 0 )
621 {
622 for ( count = 0; count < num_subrs; count++ )
623 {
624 FT_ULong len;
625
626
627 len = offsets[count + 1] - offsets[count];
628 psaux->t1_decrypt( subr->code[count], len, 4330 );
629 }
630 }
631
632 subr->num_subrs = (FT_Int)num_subrs;
633 }
634
635 Exit:
636 FT_FREE( offsets );
637 return error;
638
639 Fail:
640 if ( face->subrs )
641 {
642 for ( n = 0; n < cid->num_dicts; n++ )
643 {
644 if ( face->subrs[n].code )
645 FT_FREE( face->subrs[n].code[0] );
646
647 FT_FREE( face->subrs[n].code );
648 }
649 FT_FREE( face->subrs );
650 }
651 goto Exit;
652 }
653
654
655 static void
656 cid_init_loader( CID_Loader* loader,
657 CID_Face face )
658 {
659 FT_UNUSED( face );
660
661 FT_ZERO( loader );
662 }
663
664
665 static void
666 cid_done_loader( CID_Loader* loader )
667 {
668 CID_Parser* parser = &loader->parser;
669
670
671 /* finalize parser */
672 cid_parser_done( parser );
673 }
674
675
676 static FT_Error
677 cid_hex_to_binary( FT_Byte* data,
678 FT_ULong data_len,
679 FT_ULong offset,
680 CID_Face face,
681 FT_ULong* data_written )
682 {
683 FT_Stream stream = face->root.stream;
684 FT_Error error;
685
686 FT_Byte buffer[256];
687 FT_Byte *p, *plimit;
688 FT_Byte *d = data, *dlimit;
689 FT_Byte val;
690
691 FT_Bool upper_nibble, done;
692
693
694 if ( FT_STREAM_SEEK( offset ) )
695 goto Exit;
696
697 dlimit = d + data_len;
698 p = buffer;
699 plimit = p;
700
701 upper_nibble = 1;
702 done = 0;
703
704 while ( d < dlimit )
705 {
706 if ( p >= plimit )
707 {
708 FT_ULong oldpos = FT_STREAM_POS();
709 FT_ULong size = stream->size - oldpos;
710
711
712 if ( size == 0 )
713 {
714 error = FT_THROW( Syntax_Error );
715 goto Exit;
716 }
717
718 if ( FT_STREAM_READ( buffer, 256 > size ? size : 256 ) )
719 goto Exit;
720 p = buffer;
721 plimit = p + FT_STREAM_POS() - oldpos;
722 }
723
724 if ( ft_isdigit( *p ) )
725 val = (FT_Byte)( *p - '0' );
726 else if ( *p >= 'a' && *p <= 'f' )
727 val = (FT_Byte)( *p - 'a' + 10 );
728 else if ( *p >= 'A' && *p <= 'F' )
729 val = (FT_Byte)( *p - 'A' + 10 );
730 else if ( *p == ' ' ||
731 *p == '\t' ||
732 *p == '\r' ||
733 *p == '\n' ||
734 *p == '\f' ||
735 *p == '\0' )
736 {
737 p++;
738 continue;
739 }
740 else if ( *p == '>' )
741 {
742 val = 0;
743 done = 1;
744 }
745 else
746 {
747 error = FT_THROW( Syntax_Error );
748 goto Exit;
749 }
750
751 if ( upper_nibble )
752 *d = (FT_Byte)( val << 4 );
753 else
754 {
755 *d = (FT_Byte)( *d + val );
756 d++;
757 }
758
759 upper_nibble = (FT_Byte)( 1 - upper_nibble );
760
761 if ( done )
762 break;
763
764 p++;
765 }
766
767 error = FT_Err_Ok;
768
769 Exit:
770 *data_written = (FT_ULong)( d - data );
771 return error;
772 }
773
774
775 FT_LOCAL_DEF( FT_Error )
776 cid_face_open( CID_Face face,
777 FT_Int face_index )
778 {
779 CID_Loader loader;
780 CID_Parser* parser;
781 FT_Memory memory = face->root.memory;
782 FT_Error error;
783 FT_UInt n;
784
785 CID_FaceInfo cid = &face->cid;
786
787 FT_ULong binary_length;
788
789
790 cid_init_loader( &loader, face );
791
792 parser = &loader.parser;
793 error = cid_parser_new( parser, face->root.stream, face->root.memory,
794 (PSAux_Service)face->psaux );
795 if ( error )
796 goto Exit;
797
798 error = cid_parse_dict( face, &loader,
799 parser->postscript,
800 parser->postscript_len );
801 if ( error )
802 goto Exit;
803
804 if ( face_index < 0 )
805 goto Exit;
806
807 if ( FT_NEW( face->cid_stream ) )
808 goto Exit;
809
810 if ( parser->binary_length )
811 {
812 if ( parser->binary_length >
813 face->root.stream->size - parser->data_offset )
814 {
815 FT_TRACE0(( "cid_face_open: adjusting length of binary data\n" ));
816 FT_TRACE0(( " (from %lu to %lu bytes)\n",
817 parser->binary_length,
818 face->root.stream->size - parser->data_offset ));
819 parser->binary_length = face->root.stream->size -
820 parser->data_offset;
821 }
822
823 /* we must convert the data section from hexadecimal to binary */
824 if ( FT_QALLOC( face->binary_data, parser->binary_length ) ||
825 FT_SET_ERROR( cid_hex_to_binary( face->binary_data,
826 parser->binary_length,
827 parser->data_offset,
828 face,
829 &binary_length ) ) )
830 goto Exit;
831
832 FT_Stream_OpenMemory( face->cid_stream,
833 face->binary_data, binary_length );
834 cid->data_offset = 0;
835 }
836 else
837 {
838 *face->cid_stream = *face->root.stream;
839 cid->data_offset = loader.parser.data_offset;
840 }
841
842 /* sanity tests */
843
844 if ( cid->gd_bytes == 0 )
845 {
846 FT_ERROR(( "cid_face_open:"
847 " Invalid `GDBytes' value\n" ));
848 error = FT_THROW( Invalid_File_Format );
849 goto Exit;
850 }
851
852 /* allow at most 32bit offsets */
853 if ( cid->fd_bytes > 4 || cid->gd_bytes > 4 )
854 {
855 FT_ERROR(( "cid_face_open:"
856 " Values of `FDBytes' or `GDBytes' larger than 4\n" ));
857 FT_ERROR(( " "
858 " are not supported\n" ));
859 error = FT_THROW( Invalid_File_Format );
860 goto Exit;
861 }
862
863 binary_length = face->cid_stream->size - cid->data_offset;
864
865 if ( cid->cidmap_offset > binary_length )
866 {
867 FT_ERROR(( "cid_face_open: Invalid `CIDMapOffset' value\n" ));
868 error = FT_THROW( Invalid_File_Format );
869 goto Exit;
870 }
871
872 /* the initial pre-check prevents the multiplication overflow */
873 if ( cid->cid_count > FT_ULONG_MAX / 8 ||
874 cid->cid_count * ( cid->fd_bytes + cid->gd_bytes ) >
875 binary_length - cid->cidmap_offset )
876 {
877 FT_ERROR(( "cid_face_open: Invalid `CIDCount' value\n" ));
878 error = FT_THROW( Invalid_File_Format );
879 goto Exit;
880 }
881
882
883 for ( n = 0; n < cid->num_dicts; n++ )
884 {
885 CID_FaceDict dict = cid->font_dicts + n;
886
887
888 /* the upper limits are ad-hoc values */
889 if ( dict->private_dict.blue_shift > 1000 ||
890 dict->private_dict.blue_shift < 0 )
891 {
892 FT_TRACE2(( "cid_face_open:"
893 " setting unlikely BlueShift value %d to default (7)\n",
894 dict->private_dict.blue_shift ));
895 dict->private_dict.blue_shift = 7;
896 }
897
898 if ( dict->private_dict.blue_fuzz > 1000 ||
899 dict->private_dict.blue_fuzz < 0 )
900 {
901 FT_TRACE2(( "cid_face_open:"
902 " setting unlikely BlueFuzz value %d to default (1)\n",
903 dict->private_dict.blue_fuzz ));
904 dict->private_dict.blue_fuzz = 1;
905 }
906
907 if ( dict->num_subrs && dict->sd_bytes == 0 )
908 {
909 FT_ERROR(( "cid_face_open: Invalid `SDBytes' value\n" ));
910 error = FT_THROW( Invalid_File_Format );
911 goto Exit;
912 }
913
914 if ( dict->sd_bytes > 4 )
915 {
916 FT_ERROR(( "cid_face_open:"
917 " Values of `SDBytes' larger than 4"
918 " are not supported\n" ));
919 error = FT_THROW( Invalid_File_Format );
920 goto Exit;
921 }
922
923 if ( dict->subrmap_offset > binary_length )
924 {
925 FT_ERROR(( "cid_face_open: Invalid `SubrMapOffset' value\n" ));
926 error = FT_THROW( Invalid_File_Format );
927 goto Exit;
928 }
929
930 /* the initial pre-check prevents the multiplication overflow */
931 if ( dict->num_subrs > FT_UINT_MAX / 4 ||
932 dict->num_subrs * dict->sd_bytes >
933 binary_length - dict->subrmap_offset )
934 {
935 FT_ERROR(( "cid_face_open: Invalid `SubrCount' value\n" ));
936 error = FT_THROW( Invalid_File_Format );
937 goto Exit;
938 }
939 }
940
941 /* we can now safely proceed */
942 error = cid_read_subrs( face );
943
944 Exit:
945 cid_done_loader( &loader );
946 return error;
947 }
948
949
950/* END */
951