| 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 |