tor-browser

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

stat.cc (11971B)


      1 // Copyright (c) 2018 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 "stat.h"
      6 #include "name.h"
      7 
      8 namespace ots {
      9 
     10 // -----------------------------------------------------------------------------
     11 // OpenTypeSTAT
     12 // -----------------------------------------------------------------------------
     13 
     14 bool OpenTypeSTAT::ValidateNameId(uint16_t nameid) {
     15  OpenTypeNAME* name = static_cast<OpenTypeNAME*>(
     16      GetFont()->GetTypedTable(OTS_TAG_NAME));
     17 
     18  if (!name || !name->IsValidNameId(nameid)) {
     19    Drop("Invalid nameID: %d", nameid);
     20    return false;
     21  }
     22 
     23  if ((nameid >= 26 && nameid <= 255) || nameid >= 32768) {
     24    Warning("nameID out of range: %d", nameid);
     25    return true;
     26  }
     27 
     28  return  true;
     29 }
     30 
     31 bool OpenTypeSTAT::Parse(const uint8_t* data, size_t length) {
     32  Buffer table(data, length);
     33  if (!table.ReadU16(&this->majorVersion) ||
     34      !table.ReadU16(&this->minorVersion) ||
     35      !table.ReadU16(&this->designAxisSize) ||
     36      !table.ReadU16(&this->designAxisCount) ||
     37      !table.ReadU32(&this->designAxesOffset) ||
     38      !table.ReadU16(&this->axisValueCount) ||
     39      !table.ReadU32(&this->offsetToAxisValueOffsets) ||
     40      !(this->minorVersion < 1 || table.ReadU16(&this->elidedFallbackNameID))) {
     41    return Drop("Failed to read table header");
     42  }
     43  if (this->majorVersion != 1) {
     44    return Drop("Unknown table version");
     45  }
     46  if (this->minorVersion > 2) {
     47    Warning("Unknown minor version, downgrading to 2");
     48    this->minorVersion = 2;
     49  }
     50 
     51  size_t headerEnd = table.offset();
     52 
     53  if (this->designAxisCount == 0) {
     54    if (this->designAxesOffset != 0) {
     55      Warning("Unexpected non-zero designAxesOffset");
     56      this->designAxesOffset = 0;
     57    }
     58  } else {
     59    if (this->designAxisSize < sizeof(AxisRecord)) {
     60      return Drop("Invalid designAxisSize");
     61    }
     62    if (this->designAxesOffset < headerEnd ||
     63        size_t(this->designAxesOffset) > length ||
     64        size_t(this->designAxisCount) * size_t(this->designAxisSize) >
     65          length - size_t(this->designAxesOffset)) {
     66      return Drop("Invalid designAxesOffset");
     67    }
     68  }
     69 
     70  for (size_t i = 0; i < this->designAxisCount; i++) {
     71    table.set_offset(this->designAxesOffset + i * this->designAxisSize);
     72    this->designAxes.emplace_back();
     73    auto& axis = this->designAxes[i];
     74    if (!table.ReadU32(&axis.axisTag) ||
     75        !table.ReadU16(&axis.axisNameID) ||
     76        !table.ReadU16(&axis.axisOrdering)) {
     77      return Drop("Failed to read design axis");
     78    }
     79    if (!CheckTag(axis.axisTag)) {
     80      return Drop("Bad design axis tag");
     81    }
     82    if (!ValidateNameId(axis.axisNameID)) {
     83      return true;
     84    }
     85  }
     86 
     87  // TODO
     88  // - check that all axes defined in fvar are covered by STAT
     89  // - check that axisOrdering values are not duplicated (warn only)
     90 
     91  if (this->axisValueCount == 0) {
     92    if (this->offsetToAxisValueOffsets != 0) {
     93      Warning("Unexpected non-zero offsetToAxisValueOffsets");
     94      this->offsetToAxisValueOffsets = 0;
     95    }
     96  } else {
     97    if (this->offsetToAxisValueOffsets < headerEnd ||
     98        size_t(this->offsetToAxisValueOffsets) > length ||
     99        size_t(this->axisValueCount) * sizeof(uint16_t) >
    100          length - size_t(this->offsetToAxisValueOffsets)) {
    101      return Drop("Invalid offsetToAxisValueOffsets");
    102    }
    103  }
    104 
    105  for (size_t i = 0; i < this->axisValueCount; i++) {
    106    table.set_offset(this->offsetToAxisValueOffsets + i * sizeof(uint16_t));
    107    uint16_t axisValueOffset;
    108    if (!table.ReadU16(&axisValueOffset)) {
    109      return Drop("Failed to read axis value offset");
    110    }
    111    // We already checked that offsetToAxisValueOffsets doesn't exceed length,
    112    // so this subtraction will not underflow.
    113    if (axisValueOffset > length - this->offsetToAxisValueOffsets) {
    114      return Drop("Invalid axis value offset");
    115    }
    116    table.set_offset(this->offsetToAxisValueOffsets + axisValueOffset);
    117    uint16_t format;
    118    if (!table.ReadU16(&format)) {
    119      return Drop("Failed to read axis value format");
    120    }
    121    this->axisValues.emplace_back(format);
    122    auto& axisValue = axisValues[i];
    123    switch (format) {
    124    case 1:
    125      if (!table.ReadU16(&axisValue.format1.axisIndex) ||
    126          !table.ReadU16(&axisValue.format1.flags) ||
    127          !table.ReadU16(&axisValue.format1.valueNameID) ||
    128          !table.ReadS32(&axisValue.format1.value)) {
    129        return Drop("Failed to read axis value (format 1)");
    130      }
    131      if (axisValue.format1.axisIndex >= this->designAxisCount) {
    132        return Drop("Axis index out of range");
    133      }
    134      if ((axisValue.format1.flags & 0xFFFCu) != 0) {
    135        Warning("Unexpected axis value flags");
    136        axisValue.format1.flags &= ~0xFFFCu;
    137      }
    138      if (!ValidateNameId(axisValue.format1.valueNameID)) {
    139        return true;
    140      }
    141      break;
    142    case 2:
    143      if (!table.ReadU16(&axisValue.format2.axisIndex) ||
    144          !table.ReadU16(&axisValue.format2.flags) ||
    145          !table.ReadU16(&axisValue.format2.valueNameID) ||
    146          !table.ReadS32(&axisValue.format2.nominalValue) ||
    147          !table.ReadS32(&axisValue.format2.rangeMinValue) ||
    148          !table.ReadS32(&axisValue.format2.rangeMaxValue)) {
    149        return Drop("Failed to read axis value (format 2)");
    150      }
    151      if (axisValue.format2.axisIndex >= this->designAxisCount) {
    152        return Drop("Axis index out of range");
    153      }
    154      if ((axisValue.format2.flags & 0xFFFCu) != 0) {
    155        Warning("Unexpected axis value flags");
    156        axisValue.format1.flags &= ~0xFFFCu;
    157      }
    158      if (!ValidateNameId(axisValue.format2.valueNameID)) {
    159        return true;
    160      }
    161      if (!(axisValue.format2.rangeMinValue <= axisValue.format2.nominalValue &&
    162            axisValue.format2.nominalValue <= axisValue.format2.rangeMaxValue)) {
    163        Warning("Bad axis value range or nominal value");
    164      }
    165      break;
    166    case 3:
    167      if (!table.ReadU16(&axisValue.format3.axisIndex) ||
    168          !table.ReadU16(&axisValue.format3.flags) ||
    169          !table.ReadU16(&axisValue.format3.valueNameID) ||
    170          !table.ReadS32(&axisValue.format3.value) ||
    171          !table.ReadS32(&axisValue.format3.linkedValue)) {
    172        return Drop("Failed to read axis value (format 3)");
    173      }
    174      if (axisValue.format3.axisIndex >= this->designAxisCount) {
    175        return Drop("Axis index out of range");
    176      }
    177      if ((axisValue.format3.flags & 0xFFFCu) != 0) {
    178        Warning("Unexpected axis value flags");
    179        axisValue.format3.flags &= ~0xFFFCu;
    180      }
    181      if (!ValidateNameId(axisValue.format3.valueNameID)) {
    182        return true;
    183      }
    184      break;
    185    case 4:
    186      if (this->minorVersion < 2) {
    187        return Drop("Invalid table minorVersion for format 4 axis values: %d", this->minorVersion);
    188      }
    189      if (!table.ReadU16(&axisValue.format4.axisCount) ||
    190          !table.ReadU16(&axisValue.format4.flags) ||
    191          !table.ReadU16(&axisValue.format4.valueNameID)) {
    192        return Drop("Failed to read axis value (format 4)");
    193      }
    194      if (axisValue.format4.axisCount > this->designAxisCount) {
    195        return Drop("Axis count out of range");
    196      }
    197      if ((axisValue.format4.flags & 0xFFFCu) != 0) {
    198        Warning("Unexpected axis value flags");
    199        axisValue.format4.flags &= ~0xFFFCu;
    200      }
    201      if (!ValidateNameId(axisValue.format4.valueNameID)) {
    202        return true;
    203      }
    204      for (unsigned j = 0; j < axisValue.format4.axisCount; j++) {
    205        axisValue.format4.axisValues.emplace_back();
    206        auto& v = axisValue.format4.axisValues[j];
    207        if (!table.ReadU16(&v.axisIndex) ||
    208            !table.ReadS32(&v.value)) {
    209          return Drop("Failed to read axis value");
    210        }
    211        if (v.axisIndex >= this->designAxisCount) {
    212          return Drop("Axis index out of range");
    213        }
    214      }
    215      break;
    216    default:
    217      return Drop("Unknown axis value format");
    218    }
    219  }
    220 
    221  return true;
    222 }
    223 
    224 bool OpenTypeSTAT::Serialize(OTSStream* out) {
    225  off_t tableStart = out->Tell();
    226 
    227  size_t headerSize = 5 * sizeof(uint16_t) + 2 * sizeof(uint32_t);
    228  if (this->minorVersion >= 1) {
    229    headerSize += sizeof(uint16_t);
    230  }
    231 
    232  if (this->designAxisCount == 0) {
    233    this->designAxesOffset = 0;
    234  } else {
    235    this->designAxesOffset = headerSize;
    236  }
    237 
    238  this->designAxisSize = sizeof(AxisRecord);
    239 
    240  if (this->axisValueCount == 0) {
    241    this->offsetToAxisValueOffsets = 0;
    242  } else {
    243    if (this->designAxesOffset == 0) {
    244      this->offsetToAxisValueOffsets = headerSize;
    245    } else {
    246      this->offsetToAxisValueOffsets = this->designAxesOffset + this->designAxisCount * this->designAxisSize;
    247    }
    248  }
    249 
    250  if (!out->WriteU16(this->majorVersion) ||
    251      !out->WriteU16(this->minorVersion) ||
    252      !out->WriteU16(this->designAxisSize) ||
    253      !out->WriteU16(this->designAxisCount) ||
    254      !out->WriteU32(this->designAxesOffset) ||
    255      !out->WriteU16(this->axisValueCount) ||
    256      !out->WriteU32(this->offsetToAxisValueOffsets) ||
    257      !(this->minorVersion < 1 || out->WriteU16(this->elidedFallbackNameID))) {
    258    return Error("Failed to write table header");
    259  }
    260 
    261  if (this->designAxisCount > 0) {
    262    if (out->Tell() - tableStart != this->designAxesOffset) {
    263      return Error("Error computing designAxesOffset");
    264    }
    265  }
    266 
    267  for (unsigned i = 0; i < this->designAxisCount; i++) {
    268    const auto& axis = this->designAxes[i];
    269    if (!out->WriteU32(axis.axisTag) ||
    270        !out->WriteU16(axis.axisNameID) ||
    271        !out->WriteU16(axis.axisOrdering)) {
    272      return Error("Failed to write design axis");
    273    }
    274  }
    275 
    276  if (this->axisValueCount > 0) {
    277    if (out->Tell() - tableStart != this->offsetToAxisValueOffsets) {
    278      return Error("Error computing offsetToAxisValueOffsets");
    279    }
    280  }
    281 
    282  uint32_t axisValueOffset = this->axisValueCount * sizeof(uint16_t);
    283  for (unsigned i = 0; i < this->axisValueCount; i++) {
    284    const auto& value = this->axisValues[i];
    285    if (!out->WriteU16(axisValueOffset)) {
    286      return Error("Failed to write axis value offset");
    287    }
    288    axisValueOffset += value.Length();
    289  }
    290  for (unsigned i = 0; i < this->axisValueCount; i++) {
    291    const auto& value = this->axisValues[i];
    292    if (!out->WriteU16(value.format)) {
    293      return Error("Failed to write axis value");
    294    }
    295    switch (value.format) {
    296    case 1:
    297      if (!out->WriteU16(value.format1.axisIndex) ||
    298          !out->WriteU16(value.format1.flags) ||
    299          !out->WriteU16(value.format1.valueNameID) ||
    300          !out->WriteS32(value.format1.value)) {
    301        return Error("Failed to write axis value");
    302      }
    303      break;
    304    case 2:
    305      if (!out->WriteU16(value.format2.axisIndex) ||
    306          !out->WriteU16(value.format2.flags) ||
    307          !out->WriteU16(value.format2.valueNameID) ||
    308          !out->WriteS32(value.format2.nominalValue) ||
    309          !out->WriteS32(value.format2.rangeMinValue) ||
    310          !out->WriteS32(value.format2.rangeMaxValue)) {
    311        return Error("Failed to write axis value");
    312      }
    313      break;
    314    case 3:
    315      if (!out->WriteU16(value.format3.axisIndex) ||
    316          !out->WriteU16(value.format3.flags) ||
    317          !out->WriteU16(value.format3.valueNameID) ||
    318          !out->WriteS32(value.format3.value) ||
    319          !out->WriteS32(value.format3.linkedValue)) {
    320        return Error("Failed to write axis value");
    321      }
    322      break;
    323    case 4:
    324      if (!out->WriteU16(value.format4.axisCount) ||
    325          !out->WriteU16(value.format4.flags) ||
    326          !out->WriteU16(value.format4.valueNameID)) {
    327        return Error("Failed to write axis value");
    328      }
    329      for (unsigned j = 0; j < value.format4.axisValues.size(); j++) {
    330        if (!out->WriteU16(value.format4.axisValues[j].axisIndex) ||
    331            !out->WriteS32(value.format4.axisValues[j].value)) {
    332          return Error("Failed to write axis value");
    333        }
    334      }
    335      break;
    336    default:
    337      return Error("Bad value format");
    338    }
    339  }
    340 
    341  return true;
    342 }
    343 
    344 }  // namespace ots