1 /**************************************************************************** 2 * 3 * sfwoff2.c 4 * 5 * WOFF2 format management (base). 6 * 7 * Copyright (C) 2019-2020 by 8 * Nikhil Ramakrishnan, 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 #include <ft2build.h> 19 #include "sfwoff2.h" 20 #include "woff2tags.h" 21 #include FT_TRUETYPE_TAGS_H 22 #include FT_INTERNAL_DEBUG_H 23 #include FT_INTERNAL_STREAM_H 24 25 26 #ifdef FT_CONFIG_OPTION_USE_BROTLI 27 28 #include <brotli/decode.h> 29 30 #endif 31 32 33 /************************************************************************** 34 * 35 * The macro FT_COMPONENT is used in trace mode. It is an implicit 36 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log 37 * messages during execution. 38 */ 39 #undef FT_COMPONENT 40 #define FT_COMPONENT sfwoff2 41 42 43 #define READ_255USHORT( var ) FT_SET_ERROR( Read255UShort( stream, &var ) ) 44 45 #define READ_BASE128( var ) FT_SET_ERROR( ReadBase128( stream, &var ) ) 46 47 #define ROUND4( var ) ( ( var + 3 ) & ~3 ) 48 49 #define WRITE_USHORT( p, v ) \ 50 do \ 51 { \ 52 *(p)++ = (FT_Byte)( (v) >> 8 ); \ 53 *(p)++ = (FT_Byte)( (v) >> 0 ); \ 54 \ 55 } while ( 0 ) 56 57 #define WRITE_ULONG( p, v ) \ 58 do \ 59 { \ 60 *(p)++ = (FT_Byte)( (v) >> 24 ); \ 61 *(p)++ = (FT_Byte)( (v) >> 16 ); \ 62 *(p)++ = (FT_Byte)( (v) >> 8 ); \ 63 *(p)++ = (FT_Byte)( (v) >> 0 ); \ 64 \ 65 } while ( 0 ) 66 67 #define WRITE_SHORT( p, v ) \ 68 do \ 69 { \ 70 *(p)++ = ( (v) >> 8 ); \ 71 *(p)++ = ( (v) >> 0 ); \ 72 \ 73 } while ( 0 ) 74 75 #define WRITE_SFNT_BUF( buf, s ) \ 76 write_buf( &sfnt, sfnt_size, &dest_offset, buf, s, memory ) 77 78 #define WRITE_SFNT_BUF_AT( offset, buf, s ) \ 79 write_buf( &sfnt, sfnt_size, &offset, buf, s, memory ) 80 81 #define N_CONTOUR_STREAM 0 82 #define N_POINTS_STREAM 1 83 #define FLAG_STREAM 2 84 #define GLYPH_STREAM 3 85 #define COMPOSITE_STREAM 4 86 #define BBOX_STREAM 5 87 #define INSTRUCTION_STREAM 6 88 89 90 static void 91 stream_close( FT_Stream stream ) 92 { 93 FT_Memory memory = stream->memory; 94 95 96 FT_FREE( stream->base ); 97 98 stream->size = 0; 99 stream->base = NULL; 100 stream->close = NULL; 101 } 102 103 104 FT_CALLBACK_DEF( int ) 105 compare_tags( const void* a, 106 const void* b ) 107 { 108 WOFF2_Table table1 = *(WOFF2_Table*)a; 109 WOFF2_Table table2 = *(WOFF2_Table*)b; 110 111 FT_ULong tag1 = table1->Tag; 112 FT_ULong tag2 = table2->Tag; 113 114 115 if ( tag1 > tag2 ) 116 return 1; 117 else if ( tag1 < tag2 ) 118 return -1; 119 else 120 return 0; 121 } 122 123 124 static FT_Error 125 Read255UShort( FT_Stream stream, 126 FT_UShort* value ) 127 { 128 static const FT_Int oneMoreByteCode1 = 255; 129 static const FT_Int oneMoreByteCode2 = 254; 130 static const FT_Int wordCode = 253; 131 static const FT_Int lowestUCode = 253; 132 133 FT_Error error = FT_Err_Ok; 134 FT_Byte code; 135 FT_Byte result_byte = 0; 136 FT_UShort result_short = 0; 137 138 139 if ( FT_READ_BYTE( code ) ) 140 return error; 141 if ( code == wordCode ) 142 { 143 /* Read next two bytes and store `FT_UShort' value. */ 144 if ( FT_READ_USHORT( result_short ) ) 145 return error; 146 *value = result_short; 147 return FT_Err_Ok; 148 } 149 else if ( code == oneMoreByteCode1 ) 150 { 151 if ( FT_READ_BYTE( result_byte ) ) 152 return error; 153 *value = result_byte + lowestUCode; 154 return FT_Err_Ok; 155 } 156 else if ( code == oneMoreByteCode2 ) 157 { 158 if ( FT_READ_BYTE( result_byte ) ) 159 return error; 160 *value = result_byte + lowestUCode * 2; 161 return FT_Err_Ok; 162 } 163 else 164 { 165 *value = code; 166 return FT_Err_Ok; 167 } 168 } 169 170 171 static FT_Error 172 ReadBase128( FT_Stream stream, 173 FT_ULong* value ) 174 { 175 FT_ULong result = 0; 176 FT_Int i; 177 FT_Byte code; 178 FT_Error error = FT_Err_Ok; 179 180 181 for ( i = 0; i < 5; ++i ) 182 { 183 code = 0; 184 if ( FT_READ_BYTE( code ) ) 185 return error; 186 187 /* Leading zeros are invalid. */ 188 if ( i == 0 && code == 0x80 ) 189 return FT_THROW( Invalid_Table ); 190 191 /* If any of top seven bits are set then we're about to overflow. */ 192 if ( result & 0xfe000000 ) 193 return FT_THROW( Invalid_Table ); 194 195 result = ( result << 7 ) | ( code & 0x7f ); 196 197 /* Spin until most significant bit of data byte is false. */ 198 if ( ( code & 0x80 ) == 0 ) 199 { 200 *value = result; 201 return FT_Err_Ok; 202 } 203 } 204 205 /* Make sure not to exceed the size bound. */ 206 return FT_THROW( Invalid_Table ); 207 } 208 209 210 /* Extend memory of `dst_bytes' buffer and copy data from `src'. */ 211 static FT_Error 212 write_buf( FT_Byte** dst_bytes, 213 FT_ULong* dst_size, 214 FT_ULong* offset, 215 FT_Byte* src, 216 FT_ULong size, 217 FT_Memory memory ) 218 { 219 FT_Error error = FT_Err_Ok; 220 /* We are reallocating memory for `dst', so its pointer may change. */ 221 FT_Byte* dst = *dst_bytes; 222 223 224 /* Check whether we are within limits. */ 225 if ( ( *offset + size ) > WOFF2_DEFAULT_MAX_SIZE ) 226 return FT_THROW( Array_Too_Large ); 227 228 /* Reallocate `dst'. */ 229 if ( ( *offset + size ) > *dst_size ) 230 { 231 FT_TRACE6(( "Reallocating %lu to %lu.\n", 232 *dst_size, (*offset + size) )); 233 if ( FT_REALLOC( dst, 234 (FT_ULong)( *dst_size ), 235 (FT_ULong)( *offset + size ) ) ) 236 goto Exit; 237 238 *dst_size = *offset + size; 239 } 240 241 /* Copy data. */ 242 ft_memcpy( dst + *offset, src, size ); 243 244 *offset += size; 245 /* Set pointer of `dst' to its correct value. */ 246 *dst_bytes = dst; 247 248 Exit: 249 return error; 250 } 251 252 253 /* Pad buffer to closest multiple of 4. */ 254 static FT_Error 255 pad4( FT_Byte** sfnt_bytes, 256 FT_ULong* sfnt_size, 257 FT_ULong* out_offset, 258 FT_Memory memory ) 259 { 260 FT_Byte* sfnt = *sfnt_bytes; 261 FT_ULong dest_offset = *out_offset; 262 263 FT_Byte zeroes[] = { 0, 0, 0 }; 264 FT_ULong pad_bytes; 265 266 267 if ( dest_offset + 3 < dest_offset ) 268 return FT_THROW( Invalid_Table ); 269 270 pad_bytes = ROUND4( dest_offset ) - dest_offset; 271 if ( pad_bytes > 0 ) 272 { 273 if ( WRITE_SFNT_BUF( &zeroes[0], pad_bytes ) ) 274 return FT_THROW( Invalid_Table ); 275 } 276 277 *sfnt_bytes = sfnt; 278 *out_offset = dest_offset; 279 return FT_Err_Ok; 280 } 281 282 283 /* Calculate table checksum of `buf'. */ 284 static FT_Long 285 compute_ULong_sum( FT_Byte* buf, 286 FT_ULong size ) 287 { 288 FT_ULong checksum = 0; 289 FT_ULong aligned_size = size & ~3; 290 FT_ULong i; 291 FT_ULong v; 292 293 294 for ( i = 0; i < aligned_size; i += 4 ) 295 checksum += ( (FT_ULong)buf[i ] << 24 ) | 296 ( (FT_ULong)buf[i + 1] << 16 ) | 297 ( (FT_ULong)buf[i + 2] << 8 ) | 298 ( (FT_ULong)buf[i + 3] << 0 ); 299 300 /* If size is not aligned to 4, treat as if it is padded with 0s. */ 301 if ( size != aligned_size ) 302 { 303 v = 0; 304 for ( i = aligned_size ; i < size; ++i ) 305 v |= (FT_ULong)buf[i] << ( 24 - 8 * ( i & 3 ) ); 306 checksum += v; 307 } 308 309 return checksum; 310 } 311 312 313 static FT_Error 314 woff2_decompress( FT_Byte* dst, 315 FT_ULong dst_size, 316 const FT_Byte* src, 317 FT_ULong src_size ) 318 { 319 #ifdef FT_CONFIG_OPTION_USE_BROTLI 320 321 FT_ULong uncompressed_size = dst_size; 322 BrotliDecoderResult result; 323 324 325 result = BrotliDecoderDecompress( src_size, 326 src, 327 &uncompressed_size, 328 dst ); 329 330 if ( result != BROTLI_DECODER_RESULT_SUCCESS || 331 uncompressed_size != dst_size ) 332 { 333 FT_ERROR(( "woff2_decompress: Stream length mismatch.\n" )); 334 return FT_THROW( Invalid_Table ); 335 } 336 337 FT_TRACE2(( "woff2_decompress: Brotli stream decompressed.\n" )); 338 return FT_Err_Ok; 339 340 #else /* !FT_CONFIG_OPTION_USE_BROTLI */ 341 342 FT_ERROR(( "woff2_decompress: Brotli support not available.\n" )); 343 return FT_THROW( Unimplemented_Feature ); 344 345 #endif /* !FT_CONFIG_OPTION_USE_BROTLI */ 346 } 347 348 349 static WOFF2_Table 350 find_table( WOFF2_Table* tables, 351 FT_UShort num_tables, 352 FT_ULong tag ) 353 { 354 FT_Int i; 355 356 357 for ( i = 0; i < num_tables; i++ ) 358 { 359 if ( tables[i]->Tag == tag ) 360 return tables[i]; 361 } 362 return NULL; 363 } 364 365 366 /* Read `numberOfHMetrics' field from `hhea' table. */ 367 static FT_Error 368 read_num_hmetrics( FT_Stream stream, 369 FT_UShort* num_hmetrics ) 370 { 371 FT_Error error = FT_Err_Ok; 372 FT_UShort num_metrics; 373 374 375 if ( FT_STREAM_SKIP( 34 ) ) 376 return FT_THROW( Invalid_Table ); 377 378 if ( FT_READ_USHORT( num_metrics ) ) 379 return FT_THROW( Invalid_Table ); 380 381 *num_hmetrics = num_metrics; 382 383 return error; 384 } 385 386 387 /* An auxiliary function for overflow-safe addition. */ 388 static FT_Int 389 with_sign( FT_Byte flag, 390 FT_Int base_val ) 391 { 392 /* Precondition: 0 <= base_val < 65536 (to avoid overflow). */ 393 return ( flag & 1 ) ? base_val : -base_val; 394 } 395 396 397 /* An auxiliary function for overflow-safe addition. */ 398 static FT_Int 399 safe_int_addition( FT_Int a, 400 FT_Int b, 401 FT_Int* result ) 402 { 403 if ( ( ( a > 0 ) && ( b > FT_INT_MAX - a ) ) || 404 ( ( a < 0 ) && ( b < FT_INT_MIN - a ) ) ) 405 return FT_THROW( Invalid_Table ); 406 407 *result = a + b; 408 return FT_Err_Ok; 409 } 410 411 412 /* 413 * Decode variable-length (flag, xCoordinate, yCoordinate) triplet for a 414 * simple glyph. See 415 * 416 * https://www.w3.org/TR/WOFF2/#triplet_decoding 417 */ 418 static FT_Error 419 triplet_decode( const FT_Byte* flags_in, 420 const FT_Byte* in, 421 FT_ULong in_size, 422 FT_ULong n_points, 423 WOFF2_Point result, 424 FT_ULong* in_bytes_used ) 425 { 426 FT_Int x = 0; 427 FT_Int y = 0; 428 FT_Int dx; 429 FT_Int dy; 430 FT_Int b0, b1, b2; 431 432 FT_ULong triplet_index = 0; 433 FT_ULong data_bytes; 434 435 FT_UInt i; 436 437 438 if ( n_points > in_size ) 439 return FT_THROW( Invalid_Table ); 440 441 for ( i = 0; i < n_points; ++i ) 442 { 443 FT_Byte flag = flags_in[i]; 444 FT_Bool on_curve = !( flag >> 7 ); 445 446 447 flag &= 0x7f; 448 if ( flag < 84 ) 449 data_bytes = 1; 450 else if ( flag < 120 ) 451 data_bytes = 2; 452 else if ( flag < 124 ) 453 data_bytes = 3; 454 else 455 data_bytes = 4; 456 457 /* Overflow checks */ 458 if ( triplet_index + data_bytes > in_size || 459 triplet_index + data_bytes < triplet_index ) 460 return FT_THROW( Invalid_Table ); 461 462 if ( flag < 10 ) 463 { 464 dx = 0; 465 dy = with_sign( flag, 466 ( ( flag & 14 ) << 7 ) + in[triplet_index] ); 467 } 468 else if ( flag < 20 ) 469 { 470 dx = with_sign( flag, 471 ( ( ( flag - 10 ) & 14 ) << 7 ) + 472 in[triplet_index] ); 473 dy = 0; 474 } 475 else if ( flag < 84 ) 476 { 477 b0 = flag - 20; 478 b1 = in[triplet_index]; 479 dx = with_sign( flag, 480 1 + ( b0 & 0x30 ) + ( b1 >> 4 ) ); 481 dy = with_sign( flag >> 1, 482 1 + ( ( b0 & 0x0c ) << 2 ) + ( b1 & 0x0f ) ); 483 } 484 else if ( flag < 120 ) 485 { 486 b0 = flag - 84; 487 dx = with_sign( flag, 488 1 + ( ( b0 / 12 ) << 8 ) + in[triplet_index] ); 489 dy = with_sign( flag >> 1, 490 1 + ( ( ( b0 % 12 ) >> 2 ) << 8 ) + 491 in[triplet_index + 1] ); 492 } 493 else if ( flag < 124 ) 494 { 495 b2 = in[triplet_index + 1]; 496 dx = with_sign( flag, 497 ( in[triplet_index] << 4 ) + ( b2 >> 4 ) ); 498 dy = with_sign( flag >> 1, 499 ( ( b2 & 0x0f ) << 8 ) + in[triplet_index + 2] ); 500 } 501 else 502 { 503 dx = with_sign( flag, 504 ( in[triplet_index] << 8 ) + 505 in[triplet_index + 1] ); 506 dy = with_sign( flag >> 1, 507 ( in[triplet_index + 2] << 8 ) + 508 in[triplet_index + 3] ); 509 } 510 511 triplet_index += data_bytes; 512 513 if ( safe_int_addition( x, dx, &x ) ) 514 return FT_THROW( Invalid_Table ); 515 516 if ( safe_int_addition( y, dy, &y ) ) 517 return FT_THROW( Invalid_Table ); 518 519 result[i].x = x; 520 result[i].y = y; 521 result[i].on_curve = on_curve; 522 } 523 524 *in_bytes_used = triplet_index; 525 return FT_Err_Ok; 526 } 527 528 529 /* Store decoded points in glyph buffer. */ 530 static FT_Error 531 store_points( FT_ULong n_points, 532 const WOFF2_Point points, 533 FT_UShort n_contours, 534 FT_UShort instruction_len, 535 FT_Byte* dst, 536 FT_ULong dst_size, 537 FT_ULong* glyph_size ) 538 { 539 FT_UInt flag_offset = 10 + ( 2 * n_contours ) + 2 + instruction_len; 540 FT_Int last_flag = -1; 541 FT_Int repeat_count = 0; 542 FT_Int last_x = 0; 543 FT_Int last_y = 0; 544 FT_UInt x_bytes = 0; 545 FT_UInt y_bytes = 0; 546 FT_UInt xy_bytes; 547 FT_UInt i; 548 FT_UInt x_offset; 549 FT_UInt y_offset; 550 FT_Byte* pointer; 551 552 553 for ( i = 0; i < n_points; ++i ) 554 { 555 const WOFF2_PointRec point = points[i]; 556 557 FT_Int flag = point.on_curve ? GLYF_ON_CURVE : 0; 558 FT_Int dx = point.x - last_x; 559 FT_Int dy = point.y - last_y; 560 561 562 if ( dx == 0 ) 563 flag |= GLYF_THIS_X_IS_SAME; 564 else if ( dx > -256 && dx < 256 ) 565 { 566 flag |= GLYF_X_SHORT | ( dx > 0 ? GLYF_THIS_X_IS_SAME : 0 ); 567 x_bytes += 1; 568 } 569 else 570 x_bytes += 2; 571 572 if ( dy == 0 ) 573 flag |= GLYF_THIS_Y_IS_SAME; 574 else if ( dy > -256 && dy < 256 ) 575 { 576 flag |= GLYF_Y_SHORT | ( dy > 0 ? GLYF_THIS_Y_IS_SAME : 0 ); 577 y_bytes += 1; 578 } 579 else 580 y_bytes += 2; 581 582 if ( flag == last_flag && repeat_count != 255 ) 583 { 584 dst[flag_offset - 1] |= GLYF_REPEAT; 585 repeat_count++; 586 } 587 else 588 { 589 if ( repeat_count != 0 ) 590 { 591 if ( flag_offset >= dst_size ) 592 return FT_THROW( Invalid_Table ); 593 594 dst[flag_offset++] = repeat_count; 595 } 596 if ( flag_offset >= dst_size ) 597 return FT_THROW( Invalid_Table ); 598 599 dst[flag_offset++] = flag; 600 repeat_count = 0; 601 } 602 603 last_x = point.x; 604 last_y = point.y; 605 last_flag = flag; 606 } 607 608 if ( repeat_count != 0 ) 609 { 610 if ( flag_offset >= dst_size ) 611 return FT_THROW( Invalid_Table ); 612 613 dst[flag_offset++] = repeat_count; 614 } 615 616 xy_bytes = x_bytes + y_bytes; 617 if ( xy_bytes < x_bytes || 618 flag_offset + xy_bytes < flag_offset || 619 flag_offset + xy_bytes > dst_size ) 620 return FT_THROW( Invalid_Table ); 621 622 x_offset = flag_offset; 623 y_offset = flag_offset + x_bytes; 624 last_x = 0; 625 last_y = 0; 626 627 for ( i = 0; i < n_points; ++i ) 628 { 629 FT_Int dx = points[i].x - last_x; 630 FT_Int dy = points[i].y - last_y; 631 632 633 if ( dx == 0 ) 634 ; 635 else if ( dx > -256 && dx < 256 ) 636 dst[x_offset++] = FT_ABS( dx ); 637 else 638 { 639 pointer = dst + x_offset; 640 WRITE_SHORT( pointer, dx ); 641 x_offset += 2; 642 } 643 644 last_x += dx; 645 646 if ( dy == 0 ) 647 ; 648 else if ( dy > -256 && dy < 256 ) 649 dst[y_offset++] = FT_ABS( dy ); 650 else 651 { 652 pointer = dst + y_offset; 653 WRITE_SHORT( pointer, dy ); 654 y_offset += 2; 655 } 656 657 last_y += dy; 658 } 659 660 *glyph_size = y_offset; 661 return FT_Err_Ok; 662 } 663 664 665 static void 666 compute_bbox( FT_ULong n_points, 667 const WOFF2_Point points, 668 FT_Byte* dst, 669 FT_UShort* src_x_min ) 670 { 671 FT_Int x_min = 0; 672 FT_Int y_min = 0; 673 FT_Int x_max = 0; 674 FT_Int y_max = 0; 675 676 FT_UInt i; 677 678 FT_ULong offset; 679 FT_Byte* pointer; 680 681 682 if ( n_points > 0 ) 683 { 684 x_min = points[0].x; 685 y_min = points[0].y; 686 x_max = points[0].x; 687 y_max = points[0].y; 688 } 689 690 for ( i = 1; i < n_points; ++i ) 691 { 692 FT_Int x = points[i].x; 693 FT_Int y = points[i].y; 694 695 696 x_min = FT_MIN( x, x_min ); 697 y_min = FT_MIN( y, y_min ); 698 x_max = FT_MAX( x, x_max ); 699 y_max = FT_MAX( y, y_max ); 700 } 701 702 /* Write values to `glyf' record. */ 703 offset = 2; 704 pointer = dst + offset; 705 706 WRITE_SHORT( pointer, x_min ); 707 WRITE_SHORT( pointer, y_min ); 708 WRITE_SHORT( pointer, x_max ); 709 WRITE_SHORT( pointer, y_max ); 710 711 *src_x_min = (FT_UShort)x_min; 712 } 713 714 715 static FT_Error 716 compositeGlyph_size( FT_Stream stream, 717 FT_ULong offset, 718 FT_ULong* size, 719 FT_Bool* have_instructions ) 720 { 721 FT_Error error = FT_Err_Ok; 722 FT_ULong start_offset = offset; 723 FT_Bool we_have_inst = FALSE; 724 FT_UShort flags = FLAG_MORE_COMPONENTS; 725 726 727 if ( FT_STREAM_SEEK( start_offset ) ) 728 goto Exit; 729 while ( flags & FLAG_MORE_COMPONENTS ) 730 { 731 FT_ULong arg_size; 732 733 734 if ( FT_READ_USHORT( flags ) ) 735 goto Exit; 736 we_have_inst |= ( flags & FLAG_WE_HAVE_INSTRUCTIONS ) != 0; 737 /* glyph index */ 738 arg_size = 2; 739 if ( flags & FLAG_ARG_1_AND_2_ARE_WORDS ) 740 arg_size += 4; 741 else 742 arg_size += 2; 743 744 if ( flags & FLAG_WE_HAVE_A_SCALE ) 745 arg_size += 2; 746 else if ( flags & FLAG_WE_HAVE_AN_X_AND_Y_SCALE ) 747 arg_size += 4; 748 else if ( flags & FLAG_WE_HAVE_A_TWO_BY_TWO ) 749 arg_size += 8; 750 751 if ( FT_STREAM_SKIP( arg_size ) ) 752 goto Exit; 753 } 754 755 *size = FT_STREAM_POS() - start_offset; 756 *have_instructions = we_have_inst; 757 758 Exit: 759 return error; 760 } 761 762 763 /* Store loca values (provided by `reconstruct_glyf') to output stream. */ 764 static FT_Error 765 store_loca( FT_ULong* loca_values, 766 FT_ULong loca_values_size, 767 FT_UShort index_format, 768 FT_ULong* checksum, 769 FT_Byte** sfnt_bytes, 770 FT_ULong* sfnt_size, 771 FT_ULong* out_offset, 772 FT_Memory memory ) 773 { 774 FT_Error error = FT_Err_Ok; 775 FT_Byte* sfnt = *sfnt_bytes; 776 FT_ULong dest_offset = *out_offset; 777 778 FT_Byte* loca_buf = NULL; 779 FT_Byte* dst = NULL; 780 781 FT_UInt i = 0; 782 FT_ULong loca_buf_size; 783 784 const FT_ULong offset_size = index_format ? 4 : 2; 785 786 787 if ( ( loca_values_size << 2 ) >> 2 != loca_values_size ) 788 goto Fail; 789 790 loca_buf_size = loca_values_size * offset_size; 791 if ( FT_NEW_ARRAY( loca_buf, loca_buf_size ) ) 792 goto Fail; 793 794 dst = loca_buf; 795 for ( i = 0; i < loca_values_size; i++ ) 796 { 797 FT_ULong value = loca_values[i]; 798 799 800 if ( index_format ) 801 WRITE_ULONG( dst, value ); 802 else 803 WRITE_USHORT( dst, ( value >> 1 ) ); 804 } 805 806 *checksum = compute_ULong_sum( loca_buf, loca_buf_size ); 807 /* Write `loca' table to sfnt buffer. */ 808 if ( WRITE_SFNT_BUF( loca_buf, loca_buf_size ) ) 809 goto Fail; 810 811 /* Set pointer `sfnt_bytes' to its correct value. */ 812 *sfnt_bytes = sfnt; 813 *out_offset = dest_offset; 814 815 FT_FREE( loca_buf ); 816 return error; 817 818 Fail: 819 if ( !error ) 820 error = FT_THROW( Invalid_Table ); 821 822 FT_FREE( loca_buf ); 823 824 return error; 825 } 826 827 828 static FT_Error 829 reconstruct_glyf( FT_Stream stream, 830 FT_ULong* glyf_checksum, 831 FT_ULong* loca_checksum, 832 FT_Byte** sfnt_bytes, 833 FT_ULong* sfnt_size, 834 FT_ULong* out_offset, 835 WOFF2_Info info, 836 FT_Memory memory ) 837 { 838 FT_Error error = FT_Err_Ok; 839 FT_Byte* sfnt = *sfnt_bytes; 840 841 /* current position in stream */ 842 const FT_ULong pos = FT_STREAM_POS(); 843 844 FT_UInt num_substreams = 7; 845 846 FT_UShort num_glyphs; 847 FT_UShort index_format; 848 FT_ULong expected_loca_length; 849 FT_UInt offset; 850 FT_UInt i; 851 FT_ULong points_size; 852 FT_ULong bitmap_length; 853 FT_ULong glyph_buf_size; 854 FT_ULong bbox_bitmap_offset; 855 856 const FT_ULong glyf_start = *out_offset; 857 FT_ULong dest_offset = *out_offset; 858 859 WOFF2_Substream substreams = NULL; 860 861 FT_ULong* loca_values = NULL; 862 FT_UShort* n_points_arr = NULL; 863 FT_Byte* glyph_buf = NULL; 864 WOFF2_Point points = NULL; 865 866 867 if ( FT_NEW_ARRAY( substreams, num_substreams ) ) 868 goto Fail; 869 870 if ( FT_STREAM_SKIP( 4 ) ) 871 goto Fail; 872 if ( FT_READ_USHORT( num_glyphs ) ) 873 goto Fail; 874 if ( FT_READ_USHORT( index_format ) ) 875 goto Fail; 876 877 FT_TRACE4(( "num_glyphs = %u; index_format = %u\n", 878 num_glyphs, index_format )); 879 880 info->num_glyphs = num_glyphs; 881 882 /* Calculate expected length of loca and compare. */ 883 /* See https://www.w3.org/TR/WOFF2/#conform-mustRejectLoca */ 884 /* index_format = 0 => Short version `loca'. */ 885 /* index_format = 1 => Long version `loca'. */ 886 expected_loca_length = ( index_format ? 4 : 2 ) * 887 ( (FT_ULong)num_glyphs + 1 ); 888 if ( info->loca_table->dst_length != expected_loca_length ) 889 goto Fail; 890 891 offset = ( 2 + num_substreams ) * 4; 892 if ( offset > info->glyf_table->TransformLength ) 893 goto Fail; 894 895 for ( i = 0; i < num_substreams; ++i ) 896 { 897 FT_ULong substream_size; 898 899 900 if ( FT_READ_ULONG( substream_size ) ) 901 goto Fail; 902 if ( substream_size > info->glyf_table->TransformLength - offset ) 903 goto Fail; 904 905 substreams[i].start = pos + offset; 906 substreams[i].offset = pos + offset; 907 substreams[i].size = substream_size; 908 909 FT_TRACE5(( " Substream %d: offset = %lu; size = %lu;\n", 910 i, substreams[i].offset, substreams[i].size )); 911 offset += substream_size; 912 } 913 914 if ( FT_NEW_ARRAY( loca_values, num_glyphs + 1 ) ) 915 goto Fail; 916 917 points_size = 0; 918 bbox_bitmap_offset = substreams[BBOX_STREAM].offset; 919 920 /* Size of bboxBitmap = 4 * floor((numGlyphs + 31) / 32) */ 921 bitmap_length = ( ( num_glyphs + 31 ) >> 5 ) << 2; 922 substreams[BBOX_STREAM].offset += bitmap_length; 923 924 glyph_buf_size = WOFF2_DEFAULT_GLYPH_BUF; 925 if ( FT_NEW_ARRAY( glyph_buf, glyph_buf_size ) ) 926 goto Fail; 927 928 if ( FT_NEW_ARRAY( info->x_mins, num_glyphs ) ) 929 goto Fail; 930 931 for ( i = 0; i < num_glyphs; ++i ) 932 { 933 FT_ULong glyph_size = 0; 934 FT_UShort n_contours = 0; 935 FT_Bool have_bbox = FALSE; 936 FT_Byte bbox_bitmap; 937 FT_ULong bbox_offset; 938 FT_UShort x_min = 0; 939 940 941 /* Set `have_bbox'. */ 942 bbox_offset = bbox_bitmap_offset + ( i >> 3 ); 943 if ( FT_STREAM_SEEK( bbox_offset ) || 944 FT_READ_BYTE( bbox_bitmap ) ) 945 goto Fail; 946 if ( bbox_bitmap & ( 0x80 >> ( i & 7 ) ) ) 947 have_bbox = TRUE; 948 949 /* Read value from `nContourStream'. */ 950 if ( FT_STREAM_SEEK( substreams[N_CONTOUR_STREAM].offset ) || 951 FT_READ_USHORT( n_contours ) ) 952 goto Fail; 953 substreams[N_CONTOUR_STREAM].offset += 2; 954 955 if ( n_contours == 0xffff ) 956 { 957 /* composite glyph */ 958 FT_Bool have_instructions = FALSE; 959 FT_UShort instruction_size = 0; 960 FT_ULong composite_size; 961 FT_ULong size_needed; 962 FT_Byte* pointer = NULL; 963 964 965 /* Composite glyphs must have explicit bbox. */ 966 if ( !have_bbox ) 967 goto Fail; 968 969 if ( compositeGlyph_size( stream, 970 substreams[COMPOSITE_STREAM].offset, 971 &composite_size, 972 &have_instructions) ) 973 goto Fail; 974 975 if ( have_instructions ) 976 { 977 if ( FT_STREAM_SEEK( substreams[GLYPH_STREAM].offset ) || 978 READ_255USHORT( instruction_size ) ) 979 goto Fail; 980 substreams[GLYPH_STREAM].offset = FT_STREAM_POS(); 981 } 982 983 size_needed = 12 + composite_size + instruction_size; 984 if ( glyph_buf_size < size_needed ) 985 { 986 if ( FT_RENEW_ARRAY( glyph_buf, glyph_buf_size, size_needed ) ) 987 goto Fail; 988 glyph_buf_size = size_needed; 989 } 990 991 pointer = glyph_buf + glyph_size; 992 WRITE_USHORT( pointer, n_contours ); 993 glyph_size += 2; 994 995 /* Read x_min for current glyph. */ 996 if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) || 997 FT_READ_USHORT( x_min ) ) 998 goto Fail; 999 /* No increment here because we read again. */ 1000 1001 if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) || 1002 FT_STREAM_READ( glyph_buf + glyph_size, 8 ) ) 1003 goto Fail; 1004 1005 substreams[BBOX_STREAM].offset += 8; 1006 glyph_size += 8; 1007 1008 if ( FT_STREAM_SEEK( substreams[COMPOSITE_STREAM].offset ) || 1009 FT_STREAM_READ( glyph_buf + glyph_size, composite_size ) ) 1010 goto Fail; 1011 1012 substreams[COMPOSITE_STREAM].offset += composite_size; 1013 glyph_size += composite_size; 1014 1015 if ( have_instructions ) 1016 { 1017 pointer = glyph_buf + glyph_size; 1018 WRITE_USHORT( pointer, instruction_size ); 1019 glyph_size += 2; 1020 1021 if ( FT_STREAM_SEEK( substreams[INSTRUCTION_STREAM].offset ) || 1022 FT_STREAM_READ( glyph_buf + glyph_size, instruction_size ) ) 1023 goto Fail; 1024 1025 substreams[INSTRUCTION_STREAM].offset += instruction_size; 1026 glyph_size += instruction_size; 1027 } 1028 } 1029 else if ( n_contours > 0 ) 1030 { 1031 /* simple glyph */ 1032 FT_ULong total_n_points = 0; 1033 FT_UShort n_points_contour; 1034 FT_UInt j; 1035 FT_ULong flag_size; 1036 FT_ULong triplet_size; 1037 FT_ULong triplet_bytes_used; 1038 FT_Byte* flags_buf = NULL; 1039 FT_Byte* triplet_buf = NULL; 1040 FT_UShort instruction_size; 1041 FT_ULong size_needed; 1042 FT_Int end_point; 1043 FT_UInt contour_ix; 1044 1045 FT_Byte* pointer = NULL; 1046 1047 1048 if ( FT_NEW_ARRAY( n_points_arr, n_contours ) ) 1049 goto Fail; 1050 1051 if ( FT_STREAM_SEEK( substreams[N_POINTS_STREAM].offset ) ) 1052 goto Fail; 1053 1054 for ( j = 0; j < n_contours; ++j ) 1055 { 1056 if ( READ_255USHORT( n_points_contour ) ) 1057 goto Fail; 1058 n_points_arr[j] = n_points_contour; 1059 /* Prevent negative/overflow. */ 1060 if ( total_n_points + n_points_contour < total_n_points ) 1061 goto Fail; 1062 total_n_points += n_points_contour; 1063 } 1064 substreams[N_POINTS_STREAM].offset = FT_STREAM_POS(); 1065 1066 flag_size = total_n_points; 1067 if ( flag_size > substreams[FLAG_STREAM].size ) 1068 goto Fail; 1069 1070 flags_buf = stream->base + substreams[FLAG_STREAM].offset; 1071 triplet_buf = stream->base + substreams[GLYPH_STREAM].offset; 1072 1073 if ( substreams[GLYPH_STREAM].size < 1074 ( substreams[GLYPH_STREAM].offset - 1075 substreams[GLYPH_STREAM].start ) ) 1076 goto Fail; 1077 1078 triplet_size = substreams[GLYPH_STREAM].size - 1079 ( substreams[GLYPH_STREAM].offset - 1080 substreams[GLYPH_STREAM].start ); 1081 triplet_bytes_used = 0; 1082 1083 /* Create array to store point information. */ 1084 points_size = total_n_points; 1085 if ( FT_NEW_ARRAY( points, points_size ) ) 1086 goto Fail; 1087 1088 if ( triplet_decode( flags_buf, 1089 triplet_buf, 1090 triplet_size, 1091 total_n_points, 1092 points, 1093 &triplet_bytes_used ) ) 1094 goto Fail; 1095 1096 substreams[FLAG_STREAM].offset += flag_size; 1097 substreams[GLYPH_STREAM].offset += triplet_bytes_used; 1098 1099 if ( FT_STREAM_SEEK( substreams[GLYPH_STREAM].offset ) || 1100 READ_255USHORT( instruction_size ) ) 1101 goto Fail; 1102 1103 substreams[GLYPH_STREAM].offset = FT_STREAM_POS(); 1104 1105 if ( total_n_points >= ( 1 << 27 ) ) 1106 goto Fail; 1107 1108 size_needed = 12 + 1109 ( 2 * n_contours ) + 1110 ( 5 * total_n_points ) + 1111 instruction_size; 1112 if ( glyph_buf_size < size_needed ) 1113 { 1114 if ( FT_RENEW_ARRAY( glyph_buf, glyph_buf_size, size_needed ) ) 1115 goto Fail; 1116 glyph_buf_size = size_needed; 1117 } 1118 1119 pointer = glyph_buf + glyph_size; 1120 WRITE_USHORT( pointer, n_contours ); 1121 glyph_size += 2; 1122 1123 if ( have_bbox ) 1124 { 1125 /* Read x_min for current glyph. */ 1126 if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) || 1127 FT_READ_USHORT( x_min ) ) 1128 goto Fail; 1129 /* No increment here because we read again. */ 1130 1131 if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) || 1132 FT_STREAM_READ( glyph_buf + glyph_size, 8 ) ) 1133 goto Fail; 1134 substreams[BBOX_STREAM].offset += 8; 1135 } 1136 else 1137 compute_bbox( total_n_points, points, glyph_buf, &x_min ); 1138 1139 glyph_size = CONTOUR_OFFSET_END_POINT; 1140 1141 pointer = glyph_buf + glyph_size; 1142 end_point = -1; 1143 1144 for ( contour_ix = 0; contour_ix < n_contours; ++contour_ix ) 1145 { 1146 end_point += n_points_arr[contour_ix]; 1147 if ( end_point >= 65536 ) 1148 goto Fail; 1149 1150 WRITE_SHORT( pointer, end_point ); 1151 glyph_size += 2; 1152 } 1153 1154 WRITE_USHORT( pointer, instruction_size ); 1155 glyph_size += 2; 1156 1157 if ( FT_STREAM_SEEK( substreams[INSTRUCTION_STREAM].offset ) || 1158 FT_STREAM_READ( glyph_buf + glyph_size, instruction_size ) ) 1159 goto Fail; 1160 1161 substreams[INSTRUCTION_STREAM].offset += instruction_size; 1162 glyph_size += instruction_size; 1163 1164 if ( store_points( total_n_points, 1165 points, 1166 n_contours, 1167 instruction_size, 1168 glyph_buf, 1169 glyph_buf_size, 1170 &glyph_size ) ) 1171 goto Fail; 1172 1173 FT_FREE( points ); 1174 FT_FREE( n_points_arr ); 1175 } 1176 else 1177 { 1178 /* Empty glyph. */ 1179 /* Must not have a bbox. */ 1180 if ( have_bbox ) 1181 { 1182 FT_ERROR(( "Empty glyph has a bbox.\n" )); 1183 goto Fail; 1184 } 1185 } 1186 1187 loca_values[i] = dest_offset - glyf_start; 1188 1189 if ( WRITE_SFNT_BUF( glyph_buf, glyph_size ) ) 1190 goto Fail; 1191 1192 if ( pad4( &sfnt, sfnt_size, &dest_offset, memory ) ) 1193 goto Fail; 1194 1195 *glyf_checksum += compute_ULong_sum( glyph_buf, glyph_size ); 1196 1197 /* Store x_mins, may be required to reconstruct `hmtx'. */ 1198 if ( n_contours > 0 ) 1199 info->x_mins[i] = x_min; 1200 } 1201 1202 info->glyf_table->dst_length = dest_offset - info->glyf_table->dst_offset; 1203 info->loca_table->dst_offset = dest_offset; 1204 1205 /* `loca[n]' will be equal to the length of the `glyf' table. */ 1206 loca_values[num_glyphs] = info->glyf_table->dst_length; 1207 1208 if ( store_loca( loca_values, 1209 num_glyphs + 1, 1210 index_format, 1211 loca_checksum, 1212 &sfnt, 1213 sfnt_size, 1214 &dest_offset, 1215 memory ) ) 1216 goto Fail; 1217 1218 info->loca_table->dst_length = dest_offset - info->loca_table->dst_offset; 1219 1220 FT_TRACE4(( " loca table info:\n" )); 1221 FT_TRACE4(( " dst_offset = %lu\n", info->loca_table->dst_offset )); 1222 FT_TRACE4(( " dst_length = %lu\n", info->loca_table->dst_length )); 1223 FT_TRACE4(( " checksum = %09x\n", *loca_checksum )); 1224 1225 /* Set pointer `sfnt_bytes' to its correct value. */ 1226 *sfnt_bytes = sfnt; 1227 *out_offset = dest_offset; 1228 1229 FT_FREE( substreams ); 1230 FT_FREE( loca_values ); 1231 FT_FREE( n_points_arr ); 1232 FT_FREE( glyph_buf ); 1233 FT_FREE( points ); 1234 1235 return error; 1236 1237 Fail: 1238 if ( !error ) 1239 error = FT_THROW( Invalid_Table ); 1240 1241 /* Set pointer `sfnt_bytes' to its correct value. */ 1242 *sfnt_bytes = sfnt; 1243 1244 FT_FREE( substreams ); 1245 FT_FREE( loca_values ); 1246 FT_FREE( n_points_arr ); 1247 FT_FREE( glyph_buf ); 1248 FT_FREE( points ); 1249 1250 return error; 1251 } 1252 1253 1254 /* Get `x_mins' for untransformed `glyf' table. */ 1255 static FT_Error 1256 get_x_mins( FT_Stream stream, 1257 WOFF2_Table* tables, 1258 FT_UShort num_tables, 1259 WOFF2_Info info, 1260 FT_Memory memory ) 1261 { 1262 FT_UShort num_glyphs; 1263 FT_UShort index_format; 1264 FT_ULong glyf_offset; 1265 FT_UShort glyf_offset_short; 1266 FT_ULong loca_offset; 1267 FT_Int i; 1268 FT_Error error = FT_Err_Ok; 1269 FT_ULong offset_size; 1270 1271 /* At this point of time those tables might not have been read yet. */ 1272 const WOFF2_Table maxp_table = find_table( tables, num_tables, 1273 TTAG_maxp ); 1274 const WOFF2_Table head_table = find_table( tables, num_tables, 1275 TTAG_head ); 1276 1277 1278 if ( !maxp_table ) 1279 { 1280 FT_ERROR(( "`maxp' table is missing.\n" )); 1281 return FT_THROW( Invalid_Table ); 1282 } 1283 1284 if ( !head_table ) 1285 { 1286 FT_ERROR(( "`head' table is missing.\n" )); 1287 return FT_THROW( Invalid_Table ); 1288 } 1289 1290 /* Read `numGlyphs' field from `maxp' table. */ 1291 if ( FT_STREAM_SEEK( maxp_table->src_offset ) || FT_STREAM_SKIP( 8 ) ) 1292 return error; 1293 1294 if ( FT_READ_USHORT( num_glyphs ) ) 1295 return error; 1296 1297 info->num_glyphs = num_glyphs; 1298 1299 /* Read `indexToLocFormat' field from `head' table. */ 1300 if ( FT_STREAM_SEEK( head_table->src_offset ) || 1301 FT_STREAM_SKIP( 50 ) ) 1302 return error; 1303 1304 if ( FT_READ_USHORT( index_format ) ) 1305 return error; 1306 1307 offset_size = index_format ? 4 : 2; 1308 1309 /* Create `x_mins' array. */ 1310 if ( FT_NEW_ARRAY( info->x_mins, num_glyphs ) ) 1311 return error; 1312 1313 loca_offset = info->loca_table->src_offset; 1314 1315 for ( i = 0; i < num_glyphs; ++i ) 1316 { 1317 if ( FT_STREAM_SEEK( loca_offset ) ) 1318 return error; 1319 1320 loca_offset += offset_size; 1321 1322 if ( index_format ) 1323 { 1324 if ( FT_READ_ULONG( glyf_offset ) ) 1325 return error; 1326 } 1327 else 1328 { 1329 if ( FT_READ_USHORT( glyf_offset_short ) ) 1330 return error; 1331 1332 glyf_offset = (FT_ULong)( glyf_offset_short ); 1333 glyf_offset = glyf_offset << 1; 1334 } 1335 1336 glyf_offset += info->glyf_table->src_offset; 1337 1338 if ( FT_STREAM_SEEK( glyf_offset ) || FT_STREAM_SKIP( 2 ) ) 1339 return error; 1340 1341 if ( FT_READ_USHORT( info->x_mins[i] ) ) 1342 return error; 1343 } 1344 1345 return error; 1346 } 1347 1348 1349 static FT_Error 1350 reconstruct_hmtx( FT_Stream stream, 1351 FT_UShort num_glyphs, 1352 FT_UShort num_hmetrics, 1353 FT_Short* x_mins, 1354 FT_ULong* checksum, 1355 FT_Byte** sfnt_bytes, 1356 FT_ULong* sfnt_size, 1357 FT_ULong* out_offset, 1358 FT_Memory memory ) 1359 { 1360 FT_Error error = FT_Err_Ok; 1361 FT_Byte* sfnt = *sfnt_bytes; 1362 FT_ULong dest_offset = *out_offset; 1363 1364 FT_Byte hmtx_flags; 1365 FT_Bool has_proportional_lsbs, has_monospace_lsbs; 1366 FT_ULong hmtx_table_size; 1367 FT_Int i; 1368 1369 FT_UShort* advance_widths = NULL; 1370 FT_Short* lsbs = NULL; 1371 FT_Byte* hmtx_table = NULL; 1372 FT_Byte* dst = NULL; 1373 1374 1375 if ( FT_READ_BYTE( hmtx_flags ) ) 1376 goto Fail; 1377 1378 has_proportional_lsbs = ( hmtx_flags & 1 ) == 0; 1379 has_monospace_lsbs = ( hmtx_flags & 2 ) == 0; 1380 1381 /* Bits 2-7 are reserved and MUST be zero. */ 1382 if ( ( hmtx_flags & 0xFC ) != 0 ) 1383 goto Fail; 1384 1385 /* Are you REALLY transformed? */ 1386 if ( has_proportional_lsbs && has_monospace_lsbs ) 1387 goto Fail; 1388 1389 /* Cannot have a transformed `hmtx' without `glyf'. */ 1390 if ( ( num_hmetrics > num_glyphs ) || 1391 ( num_hmetrics < 1 ) ) 1392 goto Fail; 1393 1394 /* Must have at least one entry. */ 1395 if ( num_hmetrics < 1 ) 1396 goto Fail; 1397 1398 if ( FT_NEW_ARRAY( advance_widths, num_hmetrics ) || 1399 FT_NEW_ARRAY( lsbs, num_glyphs ) ) 1400 goto Fail; 1401 1402 /* Read `advanceWidth' stream. Always present. */ 1403 for ( i = 0; i < num_hmetrics; i++ ) 1404 { 1405 FT_UShort advance_width; 1406 1407 1408 if ( FT_READ_USHORT( advance_width ) ) 1409 goto Fail; 1410 1411 advance_widths[i] = advance_width; 1412 } 1413 1414 /* lsb values for proportional glyphs. */ 1415 for ( i = 0; i < num_hmetrics; i++ ) 1416 { 1417 FT_Short lsb; 1418 1419 1420 if ( has_proportional_lsbs ) 1421 { 1422 if ( FT_READ_SHORT( lsb ) ) 1423 goto Fail; 1424 } 1425 else 1426 lsb = x_mins[i]; 1427 1428 lsbs[i] = lsb; 1429 } 1430 1431 /* lsb values for monospaced glyphs. */ 1432 for ( i = num_hmetrics; i < num_glyphs; i++ ) 1433 { 1434 FT_Short lsb; 1435 1436 1437 if ( has_monospace_lsbs ) 1438 { 1439 if ( FT_READ_SHORT( lsb ) ) 1440 goto Fail; 1441 } 1442 else 1443 lsb = x_mins[i]; 1444 1445 lsbs[i] = lsb; 1446 } 1447 1448 /* Build the hmtx table. */ 1449 hmtx_table_size = 2 * num_hmetrics + 2 * num_glyphs; 1450 if ( FT_NEW_ARRAY( hmtx_table, hmtx_table_size ) ) 1451 goto Fail; 1452 1453 dst = hmtx_table; 1454 FT_TRACE6(( "hmtx values: \n" )); 1455 for ( i = 0; i < num_glyphs; i++ ) 1456 { 1457 if ( i < num_hmetrics ) 1458 { 1459 WRITE_SHORT( dst, advance_widths[i] ); 1460 FT_TRACE6(( "%d ", advance_widths[i] )); 1461 } 1462 1463 WRITE_SHORT( dst, lsbs[i] ); 1464 FT_TRACE6(( "%d ", lsbs[i] )); 1465 } 1466 FT_TRACE6(( "\n" )); 1467 1468 *checksum = compute_ULong_sum( hmtx_table, hmtx_table_size ); 1469 /* Write `hmtx' table to sfnt buffer. */ 1470 if ( WRITE_SFNT_BUF( hmtx_table, hmtx_table_size ) ) 1471 goto Fail; 1472 1473 /* Set pointer `sfnt_bytes' to its correct value. */ 1474 *sfnt_bytes = sfnt; 1475 *out_offset = dest_offset; 1476 1477 FT_FREE( advance_widths ); 1478 FT_FREE( lsbs ); 1479 FT_FREE( hmtx_table ); 1480 1481 return error; 1482 1483 Fail: 1484 FT_FREE( advance_widths ); 1485 FT_FREE( lsbs ); 1486 FT_FREE( hmtx_table ); 1487 1488 if ( !error ) 1489 error = FT_THROW( Invalid_Table ); 1490 1491 return error; 1492 } 1493 1494 1495 static FT_Error 1496 reconstruct_font( FT_Byte* transformed_buf, 1497 FT_ULong transformed_buf_size, 1498 WOFF2_Table* indices, 1499 WOFF2_Header woff2, 1500 WOFF2_Info info, 1501 FT_Byte** sfnt_bytes, 1502 FT_ULong* sfnt_size, 1503 FT_Memory memory ) 1504 { 1505 /* Memory management of `transformed_buf' is handled by the caller. */ 1506 1507 FT_Error error = FT_Err_Ok; 1508 FT_Stream stream = NULL; 1509 FT_Byte* buf_cursor = NULL; 1510 FT_Byte* table_entry = NULL; 1511 1512 /* We are reallocating memory for `sfnt', so its pointer may change. */ 1513 FT_Byte* sfnt = *sfnt_bytes; 1514 1515 FT_UShort num_tables = woff2->num_tables; 1516 FT_ULong dest_offset = 12 + num_tables * 16UL; 1517 1518 FT_ULong checksum = 0; 1519 FT_ULong loca_checksum = 0; 1520 FT_Int nn = 0; 1521 FT_UShort num_hmetrics = 0; 1522 FT_ULong font_checksum = info->header_checksum; 1523 FT_Bool is_glyf_xform = FALSE; 1524 1525 FT_ULong table_entry_offset = 12; 1526 1527 1528 /* A few table checks before reconstruction. */ 1529 /* `glyf' must be present with `loca'. */ 1530 info->glyf_table = find_table( indices, num_tables, TTAG_glyf ); 1531 info->loca_table = find_table( indices, num_tables, TTAG_loca ); 1532 1533 if ( ( info->glyf_table == NULL ) ^ ( info->loca_table == NULL ) ) 1534 { 1535 FT_ERROR(( "One of `glyf'/`loca' tables missing.\n" )); 1536 return FT_THROW( Invalid_Table ); 1537 } 1538 1539 /* Both `glyf' and `loca' must have same transformation. */ 1540 if ( info->glyf_table != NULL ) 1541 { 1542 if ( ( info->glyf_table->flags & WOFF2_FLAGS_TRANSFORM ) != 1543 ( info->loca_table->flags & WOFF2_FLAGS_TRANSFORM ) ) 1544 { 1545 FT_ERROR(( "Transformation mismatch" 1546 " between `glyf' and `loca' table." )); 1547 return FT_THROW( Invalid_Table ); 1548 } 1549 } 1550 1551 /* Create buffer for table entries. */ 1552 if ( FT_NEW_ARRAY( table_entry, 16 ) ) 1553 goto Fail; 1554 1555 /* Create a stream for the uncompressed buffer. */ 1556 if ( FT_NEW( stream ) ) 1557 goto Fail; 1558 FT_Stream_OpenMemory( stream, transformed_buf, transformed_buf_size ); 1559 1560 FT_ASSERT( FT_STREAM_POS() == 0 ); 1561 1562 /* Reconstruct/copy tables to output stream. */ 1563 for ( nn = 0; nn < num_tables; nn++ ) 1564 { 1565 WOFF2_TableRec table = *( indices[nn] ); 1566 1567 1568 FT_TRACE3(( "Seeking to %d with table size %d.\n", 1569 table.src_offset, table.src_length )); 1570 FT_TRACE3(( "Table tag: %c%c%c%c.\n", 1571 (FT_Char)( table.Tag >> 24 ), 1572 (FT_Char)( table.Tag >> 16 ), 1573 (FT_Char)( table.Tag >> 8 ), 1574 (FT_Char)( table.Tag ) )); 1575 1576 if ( FT_STREAM_SEEK( table.src_offset ) ) 1577 goto Fail; 1578 1579 if ( table.src_offset + table.src_length > transformed_buf_size ) 1580 goto Fail; 1581 1582 /* Get stream size for fields of `hmtx' table. */ 1583 if ( table.Tag == TTAG_hhea ) 1584 { 1585 if ( read_num_hmetrics( stream, &num_hmetrics ) ) 1586 goto Fail; 1587 } 1588 1589 info->num_hmetrics = num_hmetrics; 1590 1591 checksum = 0; 1592 if ( ( table.flags & WOFF2_FLAGS_TRANSFORM ) != WOFF2_FLAGS_TRANSFORM ) 1593 { 1594 /* Check whether `head' is at least 12 bytes. */ 1595 if ( table.Tag == TTAG_head ) 1596 { 1597 if ( table.src_length < 12 ) 1598 goto Fail; 1599 1600 buf_cursor = transformed_buf + table.src_offset + 8; 1601 /* Set checkSumAdjustment = 0 */ 1602 WRITE_ULONG( buf_cursor, 0 ); 1603 } 1604 1605 table.dst_offset = dest_offset; 1606 1607 checksum = compute_ULong_sum( transformed_buf + table.src_offset, 1608 table.src_length ); 1609 FT_TRACE4(( "Checksum = %09x.\n", checksum )); 1610 1611 if ( WRITE_SFNT_BUF( transformed_buf + table.src_offset, 1612 table.src_length ) ) 1613 goto Fail; 1614 } 1615 else 1616 { 1617 FT_TRACE3(( "This table is transformed.\n" )); 1618 1619 if ( table.Tag == TTAG_glyf ) 1620 { 1621 is_glyf_xform = TRUE; 1622 table.dst_offset = dest_offset; 1623 1624 if ( reconstruct_glyf( stream, 1625 &checksum, 1626 &loca_checksum, 1627 &sfnt, 1628 sfnt_size, 1629 &dest_offset, 1630 info, 1631 memory ) ) 1632 goto Fail; 1633 1634 FT_TRACE4(( "Checksum = %09x.\n", checksum )); 1635 } 1636 1637 else if ( table.Tag == TTAG_loca ) 1638 checksum = loca_checksum; 1639 1640 else if ( table.Tag == TTAG_hmtx ) 1641 { 1642 /* If glyf is not transformed and hmtx is, handle separately. */ 1643 if ( !is_glyf_xform ) 1644 { 1645 if ( get_x_mins( stream, indices, num_tables, info, memory ) ) 1646 goto Fail; 1647 } 1648 1649 table.dst_offset = dest_offset; 1650 1651 if ( reconstruct_hmtx( stream, 1652 info->num_glyphs, 1653 info->num_hmetrics, 1654 info->x_mins, 1655 &checksum, 1656 &sfnt, 1657 sfnt_size, 1658 &dest_offset, 1659 memory ) ) 1660 goto Fail; 1661 } 1662 else 1663 { 1664 /* Unknown transform. */ 1665 FT_ERROR(( "Unknown table transform.\n" )); 1666 goto Fail; 1667 } 1668 } 1669 1670 font_checksum += checksum; 1671 1672 buf_cursor = &table_entry[0]; 1673 WRITE_ULONG( buf_cursor, table.Tag ); 1674 WRITE_ULONG( buf_cursor, checksum ); 1675 WRITE_ULONG( buf_cursor, table.dst_offset ); 1676 WRITE_ULONG( buf_cursor, table.dst_length ); 1677 1678 WRITE_SFNT_BUF_AT( table_entry_offset, table_entry, 16 ); 1679 1680 /* Update checksum. */ 1681 font_checksum += compute_ULong_sum( table_entry, 16 ); 1682 1683 if ( pad4( &sfnt, sfnt_size, &dest_offset, memory ) ) 1684 goto Fail; 1685 1686 /* Sanity check. */ 1687 if ( (FT_ULong)( table.dst_offset + table.dst_length ) > dest_offset ) 1688 { 1689 FT_ERROR(( "Table was partially written.\n" )); 1690 goto Fail; 1691 } 1692 } 1693 1694 /* Update `head' checkSumAdjustment. */ 1695 info->head_table = find_table( indices, num_tables, TTAG_head ); 1696 if ( !info->head_table ) 1697 { 1698 FT_ERROR(( "`head' table is missing.\n" )); 1699 goto Fail; 1700 } 1701 1702 if ( info->head_table->dst_length < 12 ) 1703 goto Fail; 1704 1705 buf_cursor = sfnt + info->head_table->dst_offset + 8; 1706 font_checksum = 0xB1B0AFBA - font_checksum; 1707 1708 WRITE_ULONG( buf_cursor, font_checksum ); 1709 1710 FT_TRACE2(( "Final checksum = %09x.\n", font_checksum )); 1711 1712 woff2->actual_sfnt_size = dest_offset; 1713 1714 /* Set pointer of sfnt stream to its correct value. */ 1715 *sfnt_bytes = sfnt; 1716 1717 FT_FREE( table_entry ); 1718 FT_Stream_Close( stream ); 1719 FT_FREE( stream ); 1720 1721 return error; 1722 1723 Fail: 1724 if ( !error ) 1725 error = FT_THROW( Invalid_Table ); 1726 1727 /* Set pointer of sfnt stream to its correct value. */ 1728 *sfnt_bytes = sfnt; 1729 1730 FT_FREE( table_entry ); 1731 FT_Stream_Close( stream ); 1732 FT_FREE( stream ); 1733 1734 return error; 1735 } 1736 1737 1738 /* Replace `face->root.stream' with a stream containing the extracted */ 1739 /* SFNT of a WOFF2 font. */ 1740 1741 FT_LOCAL_DEF( FT_Error ) 1742 woff2_open_font( FT_Stream stream, 1743 TT_Face face, 1744 FT_Int* face_instance_index, 1745 FT_Long* num_faces ) 1746 { 1747 FT_Memory memory = stream->memory; 1748 FT_Error error = FT_Err_Ok; 1749 FT_Int face_index; 1750 1751 WOFF2_HeaderRec woff2; 1752 WOFF2_InfoRec info = { 0, 0, 0, NULL, NULL, NULL, NULL }; 1753 WOFF2_Table tables = NULL; 1754 WOFF2_Table* indices = NULL; 1755 WOFF2_Table* temp_indices = NULL; 1756 WOFF2_Table last_table; 1757 1758 FT_Int nn; 1759 FT_ULong j; 1760 FT_ULong flags; 1761 FT_UShort xform_version; 1762 FT_ULong src_offset = 0; 1763 1764 FT_UInt glyf_index; 1765 FT_UInt loca_index; 1766 FT_UInt32 file_offset; 1767 1768 FT_Byte* sfnt = NULL; 1769 FT_Stream sfnt_stream = NULL; 1770 FT_Byte* sfnt_header; 1771 FT_ULong sfnt_size; 1772 1773 FT_Byte* uncompressed_buf = NULL; 1774 1775 static const FT_Frame_Field woff2_header_fields[] = 1776 { 1777 #undef FT_STRUCTURE 1778 #define FT_STRUCTURE WOFF2_HeaderRec 1779 1780 FT_FRAME_START( 48 ), 1781 FT_FRAME_ULONG ( signature ), 1782 FT_FRAME_ULONG ( flavor ), 1783 FT_FRAME_ULONG ( length ), 1784 FT_FRAME_USHORT ( num_tables ), 1785 FT_FRAME_SKIP_BYTES( 2 ), 1786 FT_FRAME_ULONG ( totalSfntSize ), 1787 FT_FRAME_ULONG ( totalCompressedSize ), 1788 FT_FRAME_SKIP_BYTES( 2 * 2 ), 1789 FT_FRAME_ULONG ( metaOffset ), 1790 FT_FRAME_ULONG ( metaLength ), 1791 FT_FRAME_ULONG ( metaOrigLength ), 1792 FT_FRAME_ULONG ( privOffset ), 1793 FT_FRAME_ULONG ( privLength ), 1794 FT_FRAME_END 1795 }; 1796 1797 1798 FT_ASSERT( stream == face->root.stream ); 1799 FT_ASSERT( FT_STREAM_POS() == 0 ); 1800 1801 face_index = FT_ABS( *face_instance_index ) & 0xFFFF; 1802 1803 /* Read WOFF2 Header. */ 1804 if ( FT_STREAM_READ_FIELDS( woff2_header_fields, &woff2 ) ) 1805 return error; 1806 1807 FT_TRACE4(( "signature -> 0x%X\n", woff2.signature )); 1808 FT_TRACE2(( "flavor -> 0x%08lx\n", woff2.flavor )); 1809 FT_TRACE4(( "length -> %lu\n", woff2.length )); 1810 FT_TRACE2(( "num_tables -> %hu\n", woff2.num_tables )); 1811 FT_TRACE4(( "totalSfntSize -> %lu\n", woff2.totalSfntSize )); 1812 FT_TRACE4(( "metaOffset -> %hu\n", woff2.metaOffset )); 1813 FT_TRACE4(( "metaLength -> %hu\n", woff2.metaLength )); 1814 FT_TRACE4(( "privOffset -> %hu\n", woff2.privOffset )); 1815 FT_TRACE4(( "privLength -> %hu\n", woff2.privLength )); 1816 1817 /* Make sure we don't recurse back here. */ 1818 if ( woff2.flavor == TTAG_wOF2 ) 1819 return FT_THROW( Invalid_Table ); 1820 1821 /* Miscellaneous checks. */ 1822 if ( woff2.length != stream->size || 1823 woff2.num_tables == 0 || 1824 48 + woff2.num_tables * 20UL >= woff2.length || 1825 ( woff2.metaOffset == 0 && ( woff2.metaLength != 0 || 1826 woff2.metaOrigLength != 0 ) ) || 1827 ( woff2.metaLength != 0 && woff2.metaOrigLength == 0 ) || 1828 ( woff2.metaOffset >= woff2.length ) || 1829 ( woff2.length - woff2.metaOffset < woff2.metaLength ) || 1830 ( woff2.privOffset == 0 && woff2.privLength != 0 ) || 1831 ( woff2.privOffset >= woff2.length ) || 1832 ( woff2.length - woff2.privOffset < woff2.privLength ) ) 1833 { 1834 FT_ERROR(( "woff2_open_font: invalid WOFF2 header\n" )); 1835 return FT_THROW( Invalid_Table ); 1836 } 1837 1838 FT_TRACE2(( "woff2_open_font: WOFF2 Header is valid.\n" )); 1839 1840 woff2.ttc_fonts = NULL; 1841 1842 /* Read table directory. */ 1843 if ( FT_NEW_ARRAY( tables, woff2.num_tables ) || 1844 FT_NEW_ARRAY( indices, woff2.num_tables ) ) 1845 goto Exit; 1846 1847 FT_TRACE2(( "\n" 1848 " tag flags transform origLen transformLen\n" 1849 " --------------------------------------------------\n" )); 1850 1851 for ( nn = 0; nn < woff2.num_tables; nn++ ) 1852 { 1853 WOFF2_Table table = tables + nn; 1854 1855 1856 if ( FT_READ_BYTE( table->FlagByte ) ) 1857 goto Exit; 1858 1859 if ( ( table->FlagByte & 0x3f ) == 0x3f ) 1860 { 1861 if ( FT_READ_ULONG( table->Tag ) ) 1862 goto Exit; 1863 } 1864 else 1865 { 1866 table->Tag = woff2_known_tags( table->FlagByte & 0x3f ); 1867 if ( !table->Tag ) 1868 { 1869 FT_ERROR(( "woff2_open_font: Unknown table tag." )); 1870 error = FT_THROW( Invalid_Table ); 1871 goto Exit; 1872 } 1873 } 1874 1875 flags = 0; 1876 xform_version = ( table->FlagByte >> 6 ) & 0x03; 1877 1878 /* 0 means xform for glyph/loca, non-0 for others. */ 1879 if ( table->Tag == TTAG_glyf || table->Tag == TTAG_loca ) 1880 { 1881 if ( xform_version == 0 ) 1882 flags |= WOFF2_FLAGS_TRANSFORM; 1883 } 1884 else if ( xform_version != 0 ) 1885 flags |= WOFF2_FLAGS_TRANSFORM; 1886 1887 flags |= xform_version; 1888 1889 if ( READ_BASE128( table->dst_length ) ) 1890 goto Exit; 1891 1892 table->TransformLength = table->dst_length; 1893 1894 if ( ( flags & WOFF2_FLAGS_TRANSFORM ) != 0 ) 1895 { 1896 if ( READ_BASE128( table->TransformLength ) ) 1897 goto Exit; 1898 1899 if ( table->Tag == TTAG_loca && table->TransformLength ) 1900 { 1901 FT_ERROR(( "woff2_open_font: Invalid loca `transformLength'.\n" )); 1902 error = FT_THROW( Invalid_Table ); 1903 goto Exit; 1904 } 1905 } 1906 1907 if ( src_offset + table->TransformLength < src_offset ) 1908 { 1909 FT_ERROR(( "woff2_open_font: invalid WOFF2 table directory.\n" )); 1910 error = FT_THROW( Invalid_Table ); 1911 goto Exit; 1912 } 1913 1914 table->src_offset = src_offset; 1915 table->src_length = table->TransformLength; 1916 src_offset += table->TransformLength; 1917 table->flags = flags; 1918 1919 FT_TRACE2(( " %c%c%c%c %08d %08d %08ld %08ld\n", 1920 (FT_Char)( table->Tag >> 24 ), 1921 (FT_Char)( table->Tag >> 16 ), 1922 (FT_Char)( table->Tag >> 8 ), 1923 (FT_Char)( table->Tag ), 1924 table->FlagByte & 0x3f, 1925 ( table->FlagByte >> 6 ) & 0x03, 1926 table->dst_length, 1927 table->TransformLength, 1928 table->src_length, 1929 table->src_offset )); 1930 1931 indices[nn] = table; 1932 } 1933 1934 /* End of last table is uncompressed size. */ 1935 last_table = indices[woff2.num_tables - 1]; 1936 1937 woff2.uncompressed_size = last_table->src_offset + 1938 last_table->src_length; 1939 if ( woff2.uncompressed_size < last_table->src_offset ) 1940 { 1941 error = FT_THROW( Invalid_Table ); 1942 goto Exit; 1943 } 1944 1945 FT_TRACE2(( "Table directory parsed.\n" )); 1946 1947 /* Check for and read collection directory. */ 1948 woff2.num_fonts = 1; 1949 woff2.header_version = 0; 1950 1951 if ( woff2.flavor == TTAG_ttcf ) 1952 { 1953 FT_TRACE2(( "Font is a TTC, reading collection directory.\n" )); 1954 1955 if ( FT_READ_ULONG( woff2.header_version ) ) 1956 goto Exit; 1957 1958 if ( woff2.header_version != 0x00010000 && 1959 woff2.header_version != 0x00020000 ) 1960 { 1961 error = FT_THROW( Invalid_Table ); 1962 goto Exit; 1963 } 1964 1965 if ( READ_255USHORT( woff2.num_fonts ) ) 1966 goto Exit; 1967 1968 if ( !woff2.num_fonts ) 1969 { 1970 error = FT_THROW( Invalid_Table ); 1971 goto Exit; 1972 } 1973 1974 FT_TRACE4(( "Number of fonts in TTC: %ld\n", woff2.num_fonts )); 1975 1976 if ( FT_NEW_ARRAY( woff2.ttc_fonts, woff2.num_fonts ) ) 1977 goto Exit; 1978 1979 for ( nn = 0; nn < woff2.num_fonts; nn++ ) 1980 { 1981 WOFF2_TtcFont ttc_font = woff2.ttc_fonts + nn; 1982 1983 1984 if ( READ_255USHORT( ttc_font->num_tables ) ) 1985 goto Exit; 1986 if ( FT_READ_ULONG( ttc_font->flavor ) ) 1987 goto Exit; 1988 1989 if ( FT_NEW_ARRAY( ttc_font->table_indices, ttc_font->num_tables ) ) 1990 goto Exit; 1991 1992 FT_TRACE5(( "Number of tables in font %d: %ld\n", 1993 nn, ttc_font->num_tables )); 1994 1995 #ifdef FT_DEBUG_LEVEL_TRACE 1996 if ( ttc_font->num_tables ) 1997 FT_TRACE6(( " Indices: " )); 1998 #endif 1999 2000 glyf_index = 0; 2001 loca_index = 0; 2002 2003 for ( j = 0; j < ttc_font->num_tables; j++ ) 2004 { 2005 FT_UShort table_index; 2006 WOFF2_Table table; 2007 2008 2009 if ( READ_255USHORT( table_index ) ) 2010 goto Exit; 2011 2012 FT_TRACE6(( "%hu ", table_index )); 2013 if ( table_index >= woff2.num_tables ) 2014 { 2015 FT_ERROR(( "woff2_open_font: invalid table index\n" )); 2016 error = FT_THROW( Invalid_Table ); 2017 goto Exit; 2018 } 2019 2020 ttc_font->table_indices[j] = table_index; 2021 2022 table = indices[table_index]; 2023 if ( table->Tag == TTAG_loca ) 2024 loca_index = table_index; 2025 if ( table->Tag == TTAG_glyf ) 2026 glyf_index = table_index; 2027 } 2028 2029 #ifdef FT_DEBUG_LEVEL_TRACE 2030 if ( ttc_font->num_tables ) 2031 FT_TRACE6(( "\n" )); 2032 #endif 2033 2034 /* glyf and loca must be consecutive */ 2035 if ( glyf_index > 0 || loca_index > 0 ) 2036 { 2037 if ( glyf_index > loca_index || 2038 loca_index - glyf_index != 1 ) 2039 { 2040 error = FT_THROW( Invalid_Table ); 2041 goto Exit; 2042 } 2043 } 2044 } 2045 2046 /* Collection directory reading complete. */ 2047 FT_TRACE2(( "WOFF2 collection directory is valid.\n" )); 2048 } 2049 else 2050 woff2.ttc_fonts = NULL; 2051 2052 woff2.compressed_offset = FT_STREAM_POS(); 2053 file_offset = ROUND4( woff2.compressed_offset + 2054 woff2.totalCompressedSize ); 2055 2056 /* Some more checks before we start reading the tables. */ 2057 if ( file_offset > woff2.length ) 2058 { 2059 error = FT_THROW( Invalid_Table ); 2060 goto Exit; 2061 } 2062 2063 if ( woff2.metaOffset ) 2064 { 2065 if ( file_offset != woff2.metaOffset ) 2066 { 2067 error = FT_THROW( Invalid_Table ); 2068 goto Exit; 2069 } 2070 file_offset = ROUND4(woff2.metaOffset + woff2.metaLength); 2071 } 2072 2073 if ( woff2.privOffset ) 2074 { 2075 if ( file_offset != woff2.privOffset ) 2076 { 2077 error = FT_THROW( Invalid_Table ); 2078 goto Exit; 2079 } 2080 file_offset = ROUND4(woff2.privOffset + woff2.privLength); 2081 } 2082 2083 if ( file_offset != ( ROUND4( woff2.length ) ) ) 2084 { 2085 error = FT_THROW( Invalid_Table ); 2086 goto Exit; 2087 } 2088 2089 /* Validate requested face index. */ 2090 *num_faces = woff2.num_fonts; 2091 /* value -(N+1) requests information on index N */ 2092 if ( *face_instance_index < 0 ) 2093 face_index--; 2094 2095 if ( face_index >= woff2.num_fonts ) 2096 { 2097 if ( *face_instance_index >= 0 ) 2098 { 2099 error = FT_THROW( Invalid_Argument ); 2100 goto Exit; 2101 } 2102 else 2103 face_index = 0; 2104 } 2105 2106 /* Only retain tables of the requested face in a TTC. */ 2107 if ( woff2.header_version ) 2108 { 2109 WOFF2_TtcFont ttc_font = woff2.ttc_fonts + face_index; 2110 2111 2112 /* Create a temporary array. */ 2113 if ( FT_NEW_ARRAY( temp_indices, 2114 ttc_font->num_tables ) ) 2115 goto Exit; 2116 2117 FT_TRACE4(( "Storing tables for TTC face index %d.\n", face_index )); 2118 for ( nn = 0; nn < ttc_font->num_tables; nn++ ) 2119 temp_indices[nn] = indices[ttc_font->table_indices[nn]]; 2120 2121 /* Resize array to required size. */ 2122 if ( FT_RENEW_ARRAY( indices, 2123 woff2.num_tables, 2124 ttc_font->num_tables ) ) 2125 goto Exit; 2126 2127 for ( nn = 0; nn < ttc_font->num_tables; nn++ ) 2128 indices[nn] = temp_indices[nn]; 2129 2130 FT_FREE( temp_indices ); 2131 2132 /* Change header values. */ 2133 woff2.flavor = ttc_font->flavor; 2134 woff2.num_tables = ttc_font->num_tables; 2135 } 2136 2137 /* We need to allocate this much at the minimum. */ 2138 sfnt_size = 12 + woff2.num_tables * 16UL; 2139 /* This is what we normally expect. */ 2140 /* Initially trust `totalSfntSize' and change later as required. */ 2141 if ( woff2.totalSfntSize > sfnt_size ) 2142 { 2143 /* However, adjust the value to something reasonable. */ 2144 2145 /* Factor 64 is heuristic. */ 2146 if ( ( woff2.totalSfntSize >> 6 ) > woff2.length ) 2147 sfnt_size = woff2.length << 6; 2148 else 2149 sfnt_size = woff2.totalSfntSize; 2150 2151 /* Value 1<<26 = 67108864 is heuristic. */ 2152 if (sfnt_size >= (1 << 26)) 2153 sfnt_size = 1 << 26; 2154 2155 #ifdef FT_DEBUG_LEVEL_TRACE 2156 if ( sfnt_size != woff2.totalSfntSize ) 2157 FT_TRACE4(( "adjusting estimate of uncompressed font size" 2158 " to %lu bytes\n", 2159 sfnt_size )); 2160 #endif 2161 } 2162 2163 /* Write sfnt header. */ 2164 if ( FT_ALLOC( sfnt, sfnt_size ) || 2165 FT_NEW( sfnt_stream ) ) 2166 goto Exit; 2167 2168 sfnt_header = sfnt; 2169 2170 WRITE_ULONG( sfnt_header, woff2.flavor ); 2171 2172 if ( woff2.num_tables ) 2173 { 2174 FT_UInt searchRange, entrySelector, rangeShift, x; 2175 2176 2177 x = woff2.num_tables; 2178 entrySelector = 0; 2179 while ( x ) 2180 { 2181 x >>= 1; 2182 entrySelector += 1; 2183 } 2184 entrySelector--; 2185 2186 searchRange = ( 1 << entrySelector ) * 16; 2187 rangeShift = ( woff2.num_tables * 16 ) - searchRange; 2188 2189 WRITE_USHORT( sfnt_header, woff2.num_tables ); 2190 WRITE_USHORT( sfnt_header, searchRange ); 2191 WRITE_USHORT( sfnt_header, entrySelector ); 2192 WRITE_USHORT( sfnt_header, rangeShift ); 2193 } 2194 2195 info.header_checksum = compute_ULong_sum( sfnt, 12 ); 2196 2197 /* Sort tables by tag. */ 2198 ft_qsort( indices, 2199 woff2.num_tables, 2200 sizeof ( WOFF2_Table ), 2201 compare_tags ); 2202 2203 if ( woff2.uncompressed_size < 1 ) 2204 { 2205 error = FT_THROW( Invalid_Table ); 2206 goto Exit; 2207 } 2208 2209 if ( woff2.uncompressed_size > sfnt_size ) 2210 { 2211 FT_ERROR(( "woff2_open_font: SFNT table lengths are too large.\n" )); 2212 error = FT_THROW( Invalid_Table ); 2213 goto Exit; 2214 } 2215 2216 /* Allocate memory for uncompressed table data. */ 2217 if ( FT_ALLOC( uncompressed_buf, woff2.uncompressed_size ) || 2218 FT_FRAME_ENTER( woff2.totalCompressedSize ) ) 2219 goto Exit; 2220 2221 /* Uncompress the stream. */ 2222 error = woff2_decompress( uncompressed_buf, 2223 woff2.uncompressed_size, 2224 stream->cursor, 2225 woff2.totalCompressedSize ); 2226 2227 FT_FRAME_EXIT(); 2228 2229 if ( error ) 2230 goto Exit; 2231 2232 error = reconstruct_font( uncompressed_buf, 2233 woff2.uncompressed_size, 2234 indices, 2235 &woff2, 2236 &info, 2237 &sfnt, 2238 &sfnt_size, 2239 memory ); 2240 2241 if ( error ) 2242 goto Exit; 2243 2244 /* Resize `sfnt' to actual size of sfnt stream. */ 2245 if ( woff2.actual_sfnt_size < sfnt_size ) 2246 { 2247 FT_TRACE5(( "Trimming sfnt stream from %lu to %lu.\n", 2248 sfnt_size, woff2.actual_sfnt_size )); 2249 if ( FT_REALLOC( sfnt, 2250 (FT_ULong)( sfnt_size ), 2251 (FT_ULong)( woff2.actual_sfnt_size ) ) ) 2252 goto Exit; 2253 } 2254 2255 /* `reconstruct_font' has done all the work. */ 2256 /* Swap out stream and return. */ 2257 FT_Stream_OpenMemory( sfnt_stream, sfnt, woff2.actual_sfnt_size ); 2258 sfnt_stream->memory = stream->memory; 2259 sfnt_stream->close = stream_close; 2260 2261 FT_Stream_Free( 2262 face->root.stream, 2263 ( face->root.face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 ); 2264 2265 face->root.stream = sfnt_stream; 2266 face->root.face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM; 2267 2268 /* Set face_index to 0 or -1. */ 2269 if ( *face_instance_index >= 0 ) 2270 *face_instance_index = 0; 2271 else 2272 *face_instance_index = -1; 2273 2274 FT_TRACE2(( "woff2_open_font: SFNT synthesized.\n" )); 2275 2276 Exit: 2277 FT_FREE( tables ); 2278 FT_FREE( indices ); 2279 FT_FREE( uncompressed_buf ); 2280 FT_FREE( info.x_mins ); 2281 2282 if ( woff2.ttc_fonts ) 2283 { 2284 WOFF2_TtcFont ttc_font = woff2.ttc_fonts; 2285 2286 2287 for ( nn = 0; nn < woff2.num_fonts; nn++ ) 2288 { 2289 FT_FREE( ttc_font->table_indices ); 2290 ttc_font++; 2291 } 2292 2293 FT_FREE( woff2.ttc_fonts ); 2294 } 2295 2296 if ( error ) 2297 { 2298 FT_FREE( sfnt ); 2299 if ( sfnt_stream ) 2300 { 2301 FT_Stream_Close( sfnt_stream ); 2302 FT_FREE( sfnt_stream ); 2303 } 2304 } 2305 2306 return error; 2307 } 2308 2309 2310 #undef READ_255USHORT 2311 #undef READ_BASE128 2312 #undef ROUND4 2313 #undef WRITE_USHORT 2314 #undef WRITE_ULONG 2315 #undef WRITE_SHORT 2316 #undef WRITE_SFNT_BUF 2317 #undef WRITE_SFNT_BUF_AT 2318 2319 #undef N_CONTOUR_STREAM 2320 #undef N_POINTS_STREAM 2321 #undef FLAG_STREAM 2322 #undef GLYPH_STREAM 2323 #undef COMPOSITE_STREAM 2324 #undef BBOX_STREAM 2325 #undef INSTRUCTION_STREAM 2326 2327 2328 /* END */