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