Coverage Report

Created: 2021-08-22 09:07

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