OLD | NEW |
1 /***************************************************************************/ | 1 /***************************************************************************/ |
2 /* */ | 2 /* */ |
3 /* ttload.c */ | 3 /* ttload.c */ |
4 /* */ | 4 /* */ |
5 /* Load the basic TrueType tables, i.e., tables that can be either in */ | 5 /* Load the basic TrueType tables, i.e., tables that can be either in */ |
6 /* TTF or OTF fonts (body). */ | 6 /* TTF or OTF fonts (body). */ |
7 /* */ | 7 /* */ |
8 /* Copyright 1996-2010, 2012-2014 by */ | 8 /* Copyright 1996-2015 by */ |
9 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ | 9 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ |
10 /* */ | 10 /* */ |
11 /* This file is part of the FreeType project, and may only be used, */ | 11 /* This file is part of the FreeType project, and may only be used, */ |
12 /* modified, and distributed under the terms of the FreeType project */ | 12 /* modified, and distributed under the terms of the FreeType project */ |
13 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ | 13 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ |
14 /* this file you indicate that you have read the license and */ | 14 /* this file you indicate that you have read the license and */ |
15 /* understand and accept it fully. */ | 15 /* understand and accept it fully. */ |
16 /* */ | 16 /* */ |
17 /***************************************************************************/ | 17 /***************************************************************************/ |
18 | 18 |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
144 else | 144 else |
145 error = FT_THROW( Table_Missing ); | 145 error = FT_THROW( Table_Missing ); |
146 | 146 |
147 Exit: | 147 Exit: |
148 return error; | 148 return error; |
149 } | 149 } |
150 | 150 |
151 | 151 |
152 /* Here, we */ | 152 /* Here, we */ |
153 /* */ | 153 /* */ |
154 /* - check that `num_tables' is valid (and adjust it if necessary) */ | 154 /* - check that `num_tables' is valid (and adjust it if necessary); */ |
| 155 /* also return the number of valid table entries */ |
155 /* */ | 156 /* */ |
156 /* - look for a `head' table, check its size, and parse it to check */ | 157 /* - look for a `head' table, check its size, and parse it to check */ |
157 /* whether its `magic' field is correctly set */ | 158 /* whether its `magic' field is correctly set */ |
158 /* */ | 159 /* */ |
159 /* - errors (except errors returned by stream handling) */ | 160 /* - errors (except errors returned by stream handling) */ |
160 /* */ | 161 /* */ |
161 /* SFNT_Err_Unknown_File_Format: */ | 162 /* SFNT_Err_Unknown_File_Format: */ |
162 /* no table is defined in directory, it is not sfnt-wrapped */ | 163 /* no table is defined in directory, it is not sfnt-wrapped */ |
163 /* data */ | 164 /* data */ |
164 /* SFNT_Err_Table_Missing: */ | 165 /* SFNT_Err_Table_Missing: */ |
165 /* table directory is valid, but essential tables */ | 166 /* table directory is valid, but essential tables */ |
166 /* (head/bhed/SING) are missing */ | 167 /* (head/bhed/SING) are missing */ |
167 /* */ | 168 /* */ |
168 static FT_Error | 169 static FT_Error |
169 check_table_dir( SFNT_Header sfnt, | 170 check_table_dir( SFNT_Header sfnt, |
170 FT_Stream stream ) | 171 FT_Stream stream, |
| 172 FT_UShort* valid ) |
171 { | 173 { |
172 FT_Error error; | 174 FT_Error error; |
173 FT_UShort nn, valid_entries = 0; | 175 FT_UShort nn, valid_entries = 0; |
174 FT_UInt has_head = 0, has_sing = 0, has_meta = 0; | 176 FT_UInt has_head = 0, has_sing = 0, has_meta = 0; |
175 FT_ULong offset = sfnt->offset + 12; | 177 FT_ULong offset = sfnt->offset + 12; |
176 | 178 |
177 static const FT_Frame_Field table_dir_entry_fields[] = | 179 static const FT_Frame_Field table_dir_entry_fields[] = |
178 { | 180 { |
179 #undef FT_STRUCTURE | 181 #undef FT_STRUCTURE |
180 #define FT_STRUCTURE TT_TableRec | 182 #define FT_STRUCTURE TT_TableRec |
(...skipping 20 matching lines...) Expand all Loading... |
201 nn--; | 203 nn--; |
202 FT_TRACE2(( "check_table_dir:" | 204 FT_TRACE2(( "check_table_dir:" |
203 " can read only %d table%s in font (instead of %d)\n", | 205 " can read only %d table%s in font (instead of %d)\n", |
204 nn, nn == 1 ? "" : "s", sfnt->num_tables )); | 206 nn, nn == 1 ? "" : "s", sfnt->num_tables )); |
205 sfnt->num_tables = nn; | 207 sfnt->num_tables = nn; |
206 break; | 208 break; |
207 } | 209 } |
208 | 210 |
209 /* we ignore invalid tables */ | 211 /* we ignore invalid tables */ |
210 | 212 |
211 /* table.Offset + table.Length > stream->size ? */ | 213 if ( table.Offset > stream->size ) |
212 if ( table.Length > stream->size || | |
213 table.Offset > stream->size - table.Length ) | |
214 { | 214 { |
215 FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn )); | 215 FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn )); |
216 continue; | 216 continue; |
217 } | 217 } |
| 218 else if ( table.Length > stream->size - table.Offset ) |
| 219 { |
| 220 /* Some tables have such a simple structure that clipping its */ |
| 221 /* contents is harmless. This also makes FreeType less sensitive */ |
| 222 /* to invalid table lengths (which programs like Acroread seem to */ |
| 223 /* ignore in general). */ |
| 224 |
| 225 if ( table.Tag == TTAG_hmtx || |
| 226 table.Tag == TTAG_vmtx ) |
| 227 valid_entries++; |
| 228 else |
| 229 { |
| 230 FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn )); |
| 231 continue; |
| 232 } |
| 233 } |
218 else | 234 else |
219 valid_entries++; | 235 valid_entries++; |
220 | 236 |
221 if ( table.Tag == TTAG_head || table.Tag == TTAG_bhed ) | 237 if ( table.Tag == TTAG_head || table.Tag == TTAG_bhed ) |
222 { | 238 { |
223 FT_UInt32 magic; | 239 FT_UInt32 magic; |
224 | 240 |
225 | 241 |
226 #ifndef TT_CONFIG_OPTION_EMBEDDED_BITMAPS | 242 #ifndef TT_CONFIG_OPTION_EMBEDDED_BITMAPS |
227 if ( table.Tag == TTAG_head ) | 243 if ( table.Tag == TTAG_head ) |
(...skipping 27 matching lines...) Expand all Loading... |
255 | 271 |
256 if ( FT_STREAM_SEEK( offset + ( nn + 1 ) * 16 ) ) | 272 if ( FT_STREAM_SEEK( offset + ( nn + 1 ) * 16 ) ) |
257 goto Exit; | 273 goto Exit; |
258 } | 274 } |
259 else if ( table.Tag == TTAG_SING ) | 275 else if ( table.Tag == TTAG_SING ) |
260 has_sing = 1; | 276 has_sing = 1; |
261 else if ( table.Tag == TTAG_META ) | 277 else if ( table.Tag == TTAG_META ) |
262 has_meta = 1; | 278 has_meta = 1; |
263 } | 279 } |
264 | 280 |
265 sfnt->num_tables = valid_entries; | 281 *valid = valid_entries; |
266 | 282 |
267 if ( sfnt->num_tables == 0 ) | 283 if ( !valid_entries ) |
268 { | 284 { |
269 FT_TRACE2(( "check_table_dir: no tables found\n" )); | 285 FT_TRACE2(( "check_table_dir: no valid tables found\n" )); |
270 error = FT_THROW( Unknown_File_Format ); | 286 error = FT_THROW( Unknown_File_Format ); |
271 goto Exit; | 287 goto Exit; |
272 } | 288 } |
273 | 289 |
274 /* if `sing' and `meta' tables are present, there is no `head' table */ | 290 /* if `sing' and `meta' tables are present, there is no `head' table */ |
275 if ( has_head || ( has_sing && has_meta ) ) | 291 if ( has_head || ( has_sing && has_meta ) ) |
276 { | 292 { |
277 error = FT_Err_Ok; | 293 error = FT_Err_Ok; |
278 goto Exit; | 294 goto Exit; |
279 } | 295 } |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
315 /* <Note> */ | 331 /* <Note> */ |
316 /* The stream cursor must be at the beginning of the font directory. */ | 332 /* The stream cursor must be at the beginning of the font directory. */ |
317 /* */ | 333 /* */ |
318 FT_LOCAL_DEF( FT_Error ) | 334 FT_LOCAL_DEF( FT_Error ) |
319 tt_face_load_font_dir( TT_Face face, | 335 tt_face_load_font_dir( TT_Face face, |
320 FT_Stream stream ) | 336 FT_Stream stream ) |
321 { | 337 { |
322 SFNT_HeaderRec sfnt; | 338 SFNT_HeaderRec sfnt; |
323 FT_Error error; | 339 FT_Error error; |
324 FT_Memory memory = stream->memory; | 340 FT_Memory memory = stream->memory; |
325 TT_TableRec* entry; | 341 FT_UShort nn, valid_entries; |
326 FT_Int nn; | |
327 | 342 |
328 static const FT_Frame_Field offset_table_fields[] = | 343 static const FT_Frame_Field offset_table_fields[] = |
329 { | 344 { |
330 #undef FT_STRUCTURE | 345 #undef FT_STRUCTURE |
331 #define FT_STRUCTURE SFNT_HeaderRec | 346 #define FT_STRUCTURE SFNT_HeaderRec |
332 | 347 |
333 FT_FRAME_START( 8 ), | 348 FT_FRAME_START( 8 ), |
334 FT_FRAME_USHORT( num_tables ), | 349 FT_FRAME_USHORT( num_tables ), |
335 FT_FRAME_USHORT( search_range ), | 350 FT_FRAME_USHORT( search_range ), |
336 FT_FRAME_USHORT( entry_selector ), | 351 FT_FRAME_USHORT( entry_selector ), |
(...skipping 20 matching lines...) Expand all Loading... |
357 #endif | 372 #endif |
358 | 373 |
359 /* load the table directory */ | 374 /* load the table directory */ |
360 | 375 |
361 FT_TRACE2(( "-- Number of tables: %10u\n", sfnt.num_tables )); | 376 FT_TRACE2(( "-- Number of tables: %10u\n", sfnt.num_tables )); |
362 FT_TRACE2(( "-- Format version: 0x%08lx\n", sfnt.format_tag )); | 377 FT_TRACE2(( "-- Format version: 0x%08lx\n", sfnt.format_tag )); |
363 | 378 |
364 if ( sfnt.format_tag != TTAG_OTTO ) | 379 if ( sfnt.format_tag != TTAG_OTTO ) |
365 { | 380 { |
366 /* check first */ | 381 /* check first */ |
367 error = check_table_dir( &sfnt, stream ); | 382 error = check_table_dir( &sfnt, stream, &valid_entries ); |
368 if ( error ) | 383 if ( error ) |
369 { | 384 { |
370 FT_TRACE2(( "tt_face_load_font_dir:" | 385 FT_TRACE2(( "tt_face_load_font_dir:" |
371 " invalid table directory for TrueType\n" )); | 386 " invalid table directory for TrueType\n" )); |
372 | |
373 goto Exit; | 387 goto Exit; |
374 } | 388 } |
375 } | 389 } |
| 390 else |
| 391 valid_entries = sfnt.num_tables; |
376 | 392 |
377 face->num_tables = sfnt.num_tables; | 393 face->num_tables = valid_entries; |
378 face->format_tag = sfnt.format_tag; | 394 face->format_tag = sfnt.format_tag; |
379 | 395 |
380 if ( FT_QNEW_ARRAY( face->dir_tables, face->num_tables ) ) | 396 if ( FT_QNEW_ARRAY( face->dir_tables, face->num_tables ) ) |
381 goto Exit; | 397 goto Exit; |
382 | 398 |
383 if ( FT_STREAM_SEEK( sfnt.offset + 12 ) || | 399 if ( FT_STREAM_SEEK( sfnt.offset + 12 ) || |
384 FT_FRAME_ENTER( face->num_tables * 16L ) ) | 400 FT_FRAME_ENTER( sfnt.num_tables * 16L ) ) |
385 goto Exit; | 401 goto Exit; |
386 | 402 |
387 entry = face->dir_tables; | |
388 | |
389 FT_TRACE2(( "\n" | 403 FT_TRACE2(( "\n" |
390 " tag offset length checksum\n" | 404 " tag offset length checksum\n" |
391 " ----------------------------------\n" )); | 405 " ----------------------------------\n" )); |
392 | 406 |
| 407 valid_entries = 0; |
393 for ( nn = 0; nn < sfnt.num_tables; nn++ ) | 408 for ( nn = 0; nn < sfnt.num_tables; nn++ ) |
394 { | 409 { |
395 entry->Tag = FT_GET_TAG4(); | 410 TT_TableRec entry; |
396 entry->CheckSum = FT_GET_ULONG(); | 411 FT_UShort i; |
397 entry->Offset = FT_GET_ULONG(); | 412 FT_Bool duplicate; |
398 entry->Length = FT_GET_ULONG(); | |
399 | 413 |
400 /* ignore invalid tables */ | |
401 | 414 |
402 /* entry->Offset + entry->Length > stream->size ? */ | 415 entry.Tag = FT_GET_TAG4(); |
403 if ( entry->Length > stream->size || | 416 entry.CheckSum = FT_GET_ULONG(); |
404 entry->Offset > stream->size - entry->Length ) | 417 entry.Offset = FT_GET_ULONG(); |
| 418 entry.Length = FT_GET_ULONG(); |
| 419 |
| 420 /* ignore invalid tables that can't be sanitized */ |
| 421 |
| 422 if ( entry.Offset > stream->size ) |
405 continue; | 423 continue; |
| 424 else if ( entry.Length > stream->size - entry.Offset ) |
| 425 { |
| 426 if ( entry.Tag == TTAG_hmtx || |
| 427 entry.Tag == TTAG_vmtx ) |
| 428 { |
| 429 #ifdef FT_DEBUG_LEVEL_TRACE |
| 430 FT_ULong old_length = entry.Length; |
| 431 #endif |
| 432 |
| 433 |
| 434 /* make metrics table length a multiple of 4 */ |
| 435 entry.Length = ( stream->size - entry.Offset ) & ~3U; |
| 436 |
| 437 FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx" |
| 438 " (sanitized; original length %08lx)", |
| 439 (FT_Char)( entry.Tag >> 24 ), |
| 440 (FT_Char)( entry.Tag >> 16 ), |
| 441 (FT_Char)( entry.Tag >> 8 ), |
| 442 (FT_Char)( entry.Tag ), |
| 443 entry.Offset, |
| 444 entry.Length, |
| 445 entry.CheckSum, |
| 446 old_length )); |
| 447 } |
| 448 else |
| 449 continue; |
| 450 } |
| 451 #ifdef FT_DEBUG_LEVEL_TRACE |
| 452 else |
| 453 FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx", |
| 454 (FT_Char)( entry.Tag >> 24 ), |
| 455 (FT_Char)( entry.Tag >> 16 ), |
| 456 (FT_Char)( entry.Tag >> 8 ), |
| 457 (FT_Char)( entry.Tag ), |
| 458 entry.Offset, |
| 459 entry.Length, |
| 460 entry.CheckSum )); |
| 461 #endif |
| 462 |
| 463 /* ignore duplicate tables – the first one wins */ |
| 464 duplicate = 0; |
| 465 for ( i = 0; i < valid_entries; i++ ) |
| 466 { |
| 467 if ( face->dir_tables[i].Tag == entry.Tag ) |
| 468 { |
| 469 duplicate = 1; |
| 470 break; |
| 471 } |
| 472 } |
| 473 if ( duplicate ) |
| 474 { |
| 475 FT_TRACE2(( " (duplicate, ignored)\n" )); |
| 476 continue; |
| 477 } |
406 else | 478 else |
407 { | 479 { |
408 FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx\n", | 480 FT_TRACE2(( "\n" )); |
409 (FT_Char)( entry->Tag >> 24 ), | 481 |
410 (FT_Char)( entry->Tag >> 16 ), | 482 /* we finally have a valid entry */ |
411 (FT_Char)( entry->Tag >> 8 ), | 483 face->dir_tables[valid_entries++] = entry; |
412 (FT_Char)( entry->Tag ), | |
413 entry->Offset, | |
414 entry->Length, | |
415 entry->CheckSum )); | |
416 entry++; | |
417 } | 484 } |
418 } | 485 } |
419 | 486 |
| 487 /* final adjustment to number of tables */ |
| 488 face->num_tables = valid_entries; |
| 489 |
420 FT_FRAME_EXIT(); | 490 FT_FRAME_EXIT(); |
421 | 491 |
422 FT_TRACE2(( "table directory loaded\n\n" )); | 492 FT_TRACE2(( "table directory loaded\n\n" )); |
423 | 493 |
424 Exit: | 494 Exit: |
425 return error; | 495 return error; |
426 } | 496 } |
427 | 497 |
428 | 498 |
429 /*************************************************************************/ | 499 /*************************************************************************/ |
(...skipping 854 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1284 } | 1354 } |
1285 | 1355 |
1286 FT_FRAME_EXIT(); | 1356 FT_FRAME_EXIT(); |
1287 | 1357 |
1288 Exit: | 1358 Exit: |
1289 return error; | 1359 return error; |
1290 } | 1360 } |
1291 | 1361 |
1292 | 1362 |
1293 /* END */ | 1363 /* END */ |
OLD | NEW |