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