LCOV - code coverage report
Current view: top level - gfx/ots/src - layout.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 812 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 33 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13