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
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 )
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 )
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