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