1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/ots/src/layout.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1512 @@ 1.4 +// Copyright (c) 2011 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "layout.h" 1.9 + 1.10 +#include <limits> 1.11 +#include <vector> 1.12 + 1.13 +#include "gdef.h" 1.14 + 1.15 +// OpenType Layout Common Table Formats 1.16 +// http://www.microsoft.com/typography/otspec/chapter2.htm 1.17 + 1.18 +#define TABLE_NAME "Layout" // XXX: use individual table names 1.19 + 1.20 +namespace { 1.21 + 1.22 +// The 'DFLT' tag of script table. 1.23 +const uint32_t kScriptTableTagDflt = 0x44464c54; 1.24 +// The value which represents there is no required feature index. 1.25 +const uint16_t kNoRequiredFeatureIndexDefined = 0xFFFF; 1.26 +// The lookup flag bit which indicates existence of MarkFilteringSet. 1.27 +const uint16_t kUseMarkFilteringSetBit = 0x0010; 1.28 +// The lookup flags which require GDEF table. 1.29 +const uint16_t kGdefRequiredFlags = 0x0002 | 0x0004 | 0x0008; 1.30 +// The mask for MarkAttachmentType. 1.31 +const uint16_t kMarkAttachmentTypeMask = 0xFF00; 1.32 +// The maximum type number of format for device tables. 1.33 +const uint16_t kMaxDeltaFormatType = 3; 1.34 +// The maximum number of class value. 1.35 +const uint16_t kMaxClassDefValue = 0xFFFF; 1.36 + 1.37 +struct ScriptRecord { 1.38 + uint32_t tag; 1.39 + uint16_t offset; 1.40 +}; 1.41 + 1.42 +struct LangSysRecord { 1.43 + uint32_t tag; 1.44 + uint16_t offset; 1.45 +}; 1.46 + 1.47 +struct FeatureRecord { 1.48 + uint32_t tag; 1.49 + uint16_t offset; 1.50 +}; 1.51 + 1.52 +bool ParseLangSysTable(const ots::OpenTypeFile *file, 1.53 + ots::Buffer *subtable, const uint32_t tag, 1.54 + const uint16_t num_features) { 1.55 + uint16_t offset_lookup_order = 0; 1.56 + uint16_t req_feature_index = 0; 1.57 + uint16_t feature_count = 0; 1.58 + if (!subtable->ReadU16(&offset_lookup_order) || 1.59 + !subtable->ReadU16(&req_feature_index) || 1.60 + !subtable->ReadU16(&feature_count)) { 1.61 + return OTS_FAILURE_MSG("Failed to read langsys header for tag %4.4s", (char *)&tag); 1.62 + } 1.63 + // |offset_lookup_order| is reserved and should be NULL. 1.64 + if (offset_lookup_order != 0) { 1.65 + return OTS_FAILURE_MSG("Bad lookup offset order %d for langsys tag %4.4s", offset_lookup_order, (char *)&tag); 1.66 + } 1.67 + if (req_feature_index != kNoRequiredFeatureIndexDefined && 1.68 + req_feature_index >= num_features) { 1.69 + return OTS_FAILURE_MSG("Bad required features index %d for langsys tag %4.4s", req_feature_index, (char *)&tag); 1.70 + } 1.71 + if (feature_count > num_features) { 1.72 + return OTS_FAILURE_MSG("Bad feature count %d for langsys tag %4.4s", feature_count, (char *)&tag); 1.73 + } 1.74 + 1.75 + for (unsigned i = 0; i < feature_count; ++i) { 1.76 + uint16_t feature_index = 0; 1.77 + if (!subtable->ReadU16(&feature_index)) { 1.78 + return OTS_FAILURE_MSG("Failed to read feature index %d for langsys tag %4.4s", i, (char *)&tag); 1.79 + } 1.80 + if (feature_index >= num_features) { 1.81 + return OTS_FAILURE_MSG("Bad feature index %d for feature %d for langsys tag %4.4s", feature_index, i, (char *)&tag); 1.82 + } 1.83 + } 1.84 + return true; 1.85 +} 1.86 + 1.87 +bool ParseScriptTable(const ots::OpenTypeFile *file, 1.88 + const uint8_t *data, const size_t length, 1.89 + const uint32_t tag, const uint16_t num_features) { 1.90 + ots::Buffer subtable(data, length); 1.91 + 1.92 + uint16_t offset_default_lang_sys = 0; 1.93 + uint16_t lang_sys_count = 0; 1.94 + if (!subtable.ReadU16(&offset_default_lang_sys) || 1.95 + !subtable.ReadU16(&lang_sys_count)) { 1.96 + return OTS_FAILURE_MSG("Failed to read script header for script tag %4.4s", (char *)&tag); 1.97 + } 1.98 + 1.99 + // The spec requires a script table for 'DFLT' tag must contain non-NULL 1.100 + // |offset_default_lang_sys| and |lang_sys_count| == 0 1.101 + if (tag == kScriptTableTagDflt && 1.102 + (offset_default_lang_sys == 0 || lang_sys_count != 0)) { 1.103 + return OTS_FAILURE_MSG("DFLT table doesn't satisfy the spec. for script tag %4.4s", (char *)&tag); 1.104 + } 1.105 + 1.106 + const unsigned lang_sys_record_end = 1.107 + 6 * static_cast<unsigned>(lang_sys_count) + 4; 1.108 + if (lang_sys_record_end > std::numeric_limits<uint16_t>::max()) { 1.109 + return OTS_FAILURE_MSG("Bad end of langsys record %d for script tag %4.4s", lang_sys_record_end, (char *)&tag); 1.110 + } 1.111 + 1.112 + std::vector<LangSysRecord> lang_sys_records; 1.113 + lang_sys_records.resize(lang_sys_count); 1.114 + uint32_t last_tag = 0; 1.115 + for (unsigned i = 0; i < lang_sys_count; ++i) { 1.116 + if (!subtable.ReadU32(&lang_sys_records[i].tag) || 1.117 + !subtable.ReadU16(&lang_sys_records[i].offset)) { 1.118 + return OTS_FAILURE_MSG("Failed to read langsys record header %d for script tag %4.4s", i, (char *)&tag); 1.119 + } 1.120 + // The record array must store the records alphabetically by tag 1.121 + if (last_tag != 0 && last_tag > lang_sys_records[i].tag) { 1.122 + return OTS_FAILURE_MSG("Bad last tag %d for langsys record %d for script tag %4.4s", last_tag, i, (char *)&tag); 1.123 + } 1.124 + if (lang_sys_records[i].offset < lang_sys_record_end || 1.125 + lang_sys_records[i].offset >= length) { 1.126 + return OTS_FAILURE_MSG("bad offset to lang sys table: %x", 1.127 + lang_sys_records[i].offset); 1.128 + } 1.129 + last_tag = lang_sys_records[i].tag; 1.130 + } 1.131 + 1.132 + // Check lang sys tables 1.133 + for (unsigned i = 0; i < lang_sys_count; ++i) { 1.134 + subtable.set_offset(lang_sys_records[i].offset); 1.135 + if (!ParseLangSysTable(file, &subtable, lang_sys_records[i].tag, num_features)) { 1.136 + 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); 1.137 + } 1.138 + } 1.139 + 1.140 + return true; 1.141 +} 1.142 + 1.143 +bool ParseFeatureTable(const ots::OpenTypeFile *file, 1.144 + const uint8_t *data, const size_t length, 1.145 + const uint16_t num_lookups) { 1.146 + ots::Buffer subtable(data, length); 1.147 + 1.148 + uint16_t offset_feature_params = 0; 1.149 + uint16_t lookup_count = 0; 1.150 + if (!subtable.ReadU16(&offset_feature_params) || 1.151 + !subtable.ReadU16(&lookup_count)) { 1.152 + return OTS_FAILURE_MSG("Failed to read feature table header"); 1.153 + } 1.154 + 1.155 + const unsigned feature_table_end = 1.156 + 2 * static_cast<unsigned>(lookup_count) + 4; 1.157 + if (feature_table_end > std::numeric_limits<uint16_t>::max()) { 1.158 + return OTS_FAILURE_MSG("Bad end of feature table %d", feature_table_end); 1.159 + } 1.160 + // |offset_feature_params| is generally set to NULL. 1.161 + if (offset_feature_params != 0 && 1.162 + (offset_feature_params < feature_table_end || 1.163 + offset_feature_params >= length)) { 1.164 + return OTS_FAILURE_MSG("Bad feature params offset %d", offset_feature_params); 1.165 + } 1.166 + 1.167 + for (unsigned i = 0; i < lookup_count; ++i) { 1.168 + uint16_t lookup_index = 0; 1.169 + if (!subtable.ReadU16(&lookup_index)) { 1.170 + return OTS_FAILURE_MSG("Failed to read lookup index for lookup %d", i); 1.171 + } 1.172 + // lookup index starts with 0. 1.173 + if (lookup_index >= num_lookups) { 1.174 + return OTS_FAILURE_MSG("Bad lookup index %d for lookup %d", lookup_index, i); 1.175 + } 1.176 + } 1.177 + return true; 1.178 +} 1.179 + 1.180 +bool ParseLookupTable(ots::OpenTypeFile *file, const uint8_t *data, 1.181 + const size_t length, 1.182 + const ots::LookupSubtableParser* parser) { 1.183 + ots::Buffer subtable(data, length); 1.184 + 1.185 + uint16_t lookup_type = 0; 1.186 + uint16_t lookup_flag = 0; 1.187 + uint16_t subtable_count = 0; 1.188 + if (!subtable.ReadU16(&lookup_type) || 1.189 + !subtable.ReadU16(&lookup_flag) || 1.190 + !subtable.ReadU16(&subtable_count)) { 1.191 + return OTS_FAILURE_MSG("Failed to read lookup table header"); 1.192 + } 1.193 + 1.194 + if (lookup_type == 0 || lookup_type > parser->num_types) { 1.195 + return OTS_FAILURE_MSG("Bad lookup type %d", lookup_type); 1.196 + } 1.197 + 1.198 + // Check lookup flags. 1.199 + if ((lookup_flag & kGdefRequiredFlags) && 1.200 + (!file->gdef || !file->gdef->has_glyph_class_def)) { 1.201 + return OTS_FAILURE_MSG("Bad lookup flags %d", lookup_flag); 1.202 + } 1.203 + if ((lookup_flag & kMarkAttachmentTypeMask) && 1.204 + (!file->gdef || !file->gdef->has_mark_attachment_class_def)) { 1.205 + return OTS_FAILURE_MSG("lookup flag asks for mark attachment that is bad %d", lookup_flag); 1.206 + } 1.207 + bool use_mark_filtering_set = false; 1.208 + if (lookup_flag & kUseMarkFilteringSetBit) { 1.209 + if (!file->gdef || !file->gdef->has_mark_glyph_sets_def) { 1.210 + return OTS_FAILURE_MSG("lookup flag asks for mark filtering that is bad %d", lookup_flag); 1.211 + } 1.212 + use_mark_filtering_set = true; 1.213 + } 1.214 + 1.215 + std::vector<uint16_t> subtables; 1.216 + subtables.reserve(subtable_count); 1.217 + // If the |kUseMarkFilteringSetBit| of |lookup_flag| is set, 1.218 + // extra 2 bytes will follow after subtable offset array. 1.219 + const unsigned lookup_table_end = 2 * static_cast<unsigned>(subtable_count) + 1.220 + (use_mark_filtering_set ? 8 : 6); 1.221 + if (lookup_table_end > std::numeric_limits<uint16_t>::max()) { 1.222 + return OTS_FAILURE_MSG("Bad end of lookup %d", lookup_table_end); 1.223 + } 1.224 + for (unsigned i = 0; i < subtable_count; ++i) { 1.225 + uint16_t offset_subtable = 0; 1.226 + if (!subtable.ReadU16(&offset_subtable)) { 1.227 + return OTS_FAILURE_MSG("Failed to read subtable offset %d", i); 1.228 + } 1.229 + if (offset_subtable < lookup_table_end || 1.230 + offset_subtable >= length) { 1.231 + return OTS_FAILURE_MSG("Bad subtable offset %d for subtable %d", offset_subtable, i); 1.232 + } 1.233 + subtables.push_back(offset_subtable); 1.234 + } 1.235 + if (subtables.size() != subtable_count) { 1.236 + return OTS_FAILURE_MSG("Bad subtable size %ld", subtables.size()); 1.237 + } 1.238 + 1.239 + if (use_mark_filtering_set) { 1.240 + uint16_t mark_filtering_set = 0; 1.241 + if (!subtable.ReadU16(&mark_filtering_set)) { 1.242 + return OTS_FAILURE_MSG("Failed to read mark filtering set"); 1.243 + } 1.244 + if (file->gdef->num_mark_glyph_sets == 0 || 1.245 + mark_filtering_set >= file->gdef->num_mark_glyph_sets) { 1.246 + return OTS_FAILURE_MSG("Bad mark filtering set %d", mark_filtering_set); 1.247 + } 1.248 + } 1.249 + 1.250 + // Parse lookup subtables for this lookup type. 1.251 + for (unsigned i = 0; i < subtable_count; ++i) { 1.252 + if (!parser->Parse(file, data + subtables[i], length - subtables[i], 1.253 + lookup_type)) { 1.254 + return OTS_FAILURE_MSG("Failed to parse subtable %d", i); 1.255 + } 1.256 + } 1.257 + return true; 1.258 +} 1.259 + 1.260 +bool ParseClassDefFormat1(const ots::OpenTypeFile *file, 1.261 + const uint8_t *data, size_t length, 1.262 + const uint16_t num_glyphs, 1.263 + const uint16_t num_classes) { 1.264 + ots::Buffer subtable(data, length); 1.265 + 1.266 + // Skip format field. 1.267 + if (!subtable.Skip(2)) { 1.268 + return OTS_FAILURE_MSG("Failed to skip class definition header"); 1.269 + } 1.270 + 1.271 + uint16_t start_glyph = 0; 1.272 + if (!subtable.ReadU16(&start_glyph)) { 1.273 + return OTS_FAILURE_MSG("Failed to read starting glyph of class definition"); 1.274 + } 1.275 + if (start_glyph > num_glyphs) { 1.276 + OTS_WARNING("bad start glyph ID: %u", start_glyph); 1.277 + return OTS_FAILURE_MSG("Bad starting glyph %d in class definition", start_glyph); 1.278 + } 1.279 + 1.280 + uint16_t glyph_count = 0; 1.281 + if (!subtable.ReadU16(&glyph_count)) { 1.282 + return OTS_FAILURE_MSG("Failed to read glyph count in class definition"); 1.283 + } 1.284 + if (glyph_count > num_glyphs) { 1.285 + return OTS_FAILURE_MSG("bad glyph count: %u", glyph_count); 1.286 + } 1.287 + for (unsigned i = 0; i < glyph_count; ++i) { 1.288 + uint16_t class_value = 0; 1.289 + if (!subtable.ReadU16(&class_value)) { 1.290 + return OTS_FAILURE_MSG("Failed to read class value for glyph %d in class definition", i); 1.291 + } 1.292 + if (class_value > num_classes) { 1.293 + OTS_WARNING("bad class value: %u", class_value); 1.294 + return OTS_FAILURE_MSG("Bad class value %d for glyph %d in class definition", class_value, i); 1.295 + } 1.296 + } 1.297 + 1.298 + return true; 1.299 +} 1.300 + 1.301 +bool ParseClassDefFormat2(const ots::OpenTypeFile *file, 1.302 + const uint8_t *data, size_t length, 1.303 + const uint16_t num_glyphs, 1.304 + const uint16_t num_classes) { 1.305 + ots::Buffer subtable(data, length); 1.306 + 1.307 + // Skip format field. 1.308 + if (!subtable.Skip(2)) { 1.309 + return OTS_FAILURE_MSG("Failed to skip format of class defintion header"); 1.310 + } 1.311 + 1.312 + uint16_t range_count = 0; 1.313 + if (!subtable.ReadU16(&range_count)) { 1.314 + return OTS_FAILURE_MSG("Failed to read range count in class definition"); 1.315 + } 1.316 + if (range_count > num_glyphs) { 1.317 + return OTS_FAILURE_MSG("bad range count: %u", range_count); 1.318 + } 1.319 + 1.320 + uint16_t last_end = 0; 1.321 + for (unsigned i = 0; i < range_count; ++i) { 1.322 + uint16_t start = 0; 1.323 + uint16_t end = 0; 1.324 + uint16_t class_value = 0; 1.325 + if (!subtable.ReadU16(&start) || 1.326 + !subtable.ReadU16(&end) || 1.327 + !subtable.ReadU16(&class_value)) { 1.328 + return OTS_FAILURE_MSG("Failed to read class definition reange %d", i); 1.329 + } 1.330 + if (start > end || (last_end && start <= last_end)) { 1.331 + return OTS_FAILURE_MSG("glyph range is overlapping.in range %d", i); 1.332 + } 1.333 + if (class_value > num_classes) { 1.334 + return OTS_FAILURE_MSG("bad class value: %u", class_value); 1.335 + } 1.336 + last_end = end; 1.337 + } 1.338 + 1.339 + return true; 1.340 +} 1.341 + 1.342 +bool ParseCoverageFormat1(const ots::OpenTypeFile *file, 1.343 + const uint8_t *data, size_t length, 1.344 + const uint16_t num_glyphs, 1.345 + const uint16_t expected_num_glyphs) { 1.346 + ots::Buffer subtable(data, length); 1.347 + 1.348 + // Skip format field. 1.349 + if (!subtable.Skip(2)) { 1.350 + return OTS_FAILURE_MSG("Failed to skip coverage format"); 1.351 + } 1.352 + 1.353 + uint16_t glyph_count = 0; 1.354 + if (!subtable.ReadU16(&glyph_count)) { 1.355 + return OTS_FAILURE_MSG("Failed to read glyph count in coverage"); 1.356 + } 1.357 + if (glyph_count > num_glyphs) { 1.358 + return OTS_FAILURE_MSG("bad glyph count: %u", glyph_count); 1.359 + } 1.360 + for (unsigned i = 0; i < glyph_count; ++i) { 1.361 + uint16_t glyph = 0; 1.362 + if (!subtable.ReadU16(&glyph)) { 1.363 + return OTS_FAILURE_MSG("Failed to read glyph %d in coverage", i); 1.364 + } 1.365 + if (glyph > num_glyphs) { 1.366 + return OTS_FAILURE_MSG("bad glyph ID: %u", glyph); 1.367 + } 1.368 + } 1.369 + 1.370 + if (expected_num_glyphs && expected_num_glyphs != glyph_count) { 1.371 + return OTS_FAILURE_MSG("unexpected number of glyphs: %u", glyph_count); 1.372 + } 1.373 + 1.374 + return true; 1.375 +} 1.376 + 1.377 +bool ParseCoverageFormat2(const ots::OpenTypeFile *file, 1.378 + const uint8_t *data, size_t length, 1.379 + const uint16_t num_glyphs, 1.380 + const uint16_t expected_num_glyphs) { 1.381 + ots::Buffer subtable(data, length); 1.382 + 1.383 + // Skip format field. 1.384 + if (!subtable.Skip(2)) { 1.385 + return OTS_FAILURE_MSG("Failed to skip format of coverage type 2"); 1.386 + } 1.387 + 1.388 + uint16_t range_count = 0; 1.389 + if (!subtable.ReadU16(&range_count)) { 1.390 + return OTS_FAILURE_MSG("Failed to read range count in coverage"); 1.391 + } 1.392 + if (range_count > num_glyphs) { 1.393 + return OTS_FAILURE_MSG("bad range count: %u", range_count); 1.394 + } 1.395 + uint16_t last_end = 0; 1.396 + uint16_t last_start_coverage_index = 0; 1.397 + for (unsigned i = 0; i < range_count; ++i) { 1.398 + uint16_t start = 0; 1.399 + uint16_t end = 0; 1.400 + uint16_t start_coverage_index = 0; 1.401 + if (!subtable.ReadU16(&start) || 1.402 + !subtable.ReadU16(&end) || 1.403 + !subtable.ReadU16(&start_coverage_index)) { 1.404 + return OTS_FAILURE_MSG("Failed to read range %d in coverage", i); 1.405 + } 1.406 + 1.407 + // Some of the Adobe Pro fonts have ranges that overlap by one element: the 1.408 + // start of one range is equal to the end of the previous range. Therefore 1.409 + // the < in the following condition should be <= were it not for this. 1.410 + // See crbug.com/134135. 1.411 + if (start > end || (last_end && start < last_end)) { 1.412 + return OTS_FAILURE_MSG("glyph range is overlapping."); 1.413 + } 1.414 + if (start_coverage_index != last_start_coverage_index) { 1.415 + return OTS_FAILURE_MSG("bad start coverage index."); 1.416 + } 1.417 + last_end = end; 1.418 + last_start_coverage_index += end - start + 1; 1.419 + } 1.420 + 1.421 + if (expected_num_glyphs && 1.422 + expected_num_glyphs != last_start_coverage_index) { 1.423 + return OTS_FAILURE_MSG("unexpected number of glyphs: %u", last_start_coverage_index); 1.424 + } 1.425 + 1.426 + return true; 1.427 +} 1.428 + 1.429 +// Parsers for Contextual subtables in GSUB/GPOS tables. 1.430 + 1.431 +bool ParseLookupRecord(const ots::OpenTypeFile *file, 1.432 + ots::Buffer *subtable, const uint16_t num_glyphs, 1.433 + const uint16_t num_lookups) { 1.434 + uint16_t sequence_index = 0; 1.435 + uint16_t lookup_list_index = 0; 1.436 + if (!subtable->ReadU16(&sequence_index) || 1.437 + !subtable->ReadU16(&lookup_list_index)) { 1.438 + return OTS_FAILURE_MSG("Failed to read header for lookup record"); 1.439 + } 1.440 + if (sequence_index >= num_glyphs) { 1.441 + return OTS_FAILURE_MSG("Bad sequence index %d in lookup record", sequence_index); 1.442 + } 1.443 + if (lookup_list_index >= num_lookups) { 1.444 + return OTS_FAILURE_MSG("Bad lookup list index %d in lookup record", lookup_list_index); 1.445 + } 1.446 + return true; 1.447 +} 1.448 + 1.449 +bool ParseRuleSubtable(const ots::OpenTypeFile *file, 1.450 + const uint8_t *data, const size_t length, 1.451 + const uint16_t num_glyphs, 1.452 + const uint16_t num_lookups) { 1.453 + ots::Buffer subtable(data, length); 1.454 + 1.455 + uint16_t glyph_count = 0; 1.456 + uint16_t lookup_count = 0; 1.457 + if (!subtable.ReadU16(&glyph_count) || 1.458 + !subtable.ReadU16(&lookup_count)) { 1.459 + return OTS_FAILURE_MSG("Failed to read rule subtable header"); 1.460 + } 1.461 + 1.462 + if (glyph_count == 0 || glyph_count >= num_glyphs) { 1.463 + return OTS_FAILURE_MSG("Bad glyph count %d in rule subtable", glyph_count); 1.464 + } 1.465 + for (unsigned i = 0; i < glyph_count - static_cast<unsigned>(1); ++i) { 1.466 + uint16_t glyph_id = 0; 1.467 + if (!subtable.ReadU16(&glyph_id)) { 1.468 + return OTS_FAILURE_MSG("Failed to read glyph %d", i); 1.469 + } 1.470 + if (glyph_id > num_glyphs) { 1.471 + return OTS_FAILURE_MSG("Bad glyph %d for entry %d", glyph_id, i); 1.472 + } 1.473 + } 1.474 + 1.475 + for (unsigned i = 0; i < lookup_count; ++i) { 1.476 + if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) { 1.477 + return OTS_FAILURE_MSG("Failed to parse lookup record %d", i); 1.478 + } 1.479 + } 1.480 + return true; 1.481 +} 1.482 + 1.483 +bool ParseRuleSetTable(const ots::OpenTypeFile *file, 1.484 + const uint8_t *data, const size_t length, 1.485 + const uint16_t num_glyphs, 1.486 + const uint16_t num_lookups) { 1.487 + ots::Buffer subtable(data, length); 1.488 + 1.489 + uint16_t rule_count = 0; 1.490 + if (!subtable.ReadU16(&rule_count)) { 1.491 + return OTS_FAILURE_MSG("Failed to read rule count in rule set"); 1.492 + } 1.493 + const unsigned rule_end = 2 * static_cast<unsigned>(rule_count) + 2; 1.494 + if (rule_end > std::numeric_limits<uint16_t>::max()) { 1.495 + return OTS_FAILURE_MSG("Bad end of rule %d in rule set", rule_end); 1.496 + } 1.497 + 1.498 + for (unsigned i = 0; i < rule_count; ++i) { 1.499 + uint16_t offset_rule = 0; 1.500 + if (!subtable.ReadU16(&offset_rule)) { 1.501 + return OTS_FAILURE_MSG("Failed to read rule offset for rule set %d", i); 1.502 + } 1.503 + if (offset_rule < rule_end || offset_rule >= length) { 1.504 + return OTS_FAILURE_MSG("Bad rule offset %d in set %d", offset_rule, i); 1.505 + } 1.506 + if (!ParseRuleSubtable(file, data + offset_rule, length - offset_rule, 1.507 + num_glyphs, num_lookups)) { 1.508 + return OTS_FAILURE_MSG("Failed to parse rule set %d", i); 1.509 + } 1.510 + } 1.511 + 1.512 + return true; 1.513 +} 1.514 + 1.515 +bool ParseContextFormat1(const ots::OpenTypeFile *file, 1.516 + const uint8_t *data, const size_t length, 1.517 + const uint16_t num_glyphs, 1.518 + const uint16_t num_lookups) { 1.519 + ots::Buffer subtable(data, length); 1.520 + 1.521 + uint16_t offset_coverage = 0; 1.522 + uint16_t rule_set_count = 0; 1.523 + // Skip format field. 1.524 + if (!subtable.Skip(2) || 1.525 + !subtable.ReadU16(&offset_coverage) || 1.526 + !subtable.ReadU16(&rule_set_count)) { 1.527 + return OTS_FAILURE_MSG("Failed to read header of context format 1"); 1.528 + } 1.529 + 1.530 + const unsigned rule_set_end = static_cast<unsigned>(6) + 1.531 + rule_set_count * 2; 1.532 + if (rule_set_end > std::numeric_limits<uint16_t>::max()) { 1.533 + return OTS_FAILURE_MSG("Bad end of rule set %d of context format 1", rule_set_end); 1.534 + } 1.535 + if (offset_coverage < rule_set_end || offset_coverage >= length) { 1.536 + return OTS_FAILURE_MSG("Bad coverage offset %d in context format 1", offset_coverage); 1.537 + } 1.538 + if (!ots::ParseCoverageTable(file, data + offset_coverage, 1.539 + length - offset_coverage, num_glyphs)) { 1.540 + return OTS_FAILURE_MSG("Failed to parse coverage table in context format 1"); 1.541 + } 1.542 + 1.543 + for (unsigned i = 0; i < rule_set_count; ++i) { 1.544 + uint16_t offset_rule = 0; 1.545 + if (!subtable.ReadU16(&offset_rule)) { 1.546 + return OTS_FAILURE_MSG("Failed to read rule offset %d in context format 1", i); 1.547 + } 1.548 + if (offset_rule < rule_set_end || offset_rule >= length) { 1.549 + return OTS_FAILURE_MSG("Bad rule offset %d in rule %d in context format 1", offset_rule, i); 1.550 + } 1.551 + if (!ParseRuleSetTable(file, data + offset_rule, length - offset_rule, 1.552 + num_glyphs, num_lookups)) { 1.553 + return OTS_FAILURE_MSG("Failed to parse rule set %d in context format 1", i); 1.554 + } 1.555 + } 1.556 + 1.557 + return true; 1.558 +} 1.559 + 1.560 +bool ParseClassRuleTable(const ots::OpenTypeFile *file, 1.561 + const uint8_t *data, const size_t length, 1.562 + const uint16_t num_glyphs, 1.563 + const uint16_t num_lookups) { 1.564 + ots::Buffer subtable(data, length); 1.565 + 1.566 + uint16_t glyph_count = 0; 1.567 + uint16_t lookup_count = 0; 1.568 + if (!subtable.ReadU16(&glyph_count) || 1.569 + !subtable.ReadU16(&lookup_count)) { 1.570 + return OTS_FAILURE_MSG("Failed to read header of class rule table"); 1.571 + } 1.572 + 1.573 + if (glyph_count == 0 || glyph_count >= num_glyphs) { 1.574 + return OTS_FAILURE_MSG("Bad glyph count %d in class rule table", glyph_count); 1.575 + } 1.576 + 1.577 + // ClassRule table contains an array of classes. Each value of classes 1.578 + // could take arbitrary values including zero so we don't check these value. 1.579 + const unsigned num_classes = glyph_count - static_cast<unsigned>(1); 1.580 + if (!subtable.Skip(2 * num_classes)) { 1.581 + return OTS_FAILURE_MSG("Failed to skip classes in class rule table"); 1.582 + } 1.583 + 1.584 + for (unsigned i = 0; i < lookup_count; ++i) { 1.585 + if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) { 1.586 + return OTS_FAILURE_MSG("Failed to parse lookup record %d in class rule table", i); 1.587 + } 1.588 + } 1.589 + return true; 1.590 +} 1.591 + 1.592 +bool ParseClassSetTable(const ots::OpenTypeFile *file, 1.593 + const uint8_t *data, const size_t length, 1.594 + const uint16_t num_glyphs, 1.595 + const uint16_t num_lookups) { 1.596 + ots::Buffer subtable(data, length); 1.597 + 1.598 + uint16_t class_rule_count = 0; 1.599 + if (!subtable.ReadU16(&class_rule_count)) { 1.600 + return OTS_FAILURE_MSG("Failed to read class rule count in class set table"); 1.601 + } 1.602 + const unsigned class_rule_end = 1.603 + 2 * static_cast<unsigned>(class_rule_count) + 2; 1.604 + if (class_rule_end > std::numeric_limits<uint16_t>::max()) { 1.605 + return OTS_FAILURE_MSG("bad class rule end %d in class set table", class_rule_end); 1.606 + } 1.607 + for (unsigned i = 0; i < class_rule_count; ++i) { 1.608 + uint16_t offset_class_rule = 0; 1.609 + if (!subtable.ReadU16(&offset_class_rule)) { 1.610 + return OTS_FAILURE_MSG("Failed to read class rule offset %d in class set table", i); 1.611 + } 1.612 + if (offset_class_rule < class_rule_end || offset_class_rule >= length) { 1.613 + return OTS_FAILURE_MSG("Bad class rule offset %d in class %d", offset_class_rule, i); 1.614 + } 1.615 + if (!ParseClassRuleTable(file, data + offset_class_rule, 1.616 + length - offset_class_rule, num_glyphs, 1.617 + num_lookups)) { 1.618 + return OTS_FAILURE_MSG("Failed to parse class rule table %d", i); 1.619 + } 1.620 + } 1.621 + 1.622 + return true; 1.623 +} 1.624 + 1.625 +bool ParseContextFormat2(const ots::OpenTypeFile *file, 1.626 + const uint8_t *data, const size_t length, 1.627 + const uint16_t num_glyphs, 1.628 + const uint16_t num_lookups) { 1.629 + ots::Buffer subtable(data, length); 1.630 + 1.631 + uint16_t offset_coverage = 0; 1.632 + uint16_t offset_class_def = 0; 1.633 + uint16_t class_set_cnt = 0; 1.634 + // Skip format field. 1.635 + if (!subtable.Skip(2) || 1.636 + !subtable.ReadU16(&offset_coverage) || 1.637 + !subtable.ReadU16(&offset_class_def) || 1.638 + !subtable.ReadU16(&class_set_cnt)) { 1.639 + return OTS_FAILURE_MSG("Failed to read header for context format 2"); 1.640 + } 1.641 + 1.642 + const unsigned class_set_end = 2 * static_cast<unsigned>(class_set_cnt) + 8; 1.643 + if (class_set_end > std::numeric_limits<uint16_t>::max()) { 1.644 + return OTS_FAILURE_MSG("Bad end of class set %d for context format 2", class_set_end); 1.645 + } 1.646 + if (offset_coverage < class_set_end || offset_coverage >= length) { 1.647 + return OTS_FAILURE_MSG("Bad coverage offset %d in context format 2", offset_coverage); 1.648 + } 1.649 + if (!ots::ParseCoverageTable(file, data + offset_coverage, 1.650 + length - offset_coverage, num_glyphs)) { 1.651 + return OTS_FAILURE_MSG("Failed to parse coverage table in context format 2"); 1.652 + } 1.653 + 1.654 + if (offset_class_def < class_set_end || offset_class_def >= length) { 1.655 + return OTS_FAILURE_MSG("bad class definition offset %d in context format 2", offset_class_def); 1.656 + } 1.657 + if (!ots::ParseClassDefTable(file, data + offset_class_def, 1.658 + length - offset_class_def, 1.659 + num_glyphs, kMaxClassDefValue)) { 1.660 + return OTS_FAILURE_MSG("Failed to parse class definition table in context format 2"); 1.661 + } 1.662 + 1.663 + for (unsigned i = 0; i < class_set_cnt; ++i) { 1.664 + uint16_t offset_class_rule = 0; 1.665 + if (!subtable.ReadU16(&offset_class_rule)) { 1.666 + return OTS_FAILURE_MSG("Failed to read class rule offset %d in context format 2", i); 1.667 + } 1.668 + if (offset_class_rule) { 1.669 + if (offset_class_rule < class_set_end || offset_class_rule >= length) { 1.670 + return OTS_FAILURE_MSG("Bad class rule offset %d for rule %d in context format 2", offset_class_rule, i); 1.671 + } 1.672 + if (!ParseClassSetTable(file, data + offset_class_rule, 1.673 + length - offset_class_rule, num_glyphs, 1.674 + num_lookups)) { 1.675 + return OTS_FAILURE_MSG("Failed to parse class set %d in context format 2", i); 1.676 + } 1.677 + } 1.678 + } 1.679 + 1.680 + return true; 1.681 +} 1.682 + 1.683 +bool ParseContextFormat3(const ots::OpenTypeFile *file, 1.684 + const uint8_t *data, const size_t length, 1.685 + const uint16_t num_glyphs, 1.686 + const uint16_t num_lookups) { 1.687 + ots::Buffer subtable(data, length); 1.688 + 1.689 + uint16_t glyph_count = 0; 1.690 + uint16_t lookup_count = 0; 1.691 + // Skip format field. 1.692 + if (!subtable.Skip(2) || 1.693 + !subtable.ReadU16(&glyph_count) || 1.694 + !subtable.ReadU16(&lookup_count)) { 1.695 + return OTS_FAILURE_MSG("Failed to read header in context format 3"); 1.696 + } 1.697 + 1.698 + if (glyph_count >= num_glyphs) { 1.699 + return OTS_FAILURE_MSG("Bad glyph count %d in context format 3", glyph_count); 1.700 + } 1.701 + const unsigned lookup_record_end = 2 * static_cast<unsigned>(glyph_count) + 1.702 + 4 * static_cast<unsigned>(lookup_count) + 6; 1.703 + if (lookup_record_end > std::numeric_limits<uint16_t>::max()) { 1.704 + return OTS_FAILURE_MSG("Bad end of lookup %d in context format 3", lookup_record_end); 1.705 + } 1.706 + for (unsigned i = 0; i < glyph_count; ++i) { 1.707 + uint16_t offset_coverage = 0; 1.708 + if (!subtable.ReadU16(&offset_coverage)) { 1.709 + return OTS_FAILURE_MSG("Failed to read coverage offset %d in conxtext format 3", i); 1.710 + } 1.711 + if (offset_coverage < lookup_record_end || offset_coverage >= length) { 1.712 + return OTS_FAILURE_MSG("Bad coverage offset %d for glyph %d in context format 3", offset_coverage, i); 1.713 + } 1.714 + if (!ots::ParseCoverageTable(file, data + offset_coverage, 1.715 + length - offset_coverage, num_glyphs)) { 1.716 + return OTS_FAILURE_MSG("Failed to parse coverage table for glyph %d in context format 3", i); 1.717 + } 1.718 + } 1.719 + 1.720 + for (unsigned i = 0; i < lookup_count; ++i) { 1.721 + if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) { 1.722 + return OTS_FAILURE_MSG("Failed to parse lookup record %d in context format 3", i); 1.723 + } 1.724 + } 1.725 + 1.726 + return true; 1.727 +} 1.728 + 1.729 +// Parsers for Chaning Contextual subtables in GSUB/GPOS tables. 1.730 + 1.731 +bool ParseChainRuleSubtable(const ots::OpenTypeFile *file, 1.732 + const uint8_t *data, const size_t length, 1.733 + const uint16_t num_glyphs, 1.734 + const uint16_t num_lookups) { 1.735 + ots::Buffer subtable(data, length); 1.736 + 1.737 + uint16_t backtrack_count = 0; 1.738 + if (!subtable.ReadU16(&backtrack_count)) { 1.739 + return OTS_FAILURE_MSG("Failed to read backtrack count in chain rule subtable"); 1.740 + } 1.741 + if (backtrack_count >= num_glyphs) { 1.742 + return OTS_FAILURE_MSG("Bad backtrack count %d in chain rule subtable", backtrack_count); 1.743 + } 1.744 + for (unsigned i = 0; i < backtrack_count; ++i) { 1.745 + uint16_t glyph_id = 0; 1.746 + if (!subtable.ReadU16(&glyph_id)) { 1.747 + return OTS_FAILURE_MSG("Failed to read backtrack glyph %d in chain rule subtable", i); 1.748 + } 1.749 + if (glyph_id > num_glyphs) { 1.750 + return OTS_FAILURE_MSG("Bad glyph id %d for bactrack glyph %d in chain rule subtable", glyph_id, i); 1.751 + } 1.752 + } 1.753 + 1.754 + uint16_t input_count = 0; 1.755 + if (!subtable.ReadU16(&input_count)) { 1.756 + return OTS_FAILURE_MSG("Failed to read input count in chain rule subtable"); 1.757 + } 1.758 + if (input_count == 0 || input_count >= num_glyphs) { 1.759 + return OTS_FAILURE_MSG("Bad input count %d in chain rule subtable", input_count); 1.760 + } 1.761 + for (unsigned i = 0; i < input_count - static_cast<unsigned>(1); ++i) { 1.762 + uint16_t glyph_id = 0; 1.763 + if (!subtable.ReadU16(&glyph_id)) { 1.764 + return OTS_FAILURE_MSG("Failed to read input glyph %d in chain rule subtable", i); 1.765 + } 1.766 + if (glyph_id > num_glyphs) { 1.767 + return OTS_FAILURE_MSG("Bad glyph id %d for input glyph %d in chain rule subtable", glyph_id, i); 1.768 + } 1.769 + } 1.770 + 1.771 + uint16_t lookahead_count = 0; 1.772 + if (!subtable.ReadU16(&lookahead_count)) { 1.773 + return OTS_FAILURE_MSG("Failed to read lookahead count in chain rule subtable"); 1.774 + } 1.775 + if (lookahead_count >= num_glyphs) { 1.776 + return OTS_FAILURE_MSG("Bad lookahead count %d in chain rule subtable", lookahead_count); 1.777 + } 1.778 + for (unsigned i = 0; i < lookahead_count; ++i) { 1.779 + uint16_t glyph_id = 0; 1.780 + if (!subtable.ReadU16(&glyph_id)) { 1.781 + return OTS_FAILURE_MSG("Failed to read lookahead glyph %d in chain rule subtable", i); 1.782 + } 1.783 + if (glyph_id > num_glyphs) { 1.784 + return OTS_FAILURE_MSG("Bad glyph id %d for lookadhead glyph %d in chain rule subtable", glyph_id, i); 1.785 + } 1.786 + } 1.787 + 1.788 + uint16_t lookup_count = 0; 1.789 + if (!subtable.ReadU16(&lookup_count)) { 1.790 + return OTS_FAILURE_MSG("Failed to read lookup count in chain rule subtable"); 1.791 + } 1.792 + for (unsigned i = 0; i < lookup_count; ++i) { 1.793 + if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) { 1.794 + return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain rule subtable", i); 1.795 + } 1.796 + } 1.797 + 1.798 + return true; 1.799 +} 1.800 + 1.801 +bool ParseChainRuleSetTable(const ots::OpenTypeFile *file, 1.802 + const uint8_t *data, const size_t length, 1.803 + const uint16_t num_glyphs, 1.804 + const uint16_t num_lookups) { 1.805 + ots::Buffer subtable(data, length); 1.806 + 1.807 + uint16_t chain_rule_count = 0; 1.808 + if (!subtable.ReadU16(&chain_rule_count)) { 1.809 + return OTS_FAILURE_MSG("Failed to read rule count in chain rule set"); 1.810 + } 1.811 + const unsigned chain_rule_end = 1.812 + 2 * static_cast<unsigned>(chain_rule_count) + 2; 1.813 + if (chain_rule_end > std::numeric_limits<uint16_t>::max()) { 1.814 + return OTS_FAILURE_MSG("Bad end of chain rule %d in chain rule set", chain_rule_end); 1.815 + } 1.816 + for (unsigned i = 0; i < chain_rule_count; ++i) { 1.817 + uint16_t offset_chain_rule = 0; 1.818 + if (!subtable.ReadU16(&offset_chain_rule)) { 1.819 + return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain rule set", i); 1.820 + } 1.821 + if (offset_chain_rule < chain_rule_end || offset_chain_rule >= length) { 1.822 + return OTS_FAILURE_MSG("Bad chain rule offset %d for chain rule %d in chain rule set", offset_chain_rule, i); 1.823 + } 1.824 + if (!ParseChainRuleSubtable(file, data + offset_chain_rule, 1.825 + length - offset_chain_rule, 1.826 + num_glyphs, num_lookups)) { 1.827 + return OTS_FAILURE_MSG("Failed to parse chain rule %d in chain rule set", i); 1.828 + } 1.829 + } 1.830 + 1.831 + return true; 1.832 +} 1.833 + 1.834 +bool ParseChainContextFormat1(const ots::OpenTypeFile *file, 1.835 + const uint8_t *data, const size_t length, 1.836 + const uint16_t num_glyphs, 1.837 + const uint16_t num_lookups) { 1.838 + ots::Buffer subtable(data, length); 1.839 + 1.840 + uint16_t offset_coverage = 0; 1.841 + uint16_t chain_rule_set_count = 0; 1.842 + // Skip format field. 1.843 + if (!subtable.Skip(2) || 1.844 + !subtable.ReadU16(&offset_coverage) || 1.845 + !subtable.ReadU16(&chain_rule_set_count)) { 1.846 + return OTS_FAILURE_MSG("Failed to read header of chain context format 1"); 1.847 + } 1.848 + 1.849 + const unsigned chain_rule_set_end = 1.850 + 2 * static_cast<unsigned>(chain_rule_set_count) + 6; 1.851 + if (chain_rule_set_end > std::numeric_limits<uint16_t>::max()) { 1.852 + return OTS_FAILURE_MSG("Bad chain rule end %d in chain context format 1", chain_rule_set_end); 1.853 + } 1.854 + if (offset_coverage < chain_rule_set_end || offset_coverage >= length) { 1.855 + return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 1", chain_rule_set_end); 1.856 + } 1.857 + if (!ots::ParseCoverageTable(file, data + offset_coverage, 1.858 + length - offset_coverage, num_glyphs)) { 1.859 + return OTS_FAILURE_MSG("Failed to parse coverage table for chain context format 1"); 1.860 + } 1.861 + 1.862 + for (unsigned i = 0; i < chain_rule_set_count; ++i) { 1.863 + uint16_t offset_chain_rule_set = 0; 1.864 + if (!subtable.ReadU16(&offset_chain_rule_set)) { 1.865 + return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain context format 1", i); 1.866 + } 1.867 + if (offset_chain_rule_set < chain_rule_set_end || 1.868 + offset_chain_rule_set >= length) { 1.869 + 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); 1.870 + } 1.871 + if (!ParseChainRuleSetTable(file, data + offset_chain_rule_set, 1.872 + length - offset_chain_rule_set, 1.873 + num_glyphs, num_lookups)) { 1.874 + return OTS_FAILURE_MSG("Failed to parse chain rule set %d in chain context format 1", i); 1.875 + } 1.876 + } 1.877 + 1.878 + return true; 1.879 +} 1.880 + 1.881 +bool ParseChainClassRuleSubtable(const ots::OpenTypeFile *file, 1.882 + const uint8_t *data, const size_t length, 1.883 + const uint16_t num_glyphs, 1.884 + const uint16_t num_lookups) { 1.885 + ots::Buffer subtable(data, length); 1.886 + 1.887 + // In this subtable, we don't check the value of classes for now since 1.888 + // these could take arbitrary values. 1.889 + 1.890 + uint16_t backtrack_count = 0; 1.891 + if (!subtable.ReadU16(&backtrack_count)) { 1.892 + return OTS_FAILURE_MSG("Failed to read backtrack count in chain class rule subtable"); 1.893 + } 1.894 + if (backtrack_count >= num_glyphs) { 1.895 + return OTS_FAILURE_MSG("Bad backtrack count %d in chain class rule subtable", backtrack_count); 1.896 + } 1.897 + if (!subtable.Skip(2 * backtrack_count)) { 1.898 + return OTS_FAILURE_MSG("Failed to skip backtrack offsets in chain class rule subtable"); 1.899 + } 1.900 + 1.901 + uint16_t input_count = 0; 1.902 + if (!subtable.ReadU16(&input_count)) { 1.903 + return OTS_FAILURE_MSG("Failed to read input count in chain class rule subtable"); 1.904 + } 1.905 + if (input_count == 0 || input_count >= num_glyphs) { 1.906 + return OTS_FAILURE_MSG("Bad input count %d in chain class rule subtable", input_count); 1.907 + } 1.908 + if (!subtable.Skip(2 * (input_count - 1))) { 1.909 + return OTS_FAILURE_MSG("Failed to skip input offsets in chain class rule subtable"); 1.910 + } 1.911 + 1.912 + uint16_t lookahead_count = 0; 1.913 + if (!subtable.ReadU16(&lookahead_count)) { 1.914 + return OTS_FAILURE_MSG("Failed to read lookahead count in chain class rule subtable"); 1.915 + } 1.916 + if (lookahead_count >= num_glyphs) { 1.917 + return OTS_FAILURE_MSG("Bad lookahead count %d in chain class rule subtable", lookahead_count); 1.918 + } 1.919 + if (!subtable.Skip(2 * lookahead_count)) { 1.920 + return OTS_FAILURE_MSG("Failed to skip lookahead offsets in chain class rule subtable"); 1.921 + } 1.922 + 1.923 + uint16_t lookup_count = 0; 1.924 + if (!subtable.ReadU16(&lookup_count)) { 1.925 + return OTS_FAILURE_MSG("Failed to read lookup count in chain class rule subtable"); 1.926 + } 1.927 + for (unsigned i = 0; i < lookup_count; ++i) { 1.928 + if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) { 1.929 + return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain class rule subtable", i); 1.930 + } 1.931 + } 1.932 + 1.933 + return true; 1.934 +} 1.935 + 1.936 +bool ParseChainClassSetTable(const ots::OpenTypeFile *file, 1.937 + const uint8_t *data, const size_t length, 1.938 + const uint16_t num_glyphs, 1.939 + const uint16_t num_lookups) { 1.940 + ots::Buffer subtable(data, length); 1.941 + 1.942 + uint16_t chain_class_rule_count = 0; 1.943 + if (!subtable.ReadU16(&chain_class_rule_count)) { 1.944 + return OTS_FAILURE_MSG("Failed to read rule count in chain class set"); 1.945 + } 1.946 + const unsigned chain_class_rule_end = 1.947 + 2 * static_cast<unsigned>(chain_class_rule_count) + 2; 1.948 + if (chain_class_rule_end > std::numeric_limits<uint16_t>::max()) { 1.949 + return OTS_FAILURE_MSG("Bad end of chain class set %d in chain class set", chain_class_rule_end); 1.950 + } 1.951 + for (unsigned i = 0; i < chain_class_rule_count; ++i) { 1.952 + uint16_t offset_chain_class_rule = 0; 1.953 + if (!subtable.ReadU16(&offset_chain_class_rule)) { 1.954 + return OTS_FAILURE_MSG("Failed to read chain class rule offset %d in chain class set", i); 1.955 + } 1.956 + if (offset_chain_class_rule < chain_class_rule_end || 1.957 + offset_chain_class_rule >= length) { 1.958 + return OTS_FAILURE_MSG("Bad chain class rule offset %d for chain class %d in chain class set", offset_chain_class_rule, i); 1.959 + } 1.960 + if (!ParseChainClassRuleSubtable(file, data + offset_chain_class_rule, 1.961 + length - offset_chain_class_rule, 1.962 + num_glyphs, num_lookups)) { 1.963 + return OTS_FAILURE_MSG("Failed to parse chain class rule %d in chain class set", i); 1.964 + } 1.965 + } 1.966 + 1.967 + return true; 1.968 +} 1.969 + 1.970 +bool ParseChainContextFormat2(const ots::OpenTypeFile *file, 1.971 + const uint8_t *data, const size_t length, 1.972 + const uint16_t num_glyphs, 1.973 + const uint16_t num_lookups) { 1.974 + ots::Buffer subtable(data, length); 1.975 + 1.976 + uint16_t offset_coverage = 0; 1.977 + uint16_t offset_backtrack_class_def = 0; 1.978 + uint16_t offset_input_class_def = 0; 1.979 + uint16_t offset_lookahead_class_def = 0; 1.980 + uint16_t chain_class_set_count = 0; 1.981 + // Skip format field. 1.982 + if (!subtable.Skip(2) || 1.983 + !subtable.ReadU16(&offset_coverage) || 1.984 + !subtable.ReadU16(&offset_backtrack_class_def) || 1.985 + !subtable.ReadU16(&offset_input_class_def) || 1.986 + !subtable.ReadU16(&offset_lookahead_class_def) || 1.987 + !subtable.ReadU16(&chain_class_set_count)) { 1.988 + return OTS_FAILURE_MSG("Failed to read header of chain context format 2"); 1.989 + } 1.990 + 1.991 + const unsigned chain_class_set_end = 1.992 + 2 * static_cast<unsigned>(chain_class_set_count) + 12; 1.993 + if (chain_class_set_end > std::numeric_limits<uint16_t>::max()) { 1.994 + return OTS_FAILURE_MSG("Bad chain class set end %d in chain context format 2", chain_class_set_end); 1.995 + } 1.996 + if (offset_coverage < chain_class_set_end || offset_coverage >= length) { 1.997 + return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 2", offset_coverage); 1.998 + } 1.999 + if (!ots::ParseCoverageTable(file, data + offset_coverage, 1.1000 + length - offset_coverage, num_glyphs)) { 1.1001 + return OTS_FAILURE_MSG("Failed to parse coverage table in chain context format 2"); 1.1002 + } 1.1003 + 1.1004 + // Classes for backtrack/lookahead sequences might not be defined. 1.1005 + if (offset_backtrack_class_def) { 1.1006 + if (offset_backtrack_class_def < chain_class_set_end || 1.1007 + offset_backtrack_class_def >= length) { 1.1008 + return OTS_FAILURE_MSG("Bad backtrack class offset %d in chain context format 2", offset_backtrack_class_def); 1.1009 + } 1.1010 + if (!ots::ParseClassDefTable(file, data + offset_backtrack_class_def, 1.1011 + length - offset_backtrack_class_def, 1.1012 + num_glyphs, kMaxClassDefValue)) { 1.1013 + return OTS_FAILURE_MSG("Failed to parse backtrack class defn table in chain context format 2"); 1.1014 + } 1.1015 + } 1.1016 + 1.1017 + if (offset_input_class_def < chain_class_set_end || 1.1018 + offset_input_class_def >= length) { 1.1019 + return OTS_FAILURE_MSG("Bad input class defn offset %d in chain context format 2", offset_input_class_def); 1.1020 + } 1.1021 + if (!ots::ParseClassDefTable(file, data + offset_input_class_def, 1.1022 + length - offset_input_class_def, 1.1023 + num_glyphs, kMaxClassDefValue)) { 1.1024 + return OTS_FAILURE_MSG("Failed to parse input class defn in chain context format 2"); 1.1025 + } 1.1026 + 1.1027 + if (offset_lookahead_class_def) { 1.1028 + if (offset_lookahead_class_def < chain_class_set_end || 1.1029 + offset_lookahead_class_def >= length) { 1.1030 + return OTS_FAILURE_MSG("Bad lookahead class defn offset %d in chain context format 2", offset_lookahead_class_def); 1.1031 + } 1.1032 + if (!ots::ParseClassDefTable(file, data + offset_lookahead_class_def, 1.1033 + length - offset_lookahead_class_def, 1.1034 + num_glyphs, kMaxClassDefValue)) { 1.1035 + return OTS_FAILURE_MSG("Failed to parse lookahead class defn in chain context format 2"); 1.1036 + } 1.1037 + } 1.1038 + 1.1039 + for (unsigned i = 0; i < chain_class_set_count; ++i) { 1.1040 + uint16_t offset_chain_class_set = 0; 1.1041 + if (!subtable.ReadU16(&offset_chain_class_set)) { 1.1042 + return OTS_FAILURE_MSG("Failed to read chain class set offset %d", i); 1.1043 + } 1.1044 + // |offset_chain_class_set| could be NULL. 1.1045 + if (offset_chain_class_set) { 1.1046 + if (offset_chain_class_set < chain_class_set_end || 1.1047 + offset_chain_class_set >= length) { 1.1048 + return OTS_FAILURE_MSG("Bad chain set class offset %d for chain set %d in chain context format 2", offset_chain_class_set, i); 1.1049 + } 1.1050 + if (!ParseChainClassSetTable(file, data + offset_chain_class_set, 1.1051 + length - offset_chain_class_set, 1.1052 + num_glyphs, num_lookups)) { 1.1053 + return OTS_FAILURE_MSG("Failed to parse chain class set table %d in chain context format 2", i); 1.1054 + } 1.1055 + } 1.1056 + } 1.1057 + 1.1058 + return true; 1.1059 +} 1.1060 + 1.1061 +bool ParseChainContextFormat3(const ots::OpenTypeFile *file, 1.1062 + const uint8_t *data, const size_t length, 1.1063 + const uint16_t num_glyphs, 1.1064 + const uint16_t num_lookups) { 1.1065 + ots::Buffer subtable(data, length); 1.1066 + 1.1067 + uint16_t backtrack_count = 0; 1.1068 + // Skip format field. 1.1069 + if (!subtable.Skip(2) || 1.1070 + !subtable.ReadU16(&backtrack_count)) { 1.1071 + return OTS_FAILURE_MSG("Failed to read backtrack count in chain context format 3"); 1.1072 + } 1.1073 + 1.1074 + if (backtrack_count >= num_glyphs) { 1.1075 + return OTS_FAILURE_MSG("Bad backtrack count %d in chain context format 3", backtrack_count); 1.1076 + } 1.1077 + std::vector<uint16_t> offsets_backtrack; 1.1078 + offsets_backtrack.reserve(backtrack_count); 1.1079 + for (unsigned i = 0; i < backtrack_count; ++i) { 1.1080 + uint16_t offset = 0; 1.1081 + if (!subtable.ReadU16(&offset)) { 1.1082 + return OTS_FAILURE_MSG("Failed to read backtrack offset %d in chain context format 3", i); 1.1083 + } 1.1084 + offsets_backtrack.push_back(offset); 1.1085 + } 1.1086 + if (offsets_backtrack.size() != backtrack_count) { 1.1087 + return OTS_FAILURE_MSG("Bad backtrack offsets size %ld in chain context format 3", offsets_backtrack.size()); 1.1088 + } 1.1089 + 1.1090 + uint16_t input_count = 0; 1.1091 + if (!subtable.ReadU16(&input_count)) { 1.1092 + return OTS_FAILURE_MSG("Failed to read input count in chain context format 3"); 1.1093 + } 1.1094 + if (input_count >= num_glyphs) { 1.1095 + return OTS_FAILURE_MSG("Bad input count %d in chain context format 3", input_count); 1.1096 + } 1.1097 + std::vector<uint16_t> offsets_input; 1.1098 + offsets_input.reserve(input_count); 1.1099 + for (unsigned i = 0; i < input_count; ++i) { 1.1100 + uint16_t offset = 0; 1.1101 + if (!subtable.ReadU16(&offset)) { 1.1102 + return OTS_FAILURE_MSG("Failed to read input offset %d in chain context format 3", i); 1.1103 + } 1.1104 + offsets_input.push_back(offset); 1.1105 + } 1.1106 + if (offsets_input.size() != input_count) { 1.1107 + return OTS_FAILURE_MSG("Bad input offsets size %ld in chain context format 3", offsets_input.size()); 1.1108 + } 1.1109 + 1.1110 + uint16_t lookahead_count = 0; 1.1111 + if (!subtable.ReadU16(&lookahead_count)) { 1.1112 + return OTS_FAILURE_MSG("Failed ot read lookahead count in chain context format 3"); 1.1113 + } 1.1114 + if (lookahead_count >= num_glyphs) { 1.1115 + return OTS_FAILURE_MSG("Bad lookahead count %d in chain context format 3", lookahead_count); 1.1116 + } 1.1117 + std::vector<uint16_t> offsets_lookahead; 1.1118 + offsets_lookahead.reserve(lookahead_count); 1.1119 + for (unsigned i = 0; i < lookahead_count; ++i) { 1.1120 + uint16_t offset = 0; 1.1121 + if (!subtable.ReadU16(&offset)) { 1.1122 + return OTS_FAILURE_MSG("Failed to read lookahead offset %d in chain context format 3", i); 1.1123 + } 1.1124 + offsets_lookahead.push_back(offset); 1.1125 + } 1.1126 + if (offsets_lookahead.size() != lookahead_count) { 1.1127 + return OTS_FAILURE_MSG("Bad lookahead offsets size %ld in chain context format 3", offsets_lookahead.size()); 1.1128 + } 1.1129 + 1.1130 + uint16_t lookup_count = 0; 1.1131 + if (!subtable.ReadU16(&lookup_count)) { 1.1132 + return OTS_FAILURE_MSG("Failed to read lookup count in chain context format 3"); 1.1133 + } 1.1134 + for (unsigned i = 0; i < lookup_count; ++i) { 1.1135 + if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) { 1.1136 + return OTS_FAILURE_MSG("Failed to parse lookup %d in chain context format 3", i); 1.1137 + } 1.1138 + } 1.1139 + 1.1140 + const unsigned lookup_record_end = 1.1141 + 2 * (static_cast<unsigned>(backtrack_count) + 1.1142 + static_cast<unsigned>(input_count) + 1.1143 + static_cast<unsigned>(lookahead_count)) + 1.1144 + 4 * static_cast<unsigned>(lookup_count) + 10; 1.1145 + if (lookup_record_end > std::numeric_limits<uint16_t>::max()) { 1.1146 + return OTS_FAILURE_MSG("Bad end of lookup record %d in chain context format 3", lookup_record_end); 1.1147 + } 1.1148 + for (unsigned i = 0; i < backtrack_count; ++i) { 1.1149 + if (offsets_backtrack[i] < lookup_record_end || 1.1150 + offsets_backtrack[i] >= length) { 1.1151 + return OTS_FAILURE_MSG("Bad backtrack offset of %d for backtrack %d in chain context format 3", offsets_backtrack[i], i); 1.1152 + } 1.1153 + if (!ots::ParseCoverageTable(file, data + offsets_backtrack[i], 1.1154 + length - offsets_backtrack[i], num_glyphs)) { 1.1155 + return OTS_FAILURE_MSG("Failed to parse backtrack coverage %d in chain context format 3", i); 1.1156 + } 1.1157 + } 1.1158 + for (unsigned i = 0; i < input_count; ++i) { 1.1159 + if (offsets_input[i] < lookup_record_end || offsets_input[i] >= length) { 1.1160 + return OTS_FAILURE_MSG("Bad input offset %d for input %d in chain context format 3", offsets_input[i], i); 1.1161 + } 1.1162 + if (!ots::ParseCoverageTable(file, data + offsets_input[i], 1.1163 + length - offsets_input[i], num_glyphs)) { 1.1164 + return OTS_FAILURE_MSG("Failed to parse input coverage table %d in chain context format 3", i); 1.1165 + } 1.1166 + } 1.1167 + for (unsigned i = 0; i < lookahead_count; ++i) { 1.1168 + if (offsets_lookahead[i] < lookup_record_end || 1.1169 + offsets_lookahead[i] >= length) { 1.1170 + return OTS_FAILURE_MSG("Bad lookadhead offset %d for lookahead %d in chain context format 3", offsets_lookahead[i], i); 1.1171 + } 1.1172 + if (!ots::ParseCoverageTable(file, data + offsets_lookahead[i], 1.1173 + length - offsets_lookahead[i], num_glyphs)) { 1.1174 + return OTS_FAILURE_MSG("Failed to parse lookahead coverage table %d in chain context format 3", i); 1.1175 + } 1.1176 + } 1.1177 + 1.1178 + return true; 1.1179 +} 1.1180 + 1.1181 +} // namespace 1.1182 + 1.1183 +namespace ots { 1.1184 + 1.1185 +bool LookupSubtableParser::Parse(const OpenTypeFile *file, const uint8_t *data, 1.1186 + const size_t length, 1.1187 + const uint16_t lookup_type) const { 1.1188 + for (unsigned i = 0; i < num_types; ++i) { 1.1189 + if (parsers[i].type == lookup_type && parsers[i].parse) { 1.1190 + if (!parsers[i].parse(file, data, length)) { 1.1191 + return OTS_FAILURE_MSG("Failed to parse lookup subtable %d", i); 1.1192 + } 1.1193 + return true; 1.1194 + } 1.1195 + } 1.1196 + return OTS_FAILURE_MSG("No lookup subtables to parse"); 1.1197 +} 1.1198 + 1.1199 +// Parsing ScriptListTable requires number of features so we need to 1.1200 +// parse FeatureListTable before calling this function. 1.1201 +bool ParseScriptListTable(const ots::OpenTypeFile *file, 1.1202 + const uint8_t *data, const size_t length, 1.1203 + const uint16_t num_features) { 1.1204 + Buffer subtable(data, length); 1.1205 + 1.1206 + uint16_t script_count = 0; 1.1207 + if (!subtable.ReadU16(&script_count)) { 1.1208 + return OTS_FAILURE_MSG("Failed to read script count in script list table"); 1.1209 + } 1.1210 + 1.1211 + const unsigned script_record_end = 1.1212 + 6 * static_cast<unsigned>(script_count) + 2; 1.1213 + if (script_record_end > std::numeric_limits<uint16_t>::max()) { 1.1214 + return OTS_FAILURE_MSG("Bad end of script record %d in script list table", script_record_end); 1.1215 + } 1.1216 + std::vector<ScriptRecord> script_list; 1.1217 + script_list.reserve(script_count); 1.1218 + uint32_t last_tag = 0; 1.1219 + for (unsigned i = 0; i < script_count; ++i) { 1.1220 + ScriptRecord record; 1.1221 + if (!subtable.ReadU32(&record.tag) || 1.1222 + !subtable.ReadU16(&record.offset)) { 1.1223 + return OTS_FAILURE_MSG("Failed to read script record %d in script list table", i); 1.1224 + } 1.1225 + // Script tags should be arranged alphabetically by tag 1.1226 + if (last_tag != 0 && last_tag > record.tag) { 1.1227 + // Several fonts don't arrange tags alphabetically. 1.1228 + // It seems that the order of tags might not be a security issue 1.1229 + // so we just warn it. 1.1230 + OTS_WARNING("tags aren't arranged alphabetically."); 1.1231 + } 1.1232 + last_tag = record.tag; 1.1233 + if (record.offset < script_record_end || record.offset >= length) { 1.1234 + return OTS_FAILURE_MSG("Bad record offset %d for script %4.4s entry %d in script list table", record.offset, (char *)&record.tag, i); 1.1235 + } 1.1236 + script_list.push_back(record); 1.1237 + } 1.1238 + if (script_list.size() != script_count) { 1.1239 + return OTS_FAILURE_MSG("Bad script list size %ld in script list table", script_list.size()); 1.1240 + } 1.1241 + 1.1242 + // Check script records. 1.1243 + for (unsigned i = 0; i < script_count; ++i) { 1.1244 + if (!ParseScriptTable(file, data + script_list[i].offset, 1.1245 + length - script_list[i].offset, 1.1246 + script_list[i].tag, num_features)) { 1.1247 + return OTS_FAILURE_MSG("Failed to parse script table %d", i); 1.1248 + } 1.1249 + } 1.1250 + 1.1251 + return true; 1.1252 +} 1.1253 + 1.1254 +// Parsing FeatureListTable requires number of lookups so we need to parse 1.1255 +// LookupListTable before calling this function. 1.1256 +bool ParseFeatureListTable(const ots::OpenTypeFile *file, 1.1257 + const uint8_t *data, const size_t length, 1.1258 + const uint16_t num_lookups, 1.1259 + uint16_t* num_features) { 1.1260 + Buffer subtable(data, length); 1.1261 + 1.1262 + uint16_t feature_count = 0; 1.1263 + if (!subtable.ReadU16(&feature_count)) { 1.1264 + return OTS_FAILURE_MSG("Failed to read feature count"); 1.1265 + } 1.1266 + 1.1267 + std::vector<FeatureRecord> feature_records; 1.1268 + feature_records.resize(feature_count); 1.1269 + const unsigned feature_record_end = 1.1270 + 6 * static_cast<unsigned>(feature_count) + 2; 1.1271 + if (feature_record_end > std::numeric_limits<uint16_t>::max()) { 1.1272 + return OTS_FAILURE_MSG("Bad end of feature record %d", feature_record_end); 1.1273 + } 1.1274 + uint32_t last_tag = 0; 1.1275 + for (unsigned i = 0; i < feature_count; ++i) { 1.1276 + if (!subtable.ReadU32(&feature_records[i].tag) || 1.1277 + !subtable.ReadU16(&feature_records[i].offset)) { 1.1278 + return OTS_FAILURE_MSG("Failed to read feature header %d", i); 1.1279 + } 1.1280 + // Feature record array should be arranged alphabetically by tag 1.1281 + if (last_tag != 0 && last_tag > feature_records[i].tag) { 1.1282 + // Several fonts don't arrange tags alphabetically. 1.1283 + // It seems that the order of tags might not be a security issue 1.1284 + // so we just warn it. 1.1285 + OTS_WARNING("tags aren't arranged alphabetically."); 1.1286 + } 1.1287 + last_tag = feature_records[i].tag; 1.1288 + if (feature_records[i].offset < feature_record_end || 1.1289 + feature_records[i].offset >= length) { 1.1290 + return OTS_FAILURE_MSG("Bad feature offset %d for feature %d %4.4s", feature_records[i].offset, i, (char *)&feature_records[i].tag); 1.1291 + } 1.1292 + } 1.1293 + 1.1294 + for (unsigned i = 0; i < feature_count; ++i) { 1.1295 + if (!ParseFeatureTable(file, data + feature_records[i].offset, 1.1296 + length - feature_records[i].offset, num_lookups)) { 1.1297 + return OTS_FAILURE_MSG("Failed to parse feature table %d", i); 1.1298 + } 1.1299 + } 1.1300 + *num_features = feature_count; 1.1301 + return true; 1.1302 +} 1.1303 + 1.1304 +// For parsing GPOS/GSUB tables, this function should be called at first to 1.1305 +// obtain the number of lookups because parsing FeatureTableList requires 1.1306 +// the number. 1.1307 +bool ParseLookupListTable(OpenTypeFile *file, const uint8_t *data, 1.1308 + const size_t length, 1.1309 + const LookupSubtableParser* parser, 1.1310 + uint16_t *num_lookups) { 1.1311 + Buffer subtable(data, length); 1.1312 + 1.1313 + if (!subtable.ReadU16(num_lookups)) { 1.1314 + return OTS_FAILURE_MSG("Failed to read number of lookups"); 1.1315 + } 1.1316 + 1.1317 + std::vector<uint16_t> lookups; 1.1318 + lookups.reserve(*num_lookups); 1.1319 + const unsigned lookup_end = 1.1320 + 2 * static_cast<unsigned>(*num_lookups) + 2; 1.1321 + if (lookup_end > std::numeric_limits<uint16_t>::max()) { 1.1322 + return OTS_FAILURE_MSG("Bad end of lookups %d", lookup_end); 1.1323 + } 1.1324 + for (unsigned i = 0; i < *num_lookups; ++i) { 1.1325 + uint16_t offset = 0; 1.1326 + if (!subtable.ReadU16(&offset)) { 1.1327 + return OTS_FAILURE_MSG("Failed to read lookup offset %d", i); 1.1328 + } 1.1329 + if (offset < lookup_end || offset >= length) { 1.1330 + return OTS_FAILURE_MSG("Bad lookup offset %d for lookup %d", offset, i); 1.1331 + } 1.1332 + lookups.push_back(offset); 1.1333 + } 1.1334 + if (lookups.size() != *num_lookups) { 1.1335 + return OTS_FAILURE_MSG("Bad lookup offsets list size %ld", lookups.size()); 1.1336 + } 1.1337 + 1.1338 + for (unsigned i = 0; i < *num_lookups; ++i) { 1.1339 + if (!ParseLookupTable(file, data + lookups[i], length - lookups[i], 1.1340 + parser)) { 1.1341 + return OTS_FAILURE_MSG("Failed to parse lookup %d", i); 1.1342 + } 1.1343 + } 1.1344 + 1.1345 + return true; 1.1346 +} 1.1347 + 1.1348 +bool ParseClassDefTable(const ots::OpenTypeFile *file, 1.1349 + const uint8_t *data, size_t length, 1.1350 + const uint16_t num_glyphs, 1.1351 + const uint16_t num_classes) { 1.1352 + Buffer subtable(data, length); 1.1353 + 1.1354 + uint16_t format = 0; 1.1355 + if (!subtable.ReadU16(&format)) { 1.1356 + return OTS_FAILURE_MSG("Failed to read class defn format"); 1.1357 + } 1.1358 + if (format == 1) { 1.1359 + return ParseClassDefFormat1(file, data, length, num_glyphs, num_classes); 1.1360 + } else if (format == 2) { 1.1361 + return ParseClassDefFormat2(file, data, length, num_glyphs, num_classes); 1.1362 + } 1.1363 + 1.1364 + return OTS_FAILURE_MSG("Bad class defn format %d", format); 1.1365 +} 1.1366 + 1.1367 +bool ParseCoverageTable(const ots::OpenTypeFile *file, 1.1368 + const uint8_t *data, size_t length, 1.1369 + const uint16_t num_glyphs, 1.1370 + const uint16_t expected_num_glyphs) { 1.1371 + Buffer subtable(data, length); 1.1372 + 1.1373 + uint16_t format = 0; 1.1374 + if (!subtable.ReadU16(&format)) { 1.1375 + return OTS_FAILURE_MSG("Failed to read coverage table format"); 1.1376 + } 1.1377 + if (format == 1) { 1.1378 + return ParseCoverageFormat1(file, data, length, num_glyphs, expected_num_glyphs); 1.1379 + } else if (format == 2) { 1.1380 + return ParseCoverageFormat2(file, data, length, num_glyphs, expected_num_glyphs); 1.1381 + } 1.1382 + 1.1383 + return OTS_FAILURE_MSG("Bad coverage table format %d", format); 1.1384 +} 1.1385 + 1.1386 +bool ParseDeviceTable(const ots::OpenTypeFile *file, 1.1387 + const uint8_t *data, size_t length) { 1.1388 + Buffer subtable(data, length); 1.1389 + 1.1390 + uint16_t start_size = 0; 1.1391 + uint16_t end_size = 0; 1.1392 + uint16_t delta_format = 0; 1.1393 + if (!subtable.ReadU16(&start_size) || 1.1394 + !subtable.ReadU16(&end_size) || 1.1395 + !subtable.ReadU16(&delta_format)) { 1.1396 + return OTS_FAILURE_MSG("Failed to read device table header"); 1.1397 + } 1.1398 + if (start_size > end_size) { 1.1399 + return OTS_FAILURE_MSG("bad size range: %u > %u", start_size, end_size); 1.1400 + } 1.1401 + if (delta_format == 0 || delta_format > kMaxDeltaFormatType) { 1.1402 + return OTS_FAILURE_MSG("bad delta format: %u", delta_format); 1.1403 + } 1.1404 + // The number of delta values per uint16. The device table should contain 1.1405 + // at least |num_units| * 2 bytes compressed data. 1.1406 + const unsigned num_units = (end_size - start_size) / 1.1407 + (1 << (4 - delta_format)) + 1; 1.1408 + // Just skip |num_units| * 2 bytes since the compressed data could take 1.1409 + // arbitrary values. 1.1410 + if (!subtable.Skip(num_units * 2)) { 1.1411 + return OTS_FAILURE_MSG("Failed to skip data in device table"); 1.1412 + } 1.1413 + return true; 1.1414 +} 1.1415 + 1.1416 +bool ParseContextSubtable(const ots::OpenTypeFile *file, 1.1417 + const uint8_t *data, const size_t length, 1.1418 + const uint16_t num_glyphs, 1.1419 + const uint16_t num_lookups) { 1.1420 + Buffer subtable(data, length); 1.1421 + 1.1422 + uint16_t format = 0; 1.1423 + if (!subtable.ReadU16(&format)) { 1.1424 + return OTS_FAILURE_MSG("Failed to read context subtable format"); 1.1425 + } 1.1426 + 1.1427 + if (format == 1) { 1.1428 + if (!ParseContextFormat1(file, data, length, num_glyphs, num_lookups)) { 1.1429 + return OTS_FAILURE_MSG("Failed to parse context format 1 subtable"); 1.1430 + } 1.1431 + } else if (format == 2) { 1.1432 + if (!ParseContextFormat2(file, data, length, num_glyphs, num_lookups)) { 1.1433 + return OTS_FAILURE_MSG("Failed to parse context format 2 subtable"); 1.1434 + } 1.1435 + } else if (format == 3) { 1.1436 + if (!ParseContextFormat3(file, data, length, num_glyphs, num_lookups)) { 1.1437 + return OTS_FAILURE_MSG("Failed to parse context format 3 subtable"); 1.1438 + } 1.1439 + } else { 1.1440 + return OTS_FAILURE_MSG("Bad context subtable format %d", format); 1.1441 + } 1.1442 + 1.1443 + return true; 1.1444 +} 1.1445 + 1.1446 +bool ParseChainingContextSubtable(const ots::OpenTypeFile *file, 1.1447 + const uint8_t *data, const size_t length, 1.1448 + const uint16_t num_glyphs, 1.1449 + const uint16_t num_lookups) { 1.1450 + Buffer subtable(data, length); 1.1451 + 1.1452 + uint16_t format = 0; 1.1453 + if (!subtable.ReadU16(&format)) { 1.1454 + return OTS_FAILURE_MSG("Failed to read chaining context subtable format"); 1.1455 + } 1.1456 + 1.1457 + if (format == 1) { 1.1458 + if (!ParseChainContextFormat1(file, data, length, num_glyphs, num_lookups)) { 1.1459 + return OTS_FAILURE_MSG("Failed to parse chaining context format 1 subtable"); 1.1460 + } 1.1461 + } else if (format == 2) { 1.1462 + if (!ParseChainContextFormat2(file, data, length, num_glyphs, num_lookups)) { 1.1463 + return OTS_FAILURE_MSG("Failed to parse chaining context format 2 subtable"); 1.1464 + } 1.1465 + } else if (format == 3) { 1.1466 + if (!ParseChainContextFormat3(file, data, length, num_glyphs, num_lookups)) { 1.1467 + return OTS_FAILURE_MSG("Failed to parse chaining context format 3 subtable"); 1.1468 + } 1.1469 + } else { 1.1470 + return OTS_FAILURE_MSG("Bad chaining context subtable format %d", format); 1.1471 + } 1.1472 + 1.1473 + return true; 1.1474 +} 1.1475 + 1.1476 +bool ParseExtensionSubtable(const OpenTypeFile *file, 1.1477 + const uint8_t *data, const size_t length, 1.1478 + const LookupSubtableParser* parser) { 1.1479 + Buffer subtable(data, length); 1.1480 + 1.1481 + uint16_t format = 0; 1.1482 + uint16_t lookup_type = 0; 1.1483 + uint32_t offset_extension = 0; 1.1484 + if (!subtable.ReadU16(&format) || 1.1485 + !subtable.ReadU16(&lookup_type) || 1.1486 + !subtable.ReadU32(&offset_extension)) { 1.1487 + return OTS_FAILURE_MSG("Failed to read extension table header"); 1.1488 + } 1.1489 + 1.1490 + if (format != 1) { 1.1491 + return OTS_FAILURE_MSG("Bad extension table format %d", format); 1.1492 + } 1.1493 + // |lookup_type| should be other than |parser->extension_type|. 1.1494 + if (lookup_type < 1 || lookup_type > parser->num_types || 1.1495 + lookup_type == parser->extension_type) { 1.1496 + return OTS_FAILURE_MSG("Bad lookup type %d in extension table", lookup_type); 1.1497 + } 1.1498 + 1.1499 + const unsigned format_end = static_cast<unsigned>(8); 1.1500 + if (offset_extension < format_end || 1.1501 + offset_extension >= length) { 1.1502 + return OTS_FAILURE_MSG("Bad extension offset %d", offset_extension); 1.1503 + } 1.1504 + 1.1505 + // Parse the extension subtable of |lookup_type|. 1.1506 + if (!parser->Parse(file, data + offset_extension, length - offset_extension, 1.1507 + lookup_type)) { 1.1508 + return OTS_FAILURE_MSG("Failed to parse lookup from extension lookup"); 1.1509 + } 1.1510 + 1.1511 + return true; 1.1512 +} 1.1513 + 1.1514 +} // namespace ots 1.1515 +