tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

gdef.cc (12544B)


      1 // Copyright (c) 2011-2017 The OTS 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 "gdef.h"
      6 
      7 #include <limits>
      8 #include <vector>
      9 
     10 #include "gpos.h"
     11 #include "gsub.h"
     12 #include "layout.h"
     13 #include "maxp.h"
     14 #include "variations.h"
     15 
     16 // GDEF - The Glyph Definition Table
     17 // http://www.microsoft.com/typography/otspec/gdef.htm
     18 
     19 namespace {
     20 
     21 // The maximum class value in the glyph class definision table.
     22 const uint16_t kMaxGlyphClassDefValue = 4;
     23 // The maximum format number of caret value tables.
     24 const uint16_t kMaxCaretValueFormat = 3;
     25 
     26 }  // namespace
     27 
     28 namespace ots {
     29 
     30 bool OpenTypeGDEF::ParseAttachListTable(const uint8_t *data, size_t length) {
     31  ots::Buffer subtable(data, length);
     32 
     33  uint16_t offset_coverage = 0;
     34  uint16_t glyph_count = 0;
     35  if (!subtable.ReadU16(&offset_coverage) ||
     36      !subtable.ReadU16(&glyph_count)) {
     37    return Error("Failed to read gdef header");
     38  }
     39  const unsigned attach_points_end =
     40      2 * static_cast<unsigned>(glyph_count) + 4;
     41  if (attach_points_end > std::numeric_limits<uint16_t>::max()) {
     42    return Error("Bad glyph count in gdef");
     43  }
     44  if (offset_coverage == 0 || offset_coverage >= length ||
     45      offset_coverage < attach_points_end) {
     46    return Error("Bad coverage offset %d", offset_coverage);
     47  }
     48  if (glyph_count > this->m_num_glyphs) {
     49    return Error("Bad glyph count %u", glyph_count);
     50  }
     51 
     52  std::vector<uint16_t> attach_points;
     53  attach_points.resize(glyph_count);
     54  for (unsigned i = 0; i < glyph_count; ++i) {
     55    if (!subtable.ReadU16(&attach_points[i])) {
     56      return Error("Can't read attachment point %d", i);
     57    }
     58    if (attach_points[i] >= length ||
     59        attach_points[i] < attach_points_end) {
     60      return Error("Bad attachment point %d of %d", i, attach_points[i]);
     61    }
     62  }
     63 
     64  // Parse coverage table
     65  if (!ots::ParseCoverageTable(GetFont(), data + offset_coverage,
     66                               length - offset_coverage, this->m_num_glyphs)) {
     67    return Error("Bad coverage table");
     68  }
     69 
     70  // Parse attach point table
     71  for (unsigned i = 0; i < attach_points.size(); ++i) {
     72    subtable.set_offset(attach_points[i]);
     73    uint16_t point_count = 0;
     74    if (!subtable.ReadU16(&point_count)) {
     75      return Error("Can't read point count %d", i);
     76    }
     77    if (point_count == 0) {
     78      return Error("zero point count %d", i);
     79    }
     80    uint16_t last_point_index = 0;
     81    uint16_t point_index = 0;
     82    for (unsigned j = 0; j < point_count; ++j) {
     83      if (!subtable.ReadU16(&point_index)) {
     84        return Error("Can't read point index %d in point %d", j, i);
     85      }
     86      // Contour point indices are in increasing numerical order
     87      if (last_point_index != 0 && last_point_index >= point_index) {
     88        return Error("bad contour indices: %u >= %u",
     89                    last_point_index, point_index);
     90      }
     91      last_point_index = point_index;
     92    }
     93  }
     94  return true;
     95 }
     96 
     97 bool OpenTypeGDEF::ParseLigCaretListTable(const uint8_t *data, size_t length) {
     98  ots::Buffer subtable(data, length);
     99  uint16_t offset_coverage = 0;
    100  uint16_t lig_glyph_count = 0;
    101  if (!subtable.ReadU16(&offset_coverage) ||
    102      !subtable.ReadU16(&lig_glyph_count)) {
    103    return Error("Can't read caret structure");
    104  }
    105  const unsigned lig_glyphs_end =
    106      2 * static_cast<unsigned>(lig_glyph_count) + 4;
    107  if (lig_glyphs_end > std::numeric_limits<uint16_t>::max()) {
    108    return Error("Bad caret structure");
    109  }
    110  if (offset_coverage == 0 || offset_coverage >= length ||
    111      offset_coverage < lig_glyphs_end) {
    112    return Error("Bad caret coverate offset %d", offset_coverage);
    113  }
    114  if (lig_glyph_count > this->m_num_glyphs) {
    115    return Error("bad ligature glyph count: %u", lig_glyph_count);
    116  }
    117 
    118  std::vector<uint16_t> lig_glyphs;
    119  lig_glyphs.resize(lig_glyph_count);
    120  for (unsigned i = 0; i < lig_glyph_count; ++i) {
    121    if (!subtable.ReadU16(&lig_glyphs[i])) {
    122      return Error("Can't read ligature glyph location %d", i);
    123    }
    124    if (lig_glyphs[i] >= length || lig_glyphs[i] < lig_glyphs_end) {
    125      return Error("Bad ligature glyph location %d in glyph %d", lig_glyphs[i], i);
    126    }
    127  }
    128 
    129  // Parse coverage table
    130  if (!ots::ParseCoverageTable(GetFont(), data + offset_coverage,
    131                               length - offset_coverage, this->m_num_glyphs)) {
    132    return Error("Can't parse caret coverage table");
    133  }
    134 
    135  // Parse ligature glyph table
    136  for (unsigned i = 0; i < lig_glyphs.size(); ++i) {
    137    subtable.set_offset(lig_glyphs[i]);
    138    uint16_t caret_count = 0;
    139    if (!subtable.ReadU16(&caret_count)) {
    140      return Error("Can't read caret count for glyph %d", i);
    141    }
    142    if (caret_count == 0) {
    143      return Error("bad caret value count: %u", caret_count);
    144    }
    145 
    146    std::vector<uint16_t> caret_value_offsets;
    147    caret_value_offsets.resize(caret_count);
    148    unsigned caret_value_offsets_end = 2 * static_cast<unsigned>(caret_count) + 2;
    149    for (unsigned j = 0; j < caret_count; ++j) {
    150      if (!subtable.ReadU16(&caret_value_offsets[j])) {
    151        return Error("Can't read caret offset %d for glyph %d", j, i);
    152      }
    153      if (caret_value_offsets[j] >= length || caret_value_offsets[j] < caret_value_offsets_end) {
    154        return Error("Bad caret offset %d for caret %d glyph %d", caret_value_offsets[j], j, i);
    155      }
    156    }
    157 
    158    // Parse caret values table
    159    for (unsigned j = 0; j < caret_count; ++j) {
    160      subtable.set_offset(lig_glyphs[i] + caret_value_offsets[j]);
    161      uint16_t caret_format = 0;
    162      if (!subtable.ReadU16(&caret_format)) {
    163        return Error("Can't read caret values table %d in glyph %d", j, i);
    164      }
    165      if (caret_format == 0 || caret_format > kMaxCaretValueFormat) {
    166        return Error("bad caret value format: %u", caret_format);
    167      }
    168      // CaretValueFormats contain a 2-byte field which could be
    169      // arbitrary value.
    170      if (!subtable.Skip(2)) {
    171        return Error("Bad caret value table structure %d in glyph %d", j, i);
    172      }
    173      if (caret_format == 3) {
    174        uint16_t offset_device = 0;
    175        if (!subtable.ReadU16(&offset_device)) {
    176          return Error("Can't read device offset for caret value %d "
    177                       "in glyph %d", j, i);
    178        }
    179        size_t absolute_offset = lig_glyphs[i] + caret_value_offsets[j]
    180                                 + offset_device;
    181        if (offset_device == 0 || absolute_offset >= length) {
    182          return Error("Bad device offset for caret value %d in glyph %d: %d",
    183                       j, i, offset_device);
    184        }
    185        if (!ots::ParseDeviceTable(GetFont(), data + absolute_offset,
    186                                   length - absolute_offset)) {
    187          return Error("Bad device table for caret value %d in glyph %d",
    188                       j, i, offset_device);
    189        }
    190      }
    191    }
    192  }
    193  return true;
    194 }
    195 
    196 bool OpenTypeGDEF::ParseMarkGlyphSetsDefTable(const uint8_t *data, size_t length) {
    197  ots::Buffer subtable(data, length);
    198  uint16_t format = 0;
    199  uint16_t mark_set_count = 0;
    200  if (!subtable.ReadU16(&format) ||
    201      !subtable.ReadU16(&mark_set_count)) {
    202    return Error("Can' read mark glyph table structure");
    203  }
    204  if (format != 1) {
    205    return Error("bad mark glyph set table format: %u", format);
    206  }
    207 
    208  const unsigned mark_sets_end = 2 * static_cast<unsigned>(mark_set_count) + 4;
    209  if (mark_sets_end > std::numeric_limits<uint16_t>::max()) {
    210    return Error("Bad mark_set %d", mark_sets_end);
    211  }
    212  for (unsigned i = 0; i < mark_set_count; ++i) {
    213    uint32_t offset_coverage = 0;
    214    if (!subtable.ReadU32(&offset_coverage)) {
    215      return Error("Can't read covrage location for mark set %d", i);
    216    }
    217    if (offset_coverage >= length ||
    218        offset_coverage < mark_sets_end) {
    219      return Error("Bad coverage location %d for mark set %d", offset_coverage, i);
    220    }
    221    if (!ots::ParseCoverageTable(GetFont(), data + offset_coverage,
    222                                 length - offset_coverage, this->m_num_glyphs)) {
    223      return Error("Failed to parse coverage table for mark set %d", i);
    224    }
    225  }
    226  this->num_mark_glyph_sets = mark_set_count;
    227  return true;
    228 }
    229 
    230 bool OpenTypeGDEF::Parse(const uint8_t *data, size_t length) {
    231  OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>(
    232      GetFont()->GetTypedTable(OTS_TAG_MAXP));
    233 
    234  // Grab the number of glyphs in the font from the maxp table to check
    235  // GlyphIDs in GDEF table.
    236  if (!maxp) {
    237    return Error("No maxp table in font, needed by GDEF");
    238  }
    239  this->m_num_glyphs = maxp->num_glyphs;
    240 
    241  Buffer table(data, length);
    242 
    243  uint16_t version_major = 0, version_minor = 0;
    244  if (!table.ReadU16(&version_major) ||
    245      !table.ReadU16(&version_minor)) {
    246    return Error("Incomplete table");
    247  }
    248  if (version_major != 1 || version_minor == 1) { // there is no v1.1
    249    return Error("Bad version");
    250  }
    251 
    252  uint16_t offset_glyph_class_def = 0;
    253  uint16_t offset_attach_list = 0;
    254  uint16_t offset_lig_caret_list = 0;
    255  uint16_t offset_mark_attach_class_def = 0;
    256  if (!table.ReadU16(&offset_glyph_class_def) ||
    257      !table.ReadU16(&offset_attach_list) ||
    258      !table.ReadU16(&offset_lig_caret_list) ||
    259      !table.ReadU16(&offset_mark_attach_class_def)) {
    260    return Error("Incomplete table");
    261  }
    262  uint16_t offset_mark_glyph_sets_def = 0;
    263  if (version_minor >= 2) {
    264    if (!table.ReadU16(&offset_mark_glyph_sets_def)) {
    265      return Error("Incomplete table");
    266    }
    267  }
    268  uint32_t item_var_store_offset = 0;
    269  if (version_minor >= 3) {
    270    if (!table.ReadU32(&item_var_store_offset)) {
    271      return Error("Incomplete table");
    272    }
    273  }
    274 
    275  unsigned gdef_header_end = 4 + 4 * 2;
    276  if (version_minor >= 2)
    277    gdef_header_end += 2;
    278  if (version_minor >= 3)
    279    gdef_header_end += 4;
    280 
    281  // Parse subtables
    282  if (offset_glyph_class_def) {
    283    if (offset_glyph_class_def >= length ||
    284        offset_glyph_class_def < gdef_header_end) {
    285      return Error("Invalid offset to glyph classes");
    286    }
    287    if (!ots::ParseClassDefTable(GetFont(), data + offset_glyph_class_def,
    288                                 length - offset_glyph_class_def,
    289                                 this->m_num_glyphs, kMaxGlyphClassDefValue)) {
    290      return Error("Invalid glyph classes");
    291    }
    292  }
    293 
    294  if (offset_attach_list) {
    295    if (offset_attach_list >= length ||
    296        offset_attach_list < gdef_header_end) {
    297      return Error("Invalid offset to attachment list");
    298    }
    299    if (!ParseAttachListTable(data + offset_attach_list,
    300                              length - offset_attach_list)) {
    301      return Error("Invalid attachment list");
    302    }
    303  }
    304 
    305  if (offset_lig_caret_list) {
    306    if (offset_lig_caret_list >= length ||
    307        offset_lig_caret_list < gdef_header_end) {
    308      return Error("Invalid offset to ligature caret list");
    309    }
    310    if (!ParseLigCaretListTable(data + offset_lig_caret_list,
    311                                length - offset_lig_caret_list)) {
    312      return Error("Invalid ligature caret list");
    313    }
    314  }
    315 
    316  if (offset_mark_attach_class_def) {
    317    if (offset_mark_attach_class_def >= length ||
    318        offset_mark_attach_class_def < gdef_header_end) {
    319      return Error("Invalid offset to mark attachment list");
    320    }
    321    if (!ots::ParseClassDefTable(GetFont(),
    322                                 data + offset_mark_attach_class_def,
    323                                 length - offset_mark_attach_class_def,
    324                                 this->m_num_glyphs, kMaxClassDefValue)) {
    325      return Error("Invalid mark attachment list");
    326    }
    327  }
    328 
    329  if (offset_mark_glyph_sets_def) {
    330    if (offset_mark_glyph_sets_def >= length ||
    331        offset_mark_glyph_sets_def < gdef_header_end) {
    332      return Error("invalid offset to mark glyph sets");
    333    }
    334    if (!ParseMarkGlyphSetsDefTable(data + offset_mark_glyph_sets_def,
    335                                    length - offset_mark_glyph_sets_def)) {
    336      return Error("Invalid mark glyph sets");
    337    }
    338  }
    339 
    340  if (item_var_store_offset) {
    341    if (item_var_store_offset >= length ||
    342        item_var_store_offset < gdef_header_end) {
    343      return Error("invalid offset to item variation store");
    344    }
    345    if (!ParseItemVariationStore(GetFont(), data + item_var_store_offset,
    346                                 length - item_var_store_offset)) {
    347      return Error("Invalid item variation store");
    348    }
    349  }
    350 
    351  this->m_data = data;
    352  this->m_length = length;
    353  return true;
    354 }
    355 
    356 bool OpenTypeGDEF::Serialize(OTSStream *out) {
    357  if (!out->Write(this->m_data, this->m_length)) {
    358    return Error("Failed to write table");
    359  }
    360 
    361  return true;
    362 }
    363 
    364 }  // namespace ots