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