1 /***************************************************************************/ 2 /* */ 3 /* cidload.c */ 4 /* */ 5 /* CID-keyed Type1 font loader (body). */ 6 /* */ 7 /* Copyright 1996-2001, 2002 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 FT_INTERNAL_DEBUG_H 21 #include FT_CONFIG_CONFIG_H 22 #include FT_MULTIPLE_MASTERS_H 23 #include FT_INTERNAL_TYPE1_TYPES_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 ) cid_get_offset(FT_Byte ** start,FT_Byte offsize)42 cid_get_offset( FT_Byte** start, 43 FT_Byte offsize ) 44 { 45 FT_Long 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 result; 57 } 58 59 60 FT_LOCAL_DEF( void ) cid_decrypt(FT_Byte * buffer,FT_Offset length,FT_UShort seed)61 cid_decrypt( FT_Byte* buffer, 62 FT_Offset length, 63 FT_UShort seed ) 64 { 65 while ( length > 0 ) 66 { 67 FT_Byte plain; 68 69 70 plain = (FT_Byte)( *buffer ^ ( seed >> 8 ) ); 71 seed = (FT_UShort)( ( *buffer + seed ) * 52845U + 22719 ); 72 *buffer++ = plain; 73 length--; 74 } 75 } 76 77 78 /*************************************************************************/ 79 /*************************************************************************/ 80 /***** *****/ 81 /***** TYPE 1 SYMBOL PARSING *****/ 82 /***** *****/ 83 /*************************************************************************/ 84 /*************************************************************************/ 85 86 87 static FT_Error cid_load_keyword(CID_Face face,CID_Loader * loader,const T1_Field keyword)88 cid_load_keyword( CID_Face face, 89 CID_Loader* loader, 90 const T1_Field keyword ) 91 { 92 FT_Error error; 93 CID_Parser* parser = &loader->parser; 94 FT_Byte* object; 95 void* dummy_object; 96 CID_FaceInfo cid = &face->cid; 97 98 99 /* if the keyword has a dedicated callback, call it */ 100 if ( keyword->type == T1_FIELD_TYPE_CALLBACK ) 101 { 102 keyword->reader( (FT_Face)face, parser ); 103 error = parser->root.error; 104 goto Exit; 105 } 106 107 /* we must now compute the address of our target object */ 108 switch ( keyword->location ) 109 { 110 case T1_FIELD_LOCATION_CID_INFO: 111 object = (FT_Byte*)cid; 112 break; 113 114 case T1_FIELD_LOCATION_FONT_INFO: 115 object = (FT_Byte*)&cid->font_info; 116 break; 117 118 default: 119 { 120 CID_FaceDict dict; 121 122 123 if ( parser->num_dict < 0 ) 124 { 125 FT_ERROR(( "cid_load_keyword: invalid use of `%s'!\n", 126 keyword->ident )); 127 error = CID_Err_Syntax_Error; 128 goto Exit; 129 } 130 131 dict = cid->font_dicts + parser->num_dict; 132 switch ( keyword->location ) 133 { 134 case T1_FIELD_LOCATION_PRIVATE: 135 object = (FT_Byte*)&dict->private_dict; 136 break; 137 138 default: 139 object = (FT_Byte*)dict; 140 } 141 } 142 } 143 144 dummy_object = object; 145 146 /* now, load the keyword data in the object's field(s) */ 147 if ( keyword->type == T1_FIELD_TYPE_INTEGER_ARRAY || 148 keyword->type == T1_FIELD_TYPE_FIXED_ARRAY ) 149 error = cid_parser_load_field_table( &loader->parser, keyword, 150 &dummy_object ); 151 else 152 error = cid_parser_load_field( &loader->parser, keyword, &dummy_object ); 153 Exit: 154 return error; 155 } 156 157 158 FT_CALLBACK_DEF( FT_Error ) parse_font_bbox(CID_Face face,CID_Parser * parser)159 parse_font_bbox( CID_Face face, 160 CID_Parser* parser ) 161 { 162 FT_Fixed temp[4]; 163 FT_BBox* bbox = &face->cid.font_bbox; 164 165 166 (void)cid_parser_to_fixed_array( parser, 4, temp, 0 ); 167 bbox->xMin = FT_RoundFix( temp[0] ); 168 bbox->yMin = FT_RoundFix( temp[1] ); 169 bbox->xMax = FT_RoundFix( temp[2] ); 170 bbox->yMax = FT_RoundFix( temp[3] ); 171 172 return CID_Err_Ok; /* this is a callback function; */ 173 /* we must return an error code */ 174 } 175 176 177 FT_CALLBACK_DEF( FT_Error ) parse_font_matrix(CID_Face face,CID_Parser * parser)178 parse_font_matrix( CID_Face face, 179 CID_Parser* parser ) 180 { 181 FT_Matrix* matrix; 182 FT_Vector* offset; 183 CID_FaceDict dict; 184 FT_Face root = (FT_Face)&face->root; 185 FT_Fixed temp[6]; 186 FT_Fixed temp_scale; 187 188 189 if ( parser->num_dict >= 0 ) 190 { 191 dict = face->cid.font_dicts + parser->num_dict; 192 matrix = &dict->font_matrix; 193 offset = &dict->font_offset; 194 195 (void)cid_parser_to_fixed_array( parser, 6, temp, 3 ); 196 197 temp_scale = ABS( temp[3] ); 198 199 /* Set Units per EM based on FontMatrix values. We set the value to */ 200 /* `1000/temp_scale', because temp_scale was already multiplied by */ 201 /* 1000 (in t1_tofixed(), from psobjs.c). */ 202 root->units_per_EM = (FT_UShort)( FT_DivFix( 0x10000L, 203 FT_DivFix( temp_scale, 1000 ) ) ); 204 205 /* we need to scale the values by 1.0/temp[3] */ 206 if ( temp_scale != 0x10000L ) 207 { 208 temp[0] = FT_DivFix( temp[0], temp_scale ); 209 temp[1] = FT_DivFix( temp[1], temp_scale ); 210 temp[2] = FT_DivFix( temp[2], temp_scale ); 211 temp[4] = FT_DivFix( temp[4], temp_scale ); 212 temp[5] = FT_DivFix( temp[5], temp_scale ); 213 temp[3] = 0x10000L; 214 } 215 216 matrix->xx = temp[0]; 217 matrix->yx = temp[1]; 218 matrix->xy = temp[2]; 219 matrix->yy = temp[3]; 220 221 /* note that the font offsets are expressed in integer font units */ 222 offset->x = temp[4] >> 16; 223 offset->y = temp[5] >> 16; 224 } 225 226 return CID_Err_Ok; /* this is a callback function; */ 227 /* we must return an error code */ 228 } 229 230 231 FT_CALLBACK_DEF( FT_Error ) parse_fd_array(CID_Face face,CID_Parser * parser)232 parse_fd_array( CID_Face face, 233 CID_Parser* parser ) 234 { 235 CID_FaceInfo cid = &face->cid; 236 FT_Memory memory = face->root.memory; 237 FT_Error error = CID_Err_Ok; 238 FT_Long num_dicts; 239 240 241 num_dicts = cid_parser_to_int( parser ); 242 243 if ( !cid->font_dicts ) 244 { 245 FT_Int n; 246 247 248 if ( FT_NEW_ARRAY( cid->font_dicts, num_dicts ) ) 249 goto Exit; 250 251 cid->num_dicts = (FT_UInt)num_dicts; 252 253 /* don't forget to set a few defaults */ 254 for ( n = 0; n < cid->num_dicts; n++ ) 255 { 256 CID_FaceDict dict = cid->font_dicts + n; 257 258 259 /* default value for lenIV */ 260 dict->private_dict.lenIV = 4; 261 } 262 } 263 264 Exit: 265 return error; 266 } 267 268 269 static 270 const T1_FieldRec cid_field_records[] = 271 { 272 273 #include "cidtoken.h" 274 275 T1_FIELD_CALLBACK( "FontBBox", parse_font_bbox ) 276 T1_FIELD_CALLBACK( "FDArray", parse_fd_array ) 277 T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix ) 278 { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0 } 279 }; 280 281 282 static int is_alpha(char c)283 is_alpha( char c ) 284 { 285 return ( ft_isalnum( (int)c ) || 286 c == '.' || 287 c == '_' ); 288 } 289 290 291 static FT_Error cid_parse_dict(CID_Face face,CID_Loader * loader,FT_Byte * base,FT_Long size)292 cid_parse_dict( CID_Face face, 293 CID_Loader* loader, 294 FT_Byte* base, 295 FT_Long size ) 296 { 297 CID_Parser* parser = &loader->parser; 298 299 300 parser->root.cursor = base; 301 parser->root.limit = base + size; 302 parser->root.error = 0; 303 304 { 305 FT_Byte* cur = base; 306 FT_Byte* limit = cur + size; 307 308 309 for ( ;cur < limit; cur++ ) 310 { 311 /* look for `%ADOBeginFontDict' */ 312 if ( *cur == '%' && cur + 20 < limit && 313 ft_strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 ) 314 { 315 cur += 17; 316 317 /* if /FDArray was found, then cid->num_dicts is > 0, and */ 318 /* we can start increasing parser->num_dict */ 319 if ( face->cid.num_dicts > 0 ) 320 parser->num_dict++; 321 } 322 /* look for immediates */ 323 else if ( *cur == '/' && cur + 2 < limit ) 324 { 325 FT_Byte* cur2; 326 FT_Int len; 327 328 329 cur++; 330 331 cur2 = cur; 332 while ( cur2 < limit && is_alpha( *cur2 ) ) 333 cur2++; 334 335 len = (FT_Int)( cur2 - cur ); 336 if ( len > 0 && len < 22 ) 337 { 338 /* now compare the immediate name to the keyword table */ 339 T1_Field keyword = (T1_Field) cid_field_records; 340 341 342 for (;;) 343 { 344 FT_Byte* name; 345 346 347 name = (FT_Byte*)keyword->ident; 348 if ( !name ) 349 break; 350 351 if ( cur[0] == name[0] && 352 len == (FT_Int)ft_strlen( (const char*)name ) ) 353 { 354 FT_Int n; 355 356 357 for ( n = 1; n < len; n++ ) 358 if ( cur[n] != name[n] ) 359 break; 360 361 if ( n >= len ) 362 { 363 /* we found it - run the parsing callback */ 364 parser->root.cursor = cur2; 365 cid_parser_skip_spaces( parser ); 366 parser->root.error = cid_load_keyword( face, 367 loader, 368 keyword ); 369 if ( parser->root.error ) 370 return parser->root.error; 371 372 cur = parser->root.cursor; 373 break; 374 } 375 } 376 keyword++; 377 } 378 } 379 } 380 } 381 } 382 return parser->root.error; 383 } 384 385 386 /* read the subrmap and the subrs of each font dict */ 387 static FT_Error cid_read_subrs(CID_Face face)388 cid_read_subrs( CID_Face face ) 389 { 390 CID_FaceInfo cid = &face->cid; 391 FT_Memory memory = face->root.memory; 392 FT_Stream stream = face->root.stream; 393 FT_Error error; 394 FT_Int n; 395 CID_Subrs subr; 396 FT_UInt max_offsets = 0; 397 FT_ULong* offsets = 0; 398 399 400 if ( FT_NEW_ARRAY( face->subrs, cid->num_dicts ) ) 401 goto Exit; 402 403 subr = face->subrs; 404 for ( n = 0; n < cid->num_dicts; n++, subr++ ) 405 { 406 CID_FaceDict dict = cid->font_dicts + n; 407 FT_Int lenIV = dict->private_dict.lenIV; 408 FT_UInt count, num_subrs = dict->num_subrs; 409 FT_ULong data_len; 410 FT_Byte* p; 411 412 413 /* reallocate offsets array if needed */ 414 if ( num_subrs + 1 > max_offsets ) 415 { 416 FT_UInt new_max = ( num_subrs + 1 + 3 ) & -4; 417 418 419 if ( FT_RENEW_ARRAY( offsets, max_offsets, new_max ) ) 420 goto Fail; 421 422 max_offsets = new_max; 423 } 424 425 /* read the subrmap's offsets */ 426 if ( FT_STREAM_SEEK( cid->data_offset + dict->subrmap_offset ) || 427 FT_FRAME_ENTER( ( num_subrs + 1 ) * dict->sd_bytes ) ) 428 goto Fail; 429 430 p = (FT_Byte*)stream->cursor; 431 for ( count = 0; count <= num_subrs; count++ ) 432 offsets[count] = cid_get_offset( &p, (FT_Byte)dict->sd_bytes ); 433 434 FT_FRAME_EXIT(); 435 436 /* now, compute the size of subrs charstrings, */ 437 /* allocate, and read them */ 438 data_len = offsets[num_subrs] - offsets[0]; 439 440 if ( FT_NEW_ARRAY( subr->code, num_subrs + 1 ) || 441 FT_ALLOC( subr->code[0], data_len ) ) 442 goto Fail; 443 444 if ( FT_STREAM_SEEK( cid->data_offset + offsets[0] ) || 445 FT_STREAM_READ( subr->code[0], data_len ) ) 446 goto Fail; 447 448 /* set up pointers */ 449 for ( count = 1; count <= num_subrs; count++ ) 450 { 451 FT_ULong len; 452 453 454 len = offsets[count] - offsets[count - 1]; 455 subr->code[count] = subr->code[count - 1] + len; 456 } 457 458 /* decrypt subroutines, but only if lenIV >= 0 */ 459 if ( lenIV >= 0 ) 460 { 461 for ( count = 0; count < num_subrs; count++ ) 462 { 463 FT_ULong len; 464 465 466 len = offsets[count + 1] - offsets[count]; 467 cid_decrypt( subr->code[count], len, 4330 ); 468 } 469 } 470 471 subr->num_subrs = num_subrs; 472 } 473 474 Exit: 475 FT_FREE( offsets ); 476 return error; 477 478 Fail: 479 if ( face->subrs ) 480 { 481 for ( n = 0; n < cid->num_dicts; n++ ) 482 { 483 if ( face->subrs[n].code ) 484 FT_FREE( face->subrs[n].code[0] ); 485 486 FT_FREE( face->subrs[n].code ); 487 } 488 FT_FREE( face->subrs ); 489 } 490 goto Exit; 491 } 492 493 494 static void t1_init_loader(CID_Loader * loader,CID_Face face)495 t1_init_loader( CID_Loader* loader, 496 CID_Face face ) 497 { 498 FT_UNUSED( face ); 499 500 FT_MEM_ZERO( loader, sizeof ( *loader ) ); 501 } 502 503 504 static void t1_done_loader(CID_Loader * loader)505 t1_done_loader( CID_Loader* loader ) 506 { 507 CID_Parser* parser = &loader->parser; 508 509 510 /* finalize parser */ 511 cid_parser_done( parser ); 512 } 513 514 515 FT_LOCAL_DEF( FT_Error ) cid_face_open(CID_Face face)516 cid_face_open( CID_Face face ) 517 { 518 CID_Loader loader; 519 CID_Parser* parser; 520 FT_Error error; 521 522 523 t1_init_loader( &loader, face ); 524 525 parser = &loader.parser; 526 error = cid_parser_new( parser, face->root.stream, face->root.memory, 527 (PSAux_Service)face->psaux ); 528 if ( error ) 529 goto Exit; 530 531 error = cid_parse_dict( face, &loader, 532 parser->postscript, 533 parser->postscript_len ); 534 if ( error ) 535 goto Exit; 536 537 face->cid.data_offset = loader.parser.data_offset; 538 error = cid_read_subrs( face ); 539 540 Exit: 541 t1_done_loader( &loader ); 542 return error; 543 } 544 545 546 /* END */ 547