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