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