1 /***************************************************************************/
5 /* CID-keyed Type1 font loader (body). */
7 /* Copyright 1996-2018 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16 /***************************************************************************/
20 #include FT_INTERNAL_DEBUG_H
21 #include FT_CONFIG_CONFIG_H
22 #include FT_MULTIPLE_MASTERS_H
23 #include FT_INTERNAL_TYPE1_TYPES_H
30 /*************************************************************************/
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. */
37 #define FT_COMPONENT trace_cidload
40 /* read a single offset */
41 FT_LOCAL_DEF( FT_ULong
)
42 cid_get_offset( FT_Byte
* *start
,
49 for ( result
= 0; offsize
> 0; offsize
-- )
60 /*************************************************************************/
61 /*************************************************************************/
63 /***** TYPE 1 SYMBOL PARSING *****/
65 /*************************************************************************/
66 /*************************************************************************/
70 cid_load_keyword( CID_Face face
,
72 const T1_Field keyword
)
75 CID_Parser
* parser
= &loader
->parser
;
78 CID_FaceInfo cid
= &face
->cid
;
81 /* if the keyword has a dedicated callback, call it */
82 if ( keyword
->type
== T1_FIELD_TYPE_CALLBACK
)
84 keyword
->reader( (FT_Face
)face
, parser
);
85 error
= parser
->root
.error
;
89 /* we must now compute the address of our target object */
90 switch ( keyword
->location
)
92 case T1_FIELD_LOCATION_CID_INFO
:
93 object
= (FT_Byte
*)cid
;
96 case T1_FIELD_LOCATION_FONT_INFO
:
97 object
= (FT_Byte
*)&cid
->font_info
;
100 case T1_FIELD_LOCATION_FONT_EXTRA
:
101 object
= (FT_Byte
*)&face
->font_extra
;
104 case T1_FIELD_LOCATION_BBOX
:
105 object
= (FT_Byte
*)&cid
->font_bbox
;
113 if ( parser
->num_dict
< 0 || parser
->num_dict
>= cid
->num_dicts
)
115 FT_ERROR(( "cid_load_keyword: invalid use of `%s'\n",
117 error
= FT_THROW( Syntax_Error
);
121 dict
= cid
->font_dicts
+ parser
->num_dict
;
122 switch ( keyword
->location
)
124 case T1_FIELD_LOCATION_PRIVATE
:
125 object
= (FT_Byte
*)&dict
->private_dict
;
129 object
= (FT_Byte
*)dict
;
134 dummy_object
= object
;
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
,
142 error
= cid_parser_load_field( &loader
->parser
,
143 keyword
, &dummy_object
);
149 FT_CALLBACK_DEF( FT_Error
)
150 cid_parse_font_matrix( CID_Face face
,
154 FT_Face root
= (FT_Face
)&face
->root
;
159 if ( parser
->num_dict
>= 0 && parser
->num_dict
< face
->cid
.num_dicts
)
166 dict
= face
->cid
.font_dicts
+ parser
->num_dict
;
167 matrix
= &dict
->font_matrix
;
168 offset
= &dict
->font_offset
;
170 /* input is scaled by 1000 to accommodate default FontMatrix */
171 result
= cid_parser_to_fixed_array( parser
, 6, temp
, 3 );
174 return FT_THROW( Invalid_File_Format
);
176 temp_scale
= FT_ABS( temp
[3] );
178 if ( temp_scale
== 0 )
180 FT_ERROR(( "cid_parse_font_matrix: invalid font matrix\n" ));
181 return FT_THROW( Invalid_File_Format
);
185 if ( temp_scale
!= 0x10000L
)
187 /* set units per EM based on FontMatrix values */
188 root
->units_per_EM
= (FT_UShort
)FT_DivFix( 1000, temp_scale
);
190 temp
[0] = FT_DivFix( temp
[0], temp_scale
);
191 temp
[1] = FT_DivFix( temp
[1], temp_scale
);
192 temp
[2] = FT_DivFix( temp
[2], temp_scale
);
193 temp
[4] = FT_DivFix( temp
[4], temp_scale
);
194 temp
[5] = FT_DivFix( temp
[5], temp_scale
);
195 temp
[3] = temp
[3] < 0 ? -0x10000L
: 0x10000L
;
198 matrix
->xx
= temp
[0];
199 matrix
->yx
= temp
[1];
200 matrix
->xy
= temp
[2];
201 matrix
->yy
= temp
[3];
203 /* note that the font offsets are expressed in integer font units */
204 offset
->x
= temp
[4] >> 16;
205 offset
->y
= temp
[5] >> 16;
212 FT_CALLBACK_DEF( FT_Error
)
213 parse_fd_array( CID_Face face
,
216 CID_FaceInfo cid
= &face
->cid
;
217 FT_Memory memory
= face
->root
.memory
;
218 FT_Stream stream
= parser
->stream
;
219 FT_Error error
= FT_Err_Ok
;
223 num_dicts
= cid_parser_to_int( parser
);
226 FT_ERROR(( "parse_fd_array: invalid number of dictionaries\n" ));
227 error
= FT_THROW( Invalid_File_Format
);
232 * A single entry in the FDArray must (at least) contain the following
233 * structure elements.
235 * %ADOBeginFontDict 18
237 * /FontMatrix [X X X X] 22
238 * /Private X dict begin 22
243 * This needs 18+13+22+22+4+4+16=99 bytes or more. Normally, you also
244 * need a `dup X' at the very beginning and a `put' at the end, so a
245 * rough guess using 100 bytes as the minimum is justified.
247 if ( (FT_ULong
)num_dicts
> stream
->size
/ 100 )
249 FT_TRACE0(( "parse_fd_array: adjusting FDArray size"
250 " (from %d to %d)\n",
252 stream
->size
/ 100 ));
253 num_dicts
= (FT_Long
)( stream
->size
/ 100 );
256 if ( !cid
->font_dicts
)
261 if ( FT_NEW_ARRAY( cid
->font_dicts
, num_dicts
) )
264 cid
->num_dicts
= num_dicts
;
266 /* don't forget to set a few defaults */
267 for ( n
= 0; n
< cid
->num_dicts
; n
++ )
269 CID_FaceDict dict
= cid
->font_dicts
+ n
;
272 /* default value for lenIV */
273 dict
->private_dict
.lenIV
= 4;
282 /* by mistake, `expansion_factor' appears both in PS_PrivateRec */
283 /* and CID_FaceDictRec (both are public header files and can't */
284 /* changed); we simply copy the value */
286 FT_CALLBACK_DEF( FT_Error
)
287 parse_expansion_factor( CID_Face face
,
293 if ( parser
->num_dict
>= 0 && parser
->num_dict
< face
->cid
.num_dicts
)
295 dict
= face
->cid
.font_dicts
+ parser
->num_dict
;
297 dict
->expansion_factor
= cid_parser_to_fixed( parser
, 0 );
298 dict
->private_dict
.expansion_factor
= dict
->expansion_factor
;
306 const T1_FieldRec cid_field_records
[] =
309 #include "cidtoken.h"
311 T1_FIELD_CALLBACK( "FDArray", parse_fd_array
, 0 )
312 T1_FIELD_CALLBACK( "FontMatrix", cid_parse_font_matrix
, 0 )
313 T1_FIELD_CALLBACK( "ExpansionFactor", parse_expansion_factor
, 0 )
315 { 0, T1_FIELD_LOCATION_CID_INFO
, T1_FIELD_TYPE_NONE
, 0, 0, 0, 0, 0, 0 }
320 cid_parse_dict( CID_Face face
,
325 CID_Parser
* parser
= &loader
->parser
;
328 parser
->root
.cursor
= base
;
329 parser
->root
.limit
= base
+ size
;
330 parser
->root
.error
= FT_Err_Ok
;
334 FT_Byte
* limit
= cur
+ size
;
342 parser
->root
.cursor
= cur
;
343 cid_parser_skip_spaces( parser
);
345 if ( parser
->root
.cursor
>= limit
)
346 newlimit
= limit
- 1 - 17;
348 newlimit
= parser
->root
.cursor
- 17;
350 /* look for `%ADOBeginFontDict' */
351 for ( ; cur
< newlimit
; cur
++ )
354 ft_strncmp( (char*)cur
, "%ADOBeginFontDict", 17 ) == 0 )
356 /* if /FDArray was found, then cid->num_dicts is > 0, and */
357 /* we can start increasing parser->num_dict */
358 if ( face
->cid
.num_dicts
> 0 )
363 cur
= parser
->root
.cursor
;
364 /* no error can occur in cid_parser_skip_spaces */
368 cid_parser_skip_PS_token( parser
);
369 if ( parser
->root
.cursor
>= limit
|| parser
->root
.error
)
372 /* look for immediates */
373 if ( *cur
== '/' && cur
+ 2 < limit
)
379 len
= (FT_UInt
)( parser
->root
.cursor
- cur
);
381 if ( len
> 0 && len
< 22 )
383 /* now compare the immediate name to the keyword table */
384 T1_Field keyword
= (T1_Field
)cid_field_records
;
392 name
= (FT_Byte
*)keyword
->ident
;
396 if ( cur
[0] == name
[0] &&
397 len
== ft_strlen( (const char*)name
) )
402 for ( n
= 1; n
< len
; n
++ )
403 if ( cur
[n
] != name
[n
] )
408 /* we found it - run the parsing callback */
409 parser
->root
.error
= cid_load_keyword( face
,
412 if ( parser
->root
.error
)
413 return parser
->root
.error
;
422 cur
= parser
->root
.cursor
;
425 if ( !face
->cid
.num_dicts
)
427 FT_ERROR(( "cid_parse_dict: No font dictionary found\n" ));
428 return FT_THROW( Invalid_File_Format
);
432 return parser
->root
.error
;
436 /* read the subrmap and the subrs of each font dict */
438 cid_read_subrs( CID_Face face
)
440 CID_FaceInfo cid
= &face
->cid
;
441 FT_Memory memory
= face
->root
.memory
;
442 FT_Stream stream
= face
->cid_stream
;
446 FT_UInt max_offsets
= 0;
447 FT_ULong
* offsets
= NULL
;
448 PSAux_Service psaux
= (PSAux_Service
)face
->psaux
;
451 if ( FT_NEW_ARRAY( face
->subrs
, cid
->num_dicts
) )
455 for ( n
= 0; n
< cid
->num_dicts
; n
++, subr
++ )
457 CID_FaceDict dict
= cid
->font_dicts
+ n
;
458 FT_Int lenIV
= dict
->private_dict
.lenIV
;
459 FT_UInt count
, num_subrs
= dict
->num_subrs
;
467 /* reallocate offsets array if needed */
468 if ( num_subrs
+ 1 > max_offsets
)
470 FT_UInt new_max
= FT_PAD_CEIL( num_subrs
+ 1, 4 );
473 if ( new_max
<= max_offsets
)
475 error
= FT_THROW( Syntax_Error
);
479 if ( FT_RENEW_ARRAY( offsets
, max_offsets
, new_max
) )
482 max_offsets
= new_max
;
485 /* read the subrmap's offsets */
486 if ( FT_STREAM_SEEK( cid
->data_offset
+ dict
->subrmap_offset
) ||
487 FT_FRAME_ENTER( ( num_subrs
+ 1 ) * (FT_UInt
)dict
->sd_bytes
) )
490 p
= (FT_Byte
*)stream
->cursor
;
491 for ( count
= 0; count
<= num_subrs
; count
++ )
492 offsets
[count
] = cid_get_offset( &p
, (FT_Byte
)dict
->sd_bytes
);
496 /* offsets must be ordered */
497 for ( count
= 1; count
<= num_subrs
; count
++ )
498 if ( offsets
[count
- 1] > offsets
[count
] )
500 FT_ERROR(( "cid_read_subrs: offsets are not ordered\n" ));
501 error
= FT_THROW( Invalid_File_Format
);
505 if ( offsets
[num_subrs
] > stream
->size
- cid
->data_offset
)
507 FT_ERROR(( "cid_read_subrs: too large `subrs' offsets\n" ));
508 error
= FT_THROW( Invalid_File_Format
);
512 /* now, compute the size of subrs charstrings, */
513 /* allocate, and read them */
514 data_len
= offsets
[num_subrs
] - offsets
[0];
516 if ( FT_NEW_ARRAY( subr
->code
, num_subrs
+ 1 ) ||
517 FT_ALLOC( subr
->code
[0], data_len
) )
520 if ( FT_STREAM_SEEK( cid
->data_offset
+ offsets
[0] ) ||
521 FT_STREAM_READ( subr
->code
[0], data_len
) )
524 /* set up pointers */
525 for ( count
= 1; count
<= num_subrs
; count
++ )
530 len
= offsets
[count
] - offsets
[count
- 1];
531 subr
->code
[count
] = subr
->code
[count
- 1] + len
;
534 /* decrypt subroutines, but only if lenIV >= 0 */
537 for ( count
= 0; count
< num_subrs
; count
++ )
542 len
= offsets
[count
+ 1] - offsets
[count
];
543 psaux
->t1_decrypt( subr
->code
[count
], len
, 4330 );
547 subr
->num_subrs
= (FT_Int
)num_subrs
;
557 for ( n
= 0; n
< cid
->num_dicts
; n
++ )
559 if ( face
->subrs
[n
].code
)
560 FT_FREE( face
->subrs
[n
].code
[0] );
562 FT_FREE( face
->subrs
[n
].code
);
564 FT_FREE( face
->subrs
);
571 cid_init_loader( CID_Loader
* loader
,
581 cid_done_loader( CID_Loader
* loader
)
583 CID_Parser
* parser
= &loader
->parser
;
586 /* finalize parser */
587 cid_parser_done( parser
);
592 cid_hex_to_binary( FT_Byte
* data
,
597 FT_Stream stream
= face
->root
.stream
;
605 FT_Bool upper_nibble
, done
;
608 if ( FT_STREAM_SEEK( offset
) )
612 dlimit
= d
+ data_len
;
623 FT_ULong oldpos
= FT_STREAM_POS();
624 FT_ULong size
= stream
->size
- oldpos
;
629 error
= FT_THROW( Syntax_Error
);
633 if ( FT_STREAM_READ( buffer
, 256 > size
? size
: 256 ) )
636 plimit
= p
+ FT_STREAM_POS() - oldpos
;
639 if ( ft_isdigit( *p
) )
640 val
= (FT_Byte
)( *p
- '0' );
641 else if ( *p
>= 'a' && *p
<= 'f' )
642 val
= (FT_Byte
)( *p
- 'a' );
643 else if ( *p
>= 'A' && *p
<= 'F' )
644 val
= (FT_Byte
)( *p
- 'A' + 10 );
645 else if ( *p
== ' ' ||
655 else if ( *p
== '>' )
662 error
= FT_THROW( Syntax_Error
);
667 *d
= (FT_Byte
)( val
<< 4 );
670 *d
= (FT_Byte
)( *d
+ val
);
674 upper_nibble
= (FT_Byte
)( 1 - upper_nibble
);
689 FT_LOCAL_DEF( FT_Error
)
690 cid_face_open( CID_Face face
,
695 FT_Memory memory
= face
->root
.memory
;
699 CID_FaceInfo cid
= &face
->cid
;
701 FT_ULong binary_length
;
705 cid_init_loader( &loader
, face
);
707 parser
= &loader
.parser
;
708 error
= cid_parser_new( parser
, face
->root
.stream
, face
->root
.memory
,
709 (PSAux_Service
)face
->psaux
);
713 error
= cid_parse_dict( face
, &loader
,
715 parser
->postscript_len
);
719 if ( face_index
< 0 )
722 if ( FT_NEW( face
->cid_stream
) )
725 if ( parser
->binary_length
)
727 if ( parser
->binary_length
>
728 face
->root
.stream
->size
- parser
->data_offset
)
730 FT_TRACE0(( "cid_face_open: adjusting length of binary data\n"
731 " (from %d to %d bytes)\n",
732 parser
->binary_length
,
733 face
->root
.stream
->size
- parser
->data_offset
));
734 parser
->binary_length
= face
->root
.stream
->size
-
738 /* we must convert the data section from hexadecimal to binary */
739 if ( FT_ALLOC( face
->binary_data
, parser
->binary_length
) ||
740 FT_SET_ERROR( cid_hex_to_binary( face
->binary_data
,
741 parser
->binary_length
,
746 FT_Stream_OpenMemory( face
->cid_stream
,
747 face
->binary_data
, parser
->binary_length
);
748 cid
->data_offset
= 0;
752 *face
->cid_stream
= *face
->root
.stream
;
753 cid
->data_offset
= loader
.parser
.data_offset
;
758 if ( cid
->fd_bytes
< 0 || cid
->gd_bytes
< 1 )
760 FT_ERROR(( "cid_parse_dict:"
761 " Invalid `FDBytes' or `GDBytes' value\n" ));
762 error
= FT_THROW( Invalid_File_Format
);
766 /* allow at most 32bit offsets */
767 if ( cid
->fd_bytes
> 4 || cid
->gd_bytes
> 4 )
769 FT_ERROR(( "cid_parse_dict:"
770 " Values of `FDBytes' or `GDBytes' larger than 4\n"
772 " are not supported\n" ));
773 error
= FT_THROW( Invalid_File_Format
);
777 binary_length
= face
->cid_stream
->size
- cid
->data_offset
;
778 entry_len
= (FT_ULong
)( cid
->fd_bytes
+ cid
->gd_bytes
);
780 for ( n
= 0; n
< cid
->num_dicts
; n
++ )
782 CID_FaceDict dict
= cid
->font_dicts
+ n
;
785 if ( dict
->sd_bytes
< 0 ||
786 ( dict
->num_subrs
&& dict
->sd_bytes
< 1 ) )
788 FT_ERROR(( "cid_parse_dict: Invalid `SDBytes' value\n" ));
789 error
= FT_THROW( Invalid_File_Format
);
793 if ( dict
->sd_bytes
> 4 )
795 FT_ERROR(( "cid_parse_dict:"
796 " Values of `SDBytes' larger than 4"
797 " are not supported\n" ));
798 error
= FT_THROW( Invalid_File_Format
);
802 if ( dict
->subrmap_offset
> binary_length
)
804 FT_ERROR(( "cid_parse_dict: Invalid `SubrMapOffset' value\n" ));
805 error
= FT_THROW( Invalid_File_Format
);
809 /* `num_subrs' is scanned as a signed integer */
810 if ( (FT_Int
)dict
->num_subrs
< 0 ||
812 dict
->num_subrs
> ( binary_length
- dict
->subrmap_offset
) /
813 (FT_UInt
)dict
->sd_bytes
) )
815 FT_ERROR(( "cid_parse_dict: Invalid `SubrCount' value\n" ));
816 error
= FT_THROW( Invalid_File_Format
);
821 if ( cid
->cidmap_offset
> binary_length
)
823 FT_ERROR(( "cid_parse_dict: Invalid `CIDMapOffset' value\n" ));
824 error
= FT_THROW( Invalid_File_Format
);
830 ( binary_length
- cid
->cidmap_offset
) / entry_len
)
832 FT_ERROR(( "cid_parse_dict: Invalid `CIDCount' value\n" ));
833 error
= FT_THROW( Invalid_File_Format
);
837 /* we can now safely proceed */
838 error
= cid_read_subrs( face
);
841 cid_done_loader( &loader
);