tor-browser

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

sill.cc (5229B)


      1 // Copyright (c) 2009-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 "sill.h"
      6 
      7 #include "feat.h"
      8 #include <cmath>
      9 #include <unordered_set>
     10 
     11 namespace ots {
     12 
     13 bool OpenTypeSILL::Parse(const uint8_t* data, size_t length) {
     14  Buffer table(data, length);
     15 
     16  if (!table.ReadU32(&this->version) || this->version >> 16 != 1) {
     17    return Drop("Failed to read valid version");
     18  }
     19  if (!table.ReadU16(&this->numLangs)) {
     20    return Drop("Failed to read numLangs");
     21  }
     22 
     23  // The following three fields are deprecated and ignored. We fix them up here
     24  // just for internal consistency, but the Graphite engine doesn't care.
     25  if (!table.ReadU16(&this->searchRange) ||
     26      !table.ReadU16(&this->entrySelector) ||
     27      !table.ReadU16(&this->rangeShift)) {
     28    return Drop("Failed to read searchRange..rangeShift");
     29  }
     30  if (this->numLangs == 0) {
     31    if (this->searchRange != 0 || this->entrySelector != 0 || this->rangeShift != 0) {
     32      this->searchRange = this->entrySelector = this->rangeShift = 0;
     33    }
     34  } else {
     35    unsigned floorLog2 = std::floor(std::log2(this->numLangs));
     36    if (this->searchRange != (unsigned)std::pow(2, floorLog2) ||
     37        this->entrySelector != floorLog2 ||
     38        this->rangeShift != this->numLangs - this->searchRange) {
     39      this->searchRange = (unsigned)std::pow(2, floorLog2);
     40      this->entrySelector = floorLog2;
     41      this->rangeShift = this->numLangs - this->searchRange;
     42    }
     43  }
     44 
     45  std::unordered_set<size_t> unverified;
     46  //this->entries.resize(static_cast<unsigned long>(this->numLangs) + 1, this);
     47  for (unsigned long i = 0; i <= this->numLangs; ++i) {
     48    this->entries.emplace_back(this);
     49    LanguageEntry& entry = this->entries[i];
     50    if (!entry.ParsePart(table)) {
     51      return Drop("Failed to read entries[%u]", i);
     52    }
     53    for (unsigned j = 0; j < entry.numSettings; ++j) {
     54      size_t offset = entry.offset + j * 8;
     55      if (offset < entry.offset || offset > length) {
     56        return DropGraphite("Invalid LangFeatureSetting offset %zu/%zu",
     57                            offset, length);
     58      }
     59      unverified.insert(offset);
     60        // need to verify that this LanguageEntry points to valid
     61        // LangFeatureSetting
     62    }
     63  }
     64 
     65  while (table.remaining()) {
     66    unverified.erase(table.offset());
     67    LangFeatureSetting setting(this);
     68    if (!setting.ParsePart(table)) {
     69      return Drop("Failed to read a LangFeatureSetting");
     70    }
     71    settings.push_back(setting);
     72  }
     73 
     74  if (!unverified.empty()) {
     75    return Drop("%zu incorrect offsets into settings", unverified.size());
     76  }
     77  if (table.remaining()) {
     78    return Warning("%zu bytes unparsed", table.remaining());
     79  }
     80  return true;
     81 }
     82 
     83 bool OpenTypeSILL::Serialize(OTSStream* out) {
     84  if (!out->WriteU32(this->version) ||
     85      !out->WriteU16(this->numLangs) ||
     86      !out->WriteU16(this->searchRange) ||
     87      !out->WriteU16(this->entrySelector) ||
     88      !out->WriteU16(this->rangeShift) ||
     89      !SerializeParts(this->entries, out) ||
     90      !SerializeParts(this->settings, out)) {
     91    return Error("Failed to write table");
     92  }
     93  return true;
     94 }
     95 
     96 bool OpenTypeSILL::LanguageEntry::ParsePart(Buffer& table) {
     97  if (!table.ReadU8(&this->langcode[0]) ||
     98      !table.ReadU8(&this->langcode[1]) ||
     99      !table.ReadU8(&this->langcode[2]) ||
    100      !table.ReadU8(&this->langcode[3])) {
    101    return parent->Error("LanguageEntry: Failed to read langcode");
    102  }
    103  if (!table.ReadU16(&this->numSettings)) {
    104    return parent->Error("LanguageEntry: Failed to read numSettings");
    105  }
    106  if (!table.ReadU16(&this->offset)) {
    107    return parent->Error("LanguageEntry: Failed to read offset");
    108  }
    109  return true;
    110 }
    111 
    112 bool OpenTypeSILL::LanguageEntry::SerializePart(OTSStream* out) const {
    113  if (!out->WriteU8(this->langcode[0]) ||
    114      !out->WriteU8(this->langcode[1]) ||
    115      !out->WriteU8(this->langcode[2]) ||
    116      !out->WriteU8(this->langcode[3]) ||
    117      !out->WriteU16(this->numSettings) ||
    118      !out->WriteU16(this->offset)) {
    119    return parent->Error("LanguageEntry: Failed to write");
    120  }
    121  return true;
    122 }
    123 
    124 bool OpenTypeSILL::LangFeatureSetting::ParsePart(Buffer& table) {
    125  OpenTypeFEAT* feat = static_cast<OpenTypeFEAT*>(
    126      parent->GetFont()->GetTypedTable(OTS_TAG_FEAT));
    127  if (!feat) {
    128    return parent->Error("FeatureDefn: Required Feat table is missing");
    129  }
    130 
    131  if (!table.ReadU32(&this->featureId) ||
    132      !feat->IsValidFeatureId(this->featureId)) {
    133    return parent->Error("LangFeatureSetting: Failed to read valid featureId");
    134  }
    135  if (!table.ReadS16(&this->value)) {
    136    return parent->Error("LangFeatureSetting: Failed to read value");
    137  }
    138  if (!table.ReadU16(&this->reserved)) {
    139    return parent->Error("LangFeatureSetting: Failed to read reserved");
    140  }
    141  if (this->reserved != 0) {
    142    parent->Warning("LangFeatureSetting: Nonzero reserved");
    143  }
    144  return true;
    145 }
    146 
    147 bool OpenTypeSILL::LangFeatureSetting::SerializePart(OTSStream* out) const {
    148  if (!out->WriteU32(this->featureId) ||
    149      !out->WriteS16(this->value) ||
    150      !out->WriteU16(this->reserved)) {
    151    return parent->Error("LangFeatureSetting: Failed to read reserved");
    152  }
    153  return true;
    154 }
    155 
    156 }  // namespace ots