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