layout.cc (65426B)
1 // Copyright (c) 2011-2017 The OTS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "layout.h" 6 7 #include <limits> 8 #include <vector> 9 10 #include "fvar.h" 11 #include "gdef.h" 12 #include "maxp.h" 13 14 // OpenType Layout Common Table Formats 15 // http://www.microsoft.com/typography/otspec/chapter2.htm 16 17 #define TABLE_NAME "Layout" // XXX: use individual table names 18 19 namespace { 20 21 // The 'DFLT' tag of script table. 22 const uint32_t kScriptTableTagDflt = 0x44464c54; 23 // The value which represents there is no required feature index. 24 const uint16_t kNoRequiredFeatureIndexDefined = 0xFFFF; 25 // The lookup flag bit which indicates existence of MarkFilteringSet. 26 const uint16_t kUseMarkFilteringSetBit = 0x0010; 27 // The maximum type number of format for device tables. 28 const uint16_t kMaxDeltaFormatType = 3; 29 // In variation fonts, Device Tables are replaced by VariationIndex tables, 30 // indicated by this flag in the deltaFormat field. 31 const uint16_t kVariationIndex = 0x8000; 32 33 struct ScriptRecord { 34 uint32_t tag; 35 uint16_t offset; 36 }; 37 38 struct LangSysRecord { 39 uint32_t tag; 40 uint16_t offset; 41 }; 42 43 struct FeatureRecord { 44 uint32_t tag; 45 uint16_t offset; 46 }; 47 48 bool ParseLangSysTable(const ots::Font *font, 49 ots::Buffer *subtable, const uint32_t tag, 50 const uint16_t num_features) { 51 uint16_t offset_lookup_order = 0; 52 uint16_t req_feature_index = 0; 53 uint16_t feature_count = 0; 54 if (!subtable->ReadU16(&offset_lookup_order) || 55 !subtable->ReadU16(&req_feature_index) || 56 !subtable->ReadU16(&feature_count)) { 57 return OTS_FAILURE_MSG("Failed to read langsys header for tag %c%c%c%c", OTS_UNTAG(tag)); 58 } 59 // |offset_lookup_order| is reserved and should be NULL. 60 if (offset_lookup_order != 0) { 61 return OTS_FAILURE_MSG("Bad lookup offset order %d for langsys tag %c%c%c%c", offset_lookup_order, OTS_UNTAG(tag)); 62 } 63 if (req_feature_index != kNoRequiredFeatureIndexDefined && 64 req_feature_index >= num_features) { 65 return OTS_FAILURE_MSG("Bad required features index %d for langsys tag %c%c%c%c", req_feature_index, OTS_UNTAG(tag)); 66 } 67 if (feature_count > num_features) { 68 return OTS_FAILURE_MSG("Bad feature count %d for langsys tag %c%c%c%c", feature_count, OTS_UNTAG(tag)); 69 } 70 71 for (unsigned i = 0; i < feature_count; ++i) { 72 uint16_t feature_index = 0; 73 if (!subtable->ReadU16(&feature_index)) { 74 return OTS_FAILURE_MSG("Failed to read feature index %d for langsys tag %c%c%c%c", i, OTS_UNTAG(tag)); 75 } 76 if (feature_index >= num_features) { 77 return OTS_FAILURE_MSG("Bad feature index %d for feature %d for langsys tag %c%c%c%c", feature_index, i, OTS_UNTAG(tag)); 78 } 79 } 80 return true; 81 } 82 83 bool ParseScriptTable(const ots::Font *font, 84 const uint8_t *data, const size_t length, 85 const uint32_t tag, const uint16_t num_features) { 86 ots::Buffer subtable(data, length); 87 88 uint16_t offset_default_lang_sys = 0; 89 uint16_t lang_sys_count = 0; 90 if (!subtable.ReadU16(&offset_default_lang_sys) || 91 !subtable.ReadU16(&lang_sys_count)) { 92 return OTS_FAILURE_MSG("Failed to read script header for script tag %c%c%c%c", OTS_UNTAG(tag)); 93 } 94 95 // The spec requires a script table for 'DFLT' tag must contain non-NULL 96 // |offset_default_lang_sys|. 97 // https://www.microsoft.com/typography/otspec/chapter2.htm 98 if (tag == kScriptTableTagDflt) { 99 if (offset_default_lang_sys == 0) { 100 return OTS_FAILURE_MSG("DFLT script doesn't satisfy the spec. DefaultLangSys is NULL"); 101 } 102 } 103 104 const unsigned lang_sys_record_end = 105 6 * static_cast<unsigned>(lang_sys_count) + 4; 106 if (lang_sys_record_end > std::numeric_limits<uint16_t>::max()) { 107 return OTS_FAILURE_MSG("Bad end of langsys record %d for script tag %c%c%c%c", lang_sys_record_end, OTS_UNTAG(tag)); 108 } 109 110 std::vector<LangSysRecord> lang_sys_records; 111 lang_sys_records.resize(lang_sys_count); 112 uint32_t last_tag = 0; 113 for (unsigned i = 0; i < lang_sys_count; ++i) { 114 if (!subtable.ReadU32(&lang_sys_records[i].tag) || 115 !subtable.ReadU16(&lang_sys_records[i].offset)) { 116 return OTS_FAILURE_MSG("Failed to read langsys record header %d for script tag %c%c%c%c", i, OTS_UNTAG(tag)); 117 } 118 // The record array must store the records alphabetically by tag 119 if (last_tag != 0 && last_tag > lang_sys_records[i].tag) { 120 return OTS_FAILURE_MSG("Bad last tag %d for langsys record %d for script tag %c%c%c%c", last_tag, i, OTS_UNTAG(tag)); 121 } 122 if (lang_sys_records[i].offset < lang_sys_record_end || 123 lang_sys_records[i].offset >= length) { 124 return OTS_FAILURE_MSG("bad offset to lang sys table: %x", 125 lang_sys_records[i].offset); 126 } 127 last_tag = lang_sys_records[i].tag; 128 } 129 130 // Check lang sys tables 131 for (unsigned i = 0; i < lang_sys_count; ++i) { 132 subtable.set_offset(lang_sys_records[i].offset); 133 if (!ParseLangSysTable(font, &subtable, lang_sys_records[i].tag, num_features)) { 134 return OTS_FAILURE_MSG("Failed to parse langsys table %d (%c%c%c%c) for script tag %c%c%c%c", i, OTS_UNTAG(lang_sys_records[i].tag), OTS_UNTAG(tag)); 135 } 136 } 137 138 return true; 139 } 140 141 bool ParseFeatureTable(const ots::Font *font, 142 const uint8_t *data, const size_t length, 143 const uint16_t num_lookups) { 144 ots::Buffer subtable(data, length); 145 146 uint16_t offset_feature_params = 0; 147 uint16_t lookup_count = 0; 148 if (!subtable.ReadU16(&offset_feature_params) || 149 !subtable.ReadU16(&lookup_count)) { 150 return OTS_FAILURE_MSG("Failed to read feature table header"); 151 } 152 153 const unsigned feature_table_end = 154 2 * static_cast<unsigned>(lookup_count) + 4; 155 if (feature_table_end > std::numeric_limits<uint16_t>::max()) { 156 return OTS_FAILURE_MSG("Bad end of feature table %d", feature_table_end); 157 } 158 // |offset_feature_params| is generally set to NULL. 159 if (offset_feature_params != 0 && 160 (offset_feature_params < feature_table_end || 161 offset_feature_params >= length)) { 162 return OTS_FAILURE_MSG("Bad feature params offset %d", offset_feature_params); 163 } 164 165 for (unsigned i = 0; i < lookup_count; ++i) { 166 uint16_t lookup_index = 0; 167 if (!subtable.ReadU16(&lookup_index)) { 168 return OTS_FAILURE_MSG("Failed to read lookup index for lookup %d", i); 169 } 170 // lookup index starts with 0. 171 if (lookup_index >= num_lookups) { 172 return OTS_FAILURE_MSG("Bad lookup index %d for lookup %d", lookup_index, i); 173 } 174 } 175 return true; 176 } 177 178 bool ParseClassDefFormat1(const ots::Font *font, 179 const uint8_t *data, size_t length, 180 const uint16_t num_glyphs, 181 const uint16_t num_classes) { 182 ots::Buffer subtable(data, length); 183 184 // Skip format field. 185 if (!subtable.Skip(2)) { 186 return OTS_FAILURE_MSG("Failed to skip class definition header"); 187 } 188 189 uint16_t start_glyph = 0; 190 if (!subtable.ReadU16(&start_glyph)) { 191 return OTS_FAILURE_MSG("Failed to read starting glyph of class definition"); 192 } 193 if (start_glyph > num_glyphs) { 194 return OTS_FAILURE_MSG("Bad starting glyph %d in class definition", start_glyph); 195 } 196 197 uint16_t glyph_count = 0; 198 if (!subtable.ReadU16(&glyph_count)) { 199 return OTS_FAILURE_MSG("Failed to read glyph count in class definition"); 200 } 201 if (glyph_count > num_glyphs) { 202 return OTS_FAILURE_MSG("bad glyph count: %u", glyph_count); 203 } 204 for (unsigned i = 0; i < glyph_count; ++i) { 205 uint16_t class_value = 0; 206 if (!subtable.ReadU16(&class_value)) { 207 return OTS_FAILURE_MSG("Failed to read class value for glyph %d in class definition", i); 208 } 209 if (class_value > num_classes) { 210 return OTS_FAILURE_MSG("Bad class value %d for glyph %d in class definition", class_value, i); 211 } 212 } 213 214 return true; 215 } 216 217 bool ParseClassDefFormat2(const ots::Font *font, 218 const uint8_t *data, size_t length, 219 const uint16_t num_glyphs, 220 const uint16_t num_classes) { 221 ots::Buffer subtable(data, length); 222 223 // Skip format field. 224 if (!subtable.Skip(2)) { 225 return OTS_FAILURE_MSG("Failed to read class definition format"); 226 } 227 228 uint16_t range_count = 0; 229 if (!subtable.ReadU16(&range_count)) { 230 return OTS_FAILURE_MSG("Failed to read classRangeCount"); 231 } 232 if (range_count > num_glyphs) { 233 return OTS_FAILURE_MSG("classRangeCount > glyph count: %u > %u", range_count, num_glyphs); 234 } 235 236 uint16_t last_end = 0; 237 for (unsigned i = 0; i < range_count; ++i) { 238 uint16_t start = 0; 239 uint16_t end = 0; 240 uint16_t class_value = 0; 241 if (!subtable.ReadU16(&start) || 242 !subtable.ReadU16(&end) || 243 !subtable.ReadU16(&class_value)) { 244 return OTS_FAILURE_MSG("Failed to read ClassRangeRecord %d", i); 245 } 246 if (start > end) { 247 return OTS_FAILURE_MSG("ClassRangeRecord %d, start > end: %u > %u", i, start, end); 248 } 249 if (last_end && start <= last_end) { 250 return OTS_FAILURE_MSG("ClassRangeRecord %d start overlaps with end of the previous one: %u <= %u", i, start, last_end); 251 } 252 if (class_value > num_classes) { 253 return OTS_FAILURE_MSG("ClassRangeRecord %d class > number of classes: %u > %u", i, class_value, num_classes); 254 } 255 last_end = end; 256 } 257 258 return true; 259 } 260 261 bool ParseCoverageFormat1(const ots::Font *font, 262 const uint8_t *data, size_t length, 263 const uint16_t num_glyphs, 264 const uint16_t expected_num_glyphs) { 265 ots::Buffer subtable(data, length); 266 267 // Skip format field. 268 if (!subtable.Skip(2)) { 269 return OTS_FAILURE_MSG("Failed to skip coverage format"); 270 } 271 272 uint16_t glyph_count = 0; 273 if (!subtable.ReadU16(&glyph_count)) { 274 return OTS_FAILURE_MSG("Failed to read glyph count in coverage"); 275 } 276 if (glyph_count > num_glyphs) { 277 return OTS_FAILURE_MSG("bad glyph count: %u", glyph_count); 278 } 279 for (unsigned i = 0; i < glyph_count; ++i) { 280 uint16_t glyph = 0; 281 if (!subtable.ReadU16(&glyph)) { 282 return OTS_FAILURE_MSG("Failed to read glyph %d in coverage", i); 283 } 284 if (glyph > num_glyphs) { 285 return OTS_FAILURE_MSG("bad glyph ID: %u", glyph); 286 } 287 } 288 289 if (expected_num_glyphs && expected_num_glyphs != glyph_count) { 290 return OTS_FAILURE_MSG("unexpected number of glyphs: %u", glyph_count); 291 } 292 293 return true; 294 } 295 296 bool ParseCoverageFormat2(const ots::Font *font, 297 const uint8_t *data, size_t length, 298 const uint16_t num_glyphs, 299 const uint16_t expected_num_glyphs) { 300 ots::Buffer subtable(data, length); 301 302 // Skip format field. 303 if (!subtable.Skip(2)) { 304 return OTS_FAILURE_MSG("Failed to skip format of coverage type 2"); 305 } 306 307 uint16_t range_count = 0; 308 if (!subtable.ReadU16(&range_count)) { 309 return OTS_FAILURE_MSG("Failed to read range count in coverage"); 310 } 311 if (range_count > num_glyphs) { 312 return OTS_FAILURE_MSG("bad range count: %u", range_count); 313 } 314 uint16_t last_end = 0; 315 uint16_t last_start_coverage_index = 0; 316 for (unsigned i = 0; i < range_count; ++i) { 317 uint16_t start = 0; 318 uint16_t end = 0; 319 uint16_t start_coverage_index = 0; 320 if (!subtable.ReadU16(&start) || 321 !subtable.ReadU16(&end) || 322 !subtable.ReadU16(&start_coverage_index)) { 323 return OTS_FAILURE_MSG("Failed to read range %d in coverage", i); 324 } 325 326 // Some of the Adobe Pro fonts have ranges that overlap by one element: the 327 // start of one range is equal to the end of the previous range. Therefore 328 // the < in the following condition should be <= were it not for this. 329 // See crbug.com/134135. 330 if (start > end || (last_end && start < last_end)) { 331 return OTS_FAILURE_MSG("glyph range is overlapping."); 332 } 333 if (start_coverage_index != last_start_coverage_index) { 334 return OTS_FAILURE_MSG("bad start coverage index."); 335 } 336 last_end = end; 337 last_start_coverage_index += end - start + 1; 338 } 339 340 if (expected_num_glyphs && 341 expected_num_glyphs != last_start_coverage_index) { 342 return OTS_FAILURE_MSG("unexpected number of glyphs: %u", last_start_coverage_index); 343 } 344 345 return true; 346 } 347 348 // Parsers for Contextual subtables in GSUB/GPOS tables. 349 350 bool ParseLookupRecord(const ots::Font *font, 351 ots::Buffer *subtable, const uint16_t num_glyphs, 352 const uint16_t num_lookups) { 353 uint16_t sequence_index = 0; 354 uint16_t lookup_list_index = 0; 355 if (!subtable->ReadU16(&sequence_index) || 356 !subtable->ReadU16(&lookup_list_index)) { 357 return OTS_FAILURE_MSG("Failed to read header for lookup record"); 358 } 359 if (sequence_index >= num_glyphs) { 360 return OTS_FAILURE_MSG("Bad sequence index %d in lookup record", sequence_index); 361 } 362 if (lookup_list_index >= num_lookups) { 363 return OTS_FAILURE_MSG("Bad lookup list index %d in lookup record", lookup_list_index); 364 } 365 return true; 366 } 367 368 bool ParseRuleSubtable(const ots::Font *font, 369 const uint8_t *data, const size_t length, 370 const uint16_t num_glyphs, 371 const uint16_t num_lookups) { 372 ots::Buffer subtable(data, length); 373 374 uint16_t glyph_count = 0; 375 uint16_t lookup_count = 0; 376 if (!subtable.ReadU16(&glyph_count) || 377 !subtable.ReadU16(&lookup_count)) { 378 return OTS_FAILURE_MSG("Failed to read rule subtable header"); 379 } 380 381 if (glyph_count == 0) { 382 return OTS_FAILURE_MSG("Bad glyph count %d in rule subtable", glyph_count); 383 } 384 for (unsigned i = 0; i < glyph_count - static_cast<unsigned>(1); ++i) { 385 uint16_t glyph_id = 0; 386 if (!subtable.ReadU16(&glyph_id)) { 387 return OTS_FAILURE_MSG("Failed to read glyph %d", i); 388 } 389 if (glyph_id > num_glyphs) { 390 return OTS_FAILURE_MSG("Bad glyph %d for entry %d", glyph_id, i); 391 } 392 } 393 394 for (unsigned i = 0; i < lookup_count; ++i) { 395 if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) { 396 return OTS_FAILURE_MSG("Failed to parse lookup record %d", i); 397 } 398 } 399 return true; 400 } 401 402 bool ParseRuleSetTable(const ots::Font *font, 403 const uint8_t *data, const size_t length, 404 const uint16_t num_glyphs, 405 const uint16_t num_lookups) { 406 ots::Buffer subtable(data, length); 407 408 uint16_t rule_count = 0; 409 if (!subtable.ReadU16(&rule_count)) { 410 return OTS_FAILURE_MSG("Failed to read rule count in rule set"); 411 } 412 const unsigned rule_end = 2 * static_cast<unsigned>(rule_count) + 2; 413 if (rule_end > std::numeric_limits<uint16_t>::max()) { 414 return OTS_FAILURE_MSG("Bad end of rule %d in rule set", rule_end); 415 } 416 417 for (unsigned i = 0; i < rule_count; ++i) { 418 uint16_t offset_rule = 0; 419 if (!subtable.ReadU16(&offset_rule)) { 420 return OTS_FAILURE_MSG("Failed to read rule offset for rule set %d", i); 421 } 422 if (offset_rule < rule_end || offset_rule >= length) { 423 return OTS_FAILURE_MSG("Bad rule offset %d in set %d", offset_rule, i); 424 } 425 if (!ParseRuleSubtable(font, data + offset_rule, length - offset_rule, 426 num_glyphs, num_lookups)) { 427 return OTS_FAILURE_MSG("Failed to parse rule set %d", i); 428 } 429 } 430 431 return true; 432 } 433 434 bool ParseContextFormat1(const ots::Font *font, 435 const uint8_t *data, const size_t length, 436 const uint16_t num_glyphs, 437 const uint16_t num_lookups) { 438 ots::Buffer subtable(data, length); 439 440 uint16_t offset_coverage = 0; 441 uint16_t rule_set_count = 0; 442 // Skip format field. 443 if (!subtable.Skip(2) || 444 !subtable.ReadU16(&offset_coverage) || 445 !subtable.ReadU16(&rule_set_count)) { 446 return OTS_FAILURE_MSG("Failed to read header of context format 1"); 447 } 448 449 const unsigned rule_set_end = static_cast<unsigned>(6) + 450 rule_set_count * 2; 451 if (rule_set_end > std::numeric_limits<uint16_t>::max()) { 452 return OTS_FAILURE_MSG("Bad end of rule set %d of context format 1", rule_set_end); 453 } 454 if (offset_coverage < rule_set_end || offset_coverage >= length) { 455 return OTS_FAILURE_MSG("Bad coverage offset %d in context format 1", offset_coverage); 456 } 457 if (!ots::ParseCoverageTable(font, data + offset_coverage, 458 length - offset_coverage, num_glyphs)) { 459 return OTS_FAILURE_MSG("Failed to parse coverage table in context format 1"); 460 } 461 462 for (unsigned i = 0; i < rule_set_count; ++i) { 463 uint16_t offset_rule = 0; 464 if (!subtable.ReadU16(&offset_rule)) { 465 return OTS_FAILURE_MSG("Failed to read rule offset %d in context format 1", i); 466 } 467 if (offset_rule < rule_set_end || offset_rule >= length) { 468 return OTS_FAILURE_MSG("Bad rule offset %d in rule %d in context format 1", offset_rule, i); 469 } 470 if (!ParseRuleSetTable(font, data + offset_rule, length - offset_rule, 471 num_glyphs, num_lookups)) { 472 return OTS_FAILURE_MSG("Failed to parse rule set %d in context format 1", i); 473 } 474 } 475 476 return true; 477 } 478 479 bool ParseClassRuleTable(const ots::Font *font, 480 const uint8_t *data, const size_t length, 481 const uint16_t num_glyphs, 482 const uint16_t num_lookups) { 483 ots::Buffer subtable(data, length); 484 485 uint16_t glyph_count = 0; 486 uint16_t lookup_count = 0; 487 if (!subtable.ReadU16(&glyph_count) || 488 !subtable.ReadU16(&lookup_count)) { 489 return OTS_FAILURE_MSG("Failed to read header of class rule table"); 490 } 491 492 if (glyph_count == 0 || glyph_count >= num_glyphs) { 493 return OTS_FAILURE_MSG("Bad glyph count %d in class rule table", glyph_count); 494 } 495 496 // ClassRule table contains an array of classes. Each value of classes 497 // could take arbitrary values including zero so we don't check these value. 498 const unsigned num_classes = glyph_count - static_cast<unsigned>(1); 499 if (!subtable.Skip(2 * num_classes)) { 500 return OTS_FAILURE_MSG("Failed to skip classes in class rule table"); 501 } 502 503 for (unsigned i = 0; i < lookup_count; ++i) { 504 if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) { 505 return OTS_FAILURE_MSG("Failed to parse lookup record %d in class rule table", i); 506 } 507 } 508 return true; 509 } 510 511 bool ParseClassSetTable(const ots::Font *font, 512 const uint8_t *data, const size_t length, 513 const uint16_t num_glyphs, 514 const uint16_t num_lookups) { 515 ots::Buffer subtable(data, length); 516 517 uint16_t class_rule_count = 0; 518 if (!subtable.ReadU16(&class_rule_count)) { 519 return OTS_FAILURE_MSG("Failed to read class rule count in class set table"); 520 } 521 const unsigned class_rule_end = 522 2 * static_cast<unsigned>(class_rule_count) + 2; 523 if (class_rule_end > std::numeric_limits<uint16_t>::max()) { 524 return OTS_FAILURE_MSG("bad class rule end %d in class set table", class_rule_end); 525 } 526 for (unsigned i = 0; i < class_rule_count; ++i) { 527 uint16_t offset_class_rule = 0; 528 if (!subtable.ReadU16(&offset_class_rule)) { 529 return OTS_FAILURE_MSG("Failed to read class rule offset %d in class set table", i); 530 } 531 if (offset_class_rule < class_rule_end || offset_class_rule >= length) { 532 return OTS_FAILURE_MSG("Bad class rule offset %d in class %d", offset_class_rule, i); 533 } 534 if (!ParseClassRuleTable(font, data + offset_class_rule, 535 length - offset_class_rule, num_glyphs, 536 num_lookups)) { 537 return OTS_FAILURE_MSG("Failed to parse class rule table %d", i); 538 } 539 } 540 541 return true; 542 } 543 544 bool ParseContextFormat2(const ots::Font *font, 545 const uint8_t *data, const size_t length, 546 const uint16_t num_glyphs, 547 const uint16_t num_lookups) { 548 ots::Buffer subtable(data, length); 549 550 uint16_t offset_coverage = 0; 551 uint16_t offset_class_def = 0; 552 uint16_t class_set_cnt = 0; 553 // Skip format field. 554 if (!subtable.Skip(2) || 555 !subtable.ReadU16(&offset_coverage) || 556 !subtable.ReadU16(&offset_class_def) || 557 !subtable.ReadU16(&class_set_cnt)) { 558 return OTS_FAILURE_MSG("Failed to read header for context format 2"); 559 } 560 561 const unsigned class_set_end = 2 * static_cast<unsigned>(class_set_cnt) + 8; 562 if (class_set_end > std::numeric_limits<uint16_t>::max()) { 563 return OTS_FAILURE_MSG("Bad end of class set %d for context format 2", class_set_end); 564 } 565 if (offset_coverage < class_set_end || offset_coverage >= length) { 566 return OTS_FAILURE_MSG("Bad coverage offset %d in context format 2", offset_coverage); 567 } 568 if (!ots::ParseCoverageTable(font, data + offset_coverage, 569 length - offset_coverage, num_glyphs)) { 570 return OTS_FAILURE_MSG("Failed to parse coverage table in context format 2"); 571 } 572 573 if (offset_class_def < class_set_end || offset_class_def >= length) { 574 return OTS_FAILURE_MSG("bad class definition offset %d in context format 2", offset_class_def); 575 } 576 if (!ots::ParseClassDefTable(font, data + offset_class_def, 577 length - offset_class_def, 578 num_glyphs, ots::kMaxClassDefValue)) { 579 return OTS_FAILURE_MSG("Failed to parse class definition table in context format 2"); 580 } 581 582 for (unsigned i = 0; i < class_set_cnt; ++i) { 583 uint16_t offset_class_rule = 0; 584 if (!subtable.ReadU16(&offset_class_rule)) { 585 return OTS_FAILURE_MSG("Failed to read class rule offset %d in context format 2", i); 586 } 587 if (offset_class_rule) { 588 if (offset_class_rule < class_set_end || offset_class_rule >= length) { 589 return OTS_FAILURE_MSG("Bad class rule offset %d for rule %d in context format 2", offset_class_rule, i); 590 } 591 if (!ParseClassSetTable(font, data + offset_class_rule, 592 length - offset_class_rule, num_glyphs, 593 num_lookups)) { 594 return OTS_FAILURE_MSG("Failed to parse class set %d in context format 2", i); 595 } 596 } 597 } 598 599 return true; 600 } 601 602 bool ParseContextFormat3(const ots::Font *font, 603 const uint8_t *data, const size_t length, 604 const uint16_t num_glyphs, 605 const uint16_t num_lookups) { 606 ots::Buffer subtable(data, length); 607 608 uint16_t glyph_count = 0; 609 uint16_t lookup_count = 0; 610 // Skip format field. 611 if (!subtable.Skip(2) || 612 !subtable.ReadU16(&glyph_count) || 613 !subtable.ReadU16(&lookup_count)) { 614 return OTS_FAILURE_MSG("Failed to read header in context format 3"); 615 } 616 617 if (glyph_count >= num_glyphs) { 618 return OTS_FAILURE_MSG("Bad glyph count %d in context format 3", glyph_count); 619 } 620 const unsigned lookup_record_end = 2 * static_cast<unsigned>(glyph_count) + 621 4 * static_cast<unsigned>(lookup_count) + 6; 622 if (lookup_record_end > std::numeric_limits<uint16_t>::max()) { 623 return OTS_FAILURE_MSG("Bad end of lookup %d in context format 3", lookup_record_end); 624 } 625 for (unsigned i = 0; i < glyph_count; ++i) { 626 uint16_t offset_coverage = 0; 627 if (!subtable.ReadU16(&offset_coverage)) { 628 return OTS_FAILURE_MSG("Failed to read coverage offset %d in conxtext format 3", i); 629 } 630 if (offset_coverage < lookup_record_end || offset_coverage >= length) { 631 return OTS_FAILURE_MSG("Bad coverage offset %d for glyph %d in context format 3", offset_coverage, i); 632 } 633 if (!ots::ParseCoverageTable(font, data + offset_coverage, 634 length - offset_coverage, num_glyphs)) { 635 return OTS_FAILURE_MSG("Failed to parse coverage table for glyph %d in context format 3", i); 636 } 637 } 638 639 for (unsigned i = 0; i < lookup_count; ++i) { 640 if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) { 641 return OTS_FAILURE_MSG("Failed to parse lookup record %d in context format 3", i); 642 } 643 } 644 645 return true; 646 } 647 648 // Parsers for Chaning Contextual subtables in GSUB/GPOS tables. 649 650 bool ParseChainRuleSubtable(const ots::Font *font, 651 const uint8_t *data, const size_t length, 652 const uint16_t num_glyphs, 653 const uint16_t num_lookups) { 654 ots::Buffer subtable(data, length); 655 656 uint16_t backtrack_count = 0; 657 if (!subtable.ReadU16(&backtrack_count)) { 658 return OTS_FAILURE_MSG("Failed to read backtrack count in chain rule subtable"); 659 } 660 for (unsigned i = 0; i < backtrack_count; ++i) { 661 uint16_t glyph_id = 0; 662 if (!subtable.ReadU16(&glyph_id)) { 663 return OTS_FAILURE_MSG("Failed to read backtrack glyph %d in chain rule subtable", i); 664 } 665 if (glyph_id > num_glyphs) { 666 return OTS_FAILURE_MSG("Bad glyph id %d for bactrack glyph %d in chain rule subtable", glyph_id, i); 667 } 668 } 669 670 uint16_t input_count = 0; 671 if (!subtable.ReadU16(&input_count)) { 672 return OTS_FAILURE_MSG("Failed to read input count in chain rule subtable"); 673 } 674 if (input_count == 0) { 675 return OTS_FAILURE_MSG("Bad input count %d in chain rule subtable", input_count); 676 } 677 for (unsigned i = 0; i < input_count - static_cast<unsigned>(1); ++i) { 678 uint16_t glyph_id = 0; 679 if (!subtable.ReadU16(&glyph_id)) { 680 return OTS_FAILURE_MSG("Failed to read input glyph %d in chain rule subtable", i); 681 } 682 if (glyph_id > num_glyphs) { 683 return OTS_FAILURE_MSG("Bad glyph id %d for input glyph %d in chain rule subtable", glyph_id, i); 684 } 685 } 686 687 uint16_t lookahead_count = 0; 688 if (!subtable.ReadU16(&lookahead_count)) { 689 return OTS_FAILURE_MSG("Failed to read lookahead count in chain rule subtable"); 690 } 691 for (unsigned i = 0; i < lookahead_count; ++i) { 692 uint16_t glyph_id = 0; 693 if (!subtable.ReadU16(&glyph_id)) { 694 return OTS_FAILURE_MSG("Failed to read lookahead glyph %d in chain rule subtable", i); 695 } 696 if (glyph_id > num_glyphs) { 697 return OTS_FAILURE_MSG("Bad glyph id %d for lookadhead glyph %d in chain rule subtable", glyph_id, i); 698 } 699 } 700 701 uint16_t lookup_count = 0; 702 if (!subtable.ReadU16(&lookup_count)) { 703 return OTS_FAILURE_MSG("Failed to read lookup count in chain rule subtable"); 704 } 705 for (unsigned i = 0; i < lookup_count; ++i) { 706 if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) { 707 return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain rule subtable", i); 708 } 709 } 710 711 return true; 712 } 713 714 bool ParseChainRuleSetTable(const ots::Font *font, 715 const uint8_t *data, const size_t length, 716 const uint16_t num_glyphs, 717 const uint16_t num_lookups) { 718 ots::Buffer subtable(data, length); 719 720 uint16_t chain_rule_count = 0; 721 if (!subtable.ReadU16(&chain_rule_count)) { 722 return OTS_FAILURE_MSG("Failed to read rule count in chain rule set"); 723 } 724 const unsigned chain_rule_end = 725 2 * static_cast<unsigned>(chain_rule_count) + 2; 726 if (chain_rule_end > std::numeric_limits<uint16_t>::max()) { 727 return OTS_FAILURE_MSG("Bad end of chain rule %d in chain rule set", chain_rule_end); 728 } 729 for (unsigned i = 0; i < chain_rule_count; ++i) { 730 uint16_t offset_chain_rule = 0; 731 if (!subtable.ReadU16(&offset_chain_rule)) { 732 return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain rule set", i); 733 } 734 if (offset_chain_rule < chain_rule_end || offset_chain_rule >= length) { 735 return OTS_FAILURE_MSG("Bad chain rule offset %d for chain rule %d in chain rule set", offset_chain_rule, i); 736 } 737 if (!ParseChainRuleSubtable(font, data + offset_chain_rule, 738 length - offset_chain_rule, 739 num_glyphs, num_lookups)) { 740 return OTS_FAILURE_MSG("Failed to parse chain rule %d in chain rule set", i); 741 } 742 } 743 744 return true; 745 } 746 747 bool ParseChainContextFormat1(const ots::Font *font, 748 const uint8_t *data, const size_t length, 749 const uint16_t num_glyphs, 750 const uint16_t num_lookups) { 751 ots::Buffer subtable(data, length); 752 753 uint16_t offset_coverage = 0; 754 uint16_t chain_rule_set_count = 0; 755 // Skip format field. 756 if (!subtable.Skip(2) || 757 !subtable.ReadU16(&offset_coverage) || 758 !subtable.ReadU16(&chain_rule_set_count)) { 759 return OTS_FAILURE_MSG("Failed to read header of chain context format 1"); 760 } 761 762 const unsigned chain_rule_set_end = 763 2 * static_cast<unsigned>(chain_rule_set_count) + 6; 764 if (chain_rule_set_end > std::numeric_limits<uint16_t>::max()) { 765 return OTS_FAILURE_MSG("Bad chain rule end %d in chain context format 1", chain_rule_set_end); 766 } 767 if (offset_coverage < chain_rule_set_end || offset_coverage >= length) { 768 return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 1", chain_rule_set_end); 769 } 770 if (!ots::ParseCoverageTable(font, data + offset_coverage, 771 length - offset_coverage, num_glyphs)) { 772 return OTS_FAILURE_MSG("Failed to parse coverage table for chain context format 1"); 773 } 774 775 for (unsigned i = 0; i < chain_rule_set_count; ++i) { 776 uint16_t offset_chain_rule_set = 0; 777 if (!subtable.ReadU16(&offset_chain_rule_set)) { 778 return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain context format 1", i); 779 } 780 if (offset_chain_rule_set < chain_rule_set_end || 781 offset_chain_rule_set >= length) { 782 return OTS_FAILURE_MSG("Bad chain rule set offset %d for chain rule set %d in chain context format 1", offset_chain_rule_set, i); 783 } 784 if (!ParseChainRuleSetTable(font, data + offset_chain_rule_set, 785 length - offset_chain_rule_set, 786 num_glyphs, num_lookups)) { 787 return OTS_FAILURE_MSG("Failed to parse chain rule set %d in chain context format 1", i); 788 } 789 } 790 791 return true; 792 } 793 794 bool ParseChainClassRuleSubtable(const ots::Font *font, 795 const uint8_t *data, const size_t length, 796 const uint16_t num_glyphs, 797 const uint16_t num_lookups) { 798 ots::Buffer subtable(data, length); 799 800 // In this subtable, we don't check the value of classes for now since 801 // these could take arbitrary values. 802 803 uint16_t backtrack_count = 0; 804 if (!subtable.ReadU16(&backtrack_count)) { 805 return OTS_FAILURE_MSG("Failed to read backtrack count in chain class rule subtable"); 806 } 807 if (!subtable.Skip(2 * backtrack_count)) { 808 return OTS_FAILURE_MSG("Failed to skip backtrack offsets in chain class rule subtable"); 809 } 810 811 uint16_t input_count = 0; 812 if (!subtable.ReadU16(&input_count)) { 813 return OTS_FAILURE_MSG("Failed to read input count in chain class rule subtable"); 814 } 815 if (input_count == 0) { 816 return OTS_FAILURE_MSG("Bad input count %d in chain class rule subtable", input_count); 817 } 818 if (!subtable.Skip(2 * (input_count - 1))) { 819 return OTS_FAILURE_MSG("Failed to skip input offsets in chain class rule subtable"); 820 } 821 822 uint16_t lookahead_count = 0; 823 if (!subtable.ReadU16(&lookahead_count)) { 824 return OTS_FAILURE_MSG("Failed to read lookahead count in chain class rule subtable"); 825 } 826 if (!subtable.Skip(2 * lookahead_count)) { 827 return OTS_FAILURE_MSG("Failed to skip lookahead offsets in chain class rule subtable"); 828 } 829 830 uint16_t lookup_count = 0; 831 if (!subtable.ReadU16(&lookup_count)) { 832 return OTS_FAILURE_MSG("Failed to read lookup count in chain class rule subtable"); 833 } 834 for (unsigned i = 0; i < lookup_count; ++i) { 835 if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) { 836 return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain class rule subtable", i); 837 } 838 } 839 840 return true; 841 } 842 843 bool ParseChainClassSetTable(const ots::Font *font, 844 const uint8_t *data, const size_t length, 845 const uint16_t num_glyphs, 846 const uint16_t num_lookups) { 847 ots::Buffer subtable(data, length); 848 849 uint16_t chain_class_rule_count = 0; 850 if (!subtable.ReadU16(&chain_class_rule_count)) { 851 return OTS_FAILURE_MSG("Failed to read rule count in chain class set"); 852 } 853 const unsigned chain_class_rule_end = 854 2 * static_cast<unsigned>(chain_class_rule_count) + 2; 855 if (chain_class_rule_end > std::numeric_limits<uint16_t>::max()) { 856 return OTS_FAILURE_MSG("Bad end of chain class set %d in chain class set", chain_class_rule_end); 857 } 858 for (unsigned i = 0; i < chain_class_rule_count; ++i) { 859 uint16_t offset_chain_class_rule = 0; 860 if (!subtable.ReadU16(&offset_chain_class_rule)) { 861 return OTS_FAILURE_MSG("Failed to read chain class rule offset %d in chain class set", i); 862 } 863 if (offset_chain_class_rule < chain_class_rule_end || 864 offset_chain_class_rule >= length) { 865 return OTS_FAILURE_MSG("Bad chain class rule offset %d for chain class %d in chain class set", offset_chain_class_rule, i); 866 } 867 if (!ParseChainClassRuleSubtable(font, data + offset_chain_class_rule, 868 length - offset_chain_class_rule, 869 num_glyphs, num_lookups)) { 870 return OTS_FAILURE_MSG("Failed to parse chain class rule %d in chain class set", i); 871 } 872 } 873 874 return true; 875 } 876 877 bool ParseChainContextFormat2(const ots::Font *font, 878 const uint8_t *data, const size_t length, 879 const uint16_t num_glyphs, 880 const uint16_t num_lookups) { 881 ots::Buffer subtable(data, length); 882 883 uint16_t offset_coverage = 0; 884 uint16_t offset_backtrack_class_def = 0; 885 uint16_t offset_input_class_def = 0; 886 uint16_t offset_lookahead_class_def = 0; 887 uint16_t chain_class_set_count = 0; 888 // Skip format field. 889 if (!subtable.Skip(2) || 890 !subtable.ReadU16(&offset_coverage) || 891 !subtable.ReadU16(&offset_backtrack_class_def) || 892 !subtable.ReadU16(&offset_input_class_def) || 893 !subtable.ReadU16(&offset_lookahead_class_def) || 894 !subtable.ReadU16(&chain_class_set_count)) { 895 return OTS_FAILURE_MSG("Failed to read header of chain context format 2"); 896 } 897 898 const unsigned chain_class_set_end = 899 2 * static_cast<unsigned>(chain_class_set_count) + 12; 900 if (chain_class_set_end > std::numeric_limits<uint16_t>::max()) { 901 return OTS_FAILURE_MSG("Bad chain class set end %d in chain context format 2", chain_class_set_end); 902 } 903 if (offset_coverage < chain_class_set_end || offset_coverage >= length) { 904 return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 2", offset_coverage); 905 } 906 if (!ots::ParseCoverageTable(font, data + offset_coverage, 907 length - offset_coverage, num_glyphs)) { 908 return OTS_FAILURE_MSG("Failed to parse coverage table in chain context format 2"); 909 } 910 911 // Classes for backtrack/lookahead sequences might not be defined. 912 if (offset_backtrack_class_def) { 913 if (offset_backtrack_class_def < chain_class_set_end || 914 offset_backtrack_class_def >= length) { 915 return OTS_FAILURE_MSG("Bad backtrack class offset %d in chain context format 2", offset_backtrack_class_def); 916 } 917 if (!ots::ParseClassDefTable(font, data + offset_backtrack_class_def, 918 length - offset_backtrack_class_def, 919 num_glyphs, ots::kMaxClassDefValue)) { 920 return OTS_FAILURE_MSG("Failed to parse backtrack class defn table in chain context format 2"); 921 } 922 } 923 924 if (offset_input_class_def < chain_class_set_end || 925 offset_input_class_def >= length) { 926 return OTS_FAILURE_MSG("Bad input class defn offset %d in chain context format 2", offset_input_class_def); 927 } 928 if (!ots::ParseClassDefTable(font, data + offset_input_class_def, 929 length - offset_input_class_def, 930 num_glyphs, ots::kMaxClassDefValue)) { 931 return OTS_FAILURE_MSG("Failed to parse input class defn in chain context format 2"); 932 } 933 934 if (offset_lookahead_class_def) { 935 if (offset_lookahead_class_def < chain_class_set_end || 936 offset_lookahead_class_def >= length) { 937 return OTS_FAILURE_MSG("Bad lookahead class defn offset %d in chain context format 2", offset_lookahead_class_def); 938 } 939 if (!ots::ParseClassDefTable(font, data + offset_lookahead_class_def, 940 length - offset_lookahead_class_def, 941 num_glyphs, ots::kMaxClassDefValue)) { 942 return OTS_FAILURE_MSG("Failed to parse lookahead class defn in chain context format 2"); 943 } 944 } 945 946 for (unsigned i = 0; i < chain_class_set_count; ++i) { 947 uint16_t offset_chain_class_set = 0; 948 if (!subtable.ReadU16(&offset_chain_class_set)) { 949 return OTS_FAILURE_MSG("Failed to read chain class set offset %d", i); 950 } 951 // |offset_chain_class_set| could be NULL. 952 if (offset_chain_class_set) { 953 if (offset_chain_class_set < chain_class_set_end || 954 offset_chain_class_set >= length) { 955 return OTS_FAILURE_MSG("Bad chain set class offset %d for chain set %d in chain context format 2", offset_chain_class_set, i); 956 } 957 if (!ParseChainClassSetTable(font, data + offset_chain_class_set, 958 length - offset_chain_class_set, 959 num_glyphs, num_lookups)) { 960 return OTS_FAILURE_MSG("Failed to parse chain class set table %d in chain context format 2", i); 961 } 962 } 963 } 964 965 return true; 966 } 967 968 bool ParseChainContextFormat3(const ots::Font *font, 969 const uint8_t *data, const size_t length, 970 const uint16_t num_glyphs, 971 const uint16_t num_lookups) { 972 ots::Buffer subtable(data, length); 973 974 uint16_t backtrack_count = 0; 975 // Skip format field. 976 if (!subtable.Skip(2) || 977 !subtable.ReadU16(&backtrack_count)) { 978 return OTS_FAILURE_MSG("Failed to read backtrack count in chain context format 3"); 979 } 980 981 std::vector<uint16_t> offsets_backtrack; 982 offsets_backtrack.reserve(backtrack_count); 983 for (unsigned i = 0; i < backtrack_count; ++i) { 984 uint16_t offset = 0; 985 if (!subtable.ReadU16(&offset)) { 986 return OTS_FAILURE_MSG("Failed to read backtrack offset %d in chain context format 3", i); 987 } 988 offsets_backtrack.push_back(offset); 989 } 990 if (offsets_backtrack.size() != backtrack_count) { 991 return OTS_FAILURE_MSG("Bad backtrack offsets size %ld in chain context format 3", offsets_backtrack.size()); 992 } 993 994 uint16_t input_count = 0; 995 if (!subtable.ReadU16(&input_count)) { 996 return OTS_FAILURE_MSG("Failed to read input count in chain context format 3"); 997 } 998 std::vector<uint16_t> offsets_input; 999 offsets_input.reserve(input_count); 1000 for (unsigned i = 0; i < input_count; ++i) { 1001 uint16_t offset = 0; 1002 if (!subtable.ReadU16(&offset)) { 1003 return OTS_FAILURE_MSG("Failed to read input offset %d in chain context format 3", i); 1004 } 1005 offsets_input.push_back(offset); 1006 } 1007 if (offsets_input.size() != input_count) { 1008 return OTS_FAILURE_MSG("Bad input offsets size %ld in chain context format 3", offsets_input.size()); 1009 } 1010 1011 uint16_t lookahead_count = 0; 1012 if (!subtable.ReadU16(&lookahead_count)) { 1013 return OTS_FAILURE_MSG("Failed ot read lookahead count in chain context format 3"); 1014 } 1015 std::vector<uint16_t> offsets_lookahead; 1016 offsets_lookahead.reserve(lookahead_count); 1017 for (unsigned i = 0; i < lookahead_count; ++i) { 1018 uint16_t offset = 0; 1019 if (!subtable.ReadU16(&offset)) { 1020 return OTS_FAILURE_MSG("Failed to read lookahead offset %d in chain context format 3", i); 1021 } 1022 offsets_lookahead.push_back(offset); 1023 } 1024 if (offsets_lookahead.size() != lookahead_count) { 1025 return OTS_FAILURE_MSG("Bad lookahead offsets size %ld in chain context format 3", offsets_lookahead.size()); 1026 } 1027 1028 uint16_t lookup_count = 0; 1029 if (!subtable.ReadU16(&lookup_count)) { 1030 return OTS_FAILURE_MSG("Failed to read lookup count in chain context format 3"); 1031 } 1032 for (unsigned i = 0; i < lookup_count; ++i) { 1033 if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) { 1034 return OTS_FAILURE_MSG("Failed to parse lookup %d in chain context format 3", i); 1035 } 1036 } 1037 1038 const unsigned lookup_record_end = 1039 2 * (static_cast<unsigned>(backtrack_count) + 1040 static_cast<unsigned>(input_count) + 1041 static_cast<unsigned>(lookahead_count)) + 1042 4 * static_cast<unsigned>(lookup_count) + 10; 1043 if (lookup_record_end > std::numeric_limits<uint16_t>::max()) { 1044 return OTS_FAILURE_MSG("Bad end of lookup record %d in chain context format 3", lookup_record_end); 1045 } 1046 for (unsigned i = 0; i < backtrack_count; ++i) { 1047 if (offsets_backtrack[i] < lookup_record_end || 1048 offsets_backtrack[i] >= length) { 1049 return OTS_FAILURE_MSG("Bad backtrack offset of %d for backtrack %d in chain context format 3", offsets_backtrack[i], i); 1050 } 1051 if (!ots::ParseCoverageTable(font, data + offsets_backtrack[i], 1052 length - offsets_backtrack[i], num_glyphs)) { 1053 return OTS_FAILURE_MSG("Failed to parse backtrack coverage %d in chain context format 3", i); 1054 } 1055 } 1056 for (unsigned i = 0; i < input_count; ++i) { 1057 if (offsets_input[i] < lookup_record_end || offsets_input[i] >= length) { 1058 return OTS_FAILURE_MSG("Bad input offset %d for input %d in chain context format 3", offsets_input[i], i); 1059 } 1060 if (!ots::ParseCoverageTable(font, data + offsets_input[i], 1061 length - offsets_input[i], num_glyphs)) { 1062 return OTS_FAILURE_MSG("Failed to parse input coverage table %d in chain context format 3", i); 1063 } 1064 } 1065 for (unsigned i = 0; i < lookahead_count; ++i) { 1066 if (offsets_lookahead[i] < lookup_record_end || 1067 offsets_lookahead[i] >= length) { 1068 return OTS_FAILURE_MSG("Bad lookadhead offset %d for lookahead %d in chain context format 3", offsets_lookahead[i], i); 1069 } 1070 if (!ots::ParseCoverageTable(font, data + offsets_lookahead[i], 1071 length - offsets_lookahead[i], num_glyphs)) { 1072 return OTS_FAILURE_MSG("Failed to parse lookahead coverage table %d in chain context format 3", i); 1073 } 1074 } 1075 1076 return true; 1077 } 1078 1079 bool ParseFeatureTableSubstitutionTable(const ots::Font *font, 1080 const uint8_t *data, const size_t length, 1081 const uint16_t num_lookups) { 1082 ots::Buffer subtable(data, length); 1083 1084 uint16_t version_major = 0; 1085 uint16_t version_minor = 0; 1086 uint16_t substitution_count = 0; 1087 const size_t kFeatureTableSubstitutionHeaderSize = 3 * sizeof(uint16_t); 1088 1089 if (!subtable.ReadU16(&version_major) || 1090 !subtable.ReadU16(&version_minor) || 1091 !subtable.ReadU16(&substitution_count)) { 1092 return OTS_FAILURE_MSG("Failed to read feature table substitution table header"); 1093 } 1094 1095 for (uint16_t i = 0; i < substitution_count; i++) { 1096 uint16_t feature_index = 0; 1097 uint32_t alternate_feature_table_offset = 0; 1098 const size_t kFeatureTableSubstitutionRecordSize = sizeof(uint16_t) + sizeof(uint32_t); 1099 1100 if (!subtable.ReadU16(&feature_index) || 1101 !subtable.ReadU32(&alternate_feature_table_offset)) { 1102 return OTS_FAILURE_MSG("Failed to read feature table substitution record"); 1103 } 1104 1105 if (alternate_feature_table_offset < kFeatureTableSubstitutionHeaderSize + 1106 kFeatureTableSubstitutionRecordSize * substitution_count || 1107 alternate_feature_table_offset >= length) { 1108 return OTS_FAILURE_MSG("Invalid alternate feature table offset"); 1109 } 1110 1111 if (!ParseFeatureTable(font, data + alternate_feature_table_offset, 1112 length - alternate_feature_table_offset, num_lookups)) { 1113 return OTS_FAILURE_MSG("Failed to parse alternate feature table"); 1114 } 1115 } 1116 1117 return true; 1118 } 1119 1120 bool ParseConditionTable(const ots::Font *font, 1121 const uint8_t *data, const size_t length, 1122 const uint16_t axis_count) { 1123 ots::Buffer subtable(data, length); 1124 1125 uint16_t format = 0; 1126 if (!subtable.ReadU16(&format)) { 1127 return OTS_FAILURE_MSG("Failed to read condition table format"); 1128 } 1129 1130 if (format != 1) { 1131 // An unknown format is not an error, but should be ignored per spec. 1132 return true; 1133 } 1134 1135 uint16_t axis_index = 0; 1136 int16_t filter_range_min_value = 0; 1137 int16_t filter_range_max_value = 0; 1138 if (!subtable.ReadU16(&axis_index) || 1139 !subtable.ReadS16(&filter_range_min_value) || 1140 !subtable.ReadS16(&filter_range_max_value)) { 1141 return OTS_FAILURE_MSG("Failed to read condition table (format 1)"); 1142 } 1143 1144 if (axis_index >= axis_count) { 1145 return OTS_FAILURE_MSG("Axis index out of range in condition"); 1146 } 1147 1148 // Check min/max values are within range -1.0 .. 1.0. 1149 if (filter_range_min_value < -0x4000 || // -1.0 in F2DOT14 format 1150 filter_range_max_value > 0x4000) { // +1.0 in F2DOT14 format 1151 return OTS_FAILURE_MSG("Invalid filter range in condition"); 1152 } 1153 1154 // Warn if range is improperly ordered (and therefore useless). 1155 if (filter_range_min_value > filter_range_max_value) { 1156 OTS_WARNING("Misordered filter range in condition table"); 1157 } 1158 1159 return true; 1160 } 1161 1162 bool ParseConditionSetTable(const ots::Font *font, 1163 const uint8_t *data, const size_t length, 1164 const uint16_t axis_count) { 1165 ots::Buffer subtable(data, length); 1166 1167 uint16_t condition_count = 0; 1168 if (!subtable.ReadU16(&condition_count)) { 1169 return OTS_FAILURE_MSG("Failed to read condition count"); 1170 } 1171 1172 for (uint16_t i = 0; i < condition_count; i++) { 1173 uint32_t condition_offset = 0; 1174 if (!subtable.ReadU32(&condition_offset)) { 1175 return OTS_FAILURE_MSG("Failed to read condition offset"); 1176 } 1177 if (condition_offset < subtable.offset() || condition_offset >= length) { 1178 return OTS_FAILURE_MSG("Offset out of range"); 1179 } 1180 if (!ParseConditionTable(font, data + condition_offset, length - condition_offset, 1181 axis_count)) { 1182 return OTS_FAILURE_MSG("Failed to parse condition table"); 1183 } 1184 } 1185 1186 return true; 1187 } 1188 1189 } // namespace 1190 1191 namespace ots { 1192 1193 // Parsing ScriptListTable requires number of features so we need to 1194 // parse FeatureListTable before calling this function. 1195 bool OpenTypeLayoutTable::ParseScriptListTable(const uint8_t *data, const size_t length) { 1196 Font* font = GetFont(); 1197 Buffer subtable(data, length); 1198 1199 uint16_t script_count = 0; 1200 if (!subtable.ReadU16(&script_count)) { 1201 return Error("Failed to read script count in script list table"); 1202 } 1203 1204 const unsigned script_record_end = 1205 6 * static_cast<unsigned>(script_count) + 2; 1206 if (script_record_end > std::numeric_limits<uint16_t>::max()) { 1207 return Error("Bad end of script record %d in script list table", script_record_end); 1208 } 1209 std::vector<ScriptRecord> script_list; 1210 script_list.reserve(script_count); 1211 uint32_t last_tag = 0; 1212 for (unsigned i = 0; i < script_count; ++i) { 1213 ScriptRecord record; 1214 if (!subtable.ReadU32(&record.tag) || 1215 !subtable.ReadU16(&record.offset)) { 1216 return Error("Failed to read script record %d in script list table", i); 1217 } 1218 // Script tags should be arranged alphabetically by tag 1219 if (last_tag != 0 && last_tag > record.tag) { 1220 // Several fonts don't arrange tags alphabetically. 1221 // It seems that the order of tags might not be a security issue 1222 // so we just warn it. 1223 OTS_WARNING("tags aren't arranged alphabetically."); 1224 } 1225 last_tag = record.tag; 1226 if (record.offset < script_record_end || record.offset >= length) { 1227 return Error("Bad record offset %d for script %c%c%c%c entry %d in script list table", record.offset, OTS_UNTAG(record.tag), i); 1228 } 1229 script_list.push_back(record); 1230 } 1231 if (script_list.size() != script_count) { 1232 return Error("Bad script list size %ld in script list table", script_list.size()); 1233 } 1234 1235 // Check script records. 1236 for (unsigned i = 0; i < script_count; ++i) { 1237 if (!ParseScriptTable(font, data + script_list[i].offset, 1238 length - script_list[i].offset, 1239 script_list[i].tag, m_num_features)) { 1240 return Error("Failed to parse script table %d", i); 1241 } 1242 } 1243 1244 return true; 1245 } 1246 1247 // Parsing FeatureListTable requires number of lookups so we need to parse 1248 // LookupListTable before calling this function. 1249 bool OpenTypeLayoutTable::ParseFeatureListTable(const uint8_t *data, const size_t length) { 1250 Font *font = GetFont(); 1251 Buffer subtable(data, length); 1252 1253 uint16_t feature_count = 0; 1254 if (!subtable.ReadU16(&feature_count)) { 1255 return Error("Failed to read feature count"); 1256 } 1257 1258 std::vector<FeatureRecord> feature_records; 1259 feature_records.resize(feature_count); 1260 const unsigned feature_record_end = 1261 6 * static_cast<unsigned>(feature_count) + 2; 1262 if (feature_record_end > std::numeric_limits<uint16_t>::max()) { 1263 return Error("Bad end of feature record %d", feature_record_end); 1264 } 1265 uint32_t last_tag = 0; 1266 for (unsigned i = 0; i < feature_count; ++i) { 1267 if (!subtable.ReadU32(&feature_records[i].tag) || 1268 !subtable.ReadU16(&feature_records[i].offset)) { 1269 return Error("Failed to read feature header %d", i); 1270 } 1271 // Feature record array should be arranged alphabetically by tag 1272 if (last_tag != 0 && last_tag > feature_records[i].tag) { 1273 // Several fonts don't arrange tags alphabetically. 1274 // It seems that the order of tags might not be a security issue 1275 // so we just warn it. 1276 OTS_WARNING("tags aren't arranged alphabetically."); 1277 } 1278 last_tag = feature_records[i].tag; 1279 if (feature_records[i].offset < feature_record_end || 1280 feature_records[i].offset >= length) { 1281 return Error("Bad feature offset %d for feature %d %c%c%c%c", feature_records[i].offset, i, OTS_UNTAG(feature_records[i].tag)); 1282 } 1283 } 1284 1285 for (unsigned i = 0; i < feature_count; ++i) { 1286 if (!ParseFeatureTable(font, data + feature_records[i].offset, 1287 length - feature_records[i].offset, m_num_lookups)) { 1288 return Error("Failed to parse feature table %d", i); 1289 } 1290 } 1291 m_num_features = feature_count; 1292 return true; 1293 } 1294 1295 bool OpenTypeLayoutTable::ParseLookupTable(const uint8_t *data, 1296 const size_t length) { 1297 Font* font = GetFont(); 1298 Buffer subtable(data, length); 1299 1300 uint16_t lookup_type = 0; 1301 uint16_t lookup_flag = 0; 1302 uint16_t subtable_count = 0; 1303 if (!subtable.ReadU16(&lookup_type) || 1304 !subtable.ReadU16(&lookup_flag) || 1305 !subtable.ReadU16(&subtable_count)) { 1306 return Error("Failed to read lookup table header"); 1307 } 1308 1309 if (!ValidLookupSubtableType(lookup_type)) { 1310 return Error("Bad lookup type %d", lookup_type); 1311 } 1312 1313 bool use_mark_filtering_set = lookup_flag & kUseMarkFilteringSetBit; 1314 1315 std::vector<uint16_t> subtables; 1316 subtables.reserve(subtable_count); 1317 // If the |kUseMarkFilteringSetBit| of |lookup_flag| is set, 1318 // extra 2 bytes will follow after subtable offset array. 1319 const unsigned lookup_table_end = 2 * static_cast<unsigned>(subtable_count) + 1320 (use_mark_filtering_set ? 8 : 6); 1321 if (lookup_table_end > std::numeric_limits<uint16_t>::max()) { 1322 return Error("Bad end of lookup %d", lookup_table_end); 1323 } 1324 for (unsigned i = 0; i < subtable_count; ++i) { 1325 uint16_t offset_subtable = 0; 1326 if (!subtable.ReadU16(&offset_subtable)) { 1327 return Error("Failed to read subtable offset %d", i); 1328 } 1329 if (offset_subtable < lookup_table_end || 1330 offset_subtable >= length) { 1331 return Error("Bad subtable offset %d for subtable %d", offset_subtable, i); 1332 } 1333 subtables.push_back(offset_subtable); 1334 } 1335 if (subtables.size() != subtable_count) { 1336 return Error("Bad subtable size %ld", subtables.size()); 1337 } 1338 1339 if (use_mark_filtering_set) { 1340 uint16_t mark_filtering_set = 0; 1341 if (!subtable.ReadU16(&mark_filtering_set)) { 1342 return Error("Failed to read mark filtering set"); 1343 } 1344 1345 OpenTypeGDEF *gdef = static_cast<OpenTypeGDEF*>( 1346 font->GetTypedTable(OTS_TAG_GDEF)); 1347 1348 if (gdef && (gdef->num_mark_glyph_sets == 0 || 1349 mark_filtering_set >= gdef->num_mark_glyph_sets)) { 1350 return Error("Bad mark filtering set %d", mark_filtering_set); 1351 } 1352 } 1353 1354 // Parse lookup subtables for this lookup type. 1355 for (unsigned i = 0; i < subtable_count; ++i) { 1356 if (!ParseLookupSubtable(data + subtables[i], length - subtables[i], 1357 lookup_type)) { 1358 return Error("Failed to parse subtable %d", i); 1359 } 1360 } 1361 return true; 1362 } 1363 1364 // For parsing GPOS/GSUB tables, this function should be called at first to 1365 // obtain the number of lookups because parsing FeatureTableList requires 1366 // the number. 1367 bool OpenTypeLayoutTable::ParseLookupListTable(const uint8_t *data, 1368 const size_t length) { 1369 Buffer subtable(data, length); 1370 1371 if (!subtable.ReadU16(&m_num_lookups)) { 1372 return Error("Failed to read number of lookups"); 1373 } 1374 1375 std::vector<uint16_t> lookups; 1376 lookups.reserve(m_num_lookups); 1377 const unsigned lookup_end = 1378 2 * static_cast<unsigned>(m_num_lookups) + 2; 1379 if (lookup_end > std::numeric_limits<uint16_t>::max()) { 1380 return Error("Bad end of lookups %d", lookup_end); 1381 } 1382 for (unsigned i = 0; i < m_num_lookups; ++i) { 1383 uint16_t offset = 0; 1384 if (!subtable.ReadU16(&offset)) { 1385 return Error("Failed to read lookup offset %d", i); 1386 } 1387 if (offset < lookup_end || offset >= length) { 1388 return Error("Bad lookup offset %d for lookup %d", offset, i); 1389 } 1390 lookups.push_back(offset); 1391 } 1392 if (lookups.size() != m_num_lookups) { 1393 return Error("Bad lookup offsets list size %ld", lookups.size()); 1394 } 1395 1396 for (unsigned i = 0; i < m_num_lookups; ++i) { 1397 if (!ParseLookupTable(data + lookups[i], length - lookups[i])) { 1398 return Error("Failed to parse lookup %d", i); 1399 } 1400 } 1401 1402 return true; 1403 } 1404 1405 bool ParseClassDefTable(const ots::Font *font, 1406 const uint8_t *data, size_t length, 1407 const uint16_t num_glyphs, 1408 const uint16_t num_classes) { 1409 Buffer subtable(data, length); 1410 1411 uint16_t format = 0; 1412 if (!subtable.ReadU16(&format)) { 1413 return OTS_FAILURE_MSG("Failed to read class defn format"); 1414 } 1415 if (format == 1) { 1416 return ParseClassDefFormat1(font, data, length, num_glyphs, num_classes); 1417 } else if (format == 2) { 1418 return ParseClassDefFormat2(font, data, length, num_glyphs, num_classes); 1419 } 1420 1421 return OTS_FAILURE_MSG("Bad class defn format %d", format); 1422 } 1423 1424 bool ParseCoverageTable(const ots::Font *font, 1425 const uint8_t *data, size_t length, 1426 const uint16_t num_glyphs, 1427 const uint16_t expected_num_glyphs) { 1428 Buffer subtable(data, length); 1429 1430 uint16_t format = 0; 1431 if (!subtable.ReadU16(&format)) { 1432 return OTS_FAILURE_MSG("Failed to read coverage table format"); 1433 } 1434 if (format == 1) { 1435 return ParseCoverageFormat1(font, data, length, num_glyphs, expected_num_glyphs); 1436 } else if (format == 2) { 1437 return ParseCoverageFormat2(font, data, length, num_glyphs, expected_num_glyphs); 1438 } 1439 1440 return OTS_FAILURE_MSG("Bad coverage table format %d", format); 1441 } 1442 1443 bool ParseDeviceTable(const ots::Font *font, 1444 const uint8_t *data, size_t length) { 1445 Buffer subtable(data, length); 1446 1447 uint16_t start_size = 0; 1448 uint16_t end_size = 0; 1449 uint16_t delta_format = 0; 1450 if (!subtable.ReadU16(&start_size) || 1451 !subtable.ReadU16(&end_size) || 1452 !subtable.ReadU16(&delta_format)) { 1453 return OTS_FAILURE_MSG("Failed to read device table header"); 1454 } 1455 if (delta_format == kVariationIndex) { 1456 // start_size and end_size are replaced by deltaSetOuterIndex 1457 // and deltaSetInnerIndex respectively, but we don't attempt to 1458 // check them here, so nothing more to do. 1459 return true; 1460 } 1461 if (start_size > end_size) { 1462 return OTS_FAILURE_MSG("Bad device table size range: %u > %u", start_size, end_size); 1463 } 1464 if (delta_format == 0 || delta_format > kMaxDeltaFormatType) { 1465 return OTS_FAILURE_MSG("Bad device table delta format: 0x%x", delta_format); 1466 } 1467 // The number of delta values per uint16. The device table should contain 1468 // at least |num_units| * 2 bytes compressed data. 1469 const unsigned num_units = (end_size - start_size) / 1470 (1 << (4 - delta_format)) + 1; 1471 // Just skip |num_units| * 2 bytes since the compressed data could take 1472 // arbitrary values. 1473 if (!subtable.Skip(num_units * 2)) { 1474 return OTS_FAILURE_MSG("Failed to skip data in device table"); 1475 } 1476 return true; 1477 } 1478 1479 bool OpenTypeLayoutTable::ParseContextSubtable(const uint8_t *data, 1480 const size_t length) { 1481 Font *font = GetFont(); 1482 Buffer subtable(data, length); 1483 1484 uint16_t format = 0; 1485 if (!subtable.ReadU16(&format)) { 1486 return Error("Failed to read context subtable format"); 1487 } 1488 1489 OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>( 1490 font->GetTypedTable(OTS_TAG_MAXP)); 1491 if (!maxp) { 1492 return Error("Required maxp table missing"); 1493 } 1494 1495 if (format == 1) { 1496 if (!ParseContextFormat1(font, data, length, maxp->num_glyphs, m_num_lookups)) { 1497 return Error("Failed to parse context format 1 subtable"); 1498 } 1499 } else if (format == 2) { 1500 if (!ParseContextFormat2(font, data, length, maxp->num_glyphs, m_num_lookups)) { 1501 return Error("Failed to parse context format 2 subtable"); 1502 } 1503 } else if (format == 3) { 1504 if (!ParseContextFormat3(font, data, length, maxp->num_glyphs, m_num_lookups)) { 1505 return Error("Failed to parse context format 3 subtable"); 1506 } 1507 } else { 1508 return Error("Bad context subtable format %d", format); 1509 } 1510 1511 return true; 1512 } 1513 1514 bool OpenTypeLayoutTable::ParseChainingContextSubtable(const uint8_t *data, 1515 const size_t length) { 1516 Font *font = GetFont(); 1517 Buffer subtable(data, length); 1518 1519 uint16_t format = 0; 1520 if (!subtable.ReadU16(&format)) { 1521 return Error("Failed to read chaining context subtable format"); 1522 } 1523 1524 OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>( 1525 font->GetTypedTable(OTS_TAG_MAXP)); 1526 if (!maxp) { 1527 return Error("Required maxp table missing"); 1528 } 1529 1530 if (format == 1) { 1531 if (!ParseChainContextFormat1(font, data, length, maxp->num_glyphs, m_num_lookups)) { 1532 return Error("Failed to parse chaining context format 1 subtable"); 1533 } 1534 } else if (format == 2) { 1535 if (!ParseChainContextFormat2(font, data, length, maxp->num_glyphs, m_num_lookups)) { 1536 return Error("Failed to parse chaining context format 2 subtable"); 1537 } 1538 } else if (format == 3) { 1539 if (!ParseChainContextFormat3(font, data, length, maxp->num_glyphs, m_num_lookups)) { 1540 return Error("Failed to parse chaining context format 3 subtable"); 1541 } 1542 } else { 1543 return Error("Bad chaining context subtable format %d", format); 1544 } 1545 1546 return true; 1547 } 1548 1549 bool OpenTypeLayoutTable::ParseExtensionSubtable(const uint8_t *data, 1550 const size_t length) { 1551 Buffer subtable(data, length); 1552 1553 uint16_t format = 0; 1554 uint16_t lookup_type = 0; 1555 uint32_t offset_extension = 0; 1556 if (!subtable.ReadU16(&format) || 1557 !subtable.ReadU16(&lookup_type) || 1558 !subtable.ReadU32(&offset_extension)) { 1559 return Error("Failed to read extension table header"); 1560 } 1561 1562 if (format != 1) { 1563 return Error("Bad extension table format %d", format); 1564 } 1565 // |lookup_type| should be other than |parser->extension_type|. 1566 if (!ValidLookupSubtableType(lookup_type, true)) { 1567 return Error("Bad lookup type %d in extension table", lookup_type); 1568 } 1569 1570 const unsigned format_end = static_cast<unsigned>(8); 1571 if (offset_extension < format_end || 1572 offset_extension >= length) { 1573 return Error("Bad extension offset %d", offset_extension); 1574 } 1575 1576 // Parse the extension subtable of |lookup_type|. 1577 if (!ParseLookupSubtable(data + offset_extension, length - offset_extension, 1578 lookup_type)) { 1579 return Error("Failed to parse lookup from extension lookup"); 1580 } 1581 1582 return true; 1583 } 1584 1585 // Parsing feature variations table (in GSUB/GPOS v1.1) 1586 bool OpenTypeLayoutTable::ParseFeatureVariationsTable(const uint8_t *data, const size_t length) { 1587 Font *font = GetFont(); 1588 Buffer subtable(data, length); 1589 1590 uint16_t version_major = 0; 1591 uint16_t version_minor = 0; 1592 uint32_t feature_variation_record_count = 0; 1593 1594 if (!subtable.ReadU16(&version_major) || 1595 !subtable.ReadU16(&version_minor) || 1596 !subtable.ReadU32(&feature_variation_record_count)) { 1597 return Error("Failed to read feature variations table header"); 1598 } 1599 1600 OpenTypeFVAR* fvar = static_cast<OpenTypeFVAR*>(font->GetTypedTable(OTS_TAG_FVAR)); 1601 if (!fvar) { 1602 return Error("Not a variation font"); 1603 } 1604 const uint16_t axis_count = fvar->AxisCount(); 1605 1606 const size_t kEndOfFeatureVariationRecords = 1607 2 * sizeof(uint16_t) + sizeof(uint32_t) + 1608 feature_variation_record_count * 2 * sizeof(uint32_t); 1609 1610 for (uint32_t i = 0; i < feature_variation_record_count; i++) { 1611 uint32_t condition_set_offset = 0; 1612 uint32_t feature_table_substitution_offset = 0; 1613 if (!subtable.ReadU32(&condition_set_offset) || 1614 !subtable.ReadU32(&feature_table_substitution_offset)) { 1615 return Error("Failed to read feature variation record"); 1616 } 1617 1618 if (condition_set_offset) { 1619 if (condition_set_offset < kEndOfFeatureVariationRecords || 1620 condition_set_offset >= length) { 1621 return Error("Condition set offset out of range"); 1622 } 1623 if (!ParseConditionSetTable(font, data + condition_set_offset, 1624 length - condition_set_offset, 1625 axis_count)) { 1626 return Error("Failed to parse condition set table"); 1627 } 1628 } 1629 1630 if (feature_table_substitution_offset) { 1631 if (feature_table_substitution_offset < kEndOfFeatureVariationRecords || 1632 feature_table_substitution_offset >= length) { 1633 return Error("Feature table substitution offset out of range"); 1634 } 1635 if (!ParseFeatureTableSubstitutionTable(font, data + feature_table_substitution_offset, 1636 length - feature_table_substitution_offset, 1637 m_num_lookups)) { 1638 return Error("Failed to parse feature table substitution table"); 1639 } 1640 } 1641 } 1642 1643 return true; 1644 } 1645 1646 // GSUB/GPOS header size for table version 1.0 1647 const size_t kHeaderSize_1_0 = 4 + 3 * 2; 1648 // GSUB/GPOS header size for table versio 1.1 1649 const size_t kHeaderSize_1_1 = 4 + 3 * 2 + 4; 1650 1651 bool OpenTypeLayoutTable::Parse(const uint8_t *data, size_t length) { 1652 Buffer table(data, length); 1653 1654 uint16_t version_major = 0, version_minor = 0; 1655 uint16_t offset_script_list = 0; 1656 uint16_t offset_feature_list = 0; 1657 uint16_t offset_lookup_list = 0; 1658 uint32_t offset_feature_variations = 0; 1659 if (!table.ReadU16(&version_major) || 1660 !table.ReadU16(&version_minor) || 1661 !table.ReadU16(&offset_script_list) || 1662 !table.ReadU16(&offset_feature_list) || 1663 !table.ReadU16(&offset_lookup_list)) { 1664 return Error("Incomplete table"); 1665 } 1666 1667 if (version_major != 1 || version_minor > 1) { 1668 return Error("Bad version"); 1669 } 1670 1671 if (version_minor > 0) { 1672 if (!table.ReadU32(&offset_feature_variations)) { 1673 return Error("Incomplete table"); 1674 } 1675 } 1676 1677 const size_t header_size = 1678 (version_minor == 0) ? kHeaderSize_1_0 : kHeaderSize_1_1; 1679 1680 if (offset_lookup_list) { 1681 if (offset_lookup_list < header_size || offset_lookup_list >= length) { 1682 return Error("Bad lookup list offset in table header"); 1683 } 1684 1685 if (!ParseLookupListTable(data + offset_lookup_list, 1686 length - offset_lookup_list)) { 1687 return Error("Failed to parse lookup list table"); 1688 } 1689 } 1690 1691 if (offset_feature_list) { 1692 if (offset_feature_list < header_size || offset_feature_list >= length) { 1693 return Error("Bad feature list offset in table header"); 1694 } 1695 1696 if (!ParseFeatureListTable(data + offset_feature_list, 1697 length - offset_feature_list)) { 1698 return Error("Failed to parse feature list table"); 1699 } 1700 } 1701 1702 if (offset_script_list) { 1703 if (offset_script_list < header_size || offset_script_list >= length) { 1704 return Error("Bad script list offset in table header"); 1705 } 1706 1707 if (!ParseScriptListTable(data + offset_script_list, 1708 length - offset_script_list)) { 1709 return Error("Failed to parse script list table"); 1710 } 1711 } 1712 1713 if (offset_feature_variations) { 1714 if (offset_feature_variations < header_size || offset_feature_variations >= length) { 1715 return Error("Bad feature variations offset in table header"); 1716 } 1717 1718 if (!ParseFeatureVariationsTable(data + offset_feature_variations, 1719 length - offset_feature_variations)) { 1720 return Error("Failed to parse feature variations table"); 1721 } 1722 } 1723 1724 this->m_data = data; 1725 this->m_length = length; 1726 return true; 1727 } 1728 1729 bool OpenTypeLayoutTable::Serialize(OTSStream *out) { 1730 if (!out->Write(this->m_data, this->m_length)) { 1731 return Error("Failed to write table"); 1732 } 1733 1734 return true; 1735 } 1736 1737 } // namespace ots 1738 1739 #undef TABLE_NAME