gfx/ots/src/layout.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial