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