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