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