Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "layout.h" | 5 #include "layout.h" |
| 6 | 6 |
| 7 #include <vector> | |
| 8 | |
| 9 #include "gdef.h" | |
| 10 | |
| 7 // OpenType Layout Common Table Formats | 11 // OpenType Layout Common Table Formats |
| 8 // http://www.microsoft.com/typography/otspec/chapter2.htm | 12 // http://www.microsoft.com/typography/otspec/chapter2.htm |
| 9 | 13 |
| 10 namespace { | 14 namespace { |
| 11 | 15 |
| 16 // The 'DFLT' tag of script table. | |
| 17 const uint32_t kScriptTableTagDflt = 0x44464c54; | |
| 18 // The value which represents there is no required feature index. | |
| 19 const uint16_t kNoRequiredFeatureIndexDefined = 0xFFFF; | |
| 20 // The lookup flag bit which indicates existence of MarkFilteringSet. | |
| 21 const uint16_t kUseMarkFilteringSetBit = 0x0010; | |
| 22 // The mask for MarkAttachmentType. | |
| 23 const uint16_t kMarkAttachmentTypeMask = 0xFF00; | |
| 24 // The maximum type number of format for device tables. | |
| 25 const uint16_t kMaxDeltaFormatType = 3; | |
| 26 | |
| 27 struct ScriptRecord { | |
| 28 uint32_t tag; | |
| 29 uint16_t offset; | |
| 30 }; | |
| 31 | |
| 32 struct LangSysRecord { | |
| 33 uint32_t tag; | |
| 34 uint16_t offset; | |
| 35 }; | |
| 36 | |
| 37 struct FeatureRecord { | |
| 38 uint32_t tag; | |
| 39 uint16_t offset; | |
| 40 }; | |
| 41 | |
| 42 bool ParseLangSysTable(ots::Buffer *subtable, const uint32_t tag, | |
| 43 const uint16_t num_features) { | |
| 44 uint16_t offset_lookup_order = 0; | |
| 45 uint16_t req_feature_index = 0; | |
| 46 uint16_t feature_count = 0; | |
| 47 if (!subtable->ReadU16(&offset_lookup_order) || | |
| 48 !subtable->ReadU16(&req_feature_index) || | |
| 49 !subtable->ReadU16(&feature_count)) { | |
| 50 return OTS_FAILURE(); | |
| 51 } | |
| 52 // |offset_lookup_order| is reserved and should be NULL. | |
| 53 if (offset_lookup_order != 0) { | |
| 54 OTS_FAILURE(); | |
|
Yusuke Sato
2011/02/04 06:12:52
return is missing.
bashi
2011/02/07 01:17:07
Done.
| |
| 55 } | |
| 56 if (req_feature_index != kNoRequiredFeatureIndexDefined && | |
| 57 req_feature_index >= num_features) { | |
| 58 return OTS_FAILURE(); | |
| 59 } | |
| 60 if (feature_count > num_features) { | |
| 61 return OTS_FAILURE(); | |
| 62 } | |
| 63 | |
| 64 for (unsigned i = 0; i < feature_count; ++i) { | |
| 65 uint16_t feature_index = 0; | |
| 66 if (!subtable->ReadU16(&feature_index)) { | |
| 67 return OTS_FAILURE(); | |
| 68 } | |
| 69 if (feature_index >= num_features) { | |
| 70 return OTS_FAILURE(); | |
| 71 } | |
| 72 } | |
| 73 return true; | |
| 74 } | |
| 75 | |
| 76 bool ParseScriptTable(const uint8_t *data, const size_t length, | |
| 77 const uint32_t tag, const uint16_t num_features) { | |
| 78 ots::Buffer subtable(data, length); | |
| 79 | |
| 80 uint16_t offset_default_lang_sys = 0; | |
| 81 uint16_t lang_sys_count = 0; | |
| 82 if (!subtable.ReadU16(&offset_default_lang_sys) || | |
| 83 !subtable.ReadU16(&lang_sys_count)) { | |
| 84 return OTS_FAILURE(); | |
| 85 } | |
| 86 | |
| 87 // The spec requires a script table for 'DFLT' tag must contain non-NULL | |
| 88 // |offset_default_lang_sys| and |lang_sys_count| == 0 | |
| 89 if (tag == kScriptTableTagDflt && | |
| 90 (offset_default_lang_sys == 0 || lang_sys_count != 0)) { | |
| 91 OTS_WARNING("DFLT table doesn't satisfy the spec."); | |
| 92 OTS_FAILURE(); | |
|
Yusuke Sato
2011/02/04 06:12:52
ditto. please grep your change again.
bashi
2011/02/07 01:17:07
Done.
| |
| 93 } | |
| 94 | |
| 95 const unsigned lang_sys_record_end = static_cast<unsigned>(4) + | |
| 96 lang_sys_count * 6; | |
| 97 std::vector<LangSysRecord> lang_sys_records; | |
| 98 lang_sys_records.resize(lang_sys_count); | |
| 99 uint32_t last_tag = 0; | |
| 100 for (unsigned i = 0; i < lang_sys_count; ++i) { | |
| 101 if (!subtable.ReadU32(&lang_sys_records[i].tag) || | |
| 102 !subtable.ReadU16(&lang_sys_records[i].offset)) { | |
| 103 return OTS_FAILURE(); | |
| 104 } | |
| 105 // The record array must store the records alphabetically by tag | |
| 106 if (last_tag != 0 && last_tag > lang_sys_records[i].tag) { | |
| 107 return OTS_FAILURE(); | |
| 108 } | |
| 109 if (lang_sys_records[i].offset < lang_sys_record_end || | |
| 110 lang_sys_records[i].offset >= length) { | |
| 111 return OTS_FAILURE(); | |
| 112 } | |
| 113 last_tag = lang_sys_records[i].tag; | |
| 114 } | |
| 115 | |
| 116 // Check lang sys tables | |
| 117 for (unsigned i = 0; i < lang_sys_count; ++i) { | |
| 118 subtable.set_offset(lang_sys_records[i].offset); | |
| 119 if (!ParseLangSysTable(&subtable, lang_sys_records[i].tag, num_features)) { | |
| 120 return OTS_FAILURE(); | |
| 121 } | |
| 122 } | |
| 123 | |
| 124 return true; | |
| 125 } | |
| 126 | |
| 127 bool ParseFeatureTable(const uint8_t *data, const size_t length, | |
| 128 const uint16_t num_lookups) { | |
| 129 ots::Buffer subtable(data, length); | |
| 130 | |
| 131 uint16_t offset_feature_params = 0; | |
| 132 uint16_t lookup_count = 0; | |
| 133 if (!subtable.ReadU16(&offset_feature_params) || | |
| 134 !subtable.ReadU16(&lookup_count)) { | |
| 135 return OTS_FAILURE(); | |
| 136 } | |
| 137 | |
| 138 const unsigned feature_table_end = static_cast<unsigned>(4) + | |
| 139 num_lookups * 2; | |
| 140 // |offset_feature_params| is generally set to NULL. | |
| 141 if (offset_feature_params != 0 && | |
| 142 (offset_feature_params < feature_table_end || | |
| 143 offset_feature_params >= length)) { | |
| 144 return OTS_FAILURE(); | |
| 145 } | |
| 146 | |
| 147 for (unsigned i = 0; i < lookup_count; ++i) { | |
| 148 uint16_t lookup_index = 0; | |
| 149 if (!subtable.ReadU16(&lookup_index)) { | |
| 150 return OTS_FAILURE(); | |
| 151 } | |
| 152 // lookup index starts with 0. | |
| 153 if (lookup_index >= num_lookups) { | |
| 154 return OTS_FAILURE(); | |
| 155 } | |
| 156 } | |
| 157 return true; | |
| 158 } | |
| 159 | |
| 160 bool LookupTypeParserLess(const ots::LookupTypeParser& parser, | |
| 161 const uint16_t type) { | |
| 162 return parser.type < type; | |
| 163 } | |
| 164 | |
| 165 bool ParseLookupTable(ots::OpenTypeFile *file, const uint8_t *data, | |
| 166 const size_t length, const size_t num_types, | |
| 167 const ots::LookupTypeParser* parsers) { | |
| 168 ots::Buffer subtable(data, length); | |
| 169 | |
| 170 uint16_t lookup_type = 0; | |
| 171 uint16_t lookup_flag = 0; | |
| 172 uint16_t subtable_count = 0; | |
| 173 if (!subtable.ReadU16(&lookup_type) || | |
| 174 !subtable.ReadU16(&lookup_flag) || | |
| 175 !subtable.ReadU16(&subtable_count)) { | |
| 176 return OTS_FAILURE(); | |
| 177 } | |
| 178 | |
| 179 if (lookup_type == 0 || lookup_type > num_types) { | |
| 180 return OTS_FAILURE(); | |
| 181 } | |
| 182 | |
| 183 // Check lookup flags. | |
| 184 if (lookup_flag & kMarkAttachmentTypeMask && | |
|
Yusuke Sato
2011/02/04 06:12:52
I slightly prefer:
if ((lookup_flag & kMarkAttach
bashi
2011/02/07 01:17:07
Done.
| |
| 185 (!file->gdef || !file->gdef->has_mark_attachment_class_def)) { | |
| 186 return OTS_FAILURE(); | |
| 187 } | |
| 188 bool use_mark_filtering_set = false; | |
| 189 if (lookup_flag & kUseMarkFilteringSetBit) { | |
| 190 if (!file->gdef || !file->gdef->has_mark_glyph_sets_def) { | |
| 191 return OTS_FAILURE(); | |
| 192 } | |
| 193 use_mark_filtering_set = true; | |
| 194 } | |
| 195 | |
| 196 std::vector<uint16_t> subtables; | |
| 197 subtables.reserve(subtable_count); | |
| 198 // If the |kUseMarkFilteringSetBit| of |lookup_flag| is set, | |
| 199 // extra 2 bytes will follow after subtable offset array. | |
| 200 const unsigned lookup_table_end = | |
| 201 static_cast<unsigned>(use_mark_filtering_set ? 8 : 6) + | |
| 202 subtable_count * 2; | |
| 203 for (unsigned i = 0; i < subtable_count; ++i) { | |
| 204 if (!subtable.ReadU16(&subtables[i])) { | |
| 205 return OTS_FAILURE(); | |
| 206 } | |
| 207 if (subtables[i] < lookup_table_end || subtables[i] >= length) { | |
| 208 return OTS_FAILURE(); | |
| 209 } | |
| 210 } | |
| 211 | |
| 212 if (use_mark_filtering_set) { | |
| 213 uint16_t mark_filtering_set = 0; | |
| 214 if (!subtable.ReadU16(&mark_filtering_set)) { | |
| 215 return OTS_FAILURE(); | |
| 216 } | |
| 217 if (file->gdef->num_mark_glyph_sets == 0 || | |
| 218 mark_filtering_set >= file->gdef->num_mark_glyph_sets) { | |
| 219 return OTS_FAILURE(); | |
| 220 } | |
| 221 } | |
| 222 | |
| 223 // Parse lookup subtables for this lookup type. | |
| 224 for (unsigned i = 0; i < subtable_count; ++i) { | |
| 225 const ots::LookupTypeParser *parser = | |
| 226 std::lower_bound(parsers, parsers + num_types, lookup_type, | |
| 227 LookupTypeParserLess); | |
| 228 if (parser == parsers + num_types || parser->type != lookup_type || | |
| 229 !parser->parse) { | |
| 230 return OTS_FAILURE(); | |
| 231 } | |
| 232 if (!parser->parse(file, data + subtables[i], length - subtables[i])) { | |
| 233 return OTS_FAILURE(); | |
| 234 } | |
| 235 } | |
| 236 return true; | |
| 237 } | |
| 238 | |
| 12 bool ParseClassDefFormat1(const uint8_t *data, size_t length, | 239 bool ParseClassDefFormat1(const uint8_t *data, size_t length, |
| 13 const uint16_t num_glyphs, | 240 const uint16_t num_glyphs, |
| 14 const uint16_t num_classes) { | 241 const uint16_t num_classes) { |
| 15 ots::Buffer subtable(data, length); | 242 ots::Buffer subtable(data, length); |
| 16 | 243 |
| 17 // Skip format field. | 244 // Skip format field. |
| 18 if (!subtable.Skip(2)) { | 245 if (!subtable.Skip(2)) { |
| 19 return OTS_FAILURE(); | 246 return OTS_FAILURE(); |
| 20 } | 247 } |
| 21 | 248 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 80 return OTS_FAILURE(); | 307 return OTS_FAILURE(); |
| 81 } | 308 } |
| 82 if (start > end || (last_end && start <= last_end)) { | 309 if (start > end || (last_end && start <= last_end)) { |
| 83 OTS_WARNING("glyph range is overlapping."); | 310 OTS_WARNING("glyph range is overlapping."); |
| 84 return OTS_FAILURE(); | 311 return OTS_FAILURE(); |
| 85 } | 312 } |
| 86 if (class_value == 0 || class_value > num_classes) { | 313 if (class_value == 0 || class_value > num_classes) { |
| 87 OTS_WARNING("bad class value: %u", class_value); | 314 OTS_WARNING("bad class value: %u", class_value); |
| 88 return OTS_FAILURE(); | 315 return OTS_FAILURE(); |
| 89 } | 316 } |
| 317 last_end = end; | |
| 90 } | 318 } |
| 91 | 319 |
| 92 return true; | 320 return true; |
| 93 } | 321 } |
| 94 | 322 |
| 95 bool ParseCoverageFormat1(const uint8_t *data, size_t length, | 323 bool ParseCoverageFormat1(const uint8_t *data, size_t length, |
| 96 const uint16_t num_glyphs) { | 324 const uint16_t num_glyphs) { |
| 97 ots::Buffer subtable(data, length); | 325 ots::Buffer subtable(data, length); |
| 98 | 326 |
| 99 // Skip format field. | 327 // Skip format field. |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 129 | 357 |
| 130 // Skip format field. | 358 // Skip format field. |
| 131 if (!subtable.Skip(2)) { | 359 if (!subtable.Skip(2)) { |
| 132 return OTS_FAILURE(); | 360 return OTS_FAILURE(); |
| 133 } | 361 } |
| 134 | 362 |
| 135 uint16_t range_count = 0; | 363 uint16_t range_count = 0; |
| 136 if (!subtable.ReadU16(&range_count)) { | 364 if (!subtable.ReadU16(&range_count)) { |
| 137 return OTS_FAILURE(); | 365 return OTS_FAILURE(); |
| 138 } | 366 } |
| 139 if (range_count >= num_glyphs) { | 367 if (range_count > num_glyphs) { |
| 140 OTS_WARNING("bad range count: %u", range_count); | 368 OTS_WARNING("bad range count: %u", range_count); |
| 141 return OTS_FAILURE(); | 369 return OTS_FAILURE(); |
| 142 } | 370 } |
| 143 uint16_t last_end = 0; | 371 uint16_t last_end = 0; |
| 372 uint16_t last_start_coverage_index = 0; | |
| 144 for (unsigned i = 0; i < range_count; ++i) { | 373 for (unsigned i = 0; i < range_count; ++i) { |
| 145 uint16_t start = 0; | 374 uint16_t start = 0; |
| 146 uint16_t end = 0; | 375 uint16_t end = 0; |
| 147 uint16_t start_coverage_index = 0; | 376 uint16_t start_coverage_index = 0; |
| 148 if (!subtable.ReadU16(&start) || | 377 if (!subtable.ReadU16(&start) || |
| 149 !subtable.ReadU16(&end) || | 378 !subtable.ReadU16(&end) || |
| 150 !subtable.ReadU16(&start_coverage_index)) { | 379 !subtable.ReadU16(&start_coverage_index)) { |
| 151 return OTS_FAILURE(); | 380 return OTS_FAILURE(); |
| 152 } | 381 } |
| 153 if (start > end || (last_end && start <= last_end)) { | 382 if (start > end || (last_end && start <= last_end)) { |
| 154 OTS_WARNING("glyph range is overlapping."); | 383 OTS_WARNING("glyph range is overlapping."); |
| 155 return OTS_FAILURE(); | 384 return OTS_FAILURE(); |
| 156 } | 385 } |
| 386 if (start_coverage_index != last_start_coverage_index) { | |
| 387 OTS_WARNING("bad start coverage index."); | |
| 388 return OTS_FAILURE(); | |
| 389 } | |
| 390 last_end = end; | |
| 391 last_start_coverage_index += end - start + 1; | |
| 157 } | 392 } |
| 158 | 393 |
| 159 return true; | 394 return true; |
| 160 } | 395 } |
| 161 | 396 |
| 162 } // namespace | 397 } // namespace |
| 163 | 398 |
| 164 namespace ots { | 399 namespace ots { |
| 165 | 400 |
| 401 // Parsing ScriptListTable requires number of features so we need to | |
| 402 // parse FeatureListTable before calling this function. | |
| 403 bool ParseScriptListTable(const uint8_t *data, const size_t length, | |
| 404 const uint16_t num_features) { | |
| 405 Buffer subtable(data, length); | |
| 406 | |
| 407 uint16_t script_count = 0; | |
| 408 if (!subtable.ReadU16(&script_count)) { | |
| 409 return OTS_FAILURE(); | |
| 410 } | |
| 411 | |
| 412 const unsigned script_record_end = static_cast<unsigned>(2) + | |
| 413 script_count * 6; | |
| 414 std::vector<ScriptRecord> script_list; | |
| 415 script_list.reserve(script_count); | |
| 416 uint32_t last_tag = 0; | |
| 417 for (unsigned i = 0; i < script_count; ++i) { | |
| 418 if (!subtable.ReadU32(&script_list[i].tag) || | |
| 419 !subtable.ReadU16(&script_list[i].offset)) { | |
| 420 return OTS_FAILURE(); | |
| 421 } | |
| 422 // Script tags should be arranged alphabetically by tag | |
| 423 if (last_tag != 0 && last_tag > script_list[i].tag) { | |
| 424 return OTS_FAILURE(); | |
| 425 } | |
| 426 last_tag = script_list[i].tag; | |
| 427 if (script_list[i].offset < script_record_end || | |
| 428 script_list[i].offset >= length) { | |
| 429 return OTS_FAILURE(); | |
| 430 } | |
| 431 } | |
| 432 | |
| 433 // Check script records. | |
| 434 for (unsigned i = 0; i < script_count; ++i) { | |
| 435 if (!ParseScriptTable(data + script_list[i].offset, | |
| 436 length - script_list[i].offset, | |
| 437 script_list[i].tag, num_features)) { | |
| 438 return OTS_FAILURE(); | |
| 439 } | |
| 440 } | |
| 441 | |
| 442 return true; | |
| 443 } | |
| 444 | |
| 445 // Parsing FeatureListTable requires number of lookups so we need to parse | |
| 446 // LookupListTable before calling this function. | |
| 447 bool ParseFeatureListTable(const uint8_t *data, const size_t length, | |
| 448 const uint16_t num_lookups, | |
| 449 uint16_t* num_features) { | |
| 450 Buffer subtable(data, length); | |
| 451 | |
| 452 uint16_t feature_count = 0; | |
| 453 if (!subtable.ReadU16(&feature_count)) { | |
| 454 return OTS_FAILURE(); | |
| 455 } | |
| 456 | |
| 457 std::vector<FeatureRecord> feature_records; | |
| 458 feature_records.resize(feature_count); | |
| 459 const unsigned feature_record_end = static_cast<unsigned>(2) + | |
| 460 feature_count * 6; | |
| 461 uint32_t last_tag = 0; | |
| 462 for (unsigned i = 0; i < feature_count; ++i) { | |
| 463 if (!subtable.ReadU32(&feature_records[i].tag) || | |
| 464 !subtable.ReadU16(&feature_records[i].offset)) { | |
| 465 return OTS_FAILURE(); | |
| 466 } | |
| 467 // Feature record array should be arranged alphabetically by tag | |
| 468 if (last_tag != 0 && last_tag > feature_records[i].tag) { | |
| 469 return OTS_FAILURE(); | |
| 470 } | |
| 471 last_tag = feature_records[i].tag; | |
| 472 if (feature_records[i].offset < feature_record_end || | |
| 473 feature_records[i].offset >= length) { | |
| 474 return OTS_FAILURE(); | |
| 475 } | |
| 476 } | |
| 477 | |
| 478 for (unsigned i = 0; i < feature_count; ++i) { | |
| 479 if (!ParseFeatureTable(data + feature_records[i].offset, | |
| 480 length - feature_records[i].offset, num_lookups)) { | |
| 481 return OTS_FAILURE(); | |
| 482 } | |
| 483 } | |
| 484 *num_features = feature_count; | |
| 485 return true; | |
| 486 } | |
| 487 | |
| 488 // For parsing GPOS/GSUB tables, this function should be called at first to | |
| 489 // obtain the number of lookups because parsing FeatureTableList requires | |
| 490 // the number. | |
| 491 bool ParseLookupListTable(OpenTypeFile *file, const uint8_t *data, | |
| 492 const size_t length, const size_t num_types, | |
| 493 const LookupTypeParser* parsers, | |
| 494 uint16_t *num_lookups) { | |
| 495 Buffer subtable(data, length); | |
| 496 | |
| 497 if (!subtable.ReadU16(num_lookups)) { | |
| 498 return OTS_FAILURE(); | |
| 499 } | |
| 500 | |
| 501 std::vector<uint16_t> lookups; | |
| 502 lookups.reserve(*num_lookups); | |
| 503 const unsigned lookup_end = static_cast<unsigned>(2) + | |
| 504 (*num_lookups) * 2; | |
| 505 for (unsigned i = 0; i < *num_lookups; ++i) { | |
| 506 if (!subtable.ReadU16(&lookups[i])) { | |
| 507 return OTS_FAILURE(); | |
| 508 } | |
| 509 if (lookups[i] < lookup_end || lookups[i] >= length) { | |
| 510 return OTS_FAILURE(); | |
| 511 } | |
| 512 } | |
| 513 | |
| 514 for (unsigned i = 0; i < *num_lookups; ++i) { | |
| 515 if (!ParseLookupTable(file, data + lookups[i], length - lookups[i], | |
| 516 num_types, parsers)) { | |
| 517 return OTS_FAILURE(); | |
| 518 } | |
| 519 } | |
| 520 | |
| 521 return true; | |
| 522 } | |
| 523 | |
| 166 bool ParseClassDefTable(const uint8_t *data, size_t length, | 524 bool ParseClassDefTable(const uint8_t *data, size_t length, |
| 167 const uint16_t num_glyphs, | 525 const uint16_t num_glyphs, |
| 168 const uint16_t num_classes) { | 526 const uint16_t num_classes) { |
| 169 Buffer subtable(data, length); | 527 Buffer subtable(data, length); |
| 170 | 528 |
| 171 uint16_t format = 0; | 529 uint16_t format = 0; |
| 172 if (!subtable.ReadU16(&format)) { | 530 if (!subtable.ReadU16(&format)) { |
| 173 return OTS_FAILURE(); | 531 return OTS_FAILURE(); |
| 174 } | 532 } |
| 175 if (format == 1) { | 533 if (format == 1) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 191 } | 549 } |
| 192 if (format == 1) { | 550 if (format == 1) { |
| 193 return ParseCoverageFormat1(data, length, num_glyphs); | 551 return ParseCoverageFormat1(data, length, num_glyphs); |
| 194 } else if (format == 2) { | 552 } else if (format == 2) { |
| 195 return ParseCoverageFormat2(data, length, num_glyphs); | 553 return ParseCoverageFormat2(data, length, num_glyphs); |
| 196 } | 554 } |
| 197 | 555 |
| 198 return OTS_FAILURE(); | 556 return OTS_FAILURE(); |
| 199 } | 557 } |
| 200 | 558 |
| 559 bool ParseDeviceTable(const uint8_t *data, size_t length) { | |
| 560 Buffer subtable(data, length); | |
| 561 | |
| 562 uint16_t start_size = 0; | |
| 563 uint16_t end_size = 0; | |
| 564 uint16_t delta_format = 0; | |
| 565 if (!subtable.ReadU16(&start_size) || | |
| 566 !subtable.ReadU16(&end_size) || | |
| 567 !subtable.ReadU16(&delta_format)) { | |
| 568 return OTS_FAILURE(); | |
| 569 } | |
| 570 if (start_size > end_size) { | |
| 571 OTS_WARNING("bad size range: %u > %u", start_size, end_size); | |
| 572 return OTS_FAILURE(); | |
| 573 } | |
| 574 if (delta_format == 0 || delta_format > kMaxDeltaFormatType) { | |
| 575 OTS_WARNING("bad delta format: %u", delta_format); | |
| 576 return OTS_FAILURE(); | |
| 577 } | |
| 578 // The number of delta values per uint16. The device table should contain | |
| 579 // at least |num_units| * 2 bytes compressed data. | |
| 580 const unsigned num_units = (end_size - start_size) / | |
| 581 (1 << (4 - delta_format)) + 1; | |
| 582 // Just skip |num_units| * 2 bytes since the compressed data could take | |
| 583 // arbitrary values. | |
| 584 if (!subtable.Skip(num_units * 2)) { | |
| 585 return OTS_FAILURE(); | |
| 586 } | |
| 587 return true; | |
| 588 } | |
| 589 | |
| 201 } // namespace ots | 590 } // namespace ots |
| 202 | 591 |
| OLD | NEW |