OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "layout.h" |
| 6 |
| 7 #include <limits> |
| 8 #include <vector> |
| 9 |
| 10 #include "gdef.h" |
| 11 |
| 12 // OpenType Layout Common Table Formats |
| 13 // http://www.microsoft.com/typography/otspec/chapter2.htm |
| 14 |
| 15 #define TABLE_NAME "Layout" // XXX: use individual table names |
| 16 |
| 17 namespace { |
| 18 |
| 19 // The 'DFLT' tag of script table. |
| 20 const uint32_t kScriptTableTagDflt = 0x44464c54; |
| 21 // The value which represents there is no required feature index. |
| 22 const uint16_t kNoRequiredFeatureIndexDefined = 0xFFFF; |
| 23 // The lookup flag bit which indicates existence of MarkFilteringSet. |
| 24 const uint16_t kUseMarkFilteringSetBit = 0x0010; |
| 25 // The lookup flags which require GDEF table. |
| 26 const uint16_t kGdefRequiredFlags = 0x0002 | 0x0004 | 0x0008; |
| 27 // The mask for MarkAttachmentType. |
| 28 const uint16_t kMarkAttachmentTypeMask = 0xFF00; |
| 29 // The maximum type number of format for device tables. |
| 30 const uint16_t kMaxDeltaFormatType = 3; |
| 31 // The maximum number of class value. |
| 32 const uint16_t kMaxClassDefValue = 0xFFFF; |
| 33 |
| 34 struct ScriptRecord { |
| 35 uint32_t tag; |
| 36 uint16_t offset; |
| 37 }; |
| 38 |
| 39 struct LangSysRecord { |
| 40 uint32_t tag; |
| 41 uint16_t offset; |
| 42 }; |
| 43 |
| 44 struct FeatureRecord { |
| 45 uint32_t tag; |
| 46 uint16_t offset; |
| 47 }; |
| 48 |
| 49 bool ParseLangSysTable(const ots::OpenTypeFile *file, |
| 50 ots::Buffer *subtable, const uint32_t tag, |
| 51 const uint16_t num_features) { |
| 52 uint16_t offset_lookup_order = 0; |
| 53 uint16_t req_feature_index = 0; |
| 54 uint16_t feature_count = 0; |
| 55 if (!subtable->ReadU16(&offset_lookup_order) || |
| 56 !subtable->ReadU16(&req_feature_index) || |
| 57 !subtable->ReadU16(&feature_count)) { |
| 58 return OTS_FAILURE_MSG("Failed to read langsys header for tag %4.4s", (char
*)&tag); |
| 59 } |
| 60 // |offset_lookup_order| is reserved and should be NULL. |
| 61 if (offset_lookup_order != 0) { |
| 62 return OTS_FAILURE_MSG("Bad lookup offset order %d for langsys tag %4.4s", o
ffset_lookup_order, (char *)&tag); |
| 63 } |
| 64 if (req_feature_index != kNoRequiredFeatureIndexDefined && |
| 65 req_feature_index >= num_features) { |
| 66 return OTS_FAILURE_MSG("Bad required features index %d for langsys tag %4.4s
", req_feature_index, (char *)&tag); |
| 67 } |
| 68 if (feature_count > num_features) { |
| 69 return OTS_FAILURE_MSG("Bad feature count %d for langsys tag %4.4s", feature
_count, (char *)&tag); |
| 70 } |
| 71 |
| 72 for (unsigned i = 0; i < feature_count; ++i) { |
| 73 uint16_t feature_index = 0; |
| 74 if (!subtable->ReadU16(&feature_index)) { |
| 75 return OTS_FAILURE_MSG("Failed to read feature index %d for langsys tag %4
.4s", i, (char *)&tag); |
| 76 } |
| 77 if (feature_index >= num_features) { |
| 78 return OTS_FAILURE_MSG("Bad feature index %d for feature %d for langsys ta
g %4.4s", feature_index, i, (char *)&tag); |
| 79 } |
| 80 } |
| 81 return true; |
| 82 } |
| 83 |
| 84 bool ParseScriptTable(const ots::OpenTypeFile *file, |
| 85 const uint8_t *data, const size_t length, |
| 86 const uint32_t tag, const uint16_t num_features) { |
| 87 ots::Buffer subtable(data, length); |
| 88 |
| 89 uint16_t offset_default_lang_sys = 0; |
| 90 uint16_t lang_sys_count = 0; |
| 91 if (!subtable.ReadU16(&offset_default_lang_sys) || |
| 92 !subtable.ReadU16(&lang_sys_count)) { |
| 93 return OTS_FAILURE_MSG("Failed to read script header for script tag %4.4s",
(char *)&tag); |
| 94 } |
| 95 |
| 96 // The spec requires a script table for 'DFLT' tag must contain non-NULL |
| 97 // |offset_default_lang_sys| and |lang_sys_count| == 0 |
| 98 if (tag == kScriptTableTagDflt && |
| 99 (offset_default_lang_sys == 0 || lang_sys_count != 0)) { |
| 100 return OTS_FAILURE_MSG("DFLT table doesn't satisfy the spec. for script tag
%4.4s", (char *)&tag); |
| 101 } |
| 102 |
| 103 const unsigned lang_sys_record_end = |
| 104 6 * static_cast<unsigned>(lang_sys_count) + 4; |
| 105 if (lang_sys_record_end > std::numeric_limits<uint16_t>::max()) { |
| 106 return OTS_FAILURE_MSG("Bad end of langsys record %d for script tag %4.4s",
lang_sys_record_end, (char *)&tag); |
| 107 } |
| 108 |
| 109 std::vector<LangSysRecord> lang_sys_records; |
| 110 lang_sys_records.resize(lang_sys_count); |
| 111 uint32_t last_tag = 0; |
| 112 for (unsigned i = 0; i < lang_sys_count; ++i) { |
| 113 if (!subtable.ReadU32(&lang_sys_records[i].tag) || |
| 114 !subtable.ReadU16(&lang_sys_records[i].offset)) { |
| 115 return OTS_FAILURE_MSG("Failed to read langsys record header %d for script
tag %4.4s", i, (char *)&tag); |
| 116 } |
| 117 // The record array must store the records alphabetically by tag |
| 118 if (last_tag != 0 && last_tag > lang_sys_records[i].tag) { |
| 119 return OTS_FAILURE_MSG("Bad last tag %d for langsys record %d for script t
ag %4.4s", last_tag, i, (char *)&tag); |
| 120 } |
| 121 if (lang_sys_records[i].offset < lang_sys_record_end || |
| 122 lang_sys_records[i].offset >= length) { |
| 123 return OTS_FAILURE_MSG("bad offset to lang sys table: %x", |
| 124 lang_sys_records[i].offset); |
| 125 } |
| 126 last_tag = lang_sys_records[i].tag; |
| 127 } |
| 128 |
| 129 // Check lang sys tables |
| 130 for (unsigned i = 0; i < lang_sys_count; ++i) { |
| 131 subtable.set_offset(lang_sys_records[i].offset); |
| 132 if (!ParseLangSysTable(file, &subtable, lang_sys_records[i].tag, num_feature
s)) { |
| 133 return OTS_FAILURE_MSG("Failed to parse langsys table %d (%4.4s) for scrip
t tag %4.4s", i, (char *)&lang_sys_records[i].tag, (char *)&tag); |
| 134 } |
| 135 } |
| 136 |
| 137 return true; |
| 138 } |
| 139 |
| 140 bool ParseFeatureTable(const ots::OpenTypeFile *file, |
| 141 const uint8_t *data, const size_t length, |
| 142 const uint16_t num_lookups) { |
| 143 ots::Buffer subtable(data, length); |
| 144 |
| 145 uint16_t offset_feature_params = 0; |
| 146 uint16_t lookup_count = 0; |
| 147 if (!subtable.ReadU16(&offset_feature_params) || |
| 148 !subtable.ReadU16(&lookup_count)) { |
| 149 return OTS_FAILURE_MSG("Failed to read feature table header"); |
| 150 } |
| 151 |
| 152 const unsigned feature_table_end = |
| 153 2 * static_cast<unsigned>(lookup_count) + 4; |
| 154 if (feature_table_end > std::numeric_limits<uint16_t>::max()) { |
| 155 return OTS_FAILURE_MSG("Bad end of feature table %d", feature_table_end); |
| 156 } |
| 157 // |offset_feature_params| is generally set to NULL. |
| 158 if (offset_feature_params != 0 && |
| 159 (offset_feature_params < feature_table_end || |
| 160 offset_feature_params >= length)) { |
| 161 return OTS_FAILURE_MSG("Bad feature params offset %d", offset_feature_params
); |
| 162 } |
| 163 |
| 164 for (unsigned i = 0; i < lookup_count; ++i) { |
| 165 uint16_t lookup_index = 0; |
| 166 if (!subtable.ReadU16(&lookup_index)) { |
| 167 return OTS_FAILURE_MSG("Failed to read lookup index for lookup %d", i); |
| 168 } |
| 169 // lookup index starts with 0. |
| 170 if (lookup_index >= num_lookups) { |
| 171 return OTS_FAILURE_MSG("Bad lookup index %d for lookup %d", lookup_index,
i); |
| 172 } |
| 173 } |
| 174 return true; |
| 175 } |
| 176 |
| 177 bool ParseLookupTable(ots::OpenTypeFile *file, const uint8_t *data, |
| 178 const size_t length, |
| 179 const ots::LookupSubtableParser* parser) { |
| 180 ots::Buffer subtable(data, length); |
| 181 |
| 182 uint16_t lookup_type = 0; |
| 183 uint16_t lookup_flag = 0; |
| 184 uint16_t subtable_count = 0; |
| 185 if (!subtable.ReadU16(&lookup_type) || |
| 186 !subtable.ReadU16(&lookup_flag) || |
| 187 !subtable.ReadU16(&subtable_count)) { |
| 188 return OTS_FAILURE_MSG("Failed to read lookup table header"); |
| 189 } |
| 190 |
| 191 if (lookup_type == 0 || lookup_type > parser->num_types) { |
| 192 return OTS_FAILURE_MSG("Bad lookup type %d", lookup_type); |
| 193 } |
| 194 |
| 195 // Check lookup flags. |
| 196 if ((lookup_flag & kGdefRequiredFlags) && |
| 197 (!file->gdef || !file->gdef->has_glyph_class_def)) { |
| 198 return OTS_FAILURE_MSG("Bad lookup flags %d", lookup_flag); |
| 199 } |
| 200 if ((lookup_flag & kMarkAttachmentTypeMask) && |
| 201 (!file->gdef || !file->gdef->has_mark_attachment_class_def)) { |
| 202 return OTS_FAILURE_MSG("lookup flag asks for mark attachment that is bad %d"
, lookup_flag); |
| 203 } |
| 204 bool use_mark_filtering_set = false; |
| 205 if (lookup_flag & kUseMarkFilteringSetBit) { |
| 206 if (!file->gdef || !file->gdef->has_mark_glyph_sets_def) { |
| 207 return OTS_FAILURE_MSG("lookup flag asks for mark filtering that is bad %d
", lookup_flag); |
| 208 } |
| 209 use_mark_filtering_set = true; |
| 210 } |
| 211 |
| 212 std::vector<uint16_t> subtables; |
| 213 subtables.reserve(subtable_count); |
| 214 // If the |kUseMarkFilteringSetBit| of |lookup_flag| is set, |
| 215 // extra 2 bytes will follow after subtable offset array. |
| 216 const unsigned lookup_table_end = 2 * static_cast<unsigned>(subtable_count) + |
| 217 (use_mark_filtering_set ? 8 : 6); |
| 218 if (lookup_table_end > std::numeric_limits<uint16_t>::max()) { |
| 219 return OTS_FAILURE_MSG("Bad end of lookup %d", lookup_table_end); |
| 220 } |
| 221 for (unsigned i = 0; i < subtable_count; ++i) { |
| 222 uint16_t offset_subtable = 0; |
| 223 if (!subtable.ReadU16(&offset_subtable)) { |
| 224 return OTS_FAILURE_MSG("Failed to read subtable offset %d", i); |
| 225 } |
| 226 if (offset_subtable < lookup_table_end || |
| 227 offset_subtable >= length) { |
| 228 return OTS_FAILURE_MSG("Bad subtable offset %d for subtable %d", offset_su
btable, i); |
| 229 } |
| 230 subtables.push_back(offset_subtable); |
| 231 } |
| 232 if (subtables.size() != subtable_count) { |
| 233 return OTS_FAILURE_MSG("Bad subtable size %ld", subtables.size()); |
| 234 } |
| 235 |
| 236 if (use_mark_filtering_set) { |
| 237 uint16_t mark_filtering_set = 0; |
| 238 if (!subtable.ReadU16(&mark_filtering_set)) { |
| 239 return OTS_FAILURE_MSG("Failed to read mark filtering set"); |
| 240 } |
| 241 if (file->gdef->num_mark_glyph_sets == 0 || |
| 242 mark_filtering_set >= file->gdef->num_mark_glyph_sets) { |
| 243 return OTS_FAILURE_MSG("Bad mark filtering set %d", mark_filtering_set); |
| 244 } |
| 245 } |
| 246 |
| 247 // Parse lookup subtables for this lookup type. |
| 248 for (unsigned i = 0; i < subtable_count; ++i) { |
| 249 if (!parser->Parse(file, data + subtables[i], length - subtables[i], |
| 250 lookup_type)) { |
| 251 return OTS_FAILURE_MSG("Failed to parse subtable %d", i); |
| 252 } |
| 253 } |
| 254 return true; |
| 255 } |
| 256 |
| 257 bool ParseClassDefFormat1(const ots::OpenTypeFile *file, |
| 258 const uint8_t *data, size_t length, |
| 259 const uint16_t num_glyphs, |
| 260 const uint16_t num_classes) { |
| 261 ots::Buffer subtable(data, length); |
| 262 |
| 263 // Skip format field. |
| 264 if (!subtable.Skip(2)) { |
| 265 return OTS_FAILURE_MSG("Failed to skip class definition header"); |
| 266 } |
| 267 |
| 268 uint16_t start_glyph = 0; |
| 269 if (!subtable.ReadU16(&start_glyph)) { |
| 270 return OTS_FAILURE_MSG("Failed to read starting glyph of class definition"); |
| 271 } |
| 272 if (start_glyph > num_glyphs) { |
| 273 return OTS_FAILURE_MSG("Bad starting glyph %d in class definition", start_gl
yph); |
| 274 } |
| 275 |
| 276 uint16_t glyph_count = 0; |
| 277 if (!subtable.ReadU16(&glyph_count)) { |
| 278 return OTS_FAILURE_MSG("Failed to read glyph count in class definition"); |
| 279 } |
| 280 if (glyph_count > num_glyphs) { |
| 281 return OTS_FAILURE_MSG("bad glyph count: %u", glyph_count); |
| 282 } |
| 283 for (unsigned i = 0; i < glyph_count; ++i) { |
| 284 uint16_t class_value = 0; |
| 285 if (!subtable.ReadU16(&class_value)) { |
| 286 return OTS_FAILURE_MSG("Failed to read class value for glyph %d in class d
efinition", i); |
| 287 } |
| 288 if (class_value > num_classes) { |
| 289 return OTS_FAILURE_MSG("Bad class value %d for glyph %d in class definitio
n", class_value, i); |
| 290 } |
| 291 } |
| 292 |
| 293 return true; |
| 294 } |
| 295 |
| 296 bool ParseClassDefFormat2(const ots::OpenTypeFile *file, |
| 297 const uint8_t *data, size_t length, |
| 298 const uint16_t num_glyphs, |
| 299 const uint16_t num_classes) { |
| 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 class defintion header"); |
| 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 class definition"); |
| 310 } |
| 311 if (range_count > num_glyphs) { |
| 312 return OTS_FAILURE_MSG("bad range count: %u", range_count); |
| 313 } |
| 314 |
| 315 uint16_t last_end = 0; |
| 316 for (unsigned i = 0; i < range_count; ++i) { |
| 317 uint16_t start = 0; |
| 318 uint16_t end = 0; |
| 319 uint16_t class_value = 0; |
| 320 if (!subtable.ReadU16(&start) || |
| 321 !subtable.ReadU16(&end) || |
| 322 !subtable.ReadU16(&class_value)) { |
| 323 return OTS_FAILURE_MSG("Failed to read class definition reange %d", i); |
| 324 } |
| 325 if (start > end || (last_end && start <= last_end)) { |
| 326 return OTS_FAILURE_MSG("glyph range is overlapping.in range %d", i); |
| 327 } |
| 328 if (class_value > num_classes) { |
| 329 return OTS_FAILURE_MSG("bad class value: %u", class_value); |
| 330 } |
| 331 last_end = end; |
| 332 } |
| 333 |
| 334 return true; |
| 335 } |
| 336 |
| 337 bool ParseCoverageFormat1(const ots::OpenTypeFile *file, |
| 338 const uint8_t *data, size_t length, |
| 339 const uint16_t num_glyphs, |
| 340 const uint16_t expected_num_glyphs) { |
| 341 ots::Buffer subtable(data, length); |
| 342 |
| 343 // Skip format field. |
| 344 if (!subtable.Skip(2)) { |
| 345 return OTS_FAILURE_MSG("Failed to skip coverage format"); |
| 346 } |
| 347 |
| 348 uint16_t glyph_count = 0; |
| 349 if (!subtable.ReadU16(&glyph_count)) { |
| 350 return OTS_FAILURE_MSG("Failed to read glyph count in coverage"); |
| 351 } |
| 352 if (glyph_count > num_glyphs) { |
| 353 return OTS_FAILURE_MSG("bad glyph count: %u", glyph_count); |
| 354 } |
| 355 for (unsigned i = 0; i < glyph_count; ++i) { |
| 356 uint16_t glyph = 0; |
| 357 if (!subtable.ReadU16(&glyph)) { |
| 358 return OTS_FAILURE_MSG("Failed to read glyph %d in coverage", i); |
| 359 } |
| 360 if (glyph > num_glyphs) { |
| 361 return OTS_FAILURE_MSG("bad glyph ID: %u", glyph); |
| 362 } |
| 363 } |
| 364 |
| 365 if (expected_num_glyphs && expected_num_glyphs != glyph_count) { |
| 366 return OTS_FAILURE_MSG("unexpected number of glyphs: %u", glyph_count); |
| 367 } |
| 368 |
| 369 return true; |
| 370 } |
| 371 |
| 372 bool ParseCoverageFormat2(const ots::OpenTypeFile *file, |
| 373 const uint8_t *data, size_t length, |
| 374 const uint16_t num_glyphs, |
| 375 const uint16_t expected_num_glyphs) { |
| 376 ots::Buffer subtable(data, length); |
| 377 |
| 378 // Skip format field. |
| 379 if (!subtable.Skip(2)) { |
| 380 return OTS_FAILURE_MSG("Failed to skip format of coverage type 2"); |
| 381 } |
| 382 |
| 383 uint16_t range_count = 0; |
| 384 if (!subtable.ReadU16(&range_count)) { |
| 385 return OTS_FAILURE_MSG("Failed to read range count in coverage"); |
| 386 } |
| 387 if (range_count > num_glyphs) { |
| 388 return OTS_FAILURE_MSG("bad range count: %u", range_count); |
| 389 } |
| 390 uint16_t last_end = 0; |
| 391 uint16_t last_start_coverage_index = 0; |
| 392 for (unsigned i = 0; i < range_count; ++i) { |
| 393 uint16_t start = 0; |
| 394 uint16_t end = 0; |
| 395 uint16_t start_coverage_index = 0; |
| 396 if (!subtable.ReadU16(&start) || |
| 397 !subtable.ReadU16(&end) || |
| 398 !subtable.ReadU16(&start_coverage_index)) { |
| 399 return OTS_FAILURE_MSG("Failed to read range %d in coverage", i); |
| 400 } |
| 401 |
| 402 // Some of the Adobe Pro fonts have ranges that overlap by one element: the |
| 403 // start of one range is equal to the end of the previous range. Therefore |
| 404 // the < in the following condition should be <= were it not for this. |
| 405 // See crbug.com/134135. |
| 406 if (start > end || (last_end && start < last_end)) { |
| 407 return OTS_FAILURE_MSG("glyph range is overlapping."); |
| 408 } |
| 409 if (start_coverage_index != last_start_coverage_index) { |
| 410 return OTS_FAILURE_MSG("bad start coverage index."); |
| 411 } |
| 412 last_end = end; |
| 413 last_start_coverage_index += end - start + 1; |
| 414 } |
| 415 |
| 416 if (expected_num_glyphs && |
| 417 expected_num_glyphs != last_start_coverage_index) { |
| 418 return OTS_FAILURE_MSG("unexpected number of glyphs: %u", last_start_cover
age_index); |
| 419 } |
| 420 |
| 421 return true; |
| 422 } |
| 423 |
| 424 // Parsers for Contextual subtables in GSUB/GPOS tables. |
| 425 |
| 426 bool ParseLookupRecord(const ots::OpenTypeFile *file, |
| 427 ots::Buffer *subtable, const uint16_t num_glyphs, |
| 428 const uint16_t num_lookups) { |
| 429 uint16_t sequence_index = 0; |
| 430 uint16_t lookup_list_index = 0; |
| 431 if (!subtable->ReadU16(&sequence_index) || |
| 432 !subtable->ReadU16(&lookup_list_index)) { |
| 433 return OTS_FAILURE_MSG("Failed to read header for lookup record"); |
| 434 } |
| 435 if (sequence_index >= num_glyphs) { |
| 436 return OTS_FAILURE_MSG("Bad sequence index %d in lookup record", sequence_in
dex); |
| 437 } |
| 438 if (lookup_list_index >= num_lookups) { |
| 439 return OTS_FAILURE_MSG("Bad lookup list index %d in lookup record", lookup_l
ist_index); |
| 440 } |
| 441 return true; |
| 442 } |
| 443 |
| 444 bool ParseRuleSubtable(const ots::OpenTypeFile *file, |
| 445 const uint8_t *data, const size_t length, |
| 446 const uint16_t num_glyphs, |
| 447 const uint16_t num_lookups) { |
| 448 ots::Buffer subtable(data, length); |
| 449 |
| 450 uint16_t glyph_count = 0; |
| 451 uint16_t lookup_count = 0; |
| 452 if (!subtable.ReadU16(&glyph_count) || |
| 453 !subtable.ReadU16(&lookup_count)) { |
| 454 return OTS_FAILURE_MSG("Failed to read rule subtable header"); |
| 455 } |
| 456 |
| 457 if (glyph_count == 0 || glyph_count >= num_glyphs) { |
| 458 return OTS_FAILURE_MSG("Bad glyph count %d in rule subtable", glyph_count); |
| 459 } |
| 460 for (unsigned i = 0; i < glyph_count - static_cast<unsigned>(1); ++i) { |
| 461 uint16_t glyph_id = 0; |
| 462 if (!subtable.ReadU16(&glyph_id)) { |
| 463 return OTS_FAILURE_MSG("Failed to read glyph %d", i); |
| 464 } |
| 465 if (glyph_id > num_glyphs) { |
| 466 return OTS_FAILURE_MSG("Bad glyph %d for entry %d", glyph_id, i); |
| 467 } |
| 468 } |
| 469 |
| 470 for (unsigned i = 0; i < lookup_count; ++i) { |
| 471 if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) { |
| 472 return OTS_FAILURE_MSG("Failed to parse lookup record %d", i); |
| 473 } |
| 474 } |
| 475 return true; |
| 476 } |
| 477 |
| 478 bool ParseRuleSetTable(const ots::OpenTypeFile *file, |
| 479 const uint8_t *data, const size_t length, |
| 480 const uint16_t num_glyphs, |
| 481 const uint16_t num_lookups) { |
| 482 ots::Buffer subtable(data, length); |
| 483 |
| 484 uint16_t rule_count = 0; |
| 485 if (!subtable.ReadU16(&rule_count)) { |
| 486 return OTS_FAILURE_MSG("Failed to read rule count in rule set"); |
| 487 } |
| 488 const unsigned rule_end = 2 * static_cast<unsigned>(rule_count) + 2; |
| 489 if (rule_end > std::numeric_limits<uint16_t>::max()) { |
| 490 return OTS_FAILURE_MSG("Bad end of rule %d in rule set", rule_end); |
| 491 } |
| 492 |
| 493 for (unsigned i = 0; i < rule_count; ++i) { |
| 494 uint16_t offset_rule = 0; |
| 495 if (!subtable.ReadU16(&offset_rule)) { |
| 496 return OTS_FAILURE_MSG("Failed to read rule offset for rule set %d", i); |
| 497 } |
| 498 if (offset_rule < rule_end || offset_rule >= length) { |
| 499 return OTS_FAILURE_MSG("Bad rule offset %d in set %d", offset_rule, i); |
| 500 } |
| 501 if (!ParseRuleSubtable(file, data + offset_rule, length - offset_rule, |
| 502 num_glyphs, num_lookups)) { |
| 503 return OTS_FAILURE_MSG("Failed to parse rule set %d", i); |
| 504 } |
| 505 } |
| 506 |
| 507 return true; |
| 508 } |
| 509 |
| 510 bool ParseContextFormat1(const ots::OpenTypeFile *file, |
| 511 const uint8_t *data, const size_t length, |
| 512 const uint16_t num_glyphs, |
| 513 const uint16_t num_lookups) { |
| 514 ots::Buffer subtable(data, length); |
| 515 |
| 516 uint16_t offset_coverage = 0; |
| 517 uint16_t rule_set_count = 0; |
| 518 // Skip format field. |
| 519 if (!subtable.Skip(2) || |
| 520 !subtable.ReadU16(&offset_coverage) || |
| 521 !subtable.ReadU16(&rule_set_count)) { |
| 522 return OTS_FAILURE_MSG("Failed to read header of context format 1"); |
| 523 } |
| 524 |
| 525 const unsigned rule_set_end = static_cast<unsigned>(6) + |
| 526 rule_set_count * 2; |
| 527 if (rule_set_end > std::numeric_limits<uint16_t>::max()) { |
| 528 return OTS_FAILURE_MSG("Bad end of rule set %d of context format 1", rule_se
t_end); |
| 529 } |
| 530 if (offset_coverage < rule_set_end || offset_coverage >= length) { |
| 531 return OTS_FAILURE_MSG("Bad coverage offset %d in context format 1", offset_
coverage); |
| 532 } |
| 533 if (!ots::ParseCoverageTable(file, data + offset_coverage, |
| 534 length - offset_coverage, num_glyphs)) { |
| 535 return OTS_FAILURE_MSG("Failed to parse coverage table in context format 1")
; |
| 536 } |
| 537 |
| 538 for (unsigned i = 0; i < rule_set_count; ++i) { |
| 539 uint16_t offset_rule = 0; |
| 540 if (!subtable.ReadU16(&offset_rule)) { |
| 541 return OTS_FAILURE_MSG("Failed to read rule offset %d in context format 1"
, i); |
| 542 } |
| 543 if (offset_rule < rule_set_end || offset_rule >= length) { |
| 544 return OTS_FAILURE_MSG("Bad rule offset %d in rule %d in context format 1"
, offset_rule, i); |
| 545 } |
| 546 if (!ParseRuleSetTable(file, data + offset_rule, length - offset_rule, |
| 547 num_glyphs, num_lookups)) { |
| 548 return OTS_FAILURE_MSG("Failed to parse rule set %d in context format 1",
i); |
| 549 } |
| 550 } |
| 551 |
| 552 return true; |
| 553 } |
| 554 |
| 555 bool ParseClassRuleTable(const ots::OpenTypeFile *file, |
| 556 const uint8_t *data, const size_t length, |
| 557 const uint16_t num_glyphs, |
| 558 const uint16_t num_lookups) { |
| 559 ots::Buffer subtable(data, length); |
| 560 |
| 561 uint16_t glyph_count = 0; |
| 562 uint16_t lookup_count = 0; |
| 563 if (!subtable.ReadU16(&glyph_count) || |
| 564 !subtable.ReadU16(&lookup_count)) { |
| 565 return OTS_FAILURE_MSG("Failed to read header of class rule table"); |
| 566 } |
| 567 |
| 568 if (glyph_count == 0 || glyph_count >= num_glyphs) { |
| 569 return OTS_FAILURE_MSG("Bad glyph count %d in class rule table", glyph_count
); |
| 570 } |
| 571 |
| 572 // ClassRule table contains an array of classes. Each value of classes |
| 573 // could take arbitrary values including zero so we don't check these value. |
| 574 const unsigned num_classes = glyph_count - static_cast<unsigned>(1); |
| 575 if (!subtable.Skip(2 * num_classes)) { |
| 576 return OTS_FAILURE_MSG("Failed to skip classes in class rule table"); |
| 577 } |
| 578 |
| 579 for (unsigned i = 0; i < lookup_count; ++i) { |
| 580 if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) { |
| 581 return OTS_FAILURE_MSG("Failed to parse lookup record %d in class rule tab
le", i); |
| 582 } |
| 583 } |
| 584 return true; |
| 585 } |
| 586 |
| 587 bool ParseClassSetTable(const ots::OpenTypeFile *file, |
| 588 const uint8_t *data, const size_t length, |
| 589 const uint16_t num_glyphs, |
| 590 const uint16_t num_lookups) { |
| 591 ots::Buffer subtable(data, length); |
| 592 |
| 593 uint16_t class_rule_count = 0; |
| 594 if (!subtable.ReadU16(&class_rule_count)) { |
| 595 return OTS_FAILURE_MSG("Failed to read class rule count in class set table")
; |
| 596 } |
| 597 const unsigned class_rule_end = |
| 598 2 * static_cast<unsigned>(class_rule_count) + 2; |
| 599 if (class_rule_end > std::numeric_limits<uint16_t>::max()) { |
| 600 return OTS_FAILURE_MSG("bad class rule end %d in class set table", class_rul
e_end); |
| 601 } |
| 602 for (unsigned i = 0; i < class_rule_count; ++i) { |
| 603 uint16_t offset_class_rule = 0; |
| 604 if (!subtable.ReadU16(&offset_class_rule)) { |
| 605 return OTS_FAILURE_MSG("Failed to read class rule offset %d in class set t
able", i); |
| 606 } |
| 607 if (offset_class_rule < class_rule_end || offset_class_rule >= length) { |
| 608 return OTS_FAILURE_MSG("Bad class rule offset %d in class %d", offset_clas
s_rule, i); |
| 609 } |
| 610 if (!ParseClassRuleTable(file, data + offset_class_rule, |
| 611 length - offset_class_rule, num_glyphs, |
| 612 num_lookups)) { |
| 613 return OTS_FAILURE_MSG("Failed to parse class rule table %d", i); |
| 614 } |
| 615 } |
| 616 |
| 617 return true; |
| 618 } |
| 619 |
| 620 bool ParseContextFormat2(const ots::OpenTypeFile *file, |
| 621 const uint8_t *data, const size_t length, |
| 622 const uint16_t num_glyphs, |
| 623 const uint16_t num_lookups) { |
| 624 ots::Buffer subtable(data, length); |
| 625 |
| 626 uint16_t offset_coverage = 0; |
| 627 uint16_t offset_class_def = 0; |
| 628 uint16_t class_set_cnt = 0; |
| 629 // Skip format field. |
| 630 if (!subtable.Skip(2) || |
| 631 !subtable.ReadU16(&offset_coverage) || |
| 632 !subtable.ReadU16(&offset_class_def) || |
| 633 !subtable.ReadU16(&class_set_cnt)) { |
| 634 return OTS_FAILURE_MSG("Failed to read header for context format 2"); |
| 635 } |
| 636 |
| 637 const unsigned class_set_end = 2 * static_cast<unsigned>(class_set_cnt) + 8; |
| 638 if (class_set_end > std::numeric_limits<uint16_t>::max()) { |
| 639 return OTS_FAILURE_MSG("Bad end of class set %d for context format 2", class
_set_end); |
| 640 } |
| 641 if (offset_coverage < class_set_end || offset_coverage >= length) { |
| 642 return OTS_FAILURE_MSG("Bad coverage offset %d in context format 2", offset_
coverage); |
| 643 } |
| 644 if (!ots::ParseCoverageTable(file, data + offset_coverage, |
| 645 length - offset_coverage, num_glyphs)) { |
| 646 return OTS_FAILURE_MSG("Failed to parse coverage table in context format 2")
; |
| 647 } |
| 648 |
| 649 if (offset_class_def < class_set_end || offset_class_def >= length) { |
| 650 return OTS_FAILURE_MSG("bad class definition offset %d in context format 2",
offset_class_def); |
| 651 } |
| 652 if (!ots::ParseClassDefTable(file, data + offset_class_def, |
| 653 length - offset_class_def, |
| 654 num_glyphs, kMaxClassDefValue)) { |
| 655 return OTS_FAILURE_MSG("Failed to parse class definition table in context fo
rmat 2"); |
| 656 } |
| 657 |
| 658 for (unsigned i = 0; i < class_set_cnt; ++i) { |
| 659 uint16_t offset_class_rule = 0; |
| 660 if (!subtable.ReadU16(&offset_class_rule)) { |
| 661 return OTS_FAILURE_MSG("Failed to read class rule offset %d in context for
mat 2", i); |
| 662 } |
| 663 if (offset_class_rule) { |
| 664 if (offset_class_rule < class_set_end || offset_class_rule >= length) { |
| 665 return OTS_FAILURE_MSG("Bad class rule offset %d for rule %d in context
format 2", offset_class_rule, i); |
| 666 } |
| 667 if (!ParseClassSetTable(file, data + offset_class_rule, |
| 668 length - offset_class_rule, num_glyphs, |
| 669 num_lookups)) { |
| 670 return OTS_FAILURE_MSG("Failed to parse class set %d in context format 2
", i); |
| 671 } |
| 672 } |
| 673 } |
| 674 |
| 675 return true; |
| 676 } |
| 677 |
| 678 bool ParseContextFormat3(const ots::OpenTypeFile *file, |
| 679 const uint8_t *data, const size_t length, |
| 680 const uint16_t num_glyphs, |
| 681 const uint16_t num_lookups) { |
| 682 ots::Buffer subtable(data, length); |
| 683 |
| 684 uint16_t glyph_count = 0; |
| 685 uint16_t lookup_count = 0; |
| 686 // Skip format field. |
| 687 if (!subtable.Skip(2) || |
| 688 !subtable.ReadU16(&glyph_count) || |
| 689 !subtable.ReadU16(&lookup_count)) { |
| 690 return OTS_FAILURE_MSG("Failed to read header in context format 3"); |
| 691 } |
| 692 |
| 693 if (glyph_count >= num_glyphs) { |
| 694 return OTS_FAILURE_MSG("Bad glyph count %d in context format 3", glyph_count
); |
| 695 } |
| 696 const unsigned lookup_record_end = 2 * static_cast<unsigned>(glyph_count) + |
| 697 4 * static_cast<unsigned>(lookup_count) + 6; |
| 698 if (lookup_record_end > std::numeric_limits<uint16_t>::max()) { |
| 699 return OTS_FAILURE_MSG("Bad end of lookup %d in context format 3", lookup_re
cord_end); |
| 700 } |
| 701 for (unsigned i = 0; i < glyph_count; ++i) { |
| 702 uint16_t offset_coverage = 0; |
| 703 if (!subtable.ReadU16(&offset_coverage)) { |
| 704 return OTS_FAILURE_MSG("Failed to read coverage offset %d in conxtext form
at 3", i); |
| 705 } |
| 706 if (offset_coverage < lookup_record_end || offset_coverage >= length) { |
| 707 return OTS_FAILURE_MSG("Bad coverage offset %d for glyph %d in context for
mat 3", offset_coverage, i); |
| 708 } |
| 709 if (!ots::ParseCoverageTable(file, data + offset_coverage, |
| 710 length - offset_coverage, num_glyphs)) { |
| 711 return OTS_FAILURE_MSG("Failed to parse coverage table for glyph %d in con
text format 3", i); |
| 712 } |
| 713 } |
| 714 |
| 715 for (unsigned i = 0; i < lookup_count; ++i) { |
| 716 if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) { |
| 717 return OTS_FAILURE_MSG("Failed to parse lookup record %d in context format
3", i); |
| 718 } |
| 719 } |
| 720 |
| 721 return true; |
| 722 } |
| 723 |
| 724 // Parsers for Chaning Contextual subtables in GSUB/GPOS tables. |
| 725 |
| 726 bool ParseChainRuleSubtable(const ots::OpenTypeFile *file, |
| 727 const uint8_t *data, const size_t length, |
| 728 const uint16_t num_glyphs, |
| 729 const uint16_t num_lookups) { |
| 730 ots::Buffer subtable(data, length); |
| 731 |
| 732 uint16_t backtrack_count = 0; |
| 733 if (!subtable.ReadU16(&backtrack_count)) { |
| 734 return OTS_FAILURE_MSG("Failed to read backtrack count in chain rule subtabl
e"); |
| 735 } |
| 736 if (backtrack_count >= num_glyphs) { |
| 737 return OTS_FAILURE_MSG("Bad backtrack count %d in chain rule subtable", back
track_count); |
| 738 } |
| 739 for (unsigned i = 0; i < backtrack_count; ++i) { |
| 740 uint16_t glyph_id = 0; |
| 741 if (!subtable.ReadU16(&glyph_id)) { |
| 742 return OTS_FAILURE_MSG("Failed to read backtrack glyph %d in chain rule su
btable", i); |
| 743 } |
| 744 if (glyph_id > num_glyphs) { |
| 745 return OTS_FAILURE_MSG("Bad glyph id %d for bactrack glyph %d in chain rul
e subtable", glyph_id, i); |
| 746 } |
| 747 } |
| 748 |
| 749 uint16_t input_count = 0; |
| 750 if (!subtable.ReadU16(&input_count)) { |
| 751 return OTS_FAILURE_MSG("Failed to read input count in chain rule subtable"); |
| 752 } |
| 753 if (input_count == 0 || input_count >= num_glyphs) { |
| 754 return OTS_FAILURE_MSG("Bad input count %d in chain rule subtable", input_co
unt); |
| 755 } |
| 756 for (unsigned i = 0; i < input_count - static_cast<unsigned>(1); ++i) { |
| 757 uint16_t glyph_id = 0; |
| 758 if (!subtable.ReadU16(&glyph_id)) { |
| 759 return OTS_FAILURE_MSG("Failed to read input glyph %d in chain rule subtab
le", i); |
| 760 } |
| 761 if (glyph_id > num_glyphs) { |
| 762 return OTS_FAILURE_MSG("Bad glyph id %d for input glyph %d in chain rule s
ubtable", glyph_id, i); |
| 763 } |
| 764 } |
| 765 |
| 766 uint16_t lookahead_count = 0; |
| 767 if (!subtable.ReadU16(&lookahead_count)) { |
| 768 return OTS_FAILURE_MSG("Failed to read lookahead count in chain rule subtabl
e"); |
| 769 } |
| 770 if (lookahead_count >= num_glyphs) { |
| 771 return OTS_FAILURE_MSG("Bad lookahead count %d in chain rule subtable", look
ahead_count); |
| 772 } |
| 773 for (unsigned i = 0; i < lookahead_count; ++i) { |
| 774 uint16_t glyph_id = 0; |
| 775 if (!subtable.ReadU16(&glyph_id)) { |
| 776 return OTS_FAILURE_MSG("Failed to read lookahead glyph %d in chain rule su
btable", i); |
| 777 } |
| 778 if (glyph_id > num_glyphs) { |
| 779 return OTS_FAILURE_MSG("Bad glyph id %d for lookadhead glyph %d in chain r
ule subtable", glyph_id, i); |
| 780 } |
| 781 } |
| 782 |
| 783 uint16_t lookup_count = 0; |
| 784 if (!subtable.ReadU16(&lookup_count)) { |
| 785 return OTS_FAILURE_MSG("Failed to read lookup count in chain rule subtable")
; |
| 786 } |
| 787 for (unsigned i = 0; i < lookup_count; ++i) { |
| 788 if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) { |
| 789 return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain rule sub
table", i); |
| 790 } |
| 791 } |
| 792 |
| 793 return true; |
| 794 } |
| 795 |
| 796 bool ParseChainRuleSetTable(const ots::OpenTypeFile *file, |
| 797 const uint8_t *data, const size_t length, |
| 798 const uint16_t num_glyphs, |
| 799 const uint16_t num_lookups) { |
| 800 ots::Buffer subtable(data, length); |
| 801 |
| 802 uint16_t chain_rule_count = 0; |
| 803 if (!subtable.ReadU16(&chain_rule_count)) { |
| 804 return OTS_FAILURE_MSG("Failed to read rule count in chain rule set"); |
| 805 } |
| 806 const unsigned chain_rule_end = |
| 807 2 * static_cast<unsigned>(chain_rule_count) + 2; |
| 808 if (chain_rule_end > std::numeric_limits<uint16_t>::max()) { |
| 809 return OTS_FAILURE_MSG("Bad end of chain rule %d in chain rule set", chain_r
ule_end); |
| 810 } |
| 811 for (unsigned i = 0; i < chain_rule_count; ++i) { |
| 812 uint16_t offset_chain_rule = 0; |
| 813 if (!subtable.ReadU16(&offset_chain_rule)) { |
| 814 return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain rule
set", i); |
| 815 } |
| 816 if (offset_chain_rule < chain_rule_end || offset_chain_rule >= length) { |
| 817 return OTS_FAILURE_MSG("Bad chain rule offset %d for chain rule %d in chai
n rule set", offset_chain_rule, i); |
| 818 } |
| 819 if (!ParseChainRuleSubtable(file, data + offset_chain_rule, |
| 820 length - offset_chain_rule, |
| 821 num_glyphs, num_lookups)) { |
| 822 return OTS_FAILURE_MSG("Failed to parse chain rule %d in chain rule set",
i); |
| 823 } |
| 824 } |
| 825 |
| 826 return true; |
| 827 } |
| 828 |
| 829 bool ParseChainContextFormat1(const ots::OpenTypeFile *file, |
| 830 const uint8_t *data, const size_t length, |
| 831 const uint16_t num_glyphs, |
| 832 const uint16_t num_lookups) { |
| 833 ots::Buffer subtable(data, length); |
| 834 |
| 835 uint16_t offset_coverage = 0; |
| 836 uint16_t chain_rule_set_count = 0; |
| 837 // Skip format field. |
| 838 if (!subtable.Skip(2) || |
| 839 !subtable.ReadU16(&offset_coverage) || |
| 840 !subtable.ReadU16(&chain_rule_set_count)) { |
| 841 return OTS_FAILURE_MSG("Failed to read header of chain context format 1"); |
| 842 } |
| 843 |
| 844 const unsigned chain_rule_set_end = |
| 845 2 * static_cast<unsigned>(chain_rule_set_count) + 6; |
| 846 if (chain_rule_set_end > std::numeric_limits<uint16_t>::max()) { |
| 847 return OTS_FAILURE_MSG("Bad chain rule end %d in chain context format 1", ch
ain_rule_set_end); |
| 848 } |
| 849 if (offset_coverage < chain_rule_set_end || offset_coverage >= length) { |
| 850 return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 1", c
hain_rule_set_end); |
| 851 } |
| 852 if (!ots::ParseCoverageTable(file, data + offset_coverage, |
| 853 length - offset_coverage, num_glyphs)) { |
| 854 return OTS_FAILURE_MSG("Failed to parse coverage table for chain context for
mat 1"); |
| 855 } |
| 856 |
| 857 for (unsigned i = 0; i < chain_rule_set_count; ++i) { |
| 858 uint16_t offset_chain_rule_set = 0; |
| 859 if (!subtable.ReadU16(&offset_chain_rule_set)) { |
| 860 return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain conte
xt format 1", i); |
| 861 } |
| 862 if (offset_chain_rule_set < chain_rule_set_end || |
| 863 offset_chain_rule_set >= length) { |
| 864 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); |
| 865 } |
| 866 if (!ParseChainRuleSetTable(file, data + offset_chain_rule_set, |
| 867 length - offset_chain_rule_set, |
| 868 num_glyphs, num_lookups)) { |
| 869 return OTS_FAILURE_MSG("Failed to parse chain rule set %d in chain context
format 1", i); |
| 870 } |
| 871 } |
| 872 |
| 873 return true; |
| 874 } |
| 875 |
| 876 bool ParseChainClassRuleSubtable(const ots::OpenTypeFile *file, |
| 877 const uint8_t *data, const size_t length, |
| 878 const uint16_t num_glyphs, |
| 879 const uint16_t num_lookups) { |
| 880 ots::Buffer subtable(data, length); |
| 881 |
| 882 // In this subtable, we don't check the value of classes for now since |
| 883 // these could take arbitrary values. |
| 884 |
| 885 uint16_t backtrack_count = 0; |
| 886 if (!subtable.ReadU16(&backtrack_count)) { |
| 887 return OTS_FAILURE_MSG("Failed to read backtrack count in chain class rule s
ubtable"); |
| 888 } |
| 889 if (backtrack_count >= num_glyphs) { |
| 890 return OTS_FAILURE_MSG("Bad backtrack count %d in chain class rule subtable"
, backtrack_count); |
| 891 } |
| 892 if (!subtable.Skip(2 * backtrack_count)) { |
| 893 return OTS_FAILURE_MSG("Failed to skip backtrack offsets in chain class rule
subtable"); |
| 894 } |
| 895 |
| 896 uint16_t input_count = 0; |
| 897 if (!subtable.ReadU16(&input_count)) { |
| 898 return OTS_FAILURE_MSG("Failed to read input count in chain class rule subta
ble"); |
| 899 } |
| 900 if (input_count == 0 || input_count >= num_glyphs) { |
| 901 return OTS_FAILURE_MSG("Bad input count %d in chain class rule subtable", in
put_count); |
| 902 } |
| 903 if (!subtable.Skip(2 * (input_count - 1))) { |
| 904 return OTS_FAILURE_MSG("Failed to skip input offsets in chain class rule sub
table"); |
| 905 } |
| 906 |
| 907 uint16_t lookahead_count = 0; |
| 908 if (!subtable.ReadU16(&lookahead_count)) { |
| 909 return OTS_FAILURE_MSG("Failed to read lookahead count in chain class rule s
ubtable"); |
| 910 } |
| 911 if (lookahead_count >= num_glyphs) { |
| 912 return OTS_FAILURE_MSG("Bad lookahead count %d in chain class rule subtable"
, lookahead_count); |
| 913 } |
| 914 if (!subtable.Skip(2 * lookahead_count)) { |
| 915 return OTS_FAILURE_MSG("Failed to skip lookahead offsets in chain class rule
subtable"); |
| 916 } |
| 917 |
| 918 uint16_t lookup_count = 0; |
| 919 if (!subtable.ReadU16(&lookup_count)) { |
| 920 return OTS_FAILURE_MSG("Failed to read lookup count in chain class rule subt
able"); |
| 921 } |
| 922 for (unsigned i = 0; i < lookup_count; ++i) { |
| 923 if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) { |
| 924 return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain class ru
le subtable", i); |
| 925 } |
| 926 } |
| 927 |
| 928 return true; |
| 929 } |
| 930 |
| 931 bool ParseChainClassSetTable(const ots::OpenTypeFile *file, |
| 932 const uint8_t *data, const size_t length, |
| 933 const uint16_t num_glyphs, |
| 934 const uint16_t num_lookups) { |
| 935 ots::Buffer subtable(data, length); |
| 936 |
| 937 uint16_t chain_class_rule_count = 0; |
| 938 if (!subtable.ReadU16(&chain_class_rule_count)) { |
| 939 return OTS_FAILURE_MSG("Failed to read rule count in chain class set"); |
| 940 } |
| 941 const unsigned chain_class_rule_end = |
| 942 2 * static_cast<unsigned>(chain_class_rule_count) + 2; |
| 943 if (chain_class_rule_end > std::numeric_limits<uint16_t>::max()) { |
| 944 return OTS_FAILURE_MSG("Bad end of chain class set %d in chain class set", c
hain_class_rule_end); |
| 945 } |
| 946 for (unsigned i = 0; i < chain_class_rule_count; ++i) { |
| 947 uint16_t offset_chain_class_rule = 0; |
| 948 if (!subtable.ReadU16(&offset_chain_class_rule)) { |
| 949 return OTS_FAILURE_MSG("Failed to read chain class rule offset %d in chain
class set", i); |
| 950 } |
| 951 if (offset_chain_class_rule < chain_class_rule_end || |
| 952 offset_chain_class_rule >= length) { |
| 953 return OTS_FAILURE_MSG("Bad chain class rule offset %d for chain class %d
in chain class set", offset_chain_class_rule, i); |
| 954 } |
| 955 if (!ParseChainClassRuleSubtable(file, data + offset_chain_class_rule, |
| 956 length - offset_chain_class_rule, |
| 957 num_glyphs, num_lookups)) { |
| 958 return OTS_FAILURE_MSG("Failed to parse chain class rule %d in chain class
set", i); |
| 959 } |
| 960 } |
| 961 |
| 962 return true; |
| 963 } |
| 964 |
| 965 bool ParseChainContextFormat2(const ots::OpenTypeFile *file, |
| 966 const uint8_t *data, const size_t length, |
| 967 const uint16_t num_glyphs, |
| 968 const uint16_t num_lookups) { |
| 969 ots::Buffer subtable(data, length); |
| 970 |
| 971 uint16_t offset_coverage = 0; |
| 972 uint16_t offset_backtrack_class_def = 0; |
| 973 uint16_t offset_input_class_def = 0; |
| 974 uint16_t offset_lookahead_class_def = 0; |
| 975 uint16_t chain_class_set_count = 0; |
| 976 // Skip format field. |
| 977 if (!subtable.Skip(2) || |
| 978 !subtable.ReadU16(&offset_coverage) || |
| 979 !subtable.ReadU16(&offset_backtrack_class_def) || |
| 980 !subtable.ReadU16(&offset_input_class_def) || |
| 981 !subtable.ReadU16(&offset_lookahead_class_def) || |
| 982 !subtable.ReadU16(&chain_class_set_count)) { |
| 983 return OTS_FAILURE_MSG("Failed to read header of chain context format 2"); |
| 984 } |
| 985 |
| 986 const unsigned chain_class_set_end = |
| 987 2 * static_cast<unsigned>(chain_class_set_count) + 12; |
| 988 if (chain_class_set_end > std::numeric_limits<uint16_t>::max()) { |
| 989 return OTS_FAILURE_MSG("Bad chain class set end %d in chain context format 2
", chain_class_set_end); |
| 990 } |
| 991 if (offset_coverage < chain_class_set_end || offset_coverage >= length) { |
| 992 return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 2", o
ffset_coverage); |
| 993 } |
| 994 if (!ots::ParseCoverageTable(file, data + offset_coverage, |
| 995 length - offset_coverage, num_glyphs)) { |
| 996 return OTS_FAILURE_MSG("Failed to parse coverage table in chain context form
at 2"); |
| 997 } |
| 998 |
| 999 // Classes for backtrack/lookahead sequences might not be defined. |
| 1000 if (offset_backtrack_class_def) { |
| 1001 if (offset_backtrack_class_def < chain_class_set_end || |
| 1002 offset_backtrack_class_def >= length) { |
| 1003 return OTS_FAILURE_MSG("Bad backtrack class offset %d in chain context for
mat 2", offset_backtrack_class_def); |
| 1004 } |
| 1005 if (!ots::ParseClassDefTable(file, data + offset_backtrack_class_def, |
| 1006 length - offset_backtrack_class_def, |
| 1007 num_glyphs, kMaxClassDefValue)) { |
| 1008 return OTS_FAILURE_MSG("Failed to parse backtrack class defn table in chai
n context format 2"); |
| 1009 } |
| 1010 } |
| 1011 |
| 1012 if (offset_input_class_def < chain_class_set_end || |
| 1013 offset_input_class_def >= length) { |
| 1014 return OTS_FAILURE_MSG("Bad input class defn offset %d in chain context form
at 2", offset_input_class_def); |
| 1015 } |
| 1016 if (!ots::ParseClassDefTable(file, data + offset_input_class_def, |
| 1017 length - offset_input_class_def, |
| 1018 num_glyphs, kMaxClassDefValue)) { |
| 1019 return OTS_FAILURE_MSG("Failed to parse input class defn in chain context fo
rmat 2"); |
| 1020 } |
| 1021 |
| 1022 if (offset_lookahead_class_def) { |
| 1023 if (offset_lookahead_class_def < chain_class_set_end || |
| 1024 offset_lookahead_class_def >= length) { |
| 1025 return OTS_FAILURE_MSG("Bad lookahead class defn offset %d in chain contex
t format 2", offset_lookahead_class_def); |
| 1026 } |
| 1027 if (!ots::ParseClassDefTable(file, data + offset_lookahead_class_def, |
| 1028 length - offset_lookahead_class_def, |
| 1029 num_glyphs, kMaxClassDefValue)) { |
| 1030 return OTS_FAILURE_MSG("Failed to parse lookahead class defn in chain cont
ext format 2"); |
| 1031 } |
| 1032 } |
| 1033 |
| 1034 for (unsigned i = 0; i < chain_class_set_count; ++i) { |
| 1035 uint16_t offset_chain_class_set = 0; |
| 1036 if (!subtable.ReadU16(&offset_chain_class_set)) { |
| 1037 return OTS_FAILURE_MSG("Failed to read chain class set offset %d", i); |
| 1038 } |
| 1039 // |offset_chain_class_set| could be NULL. |
| 1040 if (offset_chain_class_set) { |
| 1041 if (offset_chain_class_set < chain_class_set_end || |
| 1042 offset_chain_class_set >= length) { |
| 1043 return OTS_FAILURE_MSG("Bad chain set class offset %d for chain set %d i
n chain context format 2", offset_chain_class_set, i); |
| 1044 } |
| 1045 if (!ParseChainClassSetTable(file, data + offset_chain_class_set, |
| 1046 length - offset_chain_class_set, |
| 1047 num_glyphs, num_lookups)) { |
| 1048 return OTS_FAILURE_MSG("Failed to parse chain class set table %d in chai
n context format 2", i); |
| 1049 } |
| 1050 } |
| 1051 } |
| 1052 |
| 1053 return true; |
| 1054 } |
| 1055 |
| 1056 bool ParseChainContextFormat3(const ots::OpenTypeFile *file, |
| 1057 const uint8_t *data, const size_t length, |
| 1058 const uint16_t num_glyphs, |
| 1059 const uint16_t num_lookups) { |
| 1060 ots::Buffer subtable(data, length); |
| 1061 |
| 1062 uint16_t backtrack_count = 0; |
| 1063 // Skip format field. |
| 1064 if (!subtable.Skip(2) || |
| 1065 !subtable.ReadU16(&backtrack_count)) { |
| 1066 return OTS_FAILURE_MSG("Failed to read backtrack count in chain context form
at 3"); |
| 1067 } |
| 1068 |
| 1069 if (backtrack_count >= num_glyphs) { |
| 1070 return OTS_FAILURE_MSG("Bad backtrack count %d in chain context format 3", b
acktrack_count); |
| 1071 } |
| 1072 std::vector<uint16_t> offsets_backtrack; |
| 1073 offsets_backtrack.reserve(backtrack_count); |
| 1074 for (unsigned i = 0; i < backtrack_count; ++i) { |
| 1075 uint16_t offset = 0; |
| 1076 if (!subtable.ReadU16(&offset)) { |
| 1077 return OTS_FAILURE_MSG("Failed to read backtrack offset %d in chain contex
t format 3", i); |
| 1078 } |
| 1079 offsets_backtrack.push_back(offset); |
| 1080 } |
| 1081 if (offsets_backtrack.size() != backtrack_count) { |
| 1082 return OTS_FAILURE_MSG("Bad backtrack offsets size %ld in chain context form
at 3", offsets_backtrack.size()); |
| 1083 } |
| 1084 |
| 1085 uint16_t input_count = 0; |
| 1086 if (!subtable.ReadU16(&input_count)) { |
| 1087 return OTS_FAILURE_MSG("Failed to read input count in chain context format 3
"); |
| 1088 } |
| 1089 if (input_count >= num_glyphs) { |
| 1090 return OTS_FAILURE_MSG("Bad input count %d in chain context format 3", input
_count); |
| 1091 } |
| 1092 std::vector<uint16_t> offsets_input; |
| 1093 offsets_input.reserve(input_count); |
| 1094 for (unsigned i = 0; i < input_count; ++i) { |
| 1095 uint16_t offset = 0; |
| 1096 if (!subtable.ReadU16(&offset)) { |
| 1097 return OTS_FAILURE_MSG("Failed to read input offset %d in chain context fo
rmat 3", i); |
| 1098 } |
| 1099 offsets_input.push_back(offset); |
| 1100 } |
| 1101 if (offsets_input.size() != input_count) { |
| 1102 return OTS_FAILURE_MSG("Bad input offsets size %ld in chain context format 3
", offsets_input.size()); |
| 1103 } |
| 1104 |
| 1105 uint16_t lookahead_count = 0; |
| 1106 if (!subtable.ReadU16(&lookahead_count)) { |
| 1107 return OTS_FAILURE_MSG("Failed ot read lookahead count in chain context form
at 3"); |
| 1108 } |
| 1109 if (lookahead_count >= num_glyphs) { |
| 1110 return OTS_FAILURE_MSG("Bad lookahead count %d in chain context format 3", l
ookahead_count); |
| 1111 } |
| 1112 std::vector<uint16_t> offsets_lookahead; |
| 1113 offsets_lookahead.reserve(lookahead_count); |
| 1114 for (unsigned i = 0; i < lookahead_count; ++i) { |
| 1115 uint16_t offset = 0; |
| 1116 if (!subtable.ReadU16(&offset)) { |
| 1117 return OTS_FAILURE_MSG("Failed to read lookahead offset %d in chain contex
t format 3", i); |
| 1118 } |
| 1119 offsets_lookahead.push_back(offset); |
| 1120 } |
| 1121 if (offsets_lookahead.size() != lookahead_count) { |
| 1122 return OTS_FAILURE_MSG("Bad lookahead offsets size %ld in chain context form
at 3", offsets_lookahead.size()); |
| 1123 } |
| 1124 |
| 1125 uint16_t lookup_count = 0; |
| 1126 if (!subtable.ReadU16(&lookup_count)) { |
| 1127 return OTS_FAILURE_MSG("Failed to read lookup count in chain context format
3"); |
| 1128 } |
| 1129 for (unsigned i = 0; i < lookup_count; ++i) { |
| 1130 if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) { |
| 1131 return OTS_FAILURE_MSG("Failed to parse lookup %d in chain context format
3", i); |
| 1132 } |
| 1133 } |
| 1134 |
| 1135 const unsigned lookup_record_end = |
| 1136 2 * (static_cast<unsigned>(backtrack_count) + |
| 1137 static_cast<unsigned>(input_count) + |
| 1138 static_cast<unsigned>(lookahead_count)) + |
| 1139 4 * static_cast<unsigned>(lookup_count) + 10; |
| 1140 if (lookup_record_end > std::numeric_limits<uint16_t>::max()) { |
| 1141 return OTS_FAILURE_MSG("Bad end of lookup record %d in chain context format
3", lookup_record_end); |
| 1142 } |
| 1143 for (unsigned i = 0; i < backtrack_count; ++i) { |
| 1144 if (offsets_backtrack[i] < lookup_record_end || |
| 1145 offsets_backtrack[i] >= length) { |
| 1146 return OTS_FAILURE_MSG("Bad backtrack offset of %d for backtrack %d in cha
in context format 3", offsets_backtrack[i], i); |
| 1147 } |
| 1148 if (!ots::ParseCoverageTable(file, data + offsets_backtrack[i], |
| 1149 length - offsets_backtrack[i], num_glyphs)) { |
| 1150 return OTS_FAILURE_MSG("Failed to parse backtrack coverage %d in chain con
text format 3", i); |
| 1151 } |
| 1152 } |
| 1153 for (unsigned i = 0; i < input_count; ++i) { |
| 1154 if (offsets_input[i] < lookup_record_end || offsets_input[i] >= length) { |
| 1155 return OTS_FAILURE_MSG("Bad input offset %d for input %d in chain context
format 3", offsets_input[i], i); |
| 1156 } |
| 1157 if (!ots::ParseCoverageTable(file, data + offsets_input[i], |
| 1158 length - offsets_input[i], num_glyphs)) { |
| 1159 return OTS_FAILURE_MSG("Failed to parse input coverage table %d in chain c
ontext format 3", i); |
| 1160 } |
| 1161 } |
| 1162 for (unsigned i = 0; i < lookahead_count; ++i) { |
| 1163 if (offsets_lookahead[i] < lookup_record_end || |
| 1164 offsets_lookahead[i] >= length) { |
| 1165 return OTS_FAILURE_MSG("Bad lookadhead offset %d for lookahead %d in chain
context format 3", offsets_lookahead[i], i); |
| 1166 } |
| 1167 if (!ots::ParseCoverageTable(file, data + offsets_lookahead[i], |
| 1168 length - offsets_lookahead[i], num_glyphs)) { |
| 1169 return OTS_FAILURE_MSG("Failed to parse lookahead coverage table %d in cha
in context format 3", i); |
| 1170 } |
| 1171 } |
| 1172 |
| 1173 return true; |
| 1174 } |
| 1175 |
| 1176 } // namespace |
| 1177 |
| 1178 namespace ots { |
| 1179 |
| 1180 bool LookupSubtableParser::Parse(const OpenTypeFile *file, const uint8_t *data, |
| 1181 const size_t length, |
| 1182 const uint16_t lookup_type) const { |
| 1183 for (unsigned i = 0; i < num_types; ++i) { |
| 1184 if (parsers[i].type == lookup_type && parsers[i].parse) { |
| 1185 if (!parsers[i].parse(file, data, length)) { |
| 1186 return OTS_FAILURE_MSG("Failed to parse lookup subtable %d", i); |
| 1187 } |
| 1188 return true; |
| 1189 } |
| 1190 } |
| 1191 return OTS_FAILURE_MSG("No lookup subtables to parse"); |
| 1192 } |
| 1193 |
| 1194 // Parsing ScriptListTable requires number of features so we need to |
| 1195 // parse FeatureListTable before calling this function. |
| 1196 bool ParseScriptListTable(const ots::OpenTypeFile *file, |
| 1197 const uint8_t *data, const size_t length, |
| 1198 const uint16_t num_features) { |
| 1199 Buffer subtable(data, length); |
| 1200 |
| 1201 uint16_t script_count = 0; |
| 1202 if (!subtable.ReadU16(&script_count)) { |
| 1203 return OTS_FAILURE_MSG("Failed to read script count in script list table"); |
| 1204 } |
| 1205 |
| 1206 const unsigned script_record_end = |
| 1207 6 * static_cast<unsigned>(script_count) + 2; |
| 1208 if (script_record_end > std::numeric_limits<uint16_t>::max()) { |
| 1209 return OTS_FAILURE_MSG("Bad end of script record %d in script list table", s
cript_record_end); |
| 1210 } |
| 1211 std::vector<ScriptRecord> script_list; |
| 1212 script_list.reserve(script_count); |
| 1213 uint32_t last_tag = 0; |
| 1214 for (unsigned i = 0; i < script_count; ++i) { |
| 1215 ScriptRecord record; |
| 1216 if (!subtable.ReadU32(&record.tag) || |
| 1217 !subtable.ReadU16(&record.offset)) { |
| 1218 return OTS_FAILURE_MSG("Failed to read script record %d in script list tab
le", i); |
| 1219 } |
| 1220 // Script tags should be arranged alphabetically by tag |
| 1221 if (last_tag != 0 && last_tag > record.tag) { |
| 1222 // Several fonts don't arrange tags alphabetically. |
| 1223 // It seems that the order of tags might not be a security issue |
| 1224 // so we just warn it. |
| 1225 OTS_WARNING("tags aren't arranged alphabetically."); |
| 1226 } |
| 1227 last_tag = record.tag; |
| 1228 if (record.offset < script_record_end || record.offset >= length) { |
| 1229 return OTS_FAILURE_MSG("Bad record offset %d for script %4.4s entry %d in
script list table", record.offset, (char *)&record.tag, i); |
| 1230 } |
| 1231 script_list.push_back(record); |
| 1232 } |
| 1233 if (script_list.size() != script_count) { |
| 1234 return OTS_FAILURE_MSG("Bad script list size %ld in script list table", scri
pt_list.size()); |
| 1235 } |
| 1236 |
| 1237 // Check script records. |
| 1238 for (unsigned i = 0; i < script_count; ++i) { |
| 1239 if (!ParseScriptTable(file, data + script_list[i].offset, |
| 1240 length - script_list[i].offset, |
| 1241 script_list[i].tag, num_features)) { |
| 1242 return OTS_FAILURE_MSG("Failed to parse script table %d", i); |
| 1243 } |
| 1244 } |
| 1245 |
| 1246 return true; |
| 1247 } |
| 1248 |
| 1249 // Parsing FeatureListTable requires number of lookups so we need to parse |
| 1250 // LookupListTable before calling this function. |
| 1251 bool ParseFeatureListTable(const ots::OpenTypeFile *file, |
| 1252 const uint8_t *data, const size_t length, |
| 1253 const uint16_t num_lookups, |
| 1254 uint16_t* num_features) { |
| 1255 Buffer subtable(data, length); |
| 1256 |
| 1257 uint16_t feature_count = 0; |
| 1258 if (!subtable.ReadU16(&feature_count)) { |
| 1259 return OTS_FAILURE_MSG("Failed to read feature count"); |
| 1260 } |
| 1261 |
| 1262 std::vector<FeatureRecord> feature_records; |
| 1263 feature_records.resize(feature_count); |
| 1264 const unsigned feature_record_end = |
| 1265 6 * static_cast<unsigned>(feature_count) + 2; |
| 1266 if (feature_record_end > std::numeric_limits<uint16_t>::max()) { |
| 1267 return OTS_FAILURE_MSG("Bad end of feature record %d", feature_record_end); |
| 1268 } |
| 1269 uint32_t last_tag = 0; |
| 1270 for (unsigned i = 0; i < feature_count; ++i) { |
| 1271 if (!subtable.ReadU32(&feature_records[i].tag) || |
| 1272 !subtable.ReadU16(&feature_records[i].offset)) { |
| 1273 return OTS_FAILURE_MSG("Failed to read feature header %d", i); |
| 1274 } |
| 1275 // Feature record array should be arranged alphabetically by tag |
| 1276 if (last_tag != 0 && last_tag > feature_records[i].tag) { |
| 1277 // Several fonts don't arrange tags alphabetically. |
| 1278 // It seems that the order of tags might not be a security issue |
| 1279 // so we just warn it. |
| 1280 OTS_WARNING("tags aren't arranged alphabetically."); |
| 1281 } |
| 1282 last_tag = feature_records[i].tag; |
| 1283 if (feature_records[i].offset < feature_record_end || |
| 1284 feature_records[i].offset >= length) { |
| 1285 return OTS_FAILURE_MSG("Bad feature offset %d for feature %d %4.4s", featu
re_records[i].offset, i, (char *)&feature_records[i].tag); |
| 1286 } |
| 1287 } |
| 1288 |
| 1289 for (unsigned i = 0; i < feature_count; ++i) { |
| 1290 if (!ParseFeatureTable(file, data + feature_records[i].offset, |
| 1291 length - feature_records[i].offset, num_lookups)) { |
| 1292 return OTS_FAILURE_MSG("Failed to parse feature table %d", i); |
| 1293 } |
| 1294 } |
| 1295 *num_features = feature_count; |
| 1296 return true; |
| 1297 } |
| 1298 |
| 1299 // For parsing GPOS/GSUB tables, this function should be called at first to |
| 1300 // obtain the number of lookups because parsing FeatureTableList requires |
| 1301 // the number. |
| 1302 bool ParseLookupListTable(OpenTypeFile *file, const uint8_t *data, |
| 1303 const size_t length, |
| 1304 const LookupSubtableParser* parser, |
| 1305 uint16_t *num_lookups) { |
| 1306 Buffer subtable(data, length); |
| 1307 |
| 1308 if (!subtable.ReadU16(num_lookups)) { |
| 1309 return OTS_FAILURE_MSG("Failed to read number of lookups"); |
| 1310 } |
| 1311 |
| 1312 std::vector<uint16_t> lookups; |
| 1313 lookups.reserve(*num_lookups); |
| 1314 const unsigned lookup_end = |
| 1315 2 * static_cast<unsigned>(*num_lookups) + 2; |
| 1316 if (lookup_end > std::numeric_limits<uint16_t>::max()) { |
| 1317 return OTS_FAILURE_MSG("Bad end of lookups %d", lookup_end); |
| 1318 } |
| 1319 for (unsigned i = 0; i < *num_lookups; ++i) { |
| 1320 uint16_t offset = 0; |
| 1321 if (!subtable.ReadU16(&offset)) { |
| 1322 return OTS_FAILURE_MSG("Failed to read lookup offset %d", i); |
| 1323 } |
| 1324 if (offset < lookup_end || offset >= length) { |
| 1325 return OTS_FAILURE_MSG("Bad lookup offset %d for lookup %d", offset, i); |
| 1326 } |
| 1327 lookups.push_back(offset); |
| 1328 } |
| 1329 if (lookups.size() != *num_lookups) { |
| 1330 return OTS_FAILURE_MSG("Bad lookup offsets list size %ld", lookups.size()); |
| 1331 } |
| 1332 |
| 1333 for (unsigned i = 0; i < *num_lookups; ++i) { |
| 1334 if (!ParseLookupTable(file, data + lookups[i], length - lookups[i], |
| 1335 parser)) { |
| 1336 return OTS_FAILURE_MSG("Failed to parse lookup %d", i); |
| 1337 } |
| 1338 } |
| 1339 |
| 1340 return true; |
| 1341 } |
| 1342 |
| 1343 bool ParseClassDefTable(const ots::OpenTypeFile *file, |
| 1344 const uint8_t *data, size_t length, |
| 1345 const uint16_t num_glyphs, |
| 1346 const uint16_t num_classes) { |
| 1347 Buffer subtable(data, length); |
| 1348 |
| 1349 uint16_t format = 0; |
| 1350 if (!subtable.ReadU16(&format)) { |
| 1351 return OTS_FAILURE_MSG("Failed to read class defn format"); |
| 1352 } |
| 1353 if (format == 1) { |
| 1354 return ParseClassDefFormat1(file, data, length, num_glyphs, num_classes); |
| 1355 } else if (format == 2) { |
| 1356 return ParseClassDefFormat2(file, data, length, num_glyphs, num_classes); |
| 1357 } |
| 1358 |
| 1359 return OTS_FAILURE_MSG("Bad class defn format %d", format); |
| 1360 } |
| 1361 |
| 1362 bool ParseCoverageTable(const ots::OpenTypeFile *file, |
| 1363 const uint8_t *data, size_t length, |
| 1364 const uint16_t num_glyphs, |
| 1365 const uint16_t expected_num_glyphs) { |
| 1366 Buffer subtable(data, length); |
| 1367 |
| 1368 uint16_t format = 0; |
| 1369 if (!subtable.ReadU16(&format)) { |
| 1370 return OTS_FAILURE_MSG("Failed to read coverage table format"); |
| 1371 } |
| 1372 if (format == 1) { |
| 1373 return ParseCoverageFormat1(file, data, length, num_glyphs, expected_num_gly
phs); |
| 1374 } else if (format == 2) { |
| 1375 return ParseCoverageFormat2(file, data, length, num_glyphs, expected_num_gly
phs); |
| 1376 } |
| 1377 |
| 1378 return OTS_FAILURE_MSG("Bad coverage table format %d", format); |
| 1379 } |
| 1380 |
| 1381 bool ParseDeviceTable(const ots::OpenTypeFile *file, |
| 1382 const uint8_t *data, size_t length) { |
| 1383 Buffer subtable(data, length); |
| 1384 |
| 1385 uint16_t start_size = 0; |
| 1386 uint16_t end_size = 0; |
| 1387 uint16_t delta_format = 0; |
| 1388 if (!subtable.ReadU16(&start_size) || |
| 1389 !subtable.ReadU16(&end_size) || |
| 1390 !subtable.ReadU16(&delta_format)) { |
| 1391 return OTS_FAILURE_MSG("Failed to read device table header"); |
| 1392 } |
| 1393 if (start_size > end_size) { |
| 1394 return OTS_FAILURE_MSG("bad size range: %u > %u", start_size, end_size); |
| 1395 } |
| 1396 if (delta_format == 0 || delta_format > kMaxDeltaFormatType) { |
| 1397 return OTS_FAILURE_MSG("bad delta format: %u", delta_format); |
| 1398 } |
| 1399 // The number of delta values per uint16. The device table should contain |
| 1400 // at least |num_units| * 2 bytes compressed data. |
| 1401 const unsigned num_units = (end_size - start_size) / |
| 1402 (1 << (4 - delta_format)) + 1; |
| 1403 // Just skip |num_units| * 2 bytes since the compressed data could take |
| 1404 // arbitrary values. |
| 1405 if (!subtable.Skip(num_units * 2)) { |
| 1406 return OTS_FAILURE_MSG("Failed to skip data in device table"); |
| 1407 } |
| 1408 return true; |
| 1409 } |
| 1410 |
| 1411 bool ParseContextSubtable(const ots::OpenTypeFile *file, |
| 1412 const uint8_t *data, const size_t length, |
| 1413 const uint16_t num_glyphs, |
| 1414 const uint16_t num_lookups) { |
| 1415 Buffer subtable(data, length); |
| 1416 |
| 1417 uint16_t format = 0; |
| 1418 if (!subtable.ReadU16(&format)) { |
| 1419 return OTS_FAILURE_MSG("Failed to read context subtable format"); |
| 1420 } |
| 1421 |
| 1422 if (format == 1) { |
| 1423 if (!ParseContextFormat1(file, data, length, num_glyphs, num_lookups)) { |
| 1424 return OTS_FAILURE_MSG("Failed to parse context format 1 subtable"); |
| 1425 } |
| 1426 } else if (format == 2) { |
| 1427 if (!ParseContextFormat2(file, data, length, num_glyphs, num_lookups)) { |
| 1428 return OTS_FAILURE_MSG("Failed to parse context format 2 subtable"); |
| 1429 } |
| 1430 } else if (format == 3) { |
| 1431 if (!ParseContextFormat3(file, data, length, num_glyphs, num_lookups)) { |
| 1432 return OTS_FAILURE_MSG("Failed to parse context format 3 subtable"); |
| 1433 } |
| 1434 } else { |
| 1435 return OTS_FAILURE_MSG("Bad context subtable format %d", format); |
| 1436 } |
| 1437 |
| 1438 return true; |
| 1439 } |
| 1440 |
| 1441 bool ParseChainingContextSubtable(const ots::OpenTypeFile *file, |
| 1442 const uint8_t *data, const size_t length, |
| 1443 const uint16_t num_glyphs, |
| 1444 const uint16_t num_lookups) { |
| 1445 Buffer subtable(data, length); |
| 1446 |
| 1447 uint16_t format = 0; |
| 1448 if (!subtable.ReadU16(&format)) { |
| 1449 return OTS_FAILURE_MSG("Failed to read chaining context subtable format"); |
| 1450 } |
| 1451 |
| 1452 if (format == 1) { |
| 1453 if (!ParseChainContextFormat1(file, data, length, num_glyphs, num_lookups))
{ |
| 1454 return OTS_FAILURE_MSG("Failed to parse chaining context format 1 subtable
"); |
| 1455 } |
| 1456 } else if (format == 2) { |
| 1457 if (!ParseChainContextFormat2(file, data, length, num_glyphs, num_lookups))
{ |
| 1458 return OTS_FAILURE_MSG("Failed to parse chaining context format 2 subtable
"); |
| 1459 } |
| 1460 } else if (format == 3) { |
| 1461 if (!ParseChainContextFormat3(file, data, length, num_glyphs, num_lookups))
{ |
| 1462 return OTS_FAILURE_MSG("Failed to parse chaining context format 3 subtable
"); |
| 1463 } |
| 1464 } else { |
| 1465 return OTS_FAILURE_MSG("Bad chaining context subtable format %d", format); |
| 1466 } |
| 1467 |
| 1468 return true; |
| 1469 } |
| 1470 |
| 1471 bool ParseExtensionSubtable(const OpenTypeFile *file, |
| 1472 const uint8_t *data, const size_t length, |
| 1473 const LookupSubtableParser* parser) { |
| 1474 Buffer subtable(data, length); |
| 1475 |
| 1476 uint16_t format = 0; |
| 1477 uint16_t lookup_type = 0; |
| 1478 uint32_t offset_extension = 0; |
| 1479 if (!subtable.ReadU16(&format) || |
| 1480 !subtable.ReadU16(&lookup_type) || |
| 1481 !subtable.ReadU32(&offset_extension)) { |
| 1482 return OTS_FAILURE_MSG("Failed to read extension table header"); |
| 1483 } |
| 1484 |
| 1485 if (format != 1) { |
| 1486 return OTS_FAILURE_MSG("Bad extension table format %d", format); |
| 1487 } |
| 1488 // |lookup_type| should be other than |parser->extension_type|. |
| 1489 if (lookup_type < 1 || lookup_type > parser->num_types || |
| 1490 lookup_type == parser->extension_type) { |
| 1491 return OTS_FAILURE_MSG("Bad lookup type %d in extension table", lookup_type)
; |
| 1492 } |
| 1493 |
| 1494 const unsigned format_end = static_cast<unsigned>(8); |
| 1495 if (offset_extension < format_end || |
| 1496 offset_extension >= length) { |
| 1497 return OTS_FAILURE_MSG("Bad extension offset %d", offset_extension); |
| 1498 } |
| 1499 |
| 1500 // Parse the extension subtable of |lookup_type|. |
| 1501 if (!parser->Parse(file, data + offset_extension, length - offset_extension, |
| 1502 lookup_type)) { |
| 1503 return OTS_FAILURE_MSG("Failed to parse lookup from extension lookup"); |
| 1504 } |
| 1505 |
| 1506 return true; |
| 1507 } |
| 1508 |
| 1509 } // namespace ots |
| 1510 |
| 1511 #undef TABLE_NAME |
OLD | NEW |