<|start_filename|>src/fvar.h<|end_filename|>
// Copyright (c) 2018 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_FVAR_H_
#define OTS_FVAR_H_

#include <vector>

#include "ots.h"

namespace ots {

// -----------------------------------------------------------------------------
// OpenTypeFVAR Interface
// -----------------------------------------------------------------------------

class OpenTypeFVAR : public Table {
 public:
  explicit OpenTypeFVAR(Font* font, uint32_t tag)
      : Table(font, tag, tag) { }

  bool Parse(const uint8_t* data, size_t length);
  bool Serialize(OTSStream* out);

  uint16_t AxisCount() const { return axisCount; }

 private:
  uint16_t majorVersion;
  uint16_t minorVersion;
  uint16_t axesArrayOffset;
  uint16_t reserved;
  uint16_t axisCount;
  uint16_t axisSize;
  uint16_t instanceCount;
  uint16_t instanceSize;

  typedef int32_t Fixed; /* 16.16 fixed-point value */

  struct VariationAxisRecord {
    uint32_t axisTag;
    Fixed    minValue;
    Fixed    defaultValue;
    Fixed    maxValue;
    uint16_t flags;
    uint16_t axisNameID;
  };
  std::vector<VariationAxisRecord> axes;

  struct InstanceRecord {
    uint16_t subfamilyNameID;
    uint16_t flags;
    std::vector<Fixed> coordinates;
    uint16_t postScriptNameID; // optional
  };
  std::vector<InstanceRecord> instances;

  bool instancesHavePostScriptNameID;
};

}  // namespace ots

#endif  // OTS_FVAR_H_


<|start_filename|>src/sill.h<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_SILL_H_
#define OTS_SILL_H_

#include "ots.h"
#include "graphite.h"

#include <vector>

namespace ots {

class OpenTypeSILL : public Table {
 public:
  explicit OpenTypeSILL(Font* font, uint32_t tag)
      : Table(font, tag, tag) { }

  bool Parse(const uint8_t* data, size_t length);
  bool Serialize(OTSStream* out);

 private:
  struct LanguageEntry : public TablePart<OpenTypeSILL> {
    explicit LanguageEntry(OpenTypeSILL* parent)
        : TablePart<OpenTypeSILL>(parent) { }
    bool ParsePart(Buffer &table);
    bool SerializePart(OTSStream* out) const;
    uint8_t langcode[4];
    uint16_t numSettings;
    uint16_t offset;
  };
  struct LangFeatureSetting : public TablePart<OpenTypeSILL> {
    explicit LangFeatureSetting(OpenTypeSILL* parent)
        : TablePart<OpenTypeSILL>(parent) { }
    bool ParsePart(Buffer &table);
    bool SerializePart(OTSStream* out) const;
    uint32_t featureId;
    int16_t value;
    uint16_t reserved;
  };
  uint32_t version;
  uint16_t numLangs;
  uint16_t searchRange;
  uint16_t entrySelector;
  uint16_t rangeShift;
  std::vector<LanguageEntry> entries;
  std::vector<LangFeatureSetting> settings;
};

}  // namespace ots

#endif  // OTS_SILL_H_


<|start_filename|>src/fvar.cc<|end_filename|>
// Copyright (c) 2018 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "fvar.h"

namespace ots {

// -----------------------------------------------------------------------------
// OpenTypeFVAR
// -----------------------------------------------------------------------------

bool OpenTypeFVAR::Parse(const uint8_t* data, size_t length) {
  Buffer table(data, length);
  if (!table.ReadU16(&this->majorVersion) ||
      !table.ReadU16(&this->minorVersion) ||
      !table.ReadU16(&this->axesArrayOffset) ||
      !table.ReadU16(&this->reserved) ||
      !table.ReadU16(&this->axisCount) ||
      !table.ReadU16(&this->axisSize) ||
      !table.ReadU16(&this->instanceCount) ||
      !table.ReadU16(&this->instanceSize)) {
    return DropVariations("Failed to read table header");
  }
  if (this->majorVersion != 1) {
    return DropVariations("Unknown table version");
  }
  if (this->minorVersion > 0) {
    Warning("Downgrading minor version to 0");
    this->minorVersion = 0;
  }
  if (this->axesArrayOffset > length || this->axesArrayOffset < table.offset()) {
    return DropVariations("Bad axesArrayOffset");
  }
  if (this->reserved != 2) {
    Warning("Expected reserved=2");
    this->reserved = 2;
  }
  if (this->axisCount == 0) {
    return DropVariations("No variation axes");
  }
  if (this->axisSize != 20) {
    return DropVariations("Invalid axisSize");
  }
  // instanceCount is not validated
  if (this->instanceSize == this->axisCount * sizeof(Fixed) + 6) {
    this->instancesHavePostScriptNameID = true;
  } else if (this->instanceSize == this->axisCount * sizeof(Fixed) + 4) {
    this->instancesHavePostScriptNameID = false;
  } else {
    return DropVariations("Invalid instanceSize");
  }

  // When we serialize, the axes array will go here, even if it was
  // originally at a different offset. So we update the axesArrayOffset
  // field for the header.
  uint32_t origAxesArrayOffset = this->axesArrayOffset;
  this->axesArrayOffset = table.offset();

  table.set_offset(origAxesArrayOffset);
  for (unsigned i = 0; i < this->axisCount; i++) {
    this->axes.emplace_back();
    auto& axis = this->axes[i];
    if (!table.ReadU32(&axis.axisTag) ||
        !table.ReadS32(&axis.minValue) ||
        !table.ReadS32(&axis.defaultValue) ||
        !table.ReadS32(&axis.maxValue) ||
        !table.ReadU16(&axis.flags) ||
        !table.ReadU16(&axis.axisNameID)) {
      return DropVariations("Failed to read axis record");
    }
    if (!CheckTag(axis.axisTag)) {
      return DropVariations("Bad axis tag");
    }
    if (!(axis.minValue <= axis.defaultValue && axis.defaultValue <= axis.maxValue)) {
      return DropVariations("Bad axis value range");
    }
    if ((axis.flags & 0xFFFEu) != 0) {
      Warning("Discarding unknown axis flags");
      axis.flags &= ~0xFFFEu;
    }
    if (axis.axisNameID <= 255 || axis.axisNameID >= 32768) {
      Warning("Axis nameID out of range");
      // We don't check that the name actually exists -- assume the client can handle
      // a missing name when it tries to read the table.
    }
  }

  for (unsigned i = 0; i < this->instanceCount; i++) {
    this->instances.emplace_back();
    auto& inst = this->instances[i];
    if (!table.ReadU16(&inst.subfamilyNameID) ||
        !table.ReadU16(&inst.flags)) {
      return DropVariations("Failed to read instance record");
    }
    inst.coordinates.reserve(this->axisCount);
    for (unsigned j = 0; j < this->axisCount; j++) {
      inst.coordinates.emplace_back();
      auto& coord = inst.coordinates[j];
      if (!table.ReadS32(&coord)) {
        return DropVariations("Failed to read instance coordinates");
      }
    }
    if (this->instancesHavePostScriptNameID) {
      if (!table.ReadU16(&inst.postScriptNameID)) {
        return DropVariations("Failed to read instance psname ID");
      }
    }
  }

  if (table.remaining()) {
    return Warning("%zu bytes unparsed", table.remaining());
  }

  return true;
}

bool OpenTypeFVAR::Serialize(OTSStream* out) {
  if (!out->WriteU16(this->majorVersion) ||
      !out->WriteU16(this->minorVersion) ||
      !out->WriteU16(this->axesArrayOffset) ||
      !out->WriteU16(this->reserved) ||
      !out->WriteU16(this->axisCount) ||
      !out->WriteU16(this->axisSize) ||
      !out->WriteU16(this->instanceCount) ||
      !out->WriteU16(this->instanceSize)) {
    return Error("Failed to write table");
  }

  for (unsigned i = 0; i < this->axisCount; i++) {
    const auto& axis = this->axes[i];
    if (!out->WriteU32(axis.axisTag) ||
        !out->WriteS32(axis.minValue) ||
        !out->WriteS32(axis.defaultValue) ||
        !out->WriteS32(axis.maxValue) ||
        !out->WriteU16(axis.flags) ||
        !out->WriteU16(axis.axisNameID)) {
      return Error("Failed to write table");
    }
  }

  for (unsigned i = 0; i < this->instanceCount; i++) {
    const auto& inst = this->instances[i];
    if (!out->WriteU16(inst.subfamilyNameID) ||
        !out->WriteU16(inst.flags)) {
      return Error("Failed to write table");
    }
    for (unsigned j = 0; j < this->axisCount; j++) {
      const auto& coord = inst.coordinates[j];
      if (!out->WriteS32(coord)) {
        return Error("Failed to write table");
      }
    }
    if (this->instancesHavePostScriptNameID) {
      if (!out->WriteU16(inst.postScriptNameID)) {
        return Error("Failed to write table");
      }
    }
  }

  return true;
}

}  // namespace ots


<|start_filename|>src/vhea.cc<|end_filename|>
// Copyright (c) 2011-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "vhea.h"

#include "head.h"
#include "maxp.h"

// vhea - Vertical Header Table
// http://www.microsoft.com/typography/otspec/vhea.htm

namespace ots {

bool OpenTypeVHEA::Parse(const uint8_t *data, size_t length) {
  Buffer table(data, length);

  if (!table.ReadU32(&this->version)) {
    return Error("Failed to read version");
  }
  if (this->version != 0x00010000 &&
      this->version != 0x00011000) {
    return Error("Unsupported table version: 0x%x", this->version);
  }

  return OpenTypeMetricsHeader::Parse(data, length);
}

}  // namespace ots


<|start_filename|>src/fpgm.h<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_FPGM_H_
#define OTS_FPGM_H_

#include "ots.h"

namespace ots {

class OpenTypeFPGM : public Table {
 public:
  explicit OpenTypeFPGM(Font *font, uint32_t tag)
      : Table(font, tag, tag) { }

  bool Parse(const uint8_t *data, size_t length);
  bool Serialize(OTSStream *out);
  bool ShouldSerialize();

 private:
  const uint8_t *data;
  uint32_t length;
};

}  // namespace ots

#endif  // OTS_FPGM_H_


<|start_filename|>src/vorg.cc<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "vorg.h"

#include <vector>

// VORG - Vertical Origin Table
// http://www.microsoft.com/typography/otspec/vorg.htm

namespace ots {

bool OpenTypeVORG::Parse(const uint8_t *data, size_t length) {
  Buffer table(data, length);

  uint16_t num_recs;
  if (!table.ReadU16(&this->major_version) ||
      !table.ReadU16(&this->minor_version) ||
      !table.ReadS16(&this->default_vert_origin_y) ||
      !table.ReadU16(&num_recs)) {
    return Error("Failed to read header");
  }
  if (this->major_version != 1) {
    return Drop("Unsupported majorVersion: %u", this->major_version);
  }
  if (this->minor_version != 0) {
    return Drop("Unsupported minorVersion: %u", this->minor_version);
  }

  // num_recs might be zero (e.g., DFHSMinchoPro5-W3-Demo.otf).
  if (!num_recs) {
    return true;
  }

  uint16_t last_glyph_index = 0;
  this->metrics.reserve(num_recs);
  for (unsigned i = 0; i < num_recs; ++i) {
    OpenTypeVORGMetrics rec;

    if (!table.ReadU16(&rec.glyph_index) ||
        !table.ReadS16(&rec.vert_origin_y)) {
      return Error("Failed to read record %d", i);
    }
    if ((i != 0) && (rec.glyph_index <= last_glyph_index)) {
      return Drop("The table is not sorted");
    }
    last_glyph_index = rec.glyph_index;

    this->metrics.push_back(rec);
  }

  return true;
}

bool OpenTypeVORG::Serialize(OTSStream *out) {
  const uint16_t num_metrics = static_cast<uint16_t>(this->metrics.size());
  if (num_metrics != this->metrics.size() ||
      !out->WriteU16(this->major_version) ||
      !out->WriteU16(this->minor_version) ||
      !out->WriteS16(this->default_vert_origin_y) ||
      !out->WriteU16(num_metrics)) {
    return Error("Failed to write table header");
  }

  for (uint16_t i = 0; i < num_metrics; ++i) {
    const OpenTypeVORGMetrics& rec = this->metrics[i];
    if (!out->WriteU16(rec.glyph_index) ||
        !out->WriteS16(rec.vert_origin_y)) {
      return Error("Failed to write record %d", i);
    }
  }

  return true;
}

bool OpenTypeVORG::ShouldSerialize() {
  return Table::ShouldSerialize() &&
         // this table is not for fonts with TT glyphs.
         GetFont()->GetTable(OTS_TAG_CFF) != NULL;
}

}  // namespace ots


<|start_filename|>src/maxp.cc<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "maxp.h"

// maxp - Maximum Profile
// http://www.microsoft.com/typography/otspec/maxp.htm

namespace ots {

bool OpenTypeMAXP::Parse(const uint8_t *data, size_t length) {
  Buffer table(data, length);

  uint32_t version = 0;
  if (!table.ReadU32(&version)) {
    return Error("Failed to read table version");
  }

  if (version >> 16 > 1) {
    return Error("Unsupported table version 0x%x", version);
  }

  if (!table.ReadU16(&this->num_glyphs)) {
    return Error("Failed to read numGlyphs");
  }

  if (!this->num_glyphs) {
    return Error("numGlyphs is 0");
  }

  if (version >> 16 == 1) {
    this->version_1 = true;
    if (!table.ReadU16(&this->max_points) ||
        !table.ReadU16(&this->max_contours) ||
        !table.ReadU16(&this->max_c_points) ||
        !table.ReadU16(&this->max_c_contours) ||
        !table.ReadU16(&this->max_zones) ||
        !table.ReadU16(&this->max_t_points) ||
        !table.ReadU16(&this->max_storage) ||
        !table.ReadU16(&this->max_fdefs) ||
        !table.ReadU16(&this->max_idefs) ||
        !table.ReadU16(&this->max_stack) ||
        !table.ReadU16(&this->max_size_glyf_instructions) ||
        !table.ReadU16(&this->max_c_components) ||
        !table.ReadU16(&this->max_c_depth)) {
      return Error("Failed to read version 1 table data");
    }

    if (this->max_zones == 0) {
      // workaround for ipa*.ttf Japanese fonts.
      Warning("Bad maxZones: %u", this->max_zones);
      this->max_zones = 1;
    } else if (this->max_zones == 3) {
      // workaround for Ecolier-*.ttf fonts.
      Warning("Bad maxZones: %u", this->max_zones);
      this->max_zones = 2;
    }

    if ((this->max_zones != 1) && (this->max_zones != 2)) {
      return Error("Bad maxZones: %u", this->max_zones);
    }
  } else {
    this->version_1 = false;
  }

  return true;
}

bool OpenTypeMAXP::Serialize(OTSStream *out) {
  if (!out->WriteU32(this->version_1 ? 0x00010000 : 0x00005000) ||
      !out->WriteU16(this->num_glyphs)) {
    return Error("Failed to write version or numGlyphs");
  }

  if (!this->version_1) return true;

  if (!out->WriteU16(this->max_points) ||
      !out->WriteU16(this->max_contours) ||
      !out->WriteU16(this->max_c_points) ||
      !out->WriteU16(this->max_c_contours)) {
    return Error("Failed to write maxp");
  }

  if (!out->WriteU16(this->max_zones) ||
      !out->WriteU16(this->max_t_points) ||
      !out->WriteU16(this->max_storage) ||
      !out->WriteU16(this->max_fdefs) ||
      !out->WriteU16(this->max_idefs) ||
      !out->WriteU16(this->max_stack) ||
      !out->WriteU16(this->max_size_glyf_instructions)) {
    return Error("Failed to write more maxp");
  }

  if (!out->WriteU16(this->max_c_components) ||
      !out->WriteU16(this->max_c_depth)) {
    return Error("Failed to write yet more maxp");
  }

  return true;
}

}  // namespace ots


<|start_filename|>src/hvar.cc<|end_filename|>
// Copyright (c) 2018 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "hvar.h"

#include "variations.h"

namespace ots {

// -----------------------------------------------------------------------------
// OpenTypeHVAR
// -----------------------------------------------------------------------------

bool OpenTypeHVAR::Parse(const uint8_t* data, size_t length) {
  Buffer table(data, length);

  uint16_t majorVersion;
  uint16_t minorVersion;
  uint32_t itemVariationStoreOffset;
  uint32_t advanceWidthMappingOffset;
  uint32_t lsbMappingOffset;
  uint32_t rsbMappingOffset;

  if (!table.ReadU16(&majorVersion) ||
      !table.ReadU16(&minorVersion) ||
      !table.ReadU32(&itemVariationStoreOffset) ||
      !table.ReadU32(&advanceWidthMappingOffset) ||
      !table.ReadU32(&lsbMappingOffset) ||
      !table.ReadU32(&rsbMappingOffset)) {
    return DropVariations("Failed to read table header");
  }

  if (majorVersion != 1) {
    return DropVariations("Unknown table version");
  }

  if (itemVariationStoreOffset > length ||
      advanceWidthMappingOffset > length ||
      lsbMappingOffset > length ||
      rsbMappingOffset > length) {
    return DropVariations("Invalid subtable offset");
  }

  if (!ParseItemVariationStore(GetFont(), data + itemVariationStoreOffset,
                               length - itemVariationStoreOffset)) {
    return DropVariations("Failed to parse item variation store");
  }

  if (advanceWidthMappingOffset) {
    if (!ParseDeltaSetIndexMap(GetFont(), data + advanceWidthMappingOffset,
                               length - advanceWidthMappingOffset)) {
      return DropVariations("Failed to parse advance width mappings");
    }
  }

  if (lsbMappingOffset) {
    if (!ParseDeltaSetIndexMap(GetFont(), data + lsbMappingOffset,
                               length - lsbMappingOffset)) {
      return DropVariations("Failed to parse LSB mappings");
    }
  }

  if (rsbMappingOffset) {
    if (!ParseDeltaSetIndexMap(GetFont(), data + rsbMappingOffset,
                               length - rsbMappingOffset)) {
      return DropVariations("Failed to parse RSB mappings");
    }
  }

  this->m_data = data;
  this->m_length = length;

  return true;
}

bool OpenTypeHVAR::Serialize(OTSStream* out) {
  if (!out->Write(this->m_data, this->m_length)) {
    return Error("Failed to write HVAR table");
  }

  return true;
}

}  // namespace ots


<|start_filename|>src/gasp.h<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_GASP_H_
#define OTS_GASP_H_

#include <new>
#include <utility>
#include <vector>

#include "ots.h"

namespace ots {

class OpenTypeGASP : public Table {
 public:
  explicit OpenTypeGASP(Font *font, uint32_t tag)
      : Table(font, tag, tag) { }

  bool Parse(const uint8_t *data, size_t length);
  bool Serialize(OTSStream *out);

 private:
  uint16_t version;
  // A array of (max PPEM, GASP behavior) pairs.
  std::vector<std::pair<uint16_t, uint16_t> > gasp_ranges;
};

}  // namespace ots

#endif  // OTS_GASP_H_


<|start_filename|>src/loca.cc<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "loca.h"

#include "head.h"
#include "maxp.h"

// loca - Index to Location
// http://www.microsoft.com/typography/otspec/loca.htm

namespace ots {

bool OpenTypeLOCA::Parse(const uint8_t *data, size_t length) {
  Buffer table(data, length);

  // We can't do anything useful in validating this data except to ensure that
  // the values are monotonically increasing.

  OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>(
      GetFont()->GetTypedTable(OTS_TAG_MAXP));
  OpenTypeHEAD *head = static_cast<OpenTypeHEAD*>(
      GetFont()->GetTypedTable(OTS_TAG_HEAD));
  if (!maxp || !head) {
    return Error("Required maxp or head tables are missing");
  }

  const unsigned num_glyphs = maxp->num_glyphs;
  unsigned last_offset = 0;
  this->offsets.resize(num_glyphs + 1);
  // maxp->num_glyphs is uint16_t, thus the addition never overflows.

  if (head->index_to_loc_format == 0) {
    // Note that the <= here (and below) is correct. There is one more offset
    // than the number of glyphs in order to give the length of the final
    // glyph.
    for (unsigned i = 0; i <= num_glyphs; ++i) {
      uint16_t offset = 0;
      if (!table.ReadU16(&offset)) {
        return Error("Failed to read offset for glyph %d", i);
      }
      if (offset < last_offset) {
        return Error("Out of order offset %d < %d for glyph %d", offset, last_offset, i);
      }
      last_offset = offset;
      this->offsets[i] = offset * 2;
    }
  } else {
    for (unsigned i = 0; i <= num_glyphs; ++i) {
      uint32_t offset = 0;
      if (!table.ReadU32(&offset)) {
        return Error("Failed to read offset for glyph %d", i);
      }
      if (offset < last_offset) {
        return Error("Out of order offset %d < %d for glyph %d", offset, last_offset, i);
      }
      last_offset = offset;
      this->offsets[i] = offset;
    }
  }

  return true;
}

bool OpenTypeLOCA::Serialize(OTSStream *out) {
  OpenTypeHEAD *head = static_cast<OpenTypeHEAD*>(
      GetFont()->GetTypedTable(OTS_TAG_HEAD));

  if (!head) {
    return Error("Required head table is missing");
  }

  if (head->index_to_loc_format == 0) {
    for (unsigned i = 0; i < this->offsets.size(); ++i) {
      const uint16_t offset = static_cast<uint16_t>(this->offsets[i] >> 1);
      if ((offset != (this->offsets[i] >> 1)) ||
          !out->WriteU16(offset)) {
        return Error("Failed to write glyph offset for glyph %d", i);
      }
    }
  } else {
    for (unsigned i = 0; i < this->offsets.size(); ++i) {
      if (!out->WriteU32(this->offsets[i])) {
        return Error("Failed to write glyph offset for glyph %d", i);
      }
    }
  }

  return true;
}

}  // namespace ots


<|start_filename|>src/head.cc<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "head.h"

#include <cstring>

// head - Font Header
// http://www.microsoft.com/typography/otspec/head.htm

namespace ots {

bool OpenTypeHEAD::Parse(const uint8_t *data, size_t length) {
  Buffer table(data, length);

  uint32_t version = 0;
  if (!table.ReadU32(&version) ||
      !table.ReadU32(&this->revision)) {
    return Error("Failed to read table header");
  }

  if (version >> 16 != 1) {
    return Error("Unsupported majorVersion: %d", version >> 16);
  }

  // Skip the checksum adjustment
  if (!table.Skip(4)) {
    return Error("Failed to read checksum");
  }

  uint32_t magic;
  if (!table.ReadU32(&magic) || magic != 0x5F0F3CF5) {
    return Error("Failed to read or incorrect magicNumber");
  }

  if (!table.ReadU16(&this->flags)) {
    return Error("Failed to read flags");
  }

  // We allow bits 0..4, 11..13
  this->flags &= 0x381f;

  if (!table.ReadU16(&this->upem)) {
    return Error("Failed to read unitsPerEm");
  }

  // upem must be in range
  if (this->upem < 16 ||
      this->upem > 16384) {
    return Error("unitsPerEm on in the range [16, 16384]: %d", this->upem);
  }

  if (!table.ReadR64(&this->created) ||
      !table.ReadR64(&this->modified)) {
    return Error("Can't read font dates");
  }

  if (!table.ReadS16(&this->xmin) ||
      !table.ReadS16(&this->ymin) ||
      !table.ReadS16(&this->xmax) ||
      !table.ReadS16(&this->ymax)) {
    return Error("Failed to read font bounding box");
  }

  if (this->xmin > this->xmax) {
    return Error("Bad x dimension in the font bounding box (%d, %d)",
                  this->xmin, this->xmax);
  }
  if (this->ymin > this->ymax) {
    return Error("Bad y dimension in the font bounding box (%d, %d)",
                  this->ymin, this->ymax);
  }

  if (!table.ReadU16(&this->mac_style)) {
    return Error("Failed to read macStyle");
  }

  // We allow bits 0..6
  this->mac_style &= 0x7f;

  if (!table.ReadU16(&this->min_ppem)) {
    return Error("Failed to read lowestRecPPEM");
  }

  // We don't care about the font direction hint
  if (!table.Skip(2)) {
    return Error("Failed to read fontDirectionHint");
  }

  if (!table.ReadS16(&this->index_to_loc_format)) {
    return Error("Failed to read indexToLocFormat");
  }
  if (this->index_to_loc_format < 0 ||
      this->index_to_loc_format > 1) {
    return Error("Bad indexToLocFormat %d", this->index_to_loc_format);
  }

  int16_t glyph_data_format;
  if (!table.ReadS16(&glyph_data_format) ||
      glyph_data_format) {
    return Error("Failed to read or bad glyphDataFormat");
  }

  return true;
}

bool OpenTypeHEAD::Serialize(OTSStream *out) {
  if (!out->WriteU32(0x00010000) ||
      !out->WriteU32(this->revision) ||
      !out->WriteU32(0) ||  // check sum not filled in yet
      !out->WriteU32(0x5F0F3CF5) ||
      !out->WriteU16(this->flags) ||
      !out->WriteU16(this->upem) ||
      !out->WriteR64(this->created) ||
      !out->WriteR64(this->modified) ||
      !out->WriteS16(this->xmin) ||
      !out->WriteS16(this->ymin) ||
      !out->WriteS16(this->xmax) ||
      !out->WriteS16(this->ymax) ||
      !out->WriteU16(this->mac_style) ||
      !out->WriteU16(this->min_ppem) ||
      !out->WriteS16(2) ||
      !out->WriteS16(this->index_to_loc_format) ||
      !out->WriteS16(0)) {
    return Error("Failed to write table");
  }

  return true;
}

}  // namespace


<|start_filename|>src/loca.h<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_LOCA_H_
#define OTS_LOCA_H_

#include <vector>

#include "ots.h"

namespace ots {

class OpenTypeLOCA : public Table {
 public:
  explicit OpenTypeLOCA(Font *font, uint32_t tag)
      : Table(font, tag, tag) { }

  bool Parse(const uint8_t *data, size_t length);
  bool Serialize(OTSStream *out);

  std::vector<uint32_t> offsets;
};

}  // namespace ots

#endif  // OTS_LOCA_H_


<|start_filename|>src/metrics.cc<|end_filename|>
// Copyright (c) 2011-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "metrics.h"

#include "head.h"
#include "maxp.h"

// OpenType horizontal and vertical common header format
// http://www.microsoft.com/typography/otspec/hhea.htm
// http://www.microsoft.com/typography/otspec/vhea.htm

namespace ots {

bool OpenTypeMetricsHeader::Parse(const uint8_t *data, size_t length) {
  Buffer table(data, length);

  // Skip already read version.
  if (!table.Skip(4)) {
    return false;
  }

  if (!table.ReadS16(&this->ascent) ||
      !table.ReadS16(&this->descent) ||
      !table.ReadS16(&this->linegap) ||
      !table.ReadU16(&this->adv_width_max) ||
      !table.ReadS16(&this->min_sb1) ||
      !table.ReadS16(&this->min_sb2) ||
      !table.ReadS16(&this->max_extent) ||
      !table.ReadS16(&this->caret_slope_rise) ||
      !table.ReadS16(&this->caret_slope_run) ||
      !table.ReadS16(&this->caret_offset)) {
    return Error("Failed to read table");
  }

  if (this->ascent < 0) {
    Warning("bad ascent: %d", this->ascent);
    this->ascent = 0;
  }
  if (this->linegap < 0) {
    Warning("bad linegap: %d", this->linegap);
    this->linegap = 0;
  }

  OpenTypeHEAD *head = static_cast<OpenTypeHEAD*>(
      GetFont()->GetTypedTable(OTS_TAG_HEAD));
  if (!head) {
    return Error("Missing head font table");
  }

  // if the font is non-slanted, caret_offset should be zero.
  if (!(head->mac_style & 2) &&
      (this->caret_offset != 0)) {
    Warning("bad caret offset: %d", this->caret_offset);
    this->caret_offset = 0;
  }

  // skip the reserved bytes
  if (!table.Skip(8)) {
    return Error("Failed to read reserverd bytes");
  }

  int16_t data_format;
  if (!table.ReadS16(&data_format)) {
    return Error("Failed to read metricDataFormat");
  }
  if (data_format) {
    return Error("Bad metricDataFormat: %d", data_format);
  }

  if (!table.ReadU16(&this->num_metrics)) {
    return Error("Failed to read number of metrics");
  }

  OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>(
      GetFont()->GetTypedTable(OTS_TAG_MAXP));
  if (!maxp) {
    return Error("Missing maxp font table");
  }

  if (this->num_metrics > maxp->num_glyphs) {
    return Error("Bad number of metrics %d", this->num_metrics);
  }

  return true;
}

bool OpenTypeMetricsHeader::Serialize(OTSStream *out) {
  if (!out->WriteU32(this->version) ||
      !out->WriteS16(this->ascent) ||
      !out->WriteS16(this->descent) ||
      !out->WriteS16(this->linegap) ||
      !out->WriteU16(this->adv_width_max) ||
      !out->WriteS16(this->min_sb1) ||
      !out->WriteS16(this->min_sb2) ||
      !out->WriteS16(this->max_extent) ||
      !out->WriteS16(this->caret_slope_rise) ||
      !out->WriteS16(this->caret_slope_run) ||
      !out->WriteS16(this->caret_offset) ||
      !out->WriteR64(0) ||  // reserved
      !out->WriteS16(0) ||  // metric data format
      !out->WriteU16(this->num_metrics)) {
    return Error("Failed to write metrics");
  }

  return true;
}

bool OpenTypeMetricsTable::Parse(const uint8_t *data, size_t length) {
  Buffer table(data, length);

  // OpenTypeMetricsHeader is a superclass of both 'hhea' and 'vhea',
  // so the cast here is OK, whichever m_header_tag we have.
  OpenTypeMetricsHeader *header = static_cast<OpenTypeMetricsHeader*>(
      GetFont()->GetTypedTable(m_header_tag));
  if (!header) {
    return Error("Required %c%c%c%c table missing", OTS_UNTAG(m_header_tag));
  }
  // |num_metrics| is a uint16_t, so it's bounded < 65536. This limits that
  // amount of memory that we'll allocate for this to a sane amount.
  const unsigned num_metrics = header->num_metrics;

  OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>(
      GetFont()->GetTypedTable(OTS_TAG_MAXP));
  if (!maxp) {
    return Error("Required maxp table missing");
  }
  if (num_metrics > maxp->num_glyphs) {
    return Error("Bad number of metrics %d", num_metrics);
  }
  if (!num_metrics) {
    return Error("No metrics!");
  }
  const unsigned num_sbs = maxp->num_glyphs - num_metrics;

  this->entries.reserve(num_metrics);
  for (unsigned i = 0; i < num_metrics; ++i) {
    uint16_t adv = 0;
    int16_t sb = 0;
    if (!table.ReadU16(&adv) || !table.ReadS16(&sb)) {
      return Error("Failed to read metric %d", i);
    }
    this->entries.push_back(std::make_pair(adv, sb));
  }

  this->sbs.reserve(num_sbs);
  for (unsigned i = 0; i < num_sbs; ++i) {
    int16_t sb;
    if (!table.ReadS16(&sb)) {
      // Some Japanese fonts (e.g., mona.ttf) fail this test.
      return Error("Failed to read side bearing %d", i + num_metrics);
    }
    this->sbs.push_back(sb);
  }

  return true;
}

bool OpenTypeMetricsTable::Serialize(OTSStream *out) {
  for (unsigned i = 0; i < this->entries.size(); ++i) {
    if (!out->WriteU16(this->entries[i].first) ||
        !out->WriteS16(this->entries[i].second)) {
      return Error("Failed to write metric %d", i);
    }
  }

  for (unsigned i = 0; i < this->sbs.size(); ++i) {
    if (!out->WriteS16(this->sbs[i])) {
      return Error("Failed to write side bearing %ld", i + this->entries.size());
    }
  }

  return true;
}

}  // namespace ots


<|start_filename|>src/vmtx.h<|end_filename|>
// Copyright (c) 2011-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_VMTX_H_
#define OTS_VMTX_H_

#include "metrics.h"
#include "vhea.h"
#include "ots.h"

namespace ots {

struct OpenTypeVMTX : public OpenTypeMetricsTable {
 public:
  explicit OpenTypeVMTX(Font *font, uint32_t tag)
      : OpenTypeMetricsTable(font, tag, tag, OTS_TAG_VHEA) { }
};

}  // namespace ots

#endif  // OTS_VMTX_H_



<|start_filename|>src/sill.cc<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "sill.h"

#include "feat.h"
#include <cmath>
#include <unordered_set>

namespace ots {

bool OpenTypeSILL::Parse(const uint8_t* data, size_t length) {
  Buffer table(data, length);

  if (!table.ReadU32(&this->version) || this->version >> 16 != 1) {
    return Drop("Failed to read valid version");
  }
  if (!table.ReadU16(&this->numLangs)) {
    return Drop("Failed to read numLangs");
  }

  // The following three fields are deprecated and ignored. We fix them up here
  // just for internal consistency, but the Graphite engine doesn't care.
  if (!table.ReadU16(&this->searchRange) ||
      !table.ReadU16(&this->entrySelector) ||
      !table.ReadU16(&this->rangeShift)) {
    return Drop("Failed to read searchRange..rangeShift");
  }
  if (this->numLangs == 0) {
    if (this->searchRange != 0 || this->entrySelector != 0 || this->rangeShift != 0) {
      this->searchRange = this->entrySelector = this->rangeShift = 0;
    }
  } else {
    unsigned floorLog2 = std::floor(std::log2(this->numLangs));
    if (this->searchRange != (unsigned)std::pow(2, floorLog2) ||
        this->entrySelector != floorLog2 ||
        this->rangeShift != this->numLangs - this->searchRange) {
      this->searchRange = (unsigned)std::pow(2, floorLog2);
      this->entrySelector = floorLog2;
      this->rangeShift = this->numLangs - this->searchRange;
    }
  }

  std::unordered_set<size_t> unverified;
  //this->entries.resize(static_cast<unsigned long>(this->numLangs) + 1, this);
  for (unsigned long i = 0; i <= this->numLangs; ++i) {
    this->entries.emplace_back(this);
    LanguageEntry& entry = this->entries[i];
    if (!entry.ParsePart(table)) {
      return Drop("Failed to read entries[%u]", i);
    }
    for (unsigned j = 0; j < entry.numSettings; ++j) {
      size_t offset = entry.offset + j * 8;
      if (offset < entry.offset || offset > length) {
        return DropGraphite("Invalid LangFeatureSetting offset %zu/%zu",
                            offset, length);
      }
      unverified.insert(offset);
        // need to verify that this LanguageEntry points to valid
        // LangFeatureSetting
    }
  }

  while (table.remaining()) {
    unverified.erase(table.offset());
    LangFeatureSetting setting(this);
    if (!setting.ParsePart(table)) {
      return Drop("Failed to read a LangFeatureSetting");
    }
    settings.push_back(setting);
  }

  if (!unverified.empty()) {
    return Drop("%zu incorrect offsets into settings", unverified.size());
  }
  if (table.remaining()) {
    return Warning("%zu bytes unparsed", table.remaining());
  }
  return true;
}

bool OpenTypeSILL::Serialize(OTSStream* out) {
  if (!out->WriteU32(this->version) ||
      !out->WriteU16(this->numLangs) ||
      !out->WriteU16(this->searchRange) ||
      !out->WriteU16(this->entrySelector) ||
      !out->WriteU16(this->rangeShift) ||
      !SerializeParts(this->entries, out) ||
      !SerializeParts(this->settings, out)) {
    return Error("Failed to write table");
  }
  return true;
}

bool OpenTypeSILL::LanguageEntry::ParsePart(Buffer& table) {
  if (!table.ReadU8(&this->langcode[0]) ||
      !table.ReadU8(&this->langcode[1]) ||
      !table.ReadU8(&this->langcode[2]) ||
      !table.ReadU8(&this->langcode[3])) {
    return parent->Error("LanguageEntry: Failed to read langcode");
  }
  if (!table.ReadU16(&this->numSettings)) {
    return parent->Error("LanguageEntry: Failed to read numSettings");
  }
  if (!table.ReadU16(&this->offset)) {
    return parent->Error("LanguageEntry: Failed to read offset");
  }
  return true;
}

bool OpenTypeSILL::LanguageEntry::SerializePart(OTSStream* out) const {
  if (!out->WriteU8(this->langcode[0]) ||
      !out->WriteU8(this->langcode[1]) ||
      !out->WriteU8(this->langcode[2]) ||
      !out->WriteU8(this->langcode[3]) ||
      !out->WriteU16(this->numSettings) ||
      !out->WriteU16(this->offset)) {
    return parent->Error("LanguageEntry: Failed to write");
  }
  return true;
}

bool OpenTypeSILL::LangFeatureSetting::ParsePart(Buffer& table) {
  OpenTypeFEAT* feat = static_cast<OpenTypeFEAT*>(
      parent->GetFont()->GetTypedTable(OTS_TAG_FEAT));
  if (!feat) {
    return parent->Error("FeatureDefn: Required Feat table is missing");
  }

  if (!table.ReadU32(&this->featureId) ||
      !feat->IsValidFeatureId(this->featureId)) {
    return parent->Error("LangFeatureSetting: Failed to read valid featureId");
  }
  if (!table.ReadS16(&this->value)) {
    return parent->Error("LangFeatureSetting: Failed to read value");
  }
  if (!table.ReadU16(&this->reserved)) {
    return parent->Error("LangFeatureSetting: Failed to read reserved");
  }
  if (this->reserved != 0) {
    parent->Warning("LangFeatureSetting: Nonzero reserved");
  }
  return true;
}

bool OpenTypeSILL::LangFeatureSetting::SerializePart(OTSStream* out) const {
  if (!out->WriteU32(this->featureId) ||
      !out->WriteS16(this->value) ||
      !out->WriteU16(this->reserved)) {
    return parent->Error("LangFeatureSetting: Failed to read reserved");
  }
  return true;
}

}  // namespace ots


<|start_filename|>src/variations.h<|end_filename|>
// Copyright (c) 2018 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_VARIATIONS_H_
#define OTS_VARIATIONS_H_

#include <vector>
#include "ots.h"

// Utility functions for OpenType variations common table formats.

namespace ots {

bool ParseItemVariationStore(const Font* font,
                             const uint8_t* data, const size_t length,
                             std::vector<uint16_t>* out_region_index_count = NULL);

bool ParseDeltaSetIndexMap(const Font* font, const uint8_t* data, const size_t length);

bool ParseVariationData(const Font* font, const uint8_t* data, size_t length,
                        size_t axisCount, size_t sharedTupleCount);

}  // namespace ots

#endif  // OTS_VARIATIONS_H_


<|start_filename|>src/cff.h<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_CFF_H_
#define OTS_CFF_H_

#include "ots.h"

#include <map>
#include <string>
#include <vector>

#undef major // glibc defines major!

namespace ots {

struct CFFIndex {
  CFFIndex()
      : count(0), off_size(0), offset_to_next(0) {}
  uint32_t count;
  uint8_t off_size;
  std::vector<uint32_t> offsets;
  uint32_t offset_to_next;
};

typedef std::map<uint32_t, uint16_t> CFFFDSelect;

class OpenTypeCFF : public Table {
 public:
  explicit OpenTypeCFF(Font *font, uint32_t tag)
      : Table(font, tag, tag),
        major(0),
        font_dict_length(0),
        charstrings_index(NULL),
        local_subrs(NULL),
        m_data(NULL),
        m_length(0) {
  }

  ~OpenTypeCFF();

  bool Parse(const uint8_t *data, size_t length);
  bool Serialize(OTSStream *out);

  // Major version number.
  uint8_t major;

  // Name INDEX. This name is used in name.cc as a postscript font name.
  std::string name;

  // The number of fonts the file has.
  size_t font_dict_length;
  // A map from glyph # to font #.
  CFFFDSelect fd_select;

  // A list of char strings.
  CFFIndex* charstrings_index;
  // A list of Local Subrs associated with FDArrays. Can be empty.
  std::vector<CFFIndex *> local_subrs_per_font;
  // A Local Subrs associated with Top DICT. Can be NULL.
  CFFIndex *local_subrs;

  // CFF2 VariationStore regionIndexCount.
  std::vector<uint16_t> region_index_count;

 protected:
  bool ValidateFDSelect(uint16_t num_glyphs);

 private:
  const uint8_t *m_data;
  size_t m_length;
};

class OpenTypeCFF2 : public OpenTypeCFF {
 public:
  explicit OpenTypeCFF2(Font *font, uint32_t tag)
      : OpenTypeCFF(font, tag),
        m_data(NULL),
        m_length(0) {
  }

  bool Parse(const uint8_t *data, size_t length);
  bool Serialize(OTSStream *out);

 private:
  const uint8_t *m_data;
  size_t m_length;
};

}  // namespace ots

#endif  // OTS_CFF_H_


<|start_filename|>src/post.h<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_POST_H_
#define OTS_POST_H_

#include "ots.h"

#include <map>
#include <string>
#include <vector>

namespace ots {

class OpenTypePOST : public Table {
 public:
  explicit OpenTypePOST(Font *font, uint32_t tag)
      : Table(font, tag, tag) { }

  bool Parse(const uint8_t *data, size_t length);
  bool Serialize(OTSStream *out);

private:
  uint32_t version;
  uint32_t italic_angle;
  int16_t underline;
  int16_t underline_thickness;
  uint32_t is_fixed_pitch;

  std::vector<uint16_t> glyph_name_index;
  std::vector<std::string> names;
};

}  // namespace ots

#endif  // OTS_POST_H_


<|start_filename|>src/kern.h<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_KERN_H_
#define OTS_KERN_H_

#include <vector>

#include "ots.h"

namespace ots {

struct OpenTypeKERNFormat0Pair {
  uint16_t left;
  uint16_t right;
  int16_t value;
};

struct OpenTypeKERNFormat0 {
  uint16_t version;
  uint16_t coverage;
  uint16_t search_range;
  uint16_t entry_selector;
  uint16_t range_shift;
  std::vector<OpenTypeKERNFormat0Pair> pairs;
};

// Format 2 is not supported. Since the format is not supported by Windows,
// WebFonts unlikely use it. I've checked thousands of proprietary fonts and
// free fonts, and found no font uses the format.

class OpenTypeKERN : public Table {
 public:
  explicit OpenTypeKERN(Font *font, uint32_t tag)
      : Table(font, tag, tag) { }

  bool Parse(const uint8_t *data, size_t length);
  bool Serialize(OTSStream *out);
  bool ShouldSerialize();

 private:
  uint16_t version;
  std::vector<OpenTypeKERNFormat0> subtables;
};

}  // namespace ots

#endif  // OTS_KERN_H_


<|start_filename|>src/math_.h<|end_filename|>
// Copyright (c) 2014-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_MATH_H_
#define OTS_MATH_H_

#include "ots.h"

namespace ots {

class OpenTypeMATH : public Table {
 public:
  explicit OpenTypeMATH(Font *font, uint32_t tag)
      : Table(font, tag, tag),
        m_data(NULL),
        m_length(0) { }

  bool Parse(const uint8_t *data, size_t length);
  bool Serialize(OTSStream *out);
  bool ShouldSerialize();

 private:
  bool ParseMathValueRecord(ots::Buffer* subtable,
                            const uint8_t *data,
                            const size_t length);
  bool ParseMathConstantsTable(const uint8_t *data, size_t length);
  bool ParseMathValueRecordSequenceForGlyphs(ots::Buffer* subtable,
                                             const uint8_t *data,
                                             const size_t length,
                                             const uint16_t num_glyphs);
  bool ParseMathItalicsCorrectionInfoTable(const uint8_t *data,
                                           size_t length,
                                           const uint16_t num_glyphs);
  bool ParseMathTopAccentAttachmentTable(const uint8_t *data,
                                         size_t length,
                                         const uint16_t num_glyphs);
  bool ParseMathKernTable(const uint8_t *data, size_t length);
  bool ParseMathKernInfoTable(const uint8_t *data,
                              size_t length,
                              const uint16_t num_glyphs);
  bool ParseMathGlyphInfoTable(const uint8_t *data,
                               size_t length,
                               const uint16_t num_glyphs);
  bool ParseGlyphAssemblyTable(const uint8_t *data,
                               size_t length,
                               const uint16_t num_glyphs);
  bool ParseMathGlyphConstructionTable(const uint8_t *data,
                                       size_t length,
                                       const uint16_t num_glyphs);
  bool ParseMathGlyphConstructionSequence(ots::Buffer* subtable,
                                          const uint8_t *data,
                                          size_t length,
                                          const uint16_t num_glyphs,
                                          uint16_t offset_coverage,
                                          uint16_t glyph_count,
                                          const unsigned sequence_end);
  bool ParseMathVariantsTable(const uint8_t *data,
                              size_t length,
                              const uint16_t num_glyphs);

  const uint8_t *m_data;
  size_t m_length;
};

}  // namespace ots

#endif



<|start_filename|>src/hdmx.cc<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "hdmx.h"
#include "head.h"
#include "maxp.h"

// hdmx - Horizontal Device Metrics
// http://www.microsoft.com/typography/otspec/hdmx.htm

namespace ots {

bool OpenTypeHDMX::Parse(const uint8_t *data, size_t length) {
  Buffer table(data, length);

  OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>(
      GetFont()->GetTypedTable(OTS_TAG_MAXP));
  OpenTypeHEAD *head = static_cast<OpenTypeHEAD*>(
      GetFont()->GetTypedTable(OTS_TAG_HEAD));
  if (!head || !maxp) {
    return Error("Missing maxp or head tables in font, needed by hdmx");
  }

  if ((head->flags & 0x14) == 0) {
    // http://www.microsoft.com/typography/otspec/recom.htm#hdmx
    return Drop("the table should not be present when bit 2 and 4 of the "
                "head->flags are not set");
  }

  int16_t num_recs;
  if (!table.ReadU16(&this->version) ||
      !table.ReadS16(&num_recs) ||
      !table.ReadS32(&this->size_device_record)) {
    return Error("Failed to read table header");
  }
  if (this->version != 0) {
    return Drop("Unsupported version: %u", this->version);
  }
  if (num_recs <= 0) {
    return Drop("Bad numRecords: %d", num_recs);
  }
  const int32_t actual_size_device_record = maxp->num_glyphs + 2;
  if (this->size_device_record < actual_size_device_record) {
    return Drop("Bad sizeDeviceRecord: %d", this->size_device_record);
  }

  this->pad_len = this->size_device_record - actual_size_device_record;
  if (this->pad_len > 3) {
    return Error("Bad DeviceRecord padding %d", this->pad_len);
  }

  uint8_t last_pixel_size = 0;
  this->records.reserve(num_recs);
  for (int i = 0; i < num_recs; ++i) {
    OpenTypeHDMXDeviceRecord rec;

    if (!table.ReadU8(&rec.pixel_size) ||
        !table.ReadU8(&rec.max_width)) {
      return Error("Failed to read DeviceRecord %d", i);
    }
    if ((i != 0) &&
        (rec.pixel_size <= last_pixel_size)) {
      return Drop("DeviceRecord's are not sorted");
    }
    last_pixel_size = rec.pixel_size;

    rec.widths.reserve(maxp->num_glyphs);
    for (unsigned j = 0; j < maxp->num_glyphs; ++j) {
      uint8_t width;
      if (!table.ReadU8(&width)) {
        return Error("Failed to read glyph width %d in DeviceRecord %d", j, i);
      }
      rec.widths.push_back(width);
    }

    if ((this->pad_len > 0) &&
        !table.Skip(this->pad_len)) {
      return Error("DeviceRecord %d should be padded by %d", i, this->pad_len);
    }

    this->records.push_back(rec);
  }

  return true;
}

bool OpenTypeHDMX::ShouldSerialize() {
  return Table::ShouldSerialize() &&
         // this table is not for CFF fonts.
         GetFont()->GetTable(OTS_TAG_GLYF) != NULL;
}

bool OpenTypeHDMX::Serialize(OTSStream *out) {
  const int16_t num_recs = static_cast<int16_t>(this->records.size());
  if (this->records.size() >
          static_cast<size_t>(std::numeric_limits<int16_t>::max()) ||
      !out->WriteU16(this->version) ||
      !out->WriteS16(num_recs) ||
      !out->WriteS32(this->size_device_record)) {
    return Error("Failed to write table header");
  }

  for (int16_t i = 0; i < num_recs; ++i) {
    const OpenTypeHDMXDeviceRecord& rec = this->records[i];
    if (!out->Write(&rec.pixel_size, 1) ||
        !out->Write(&rec.max_width, 1) ||
        !out->Write(&rec.widths[0], rec.widths.size())) {
      return Error("Failed to write DeviceRecord %d", i);
    }
    if ((this->pad_len > 0) &&
        !out->Write((const uint8_t *)"\x00\x00\x00", this->pad_len)) {
      return Error("Failed to write padding of length %d", this->pad_len);
    }
  }

  return true;
}

}  // namespace ots


<|start_filename|>src/vorg.h<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_VORG_H_
#define OTS_VORG_H_

#include <vector>

#include "ots.h"

namespace ots {

struct OpenTypeVORGMetrics {
  uint16_t glyph_index;
  int16_t vert_origin_y;
};

class OpenTypeVORG : public Table {
 public:
  explicit OpenTypeVORG(Font *font, uint32_t tag)
      : Table(font, tag, tag) { }

  bool Parse(const uint8_t *data, size_t length);
  bool Serialize(OTSStream *out);
  bool ShouldSerialize();

 private:
  uint16_t major_version;
  uint16_t minor_version;
  int16_t default_vert_origin_y;
  std::vector<OpenTypeVORGMetrics> metrics;
};

}  // namespace ots

#endif  // OTS_VORG_H_


<|start_filename|>src/name.h<|end_filename|>
// Copyright (c) 2011-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_NAME_H_
#define OTS_NAME_H_

#include <new>
#include <string>
#include <utility>
#include <vector>
#include <unordered_set>

#include "ots.h"

namespace ots {

struct NameRecord {
  NameRecord() {
  }

  NameRecord(uint16_t platformID, uint16_t encodingID,
             uint16_t languageID, uint16_t nameID)
    : platform_id(platformID),
      encoding_id(encodingID),
      language_id(languageID),
      name_id(nameID) {
  }

  uint16_t platform_id;
  uint16_t encoding_id;
  uint16_t language_id;
  uint16_t name_id;
  std::string text;

  bool operator<(const NameRecord& rhs) const {
    if (platform_id < rhs.platform_id) return true;
    if (platform_id > rhs.platform_id) return false;
    if (encoding_id < rhs.encoding_id) return true;
    if (encoding_id > rhs.encoding_id) return false;
    if (language_id < rhs.language_id) return true;
    if (language_id > rhs.language_id) return false;
    return name_id < rhs.name_id;
  }
};

class OpenTypeNAME : public Table {
 public:
  explicit OpenTypeNAME(Font *font, uint32_t tag)
      : Table(font, tag, tag) { }

  bool Parse(const uint8_t *data, size_t length);
  bool Serialize(OTSStream *out);
  bool IsValidNameId(uint16_t nameID, bool addIfMissing = false);

 private:
  std::vector<NameRecord> names;
  std::vector<std::string> lang_tags;
  std::unordered_set<uint16_t> name_ids;
};

}  // namespace ots

#endif  // OTS_NAME_H_


<|start_filename|>src/gvar.cc<|end_filename|>
// Copyright (c) 2018 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gvar.h"

#include "fvar.h"
#include "maxp.h"
#include "variations.h"

#define TABLE_NAME "gvar"

namespace ots {

// -----------------------------------------------------------------------------
// OpenTypeGVAR
// -----------------------------------------------------------------------------

static bool ParseSharedTuples(const Font* font, const uint8_t* data, size_t length,
                              size_t sharedTupleCount, size_t axisCount) {
  Buffer subtable(data, length);
  for (unsigned i = 0; i < sharedTupleCount; i++) {
    for (unsigned j = 0; j < axisCount; j++) {
      int16_t coordinate;
      if (!subtable.ReadS16(&coordinate)) {
        return OTS_FAILURE_MSG("Failed to read shared tuple coordinate");
      }
    }
  }
  return true;
}

static bool ParseGlyphVariationDataArray(const Font* font, const uint8_t* data, size_t length,
                                         uint16_t flags, size_t glyphCount, size_t axisCount,
                                         size_t sharedTupleCount,
                                         const uint8_t* glyphVariationData,
                                         size_t glyphVariationDataLength) {
  Buffer subtable(data, length);

  bool glyphVariationDataOffsetsAreLong = (flags & 0x0001u);
  uint32_t prevOffset = 0;
  for (size_t i = 0; i < glyphCount + 1; i++) {
    uint32_t offset;
    if (glyphVariationDataOffsetsAreLong) {
      if (!subtable.ReadU32(&offset)) {
        return OTS_FAILURE_MSG("Failed to read GlyphVariationData offset");
      }
    } else {
      uint16_t halfOffset;
      if (!subtable.ReadU16(&halfOffset)) {
        return OTS_FAILURE_MSG("Failed to read GlyphVariationData offset");
      }
      offset = halfOffset * 2;
    }

    if (i > 0 && offset > prevOffset) {
      if (prevOffset > glyphVariationDataLength) {
        return OTS_FAILURE_MSG("Invalid GlyphVariationData offset");
      }
      if (!ParseVariationData(font, glyphVariationData + prevOffset,
                              glyphVariationDataLength - prevOffset,
                              axisCount, sharedTupleCount)) {
        return OTS_FAILURE_MSG("Failed to parse GlyphVariationData");
      }
    }
    prevOffset = offset;
  }

  return true;
}

bool OpenTypeGVAR::Parse(const uint8_t* data, size_t length) {
  Buffer table(data, length);

  uint16_t majorVersion;
  uint16_t minorVersion;
  uint16_t axisCount;
  uint16_t sharedTupleCount;
  uint32_t sharedTuplesOffset;
  uint16_t glyphCount;
  uint16_t flags;
  uint32_t glyphVariationDataArrayOffset;

  if (!table.ReadU16(&majorVersion) ||
      !table.ReadU16(&minorVersion) ||
      !table.ReadU16(&axisCount) ||
      !table.ReadU16(&sharedTupleCount) ||
      !table.ReadU32(&sharedTuplesOffset) ||
      !table.ReadU16(&glyphCount) ||
      !table.ReadU16(&flags) ||
      !table.ReadU32(&glyphVariationDataArrayOffset)) {
    return DropVariations("Failed to read table header");
  }
  if (majorVersion != 1) {
    return DropVariations("Unknown table version");
  }

  // check axisCount == fvar->axisCount
  OpenTypeFVAR* fvar = static_cast<OpenTypeFVAR*>(
      GetFont()->GetTypedTable(OTS_TAG_FVAR));
  if (!fvar) {
    return DropVariations("Required fvar table is missing");
  }
  if (axisCount != fvar->AxisCount()) {
    return DropVariations("Axis count mismatch");
  }

  // check glyphCount == maxp->num_glyphs
  OpenTypeMAXP* maxp = static_cast<OpenTypeMAXP*>(
      GetFont()->GetTypedTable(OTS_TAG_MAXP));
  if (!maxp) {
    return DropVariations("Required maxp table is missing");
  }
  if (glyphCount != maxp->num_glyphs) {
    return DropVariations("Glyph count mismatch");
  }

  if (sharedTupleCount > 0) {
    if (sharedTuplesOffset < table.offset() || sharedTuplesOffset > length) {
      return DropVariations("Invalid sharedTuplesOffset");
    }
    if (!ParseSharedTuples(GetFont(),
                           data + sharedTuplesOffset, length - sharedTuplesOffset,
                           sharedTupleCount, axisCount)) {
      return DropVariations("Failed to parse shared tuples");
    }
  }

  if (glyphVariationDataArrayOffset) {
    if (glyphVariationDataArrayOffset > length) {
      return DropVariations("Invalid glyphVariationDataArrayOffset");
    }
    if (!ParseGlyphVariationDataArray(GetFont(),
                                      data + table.offset(), length - table.offset(),
                                      flags, glyphCount, axisCount, sharedTupleCount,
                                      data + glyphVariationDataArrayOffset,
                                      length - glyphVariationDataArrayOffset)) {
      return DropVariations("Failed to read glyph variation data array");
    }
  }

  this->m_data = data;
  this->m_length = length;

  return true;
}

bool OpenTypeGVAR::Serialize(OTSStream* out) {
  if (!out->Write(this->m_data, this->m_length)) {
    return Error("Failed to write gvar table");
  }

  return true;
}

}  // namespace ots

#undef TABLE_NAME


<|start_filename|>src/maxp.h<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_MAXP_H_
#define OTS_MAXP_H_

#include "ots.h"

namespace ots {

class OpenTypeMAXP : public Table {
 public:
  explicit OpenTypeMAXP(Font *font, uint32_t tag)
      : Table(font, tag, tag) { }

  bool Parse(const uint8_t *data, size_t length);
  bool Serialize(OTSStream *out);

  uint16_t num_glyphs;
  bool version_1;

  uint16_t max_points;
  uint16_t max_contours;
  uint16_t max_c_points;
  uint16_t max_c_contours;

  uint16_t max_zones;
  uint16_t max_t_points;
  uint16_t max_storage;
  uint16_t max_fdefs;
  uint16_t max_idefs;
  uint16_t max_stack;
  uint16_t max_size_glyf_instructions;

  uint16_t max_c_components;
  uint16_t max_c_depth;
};

}  // namespace ots

#endif  // OTS_MAXP_H_


<|start_filename|>src/hvar.h<|end_filename|>
// Copyright (c) 2018 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_HVAR_H_
#define OTS_HVAR_H_

#include "ots.h"

namespace ots {

// -----------------------------------------------------------------------------
// OpenTypeHVAR Interface
// -----------------------------------------------------------------------------

class OpenTypeHVAR : public Table {
 public:
  explicit OpenTypeHVAR(Font* font, uint32_t tag)
      : Table(font, tag, tag) { }

  bool Parse(const uint8_t* data, size_t length);
  bool Serialize(OTSStream* out);

 private:
  const uint8_t *m_data;
  size_t m_length;
};

}  // namespace ots

#endif  // OTS_HVAR_H_


<|start_filename|>src/vdmx.cc<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "vdmx.h"

// VDMX - Vertical Device Metrics
// http://www.microsoft.com/typography/otspec/vdmx.htm

namespace ots {

bool OpenTypeVDMX::Parse(const uint8_t *data, size_t length) {
  Buffer table(data, length);

  if (!table.ReadU16(&this->version) ||
      !table.ReadU16(&this->num_recs) ||
      !table.ReadU16(&this->num_ratios)) {
    return Error("Failed to read table header");
  }

  if (this->version > 1) {
    return Drop("Unsupported table version: %u", this->version);
  }

  this->rat_ranges.reserve(this->num_ratios);
  for (unsigned i = 0; i < this->num_ratios; ++i) {
    OpenTypeVDMXRatioRecord rec;

    if (!table.ReadU8(&rec.charset) ||
        !table.ReadU8(&rec.x_ratio) ||
        !table.ReadU8(&rec.y_start_ratio) ||
        !table.ReadU8(&rec.y_end_ratio)) {
      return Error("Failed to read RatioRange record %d", i);
    }

    if (rec.charset > 1) {
      return Drop("Unsupported character set: %u", rec.charset);
    }

    if (rec.y_start_ratio > rec.y_end_ratio) {
      return Drop("Bad y ratio");
    }

    // All values set to zero signal the default grouping to use;
    // if present, this must be the last Ratio group in the table.
    if ((i < this->num_ratios - 1u) &&
        (rec.x_ratio == 0) &&
        (rec.y_start_ratio == 0) &&
        (rec.y_end_ratio == 0)) {
      // workaround for fonts which have 2 or more {0, 0, 0} terminators.
      return Drop("Superfluous terminator found");
    }

    this->rat_ranges.push_back(rec);
  }

  this->offsets.reserve(this->num_ratios);
  const size_t current_offset = table.offset();
  // current_offset is less than (2 bytes * 3) + (4 bytes * USHRT_MAX) = 256k.
  for (unsigned i = 0; i < this->num_ratios; ++i) {
    uint16_t offset;
    if (!table.ReadU16(&offset)) {
      return Error("Failed to read ratio offset %d", i);
    }
    if (current_offset + offset >= length) {  // thus doesn't overflow.
      return Error("Bad ratio offset %d for ration %d", offset, i);
    }

    this->offsets.push_back(offset);
  }

  this->groups.reserve(this->num_recs);
  for (unsigned i = 0; i < this->num_recs; ++i) {
    OpenTypeVDMXGroup group;
    if (!table.ReadU16(&group.recs) ||
        !table.ReadU8(&group.startsz) ||
        !table.ReadU8(&group.endsz)) {
      return Error("Failed to read record header %d", i);
    }
    group.entries.reserve(group.recs);
    for (unsigned j = 0; j < group.recs; ++j) {
      OpenTypeVDMXVTable vt;
      if (!table.ReadU16(&vt.y_pel_height) ||
          !table.ReadS16(&vt.y_max) ||
          !table.ReadS16(&vt.y_min)) {
        return Error("Failed to read reacord %d group %d", i, j);
      }
      if (vt.y_max < vt.y_min) {
        return Drop("bad y min/max");
      }

      // This table must appear in sorted order (sorted by yPelHeight),
      // but need not be continuous.
      if ((j != 0) && (group.entries[j - 1].y_pel_height >= vt.y_pel_height)) {
        return Drop("The table is not sorted");
      }

      group.entries.push_back(vt);
    }
    this->groups.push_back(group);
  }

  return true;
}

bool OpenTypeVDMX::ShouldSerialize() {
  return Table::ShouldSerialize() &&
         // this table is not for CFF fonts.
         GetFont()->GetTable(OTS_TAG_GLYF) != NULL;
}

bool OpenTypeVDMX::Serialize(OTSStream *out) {
  if (!out->WriteU16(this->version) ||
      !out->WriteU16(this->num_recs) ||
      !out->WriteU16(this->num_ratios)) {
    return Error("Failed to write table header");
  }

  for (unsigned i = 0; i < this->rat_ranges.size(); ++i) {
    const OpenTypeVDMXRatioRecord& rec = this->rat_ranges[i];
    if (!out->Write(&rec.charset, 1) ||
        !out->Write(&rec.x_ratio, 1) ||
        !out->Write(&rec.y_start_ratio, 1) ||
        !out->Write(&rec.y_end_ratio, 1)) {
      return Error("Failed to write RatioRange record %d", i);
    }
  }

  for (unsigned i = 0; i < this->offsets.size(); ++i) {
    if (!out->WriteU16(this->offsets[i])) {
      return Error("Failed to write ratio offset %d", i);
    }
  }

  for (unsigned i = 0; i < this->groups.size(); ++i) {
    const OpenTypeVDMXGroup& group = this->groups[i];
    if (!out->WriteU16(group.recs) ||
        !out->Write(&group.startsz, 1) ||
        !out->Write(&group.endsz, 1)) {
      return Error("Failed to write group %d", i);
    }
    for (unsigned j = 0; j < group.entries.size(); ++j) {
      const OpenTypeVDMXVTable& vt = group.entries[j];
      if (!out->WriteU16(vt.y_pel_height) ||
          !out->WriteS16(vt.y_max) ||
          !out->WriteS16(vt.y_min)) {
        return Error("Failed to write group %d entry %d", i, j);
      }
    }
  }

  return true;
}

}  // namespace ots


<|start_filename|>util/ots-sanitize.cc<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"

#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

#include "test-context.h"

namespace {

bool g_quiet = false;


int Log(const std::string& msg) {
  if (!g_quiet)
    std::cout << msg << std::endl;
  return 0;
}

int Error(const std::string& msg) {
  if (!g_quiet)
    std::cerr << msg << std::endl;
  return 1;
}

class FileStream : public ots::OTSStream {
 public:
  explicit FileStream(std::string& filename)
      : file_(false), off_(0) {
    if (!filename.empty()) {
      stream_.open(filename.c_str(), std::ofstream::out | std::ofstream::binary);
      file_ = true;
    }
  }

  bool WriteRaw(const void *data, size_t length) {
    off_ += length;
    if (file_) {
      stream_.write(static_cast<const char*>(data), length);
      return stream_.good();
    }
    return true;
  }

  bool Seek(off_t position) {
    off_ = position;
    if (file_) {
      stream_.seekp(position);
      return stream_.good();
    }
    return true;
  }

  off_t Tell() const {
    return off_;
  }

 private:
  std::ofstream stream_;
  bool file_;
  off_t off_;
};

int Usage(const std::string& name) {
  return Error("Usage: " + name + " [options] font_file [dest_font_file] [font_index]");
}

}  // namespace

int main(int argc, char **argv) {
  std::string in_filename;
  std::string out_filename;
  int font_index = -1;

  for (int i = 1; i < argc; i++) {
    std::string arg(argv[i]);
    if (arg.at(0) == '-') {
      if (arg == "--version")
        return Log(PACKAGE " " VERSION);
      else if (arg == "--quiet")
        g_quiet = true;
      else
        return Error("Unrecognized option: " + arg);
    }
    else if (in_filename.empty())
      in_filename = arg;
    else if (out_filename.empty())
      out_filename = arg;
    else if (font_index == -1)
      font_index = std::strtol(arg.c_str(), NULL, 10);
    else
      return Error("Unrecognized argument: " + arg);
  }

  if (in_filename.empty())
    return Usage(argv[0]);

  std::ifstream ifs(in_filename.c_str(), std::ifstream::binary);
  if (!ifs.good())
    return Error("Failed to open: " + in_filename);

  std::vector<uint8_t> in((std::istreambuf_iterator<char>(ifs)),
                          (std::istreambuf_iterator<char>()));

  ots::TestContext context(g_quiet ? -1 : 4);

  FileStream output(out_filename);
  const bool result = context.Process(&output, in.data(), in.size(), font_index);

  if (result)
    Log("File sanitized successfully!");
  else
    Log("Failed to sanitize file!");

  return !result;
}


<|start_filename|>src/cff.cc<|end_filename|>
// Copyright (c) 2012-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cff.h"

#include <cstring>
#include <utility>
#include <vector>

#include "maxp.h"
#include "cff_charstring.h"
#include "variations.h"

// CFF - PostScript font program (Compact Font Format) table
// http://www.microsoft.com/typography/otspec/cff.htm
// http://www.microsoft.com/typography/otspec/cffspec.htm

#define TABLE_NAME "CFF"

namespace {

enum DICT_OPERAND_TYPE {
  DICT_OPERAND_INTEGER,
  DICT_OPERAND_REAL,
  DICT_OPERATOR,
};

enum DICT_DATA_TYPE {
  DICT_DATA_TOPLEVEL,
  DICT_DATA_FDARRAY,
  DICT_DATA_PRIVATE,
};

enum FONT_FORMAT {
  FORMAT_UNKNOWN,
  FORMAT_CID_KEYED,
  FORMAT_OTHER,  // Including synthetic fonts
};

// see Appendix. A
const size_t kNStdString = 390;

typedef std::pair<uint32_t, DICT_OPERAND_TYPE> Operand;

bool ReadOffset(ots::Buffer &table, uint8_t off_size, uint32_t *offset) {
  if (off_size > 4) {
    return OTS_FAILURE();
  }

  uint32_t tmp32 = 0;
  for (unsigned i = 0; i < off_size; ++i) {
    uint8_t tmp8 = 0;
    if (!table.ReadU8(&tmp8)) {
      return OTS_FAILURE();
    }
    tmp32 <<= 8;
    tmp32 += tmp8;
  }
  *offset = tmp32;
  return true;
}

bool ParseIndex(ots::Buffer &table, ots::CFFIndex &index, bool cff2 = false) {
  index.off_size = 0;
  index.offsets.clear();

  if (cff2) {
    if (!table.ReadU32(&(index.count))) {
      return OTS_FAILURE();
    }
  } else {
    uint16_t count;
    if (!table.ReadU16(&count)) {
      return OTS_FAILURE();
    }
    index.count = count;
  }

  if (index.count == 0) {
    // An empty INDEX.
    index.offset_to_next = table.offset();
    return true;
  }

  if (!table.ReadU8(&(index.off_size))) {
    return OTS_FAILURE();
  }
  if (index.off_size < 1 || index.off_size > 4) {
    return OTS_FAILURE();
  }

  const size_t array_size = (index.count + 1) * index.off_size;
  // less than ((64k + 1) * 4), thus does not overflow.
  const size_t object_data_offset = table.offset() + array_size;
  // does not overflow too, since offset() <= 1GB.

  if (object_data_offset >= table.length()) {
    return OTS_FAILURE();
  }

  for (unsigned i = 0; i <= index.count; ++i) {  // '<=' is not a typo.
    uint32_t rel_offset = 0;
    if (!ReadOffset(table, index.off_size, &rel_offset)) {
      return OTS_FAILURE();
    }
    if (rel_offset < 1) {
      return OTS_FAILURE();
    }
    if (i == 0 && rel_offset != 1) {
      return OTS_FAILURE();
    }

    if (rel_offset > table.length()) {
      return OTS_FAILURE();
    }

    // does not underflow.
    if (object_data_offset > table.length() - (rel_offset - 1)) {
      return OTS_FAILURE();
    }

    index.offsets.push_back(
        object_data_offset + (rel_offset - 1));  // less than length(), 1GB.
  }

  for (unsigned i = 1; i < index.offsets.size(); ++i) {
    // We allow consecutive identical offsets here for zero-length strings.
    // See http://crbug.com/69341 for more details.
    if (index.offsets[i] < index.offsets[i - 1]) {
      return OTS_FAILURE();
    }
  }

  index.offset_to_next = index.offsets.back();
  return true;
}

bool ParseNameData(
    ots::Buffer *table, const ots::CFFIndex &index, std::string* out_name) {
  uint8_t name[256] = {0};

  const size_t length = index.offsets[1] - index.offsets[0];
  // font names should be no longer than 127 characters.
  if (length > 127) {
    return OTS_FAILURE();
  }

  table->set_offset(index.offsets[0]);
  if (!table->Read(name, length)) {
    return OTS_FAILURE();
  }

  for (size_t i = 0; i < length; ++i) {
    // setting the first byte to NUL is allowed.
    if (i == 0 && name[i] == 0) continue;
    // non-ASCII characters are not recommended (except the first character).
    if (name[i] < 33 || name[i] > 126) {
      return OTS_FAILURE();
    }
    // [, ], ... are not allowed.
    if (std::strchr("[](){}<>/% ", name[i])) {
      return OTS_FAILURE();
    }
  }

  *out_name = reinterpret_cast<char *>(name);
  return true;
}

bool CheckOffset(const Operand& operand, size_t table_length) {
  if (operand.second != DICT_OPERAND_INTEGER) {
    return OTS_FAILURE();
  }
  if (operand.first >= table_length) {
    return OTS_FAILURE();
  }
  return true;
}

bool CheckSid(const Operand& operand, size_t sid_max) {
  if (operand.second != DICT_OPERAND_INTEGER) {
    return OTS_FAILURE();
  }
  if (operand.first > sid_max) {
    return OTS_FAILURE();
  }
  return true;
}

bool ParseDictDataBcd(ots::Buffer &table, std::vector<Operand> &operands) {
  bool read_decimal_point = false;
  bool read_e = false;

  uint8_t nibble = 0;
  size_t count = 0;
  while (true) {
    if (!table.ReadU8(&nibble)) {
      return OTS_FAILURE();
    }
    if ((nibble & 0xf0) == 0xf0) {
      if ((nibble & 0xf) == 0xf) {
        // TODO(yusukes): would be better to store actual double value,
        // rather than the dummy integer.
        operands.push_back(std::make_pair(static_cast<uint32_t>(0),
                                           DICT_OPERAND_REAL));
        return true;
      }
      return OTS_FAILURE();
    }
    if ((nibble & 0x0f) == 0x0f) {
      operands.push_back(std::make_pair(static_cast<uint32_t>(0),
                                         DICT_OPERAND_REAL));
      return true;
    }

    // check number format
    uint8_t nibbles[2];
    nibbles[0] = (nibble & 0xf0) >> 8;
    nibbles[1] = (nibble & 0x0f);
    for (unsigned i = 0; i < 2; ++i) {
      if (nibbles[i] == 0xd) {  // reserved number
        return OTS_FAILURE();
      }
      if ((nibbles[i] == 0xe) &&  // minus
          ((count > 0) || (i > 0))) {
        return OTS_FAILURE();  // minus sign should be the first character.
      }
      if (nibbles[i] == 0xa) {  // decimal point
        if (!read_decimal_point) {
          read_decimal_point = true;
        } else {
          return OTS_FAILURE();  // two or more points.
        }
      }
      if ((nibbles[i] == 0xb) ||  // E+
          (nibbles[i] == 0xc)) {  // E-
        if (!read_e) {
          read_e = true;
        } else {
          return OTS_FAILURE();  // two or more E's.
        }
      }
    }
    ++count;
  }
}

bool ParseDictDataEscapedOperator(ots::Buffer &table,
                                  std::vector<Operand> &operands) {
  uint8_t op = 0;
  if (!table.ReadU8(&op)) {
    return OTS_FAILURE();
  }

  if ((op <= 14) ||
      (op >= 17 && op <= 23) ||
      (op >= 30 && op <= 38)) {
    operands.push_back(std::make_pair((12U << 8) + op, DICT_OPERATOR));
    return true;
  }

  // reserved area.
  return OTS_FAILURE();
}

bool ParseDictDataNumber(ots::Buffer &table, uint8_t b0,
                         std::vector<Operand> &operands) {
  uint8_t b1 = 0;
  uint8_t b2 = 0;
  uint8_t b3 = 0;
  uint8_t b4 = 0;

  switch (b0) {
    case 28:  // shortint
      if (!table.ReadU8(&b1) ||
          !table.ReadU8(&b2)) {
        return OTS_FAILURE();
      }
      operands.push_back(std::make_pair(
          static_cast<uint32_t>((b1 << 8) + b2), DICT_OPERAND_INTEGER));
      return true;

    case 29:  // longint
      if (!table.ReadU8(&b1) ||
          !table.ReadU8(&b2) ||
          !table.ReadU8(&b3) ||
          !table.ReadU8(&b4)) {
        return OTS_FAILURE();
      }
      operands.push_back(std::make_pair(
          static_cast<uint32_t>((b1 << 24) + (b2 << 16) + (b3 << 8) + b4),
          DICT_OPERAND_INTEGER));
      return true;

    case 30:  // binary coded decimal
      return ParseDictDataBcd(table, operands);

    default:
      break;
  }

  uint32_t result;
  if (b0 >=32 && b0 <=246) {
    result = b0 - 139;
  } else if (b0 >=247 && b0 <= 250) {
    if (!table.ReadU8(&b1)) {
      return OTS_FAILURE();
    }
    result = (b0 - 247) * 256 + b1 + 108;
  } else if (b0 >= 251 && b0 <= 254) {
    if (!table.ReadU8(&b1)) {
      return OTS_FAILURE();
    }
    result = -(b0 - 251) * 256 + b1 - 108;
  } else {
    return OTS_FAILURE();
  }

  operands.push_back(std::make_pair(result, DICT_OPERAND_INTEGER));
  return true;
}

bool ParseDictDataReadNext(ots::Buffer &table,
                           std::vector<Operand> &operands) {
  uint8_t op = 0;
  if (!table.ReadU8(&op)) {
    return OTS_FAILURE();
  }
  if (op <= 24) {
    if (op == 12) {
      return ParseDictDataEscapedOperator(table, operands);
    }
    operands.push_back(std::make_pair(
        static_cast<uint32_t>(op), DICT_OPERATOR));
    return true;
  } else if (op <= 27 || op == 31 || op == 255) {
    // reserved area.
    return OTS_FAILURE();
  }

  return ParseDictDataNumber(table, op, operands);
}

bool OperandsOverflow(std::vector<Operand>& operands, bool cff2) {
  // An operator may be preceded by up to a maximum of 48 operands in CFF1 and
  // 513 operands in CFF2.
  if ((cff2 && operands.size() > ots::kMaxCFF2ArgumentStack) ||
      (!cff2 && operands.size() > ots::kMaxCFF1ArgumentStack)) {
    return true;
  }
  return false;
}

bool ParseDictDataReadOperands(ots::Buffer& dict,
                               std::vector<Operand>& operands,
                               bool cff2) {
  if (!ParseDictDataReadNext(dict, operands)) {
    return OTS_FAILURE();
  }
  if (operands.empty()) {
    return OTS_FAILURE();
  }
  if (OperandsOverflow(operands, cff2)) {
    return OTS_FAILURE();
  }
  return true;
}

bool ValidCFF2DictOp(uint32_t op, DICT_DATA_TYPE type) {
  if (type == DICT_DATA_TOPLEVEL) {
    switch (op) {
      case (12U << 8) + 7:  // FontMatrix
      case 17:              // CharStrings
      case (12U << 8) + 36: // FDArray
      case (12U << 8) + 37: // FDSelect
      case 24:              // vstore
        return true;
      default:
        return false;
    }
  } else if (type == DICT_DATA_FDARRAY) {
    if (op == 18) // Private DICT
      return true;
  } else if (type == DICT_DATA_PRIVATE) {
    switch (op) {
      case (12U << 8) + 14: // ForceBold
      case (12U << 8) + 19: // initialRandomSeed
      case 20:              // defaultWidthX
      case 21:              // nominalWidthX
        return false;
      default:
        return true;
    }
  }

  return false;
}

bool ParsePrivateDictData(
    ots::Buffer &table, size_t offset, size_t dict_length,
    DICT_DATA_TYPE type, ots::OpenTypeCFF *out_cff) {
  ots::Buffer dict(table.buffer() + offset, dict_length);
  std::vector<Operand> operands;
  bool cff2 = (out_cff->major == 2);
  bool blend_seen = false;
  uint32_t vsindex = 0;

  // Since a Private DICT for FDArray might not have a Local Subr (e.g. Hiragino
  // Kaku Gothic Std W8), we create an empty Local Subr here to match the size
  // of FDArray the size of |local_subrs_per_font|.
  if (type == DICT_DATA_FDARRAY) {
    out_cff->local_subrs_per_font.push_back(new ots::CFFIndex);
  }

  while (dict.offset() < dict.length()) {
    if (!ParseDictDataReadOperands(dict, operands, cff2)) {
      return OTS_FAILURE();
    }
    if (operands.back().second != DICT_OPERATOR) {
      continue;
    }

    // got operator
    const uint32_t op = operands.back().first;
    operands.pop_back();

    if (cff2 && !ValidCFF2DictOp(op, DICT_DATA_PRIVATE)) {
      return OTS_FAILURE();
    }

    bool clear_operands = true;
    switch (op) {
      // hints
      case 6:  // BlueValues
      case 7:  // OtherBlues
      case 8:  // FamilyBlues
      case 9:  // FamilyOtherBlues
        if ((operands.size() % 2) != 0) {
          return OTS_FAILURE();
        }
        break;

      // array
      case (12U << 8) + 12:  // StemSnapH (delta)
      case (12U << 8) + 13:  // StemSnapV (delta)
        if (operands.empty()) {
          return OTS_FAILURE();
        }
        break;

      // number
      case 10:  // StdHW
      case 11:  // StdVW
      case 20:  // defaultWidthX
      case 21:  // nominalWidthX
      case (12U << 8) + 9:   // BlueScale
      case (12U << 8) + 10:  // BlueShift
      case (12U << 8) + 11:  // BlueFuzz
      case (12U << 8) + 17:  // LanguageGroup
      case (12U << 8) + 18:  // ExpansionFactor
      case (12U << 8) + 19:  // initialRandomSeed
        if (operands.size() != 1) {
          return OTS_FAILURE();
        }
        break;

      // Local Subrs INDEX, offset(self)
      case 19: {
        if (operands.size() != 1) {
          return OTS_FAILURE();
        }
        if (operands.back().second != DICT_OPERAND_INTEGER) {
          return OTS_FAILURE();
        }
        if (operands.back().first >= 1024 * 1024 * 1024) {
          return OTS_FAILURE();
        }
        if (operands.back().first + offset >= table.length()) {
          return OTS_FAILURE();
        }
        // parse "16. Local Subrs INDEX"
        table.set_offset(operands.back().first + offset);
        ots::CFFIndex *local_subrs_index = NULL;
        if (type == DICT_DATA_FDARRAY) {
          if (out_cff->local_subrs_per_font.empty()) {
            return OTS_FAILURE();  // not reached.
          }
          local_subrs_index = out_cff->local_subrs_per_font.back();
        } else { // type == DICT_DATA_TOPLEVEL
          if (out_cff->local_subrs) {
            return OTS_FAILURE();  // two or more local_subrs?
          }
          local_subrs_index = new ots::CFFIndex;
          out_cff->local_subrs = local_subrs_index;
        }
        if (!ParseIndex(table, *local_subrs_index, cff2)) {
          return OTS_FAILURE();
        }
        break;
      }

      // boolean
      case (12U << 8) + 14:  // ForceBold
        if (operands.size() != 1) {
          return OTS_FAILURE();
        }
        if (operands.back().second != DICT_OPERAND_INTEGER) {
          return OTS_FAILURE();
        }
        if (operands.back().first >= 2) {
          return OTS_FAILURE();
        }
        break;

      case 22: { // vsindex
        if (!cff2) {
          return OTS_FAILURE();
        }
        if (operands.size() != 1) {
          return OTS_FAILURE();
        }
        if (operands.back().second != DICT_OPERAND_INTEGER) {
          return OTS_FAILURE();
        }
        if (blend_seen) {
          return OTS_FAILURE();
        }
        vsindex = operands.back().first;
        if (vsindex >= out_cff->region_index_count.size()) {
          return OTS_FAILURE();
        }
        break;
      }

      case 23: { // blend
        if (!cff2) {
          return OTS_FAILURE();
        }
        if (operands.size() < 1) {
          return OTS_FAILURE();
        }
        if (vsindex >= out_cff->region_index_count.size()) {
          return OTS_FAILURE();
        }
        uint16_t k = out_cff->region_index_count.at(vsindex);
        uint16_t n = operands.back().first;
        if (operands.size() < n * (k + 1) + 1) {
          return OTS_FAILURE();
        }
        size_t operands_size = operands.size();
        // Keep the 1st n operands on the stack for the next operator to use
        // and pop the rest. There can be multiple consecutive blend operator,
        // so this makes sure the operands of all of them are kept on the
        // stack.
        while (operands.size() > operands_size - ((n * k) + 1))
          operands.pop_back();
        clear_operands = false;
        blend_seen = true;
        break;
      }

      default:
        return OTS_FAILURE();
    }
    if (clear_operands) {
      operands.clear();
    }
  }

  return true;
}

bool ParseVariationStore(ots::OpenTypeCFF& out_cff, ots::Buffer& table) {
  uint16_t length;

  if (!table.ReadU16(&length)) {
    return OTS_FAILURE();
  }

  // Empty VariationStore is allowed.
  if (!length) {
    return true;
  }

  if (length > table.remaining()) {
    return OTS_FAILURE();
  }

  if (!ParseItemVariationStore(out_cff.GetFont(),
                               table.buffer() + table.offset(), length,
                               &(out_cff.region_index_count))) {
    return OTS_FAILURE();
  }

  return true;
}

bool ParseDictData(ots::Buffer& table, ots::Buffer& dict,
                   uint16_t glyphs, size_t sid_max, DICT_DATA_TYPE type,
                   ots::OpenTypeCFF *out_cff);

bool ParseDictData(ots::Buffer& table, const ots::CFFIndex &index,
                   uint16_t glyphs, size_t sid_max, DICT_DATA_TYPE type,
                   ots::OpenTypeCFF *out_cff) {
  for (unsigned i = 1; i < index.offsets.size(); ++i) {
    size_t dict_length = index.offsets[i] - index.offsets[i - 1];
    ots::Buffer dict(table.buffer() + index.offsets[i - 1], dict_length);

    if (!ParseDictData(table, dict, glyphs, sid_max, type, out_cff)) {
      return OTS_FAILURE();
    }
  }
  return true;
}

bool ParseDictData(ots::Buffer& table, ots::Buffer& dict,
                   uint16_t glyphs, size_t sid_max, DICT_DATA_TYPE type,
                   ots::OpenTypeCFF *out_cff) {
  bool cff2 = (out_cff->major == 2);
  std::vector<Operand> operands;

  FONT_FORMAT font_format = FORMAT_UNKNOWN;
  bool have_ros = false;
  bool have_charstrings = false;
  bool have_vstore = false;
  size_t charset_offset = 0;

  if (cff2) {
    // Parse VariationStore first, since it might be referenced in other places
    // (e.g. FDArray) that might be parsed after it.
    size_t dict_offset = dict.offset();
    while (dict.offset() < dict.length()) {
      if (!ParseDictDataReadOperands(dict, operands, cff2)) {
        return OTS_FAILURE();
      }
      if (operands.back().second != DICT_OPERATOR) continue;

      // got operator
      const uint32_t op = operands.back().first;
      operands.pop_back();

      if (op == 24) {  // vstore
        if (type != DICT_DATA_TOPLEVEL) {
          return OTS_FAILURE();
        }
        if (operands.size() != 1) {
          return OTS_FAILURE();
        }
        if (!CheckOffset(operands.back(), table.length())) {
          return OTS_FAILURE();
        }
        // parse "VariationStore Data Contents"
        table.set_offset(operands.back().first);
        if (!ParseVariationStore(*out_cff, table)) {
          return OTS_FAILURE();
        }
        break;
      }
      operands.clear();
    }
    operands.clear();
    dict.set_offset(dict_offset);
  }

  while (dict.offset() < dict.length()) {
    if (!ParseDictDataReadOperands(dict, operands, cff2)) {
      return OTS_FAILURE();
    }
    if (operands.back().second != DICT_OPERATOR) continue;

    // got operator
    const uint32_t op = operands.back().first;
    operands.pop_back();

    if (cff2 && !ValidCFF2DictOp(op, type)) {
      return OTS_FAILURE();
    }

    switch (op) {
      // SID
      case 0:   // version
      case 1:   // Notice
      case 2:   // Copyright
      case 3:   // FullName
      case 4:   // FamilyName
      case (12U << 8) + 0:   // Copyright
      case (12U << 8) + 21:  // PostScript
      case (12U << 8) + 22:  // BaseFontName
      case (12U << 8) + 38:  // FontName
        if (operands.size() != 1) {
          return OTS_FAILURE();
        }
        if (!CheckSid(operands.back(), sid_max)) {
          return OTS_FAILURE();
        }
        break;

      // array
      case 5:   // FontBBox
      case 14:  // XUID
      case (12U << 8) + 7:   // FontMatrix
      case (12U << 8) + 23:  // BaseFontBlend (delta)
        if (operands.empty()) {
          return OTS_FAILURE();
        }
        break;

      // number
      case 13:  // UniqueID
      case (12U << 8) + 2:   // ItalicAngle
      case (12U << 8) + 3:   // UnderlinePosition
      case (12U << 8) + 4:   // UnderlineThickness
      case (12U << 8) + 5:   // PaintType
      case (12U << 8) + 8:   // StrokeWidth
      case (12U << 8) + 20:  // SyntheticBase
        if (operands.size() != 1) {
          return OTS_FAILURE();
        }
        break;
      case (12U << 8) + 31:  // CIDFontVersion
      case (12U << 8) + 32:  // CIDFontRevision
      case (12U << 8) + 33:  // CIDFontType
      case (12U << 8) + 34:  // CIDCount
      case (12U << 8) + 35:  // UIDBase
        if (operands.size() != 1) {
          return OTS_FAILURE();
        }
        if (font_format != FORMAT_CID_KEYED) {
          return OTS_FAILURE();
        }
        break;
      case (12U << 8) + 6:   // CharstringType
        if (operands.size() != 1) {
          return OTS_FAILURE();
        }
        if(operands.back().second != DICT_OPERAND_INTEGER) {
          return OTS_FAILURE();
        }
        if (operands.back().first != 2) {
          // We only support the "Type 2 Charstring Format."
          // TODO(yusukes): Support Type 1 format? Is that still in use?
          return OTS_FAILURE();
        }
        break;

      // boolean
      case (12U << 8) + 1:   // isFixedPitch
        if (operands.size() != 1) {
          return OTS_FAILURE();
        }
        if (operands.back().second != DICT_OPERAND_INTEGER) {
          return OTS_FAILURE();
        }
        if (operands.back().first >= 2) {
          return OTS_FAILURE();
        }
        break;

      // offset(0)
      case 15:  // charset
        if (operands.size() != 1) {
          return OTS_FAILURE();
        }
        if (operands.back().first <= 2) {
          // predefined charset, ISOAdobe, Expert or ExpertSubset, is used.
          break;
        }
        if (!CheckOffset(operands.back(), table.length())) {
          return OTS_FAILURE();
        }
        if (charset_offset) {
          return OTS_FAILURE();  // multiple charset tables?
        }
        charset_offset = operands.back().first;
        break;

      case 16: {  // Encoding
        if (operands.size() != 1) {
          return OTS_FAILURE();
        }
        if (operands.back().first <= 1) {
          break;  // predefined encoding, "Standard" or "Expert", is used.
        }
        if (!CheckOffset(operands.back(), table.length())) {
          return OTS_FAILURE();
        }

        table.set_offset(operands.back().first);
        uint8_t format = 0;
        if (!table.ReadU8(&format)) {
          return OTS_FAILURE();
        }
        if (format & 0x80) {
          // supplemental encoding is not supported at the moment.
          return OTS_FAILURE();
        }
        // TODO(yusukes): support & parse supplemental encoding tables.
        break;
      }

      case 17: {  // CharStrings
        if (type != DICT_DATA_TOPLEVEL) {
          return OTS_FAILURE();
        }
        if (operands.size() != 1) {
          return OTS_FAILURE();
        }
        if (!CheckOffset(operands.back(), table.length())) {
          return OTS_FAILURE();
        }
        // parse "14. CharStrings INDEX"
        table.set_offset(operands.back().first);
        ots::CFFIndex *charstring_index = out_cff->charstrings_index;
        if (!ParseIndex(table, *charstring_index, cff2)) {
          return OTS_FAILURE();
        }
        if (charstring_index->count < 2) {
          return OTS_FAILURE();
        }
        if (have_charstrings) {
          return OTS_FAILURE();  // multiple charstring tables?
        }
        have_charstrings = true;
        if (charstring_index->count != glyphs) {
          return OTS_FAILURE();  // CFF and maxp have different number of glyphs?
        }
        break;
      }

      case 24: {  // vstore
        if (!cff2) {
          return OTS_FAILURE();
        }
        if (have_vstore) {
          return OTS_FAILURE();  // multiple vstore tables?
        }
        have_vstore = true;
        // parsed above.
        break;
      }

      case (12U << 8) + 36: {  // FDArray
        if (type != DICT_DATA_TOPLEVEL) {
          return OTS_FAILURE();
        }
        if (operands.size() != 1) {
          return OTS_FAILURE();
        }
        if (!CheckOffset(operands.back(), table.length())) {
          return OTS_FAILURE();
        }

        // parse Font DICT INDEX.
        table.set_offset(operands.back().first);
        ots::CFFIndex sub_dict_index;
        if (!ParseIndex(table, sub_dict_index, cff2)) {
          return OTS_FAILURE();
        }
        if (!ParseDictData(table, sub_dict_index,
                           glyphs, sid_max, DICT_DATA_FDARRAY,
                           out_cff)) {
          return OTS_FAILURE();
        }
        if (out_cff->font_dict_length != 0) {
          return OTS_FAILURE();  // two or more FDArray found.
        }
        out_cff->font_dict_length = sub_dict_index.count;
        break;
      }

      case (12U << 8) + 37: {  // FDSelect
        if (type != DICT_DATA_TOPLEVEL) {
          return OTS_FAILURE();
        }
        if (operands.size() != 1) {
          return OTS_FAILURE();
        }
        if (!CheckOffset(operands.back(), table.length())) {
          return OTS_FAILURE();
        }

        // parse FDSelect data structure
        table.set_offset(operands.back().first);
        uint8_t format = 0;
        if (!table.ReadU8(&format)) {
          return OTS_FAILURE();
        }
        if (format == 0) {
          for (uint16_t j = 0; j < glyphs; ++j) {
            uint8_t fd_index = 0;
            if (!table.ReadU8(&fd_index)) {
              return OTS_FAILURE();
            }
            (out_cff->fd_select)[j] = fd_index;
          }
        } else if (format == 3) {
          uint16_t n_ranges = 0;
          if (!table.ReadU16(&n_ranges)) {
            return OTS_FAILURE();
          }
          if (n_ranges == 0) {
            return OTS_FAILURE();
          }

          uint16_t last_gid = 0;
          uint8_t fd_index = 0;
          for (unsigned j = 0; j < n_ranges; ++j) {
            uint16_t first = 0;  // GID
            if (!table.ReadU16(&first)) {
              return OTS_FAILURE();
            }

            // Sanity checks.
            if ((j == 0) && (first != 0)) {
              return OTS_FAILURE();
            }
            if ((j != 0) && (last_gid >= first)) {
              return OTS_FAILURE();  // not increasing order.
            }
            if (first >= glyphs) {
              return OTS_FAILURE();  // invalid gid.
            }

            // Copy the mapping to |out_cff->fd_select|.
            if (j != 0) {
              for (auto k = last_gid; k < first; ++k) {
                if (!out_cff->fd_select.insert(
                        std::make_pair(k, fd_index)).second) {
                  return OTS_FAILURE();
                }
              }
            }

            if (!table.ReadU8(&fd_index)) {
              return OTS_FAILURE();
            }
            last_gid = first;
          }
          uint16_t sentinel = 0;
          if (!table.ReadU16(&sentinel)) {
            return OTS_FAILURE();
          }
          if (last_gid >= sentinel) {
            return OTS_FAILURE();
          }
          if (sentinel > glyphs) {
            return OTS_FAILURE();  // invalid gid.
          }
          for (auto k = last_gid; k < sentinel; ++k) {
            if (!out_cff->fd_select.insert(
                    std::make_pair(k, fd_index)).second) {
              return OTS_FAILURE();
            }
          }
        } else if (cff2 && format == 4) {
          uint32_t n_ranges = 0;
          if (!table.ReadU32(&n_ranges)) {
            return OTS_FAILURE();
          }
          if (n_ranges == 0) {
            return OTS_FAILURE();
          }

          uint32_t last_gid = 0;
          uint16_t fd_index = 0;
          for (unsigned j = 0; j < n_ranges; ++j) {
            uint32_t first = 0;  // GID
            if (!table.ReadU32(&first)) {
              return OTS_FAILURE();
            }

            // Sanity checks.
            if ((j == 0) && (first != 0)) {
              return OTS_FAILURE();
            }
            if ((j != 0) && (last_gid >= first)) {
              return OTS_FAILURE();  // not increasing order.
            }
            if (first >= glyphs) {
              return OTS_FAILURE();  // invalid gid.
            }

            // Copy the mapping to |out_cff->fd_select|.
            if (j != 0) {
              for (auto k = last_gid; k < first; ++k) {
                if (!out_cff->fd_select.insert(
                        std::make_pair(k, fd_index)).second) {
                  return OTS_FAILURE();
                }
              }
            }

            if (!table.ReadU16(&fd_index)) {
              return OTS_FAILURE();
            }
            last_gid = first;
          }
          uint32_t sentinel = 0;
          if (!table.ReadU32(&sentinel)) {
            return OTS_FAILURE();
          }
          if (last_gid >= sentinel) {
            return OTS_FAILURE();
          }
          if (sentinel > glyphs) {
            return OTS_FAILURE();  // invalid gid.
          }
          for (auto k = last_gid; k < sentinel; ++k) {
            if (!out_cff->fd_select.insert(
                    std::make_pair(k, fd_index)).second) {
              return OTS_FAILURE();
            }
          }
        } else {
          // unknown format
          return OTS_FAILURE();
        }
        break;
      }

      // Private DICT (2 * number)
      case 18: {
        if (operands.size() != 2) {
          return OTS_FAILURE();
        }
        if (operands.back().second != DICT_OPERAND_INTEGER) {
          return OTS_FAILURE();
        }
        const uint32_t private_offset = operands.back().first;
        operands.pop_back();
        if (operands.back().second != DICT_OPERAND_INTEGER) {
          return OTS_FAILURE();
        }
        const uint32_t private_length = operands.back().first;
        if (private_offset > table.length()) {
          return OTS_FAILURE();
        }
        if (private_length >= table.length()) {
          return OTS_FAILURE();
        }
        if (private_length + private_offset > table.length()) {
          return OTS_FAILURE();
        }
        // parse "15. Private DICT data"
        if (!ParsePrivateDictData(table, private_offset, private_length,
                                  type, out_cff)) {
          return OTS_FAILURE();
        }
        break;
      }

      // ROS
      case (12U << 8) + 30:
        if (font_format != FORMAT_UNKNOWN) {
          return OTS_FAILURE();
        }
        font_format = FORMAT_CID_KEYED;
        if (operands.size() != 3) {
          return OTS_FAILURE();
        }
        // check SIDs
        operands.pop_back();  // ignore the first number.
        if (!CheckSid(operands.back(), sid_max)) {
          return OTS_FAILURE();
        }
        operands.pop_back();
        if (!CheckSid(operands.back(), sid_max)) {
          return OTS_FAILURE();
        }
        if (have_ros) {
          return OTS_FAILURE();  // multiple ROS tables?
        }
        have_ros = true;
        break;

      default:
        return OTS_FAILURE();
    }
    operands.clear();

    if (font_format == FORMAT_UNKNOWN) {
      font_format = FORMAT_OTHER;
    }
  }

  // parse "13. Charsets"
  if (charset_offset) {
    table.set_offset(charset_offset);
    uint8_t format = 0;
    if (!table.ReadU8(&format)) {
      return OTS_FAILURE();
    }
    switch (format) {
      case 0:
        for (uint16_t j = 1 /* .notdef is omitted */; j < glyphs; ++j) {
          uint16_t sid = 0;
          if (!table.ReadU16(&sid)) {
            return OTS_FAILURE();
          }
          if (!have_ros && (sid > sid_max)) {
            return OTS_FAILURE();
          }
          // TODO(yusukes): check CIDs when have_ros is true.
        }
        break;

      case 1:
      case 2: {
        uint32_t total = 1;  // .notdef is omitted.
        while (total < glyphs) {
          uint16_t sid = 0;
          if (!table.ReadU16(&sid)) {
            return OTS_FAILURE();
          }
          if (!have_ros && (sid > sid_max)) {
            return OTS_FAILURE();
          }
          // TODO(yusukes): check CIDs when have_ros is true.

          if (format == 1) {
            uint8_t left = 0;
            if (!table.ReadU8(&left)) {
              return OTS_FAILURE();
            }
            total += (left + 1);
          } else {
            uint16_t left = 0;
            if (!table.ReadU16(&left)) {
              return OTS_FAILURE();
            }
            total += (left + 1);
          }
        }
        break;
      }

      default:
        return OTS_FAILURE();
    }
  }
  return true;
}

}  // namespace

namespace ots {

bool OpenTypeCFF::ValidateFDSelect(uint16_t num_glyphs) {
  for (const auto& fd_select : this->fd_select) {
    if (fd_select.first >= num_glyphs) {
      return Error("Invalid glyph index in FDSelect: %d >= %d\n",
                   fd_select.first, num_glyphs);
    }
    if (fd_select.second >= this->font_dict_length) {
      return Error("Invalid FD index: %d >= %d\n",
                   fd_select.second, this->font_dict_length);
    }
  }
  return true;
}

bool OpenTypeCFF::Parse(const uint8_t *data, size_t length) {
  Buffer table(data, length);

  Font *font = GetFont();

  this->m_data = data;
  this->m_length = length;

  // parse "6. Header" in the Adobe Compact Font Format Specification
  uint8_t major = 0;
  uint8_t minor = 0;
  uint8_t hdr_size = 0;
  uint8_t off_size = 0;
  if (!table.ReadU8(&major) ||
      !table.ReadU8(&minor) ||
      !table.ReadU8(&hdr_size) ||
      !table.ReadU8(&off_size)) {
    return Error("Failed to read table header");
  }

  if (off_size < 1 || off_size > 4) {
    return Error("Bad offSize: %d", off_size);
  }

  if (major != 1 || minor != 0) {
    return Error("Unsupported table version: %d.%d", major, minor);
  }

  this->major = major;

  if (hdr_size != 4 || hdr_size >= length) {
    return Error("Bad hdrSize: %d", hdr_size);
  }

  // parse "7. Name INDEX"
  table.set_offset(hdr_size);
  CFFIndex name_index;
  if (!ParseIndex(table, name_index)) {
    return Error("Failed to parse Name INDEX");
  }
  if (name_index.count != 1 || name_index.offsets.size() != 2) {
    return Error("Name INDEX must contain only one entry, not %d",
                 name_index.count);
  }
  if (!ParseNameData(&table, name_index, &(this->name))) {
    return Error("Failed to parse Name INDEX data");
  }

  // parse "8. Top DICT INDEX"
  table.set_offset(name_index.offset_to_next);
  CFFIndex top_dict_index;
  if (!ParseIndex(table, top_dict_index)) {
    return Error("Failed to parse Top DICT INDEX");
  }
  if (top_dict_index.count != 1) {
    return Error("Top DICT INDEX must contain only one entry, not %d",
                 top_dict_index.count);
  }

  // parse "10. String INDEX"
  table.set_offset(top_dict_index.offset_to_next);
  CFFIndex string_index;
  if (!ParseIndex(table, string_index)) {
    return Error("Failed to parse String INDEX");
  }
  if (string_index.count >= 65000 - kNStdString) {
    return Error("Too many entries in String INDEX: %d", string_index.count);
  }

  OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>(
    font->GetTypedTable(OTS_TAG_MAXP));
  if (!maxp) {
    return Error("Required maxp table missing");
  }
  const uint16_t num_glyphs = maxp->num_glyphs;
  const size_t sid_max = string_index.count + kNStdString;
  // string_index.count == 0 is allowed.

  // parse "9. Top DICT Data"
  this->charstrings_index = new ots::CFFIndex;
  if (!ParseDictData(table, top_dict_index,
                     num_glyphs, sid_max,
                     DICT_DATA_TOPLEVEL, this)) {
    return Error("Failed to parse Top DICT Data");
  }

  // parse "16. Global Subrs INDEX"
  table.set_offset(string_index.offset_to_next);
  CFFIndex global_subrs_index;
  if (!ParseIndex(table, global_subrs_index)) {
    return Error("Failed to parse Global Subrs INDEX");
  }

  // Check if all fd and glyph indices in FDSelect are valid.
  if (!ValidateFDSelect(num_glyphs)) {
    return Error("Failed to validate FDSelect");
  }

  // Check if all charstrings (font hinting code for each glyph) are valid.
  if (!ValidateCFFCharStrings(*this, global_subrs_index, &table)) {
    return Error("Failed validating CharStrings INDEX");
  }

  return true;
}

bool OpenTypeCFF::Serialize(OTSStream *out) {
  if (!out->Write(this->m_data, this->m_length)) {
    return Error("Failed to write table");
  }
  return true;
}

OpenTypeCFF::~OpenTypeCFF() {
  for (size_t i = 0; i < this->local_subrs_per_font.size(); ++i) {
    delete (this->local_subrs_per_font)[i];
  }
  delete this->charstrings_index;
  delete this->local_subrs;
}

bool OpenTypeCFF2::Parse(const uint8_t *data, size_t length) {
  Buffer table(data, length);

  Font *font = GetFont();

  this->m_data = data;
  this->m_length = length;

  // parse "6. Header"
  uint8_t major = 0;
  uint8_t minor = 0;
  uint8_t hdr_size = 0;
  uint16_t top_dict_size = 0;
  if (!table.ReadU8(&major) ||
      !table.ReadU8(&minor) ||
      !table.ReadU8(&hdr_size) ||
      !table.ReadU16(&top_dict_size)) {
    return Error("Failed to read table header");
  }

  if (major != 2 || minor != 0) {
    return Error("Unsupported table version: %d.%d", major, minor);
  }

  this->major = major;

  if (hdr_size >= length) {
    return Error("Bad hdrSize: %d", hdr_size);
  }

  if (top_dict_size == 0 || hdr_size + top_dict_size > length) {
    return Error("Bad topDictLength: %d", top_dict_size);
  }

  OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>(
    font->GetTypedTable(OTS_TAG_MAXP));
  if (!maxp) {
    return Error("Required maxp table missing");
  }
  const uint16_t num_glyphs = maxp->num_glyphs;
  const size_t sid_max = kNStdString;

  // parse "7. Top DICT Data"
  ots::Buffer top_dict(data + hdr_size, top_dict_size);
  table.set_offset(hdr_size);
  this->charstrings_index = new ots::CFFIndex;
  if (!ParseDictData(table, top_dict,
                     num_glyphs, sid_max,
                     DICT_DATA_TOPLEVEL, this)) {
    return Error("Failed to parse Top DICT Data");
  }

  // parse "9. Global Subrs INDEX"
  table.set_offset(hdr_size + top_dict_size);
  CFFIndex global_subrs_index;
  if (!ParseIndex(table, global_subrs_index, true)) {
    return Error("Failed to parse Global Subrs INDEX");
  }

  // Check if all fd and glyph indices in FDSelect are valid.
  if (!ValidateFDSelect(num_glyphs)) {
    return Error("Failed to validate FDSelect");
  }

  // Check if all charstrings (font hinting code for each glyph) are valid.
  if (!ValidateCFFCharStrings(*this, global_subrs_index, &table)) {
    return Error("Failed validating CharStrings INDEX");
  }

  return true;
}

bool OpenTypeCFF2::Serialize(OTSStream *out) {
  if (!out->Write(this->m_data, this->m_length)) {
    return Error("Failed to write table");
  }
  return true;
}

}  // namespace ots

#undef TABLE_NAME


<|start_filename|>src/hhea.h<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_HHEA_H_
#define OTS_HHEA_H_

#include "metrics.h"
#include "ots.h"

namespace ots {

class OpenTypeHHEA : public OpenTypeMetricsHeader {
 public:
  explicit OpenTypeHHEA(Font *font, uint32_t tag)
      : OpenTypeMetricsHeader(font, tag, tag) { }

  bool Parse(const uint8_t *data, size_t length);
};

}  // namespace ots

#endif  // OTS_HHEA_H_


<|start_filename|>src/vvar.cc<|end_filename|>
// Copyright (c) 2018 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "vvar.h"

#include "variations.h"

namespace ots {

// -----------------------------------------------------------------------------
// OpenTypeVVAR
// -----------------------------------------------------------------------------

bool OpenTypeVVAR::Parse(const uint8_t* data, size_t length) {
  Buffer table(data, length);

  uint16_t majorVersion;
  uint16_t minorVersion;
  uint32_t itemVariationStoreOffset;
  uint32_t advanceHeightMappingOffset;
  uint32_t tsbMappingOffset;
  uint32_t bsbMappingOffset;
  uint32_t vOrgMappingOffset;

  if (!table.ReadU16(&majorVersion) ||
      !table.ReadU16(&minorVersion) ||
      !table.ReadU32(&itemVariationStoreOffset) ||
      !table.ReadU32(&advanceHeightMappingOffset) ||
      !table.ReadU32(&tsbMappingOffset) ||
      !table.ReadU32(&bsbMappingOffset) ||
      !table.ReadU32(&vOrgMappingOffset)) {
    return DropVariations("Failed to read table header");
  }

  if (majorVersion != 1) {
    return DropVariations("Unknown table version");
  }

  if (itemVariationStoreOffset > length ||
      advanceHeightMappingOffset > length ||
      tsbMappingOffset > length ||
      bsbMappingOffset > length ||
      vOrgMappingOffset > length) {
    return DropVariations("Invalid subtable offset");
  }

  if (!ParseItemVariationStore(GetFont(), data + itemVariationStoreOffset,
                               length - itemVariationStoreOffset)) {
    return DropVariations("Failed to parse item variation store");
  }

  if (advanceHeightMappingOffset) {
    if (!ParseDeltaSetIndexMap(GetFont(), data + advanceHeightMappingOffset,
                               length - advanceHeightMappingOffset)) {
      return DropVariations("Failed to parse advance height mappings");
    }
  }

  if (tsbMappingOffset) {
    if (!ParseDeltaSetIndexMap(GetFont(), data + tsbMappingOffset,
                               length - tsbMappingOffset)) {
      return DropVariations("Failed to parse TSB mappings");
    }
  }

  if (bsbMappingOffset) {
    if (!ParseDeltaSetIndexMap(GetFont(), data + bsbMappingOffset,
                               length - bsbMappingOffset)) {
      return DropVariations("Failed to parse BSB mappings");
    }
  }

  if (vOrgMappingOffset) {
    if (!ParseDeltaSetIndexMap(GetFont(), data + vOrgMappingOffset,
                               length - vOrgMappingOffset)) {
      return DropVariations("Failed to parse vOrg mappings");
    }
  }

  this->m_data = data;
  this->m_length = length;

  return true;
}

bool OpenTypeVVAR::Serialize(OTSStream* out) {
  if (!out->Write(this->m_data, this->m_length)) {
    return Error("Failed to write VVAR table");
  }

  return true;
}

}  // namespace ots


<|start_filename|>src/stat.cc<|end_filename|>
// Copyright (c) 2018 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "stat.h"
#include "name.h"

namespace ots {

// -----------------------------------------------------------------------------
// OpenTypeSTAT
// -----------------------------------------------------------------------------

bool OpenTypeSTAT::ValidateNameId(uint16_t nameid, bool allowPredefined) {
  OpenTypeNAME* name = static_cast<OpenTypeNAME*>(
      GetFont()->GetTypedTable(OTS_TAG_NAME));

  if (!name || !name->IsValidNameId(nameid)) {
    Drop("Invalid nameID: %d", nameid);
    return false;
  }

  if (!allowPredefined && nameid < 26) {
    Warning("nameID out of range: %d", nameid);
    return true;
  }

  if ((nameid >= 26 && nameid <= 255) || nameid >= 32768) {
    Warning("nameID out of range: %d", nameid);
    return true;
  }

  return  true;
}

bool OpenTypeSTAT::Parse(const uint8_t* data, size_t length) {
  Buffer table(data, length);
  if (!table.ReadU16(&this->majorVersion) ||
      !table.ReadU16(&this->minorVersion) ||
      !table.ReadU16(&this->designAxisSize) ||
      !table.ReadU16(&this->designAxisCount) ||
      !table.ReadU32(&this->designAxesOffset) ||
      !table.ReadU16(&this->axisValueCount) ||
      !table.ReadU32(&this->offsetToAxisValueOffsets) ||
      !(this->minorVersion < 1 || table.ReadU16(&this->elidedFallbackNameID))) {
    return Drop("Failed to read table header");
  }
  if (this->majorVersion != 1) {
    return Drop("Unknown table version");
  }
  if (this->minorVersion > 2) {
    Warning("Unknown minor version, downgrading to 2");
    this->minorVersion = 2;
  }

  if (this->designAxisSize < sizeof(AxisRecord)) {
    return Drop("Invalid designAxisSize");
  }

  size_t headerEnd = table.offset();

  if (this->designAxisCount == 0) {
    if (this->designAxesOffset != 0) {
      Warning("Unexpected non-zero designAxesOffset");
      this->designAxesOffset = 0;
    }
  } else {
    if (this->designAxesOffset < headerEnd ||
        size_t(this->designAxesOffset) +
          size_t(this->designAxisCount) * size_t(this->designAxisSize) > length) {
      return Drop("Invalid designAxesOffset");
    }
  }

  for (size_t i = 0; i < this->designAxisCount; i++) {
    table.set_offset(this->designAxesOffset + i * this->designAxisSize);
    this->designAxes.emplace_back();
    auto& axis = this->designAxes[i];
    if (!table.ReadU32(&axis.axisTag) ||
        !table.ReadU16(&axis.axisNameID) ||
        !table.ReadU16(&axis.axisOrdering)) {
      return Drop("Failed to read design axis");
    }
    if (!CheckTag(axis.axisTag)) {
      return Drop("Bad design axis tag");
    }
    if (!ValidateNameId(axis.axisNameID, false)) {
      return true;
    }
  }

  // TODO
  // - check that all axes defined in fvar are covered by STAT
  // - check that axisOrdering values are not duplicated (warn only)

  if (this->axisValueCount == 0) {
    if (this->offsetToAxisValueOffsets != 0) {
      Warning("Unexpected non-zero offsetToAxisValueOffsets");
      this->offsetToAxisValueOffsets = 0;
    }
  } else {
    if (this->offsetToAxisValueOffsets < headerEnd ||
        size_t(this->offsetToAxisValueOffsets) +
          size_t(this->axisValueCount) * sizeof(uint16_t) > length) {
      return Drop("Invalid offsetToAxisValueOffsets");
    }
  }

  for (size_t i = 0; i < this->axisValueCount; i++) {
    table.set_offset(this->offsetToAxisValueOffsets + i * sizeof(uint16_t));
    uint16_t axisValueOffset;
    if (!table.ReadU16(&axisValueOffset)) {
      return Drop("Failed to read axis value offset");
    }
    if (this->offsetToAxisValueOffsets + axisValueOffset > length) {
      return Drop("Invalid axis value offset");
    }
    table.set_offset(this->offsetToAxisValueOffsets + axisValueOffset);
    uint16_t format;
    if (!table.ReadU16(&format)) {
      return Drop("Failed to read axis value format");
    }
    this->axisValues.emplace_back(format);
    auto& axisValue = axisValues[i];
    switch (format) {
    case 1:
      if (!table.ReadU16(&axisValue.format1.axisIndex) ||
          !table.ReadU16(&axisValue.format1.flags) ||
          !table.ReadU16(&axisValue.format1.valueNameID) ||
          !table.ReadS32(&axisValue.format1.value)) {
        return Drop("Failed to read axis value (format 1)");
      }
      if (axisValue.format1.axisIndex >= this->designAxisCount) {
        return Drop("Axis index out of range");
      }
      if ((axisValue.format1.flags & 0xFFFCu) != 0) {
        Warning("Unexpected axis value flags");
        axisValue.format1.flags &= ~0xFFFCu;
      }
      if (!ValidateNameId(axisValue.format1.valueNameID)) {
        return true;
      }
      break;
    case 2:
      if (!table.ReadU16(&axisValue.format2.axisIndex) ||
          !table.ReadU16(&axisValue.format2.flags) ||
          !table.ReadU16(&axisValue.format2.valueNameID) ||
          !table.ReadS32(&axisValue.format2.nominalValue) ||
          !table.ReadS32(&axisValue.format2.rangeMinValue) ||
          !table.ReadS32(&axisValue.format2.rangeMaxValue)) {
        return Drop("Failed to read axis value (format 2)");
      }
      if (axisValue.format2.axisIndex >= this->designAxisCount) {
        return Drop("Axis index out of range");
      }
      if ((axisValue.format2.flags & 0xFFFCu) != 0) {
        Warning("Unexpected axis value flags");
        axisValue.format1.flags &= ~0xFFFCu;
      }
      if (!ValidateNameId(axisValue.format2.valueNameID)) {
        return true;
      }
      if (!(axisValue.format2.rangeMinValue <= axisValue.format2.nominalValue &&
            axisValue.format2.nominalValue <= axisValue.format2.rangeMaxValue)) {
        Warning("Bad axis value range or nominal value");
      }
      break;
    case 3:
      if (!table.ReadU16(&axisValue.format3.axisIndex) ||
          !table.ReadU16(&axisValue.format3.flags) ||
          !table.ReadU16(&axisValue.format3.valueNameID) ||
          !table.ReadS32(&axisValue.format3.value) ||
          !table.ReadS32(&axisValue.format3.linkedValue)) {
        return Drop("Failed to read axis value (format 3)");
      }
      if (axisValue.format3.axisIndex >= this->designAxisCount) {
        return Drop("Axis index out of range");
      }
      if ((axisValue.format3.flags & 0xFFFCu) != 0) {
        Warning("Unexpected axis value flags");
        axisValue.format3.flags &= ~0xFFFCu;
      }
      if (!ValidateNameId(axisValue.format3.valueNameID)) {
        return true;
      }
      break;
    case 4:
      if (this->minorVersion < 2) {
        return Drop("Invalid table minorVersion for format 4 axis values: %d", this->minorVersion);
      }
      if (!table.ReadU16(&axisValue.format4.axisCount) ||
          !table.ReadU16(&axisValue.format4.flags) ||
          !table.ReadU16(&axisValue.format4.valueNameID)) {
        return Drop("Failed to read axis value (format 4)");
      }
      if (axisValue.format4.axisCount > this->designAxisCount) {
        return Drop("Axis count out of range");
      }
      if ((axisValue.format4.flags & 0xFFFCu) != 0) {
        Warning("Unexpected axis value flags");
        axisValue.format4.flags &= ~0xFFFCu;
      }
      if (!ValidateNameId(axisValue.format4.valueNameID)) {
        return true;
      }
      for (unsigned j = 0; j < axisValue.format4.axisCount; j++) {
        axisValue.format4.axisValues.emplace_back();
        auto& v = axisValue.format4.axisValues[j];
        if (!table.ReadU16(&v.axisIndex) ||
            !table.ReadS32(&v.value)) {
          return Drop("Failed to read axis value");
        }
        if (v.axisIndex >= this->designAxisCount) {
          return Drop("Axis index out of range");
        }
      }
      break;
    default:
      return Drop("Unknown axis value format");
    }
  }

  return true;
}

bool OpenTypeSTAT::Serialize(OTSStream* out) {
  off_t tableStart = out->Tell();

  size_t headerSize = 5 * sizeof(uint16_t) + 2 * sizeof(uint32_t);
  if (this->minorVersion >= 1) {
    headerSize += sizeof(uint16_t);
  }

  if (this->designAxisCount == 0) {
    this->designAxesOffset = 0;
  } else {
    this->designAxesOffset = headerSize;
  }

  this->designAxisSize = sizeof(AxisRecord);

  if (this->axisValueCount == 0) {
    this->offsetToAxisValueOffsets = 0;
  } else {
    if (this->designAxesOffset == 0) {
      this->offsetToAxisValueOffsets = headerSize;
    } else {
      this->offsetToAxisValueOffsets = this->designAxesOffset + this->designAxisCount * this->designAxisSize;
    }
  }

  if (!out->WriteU16(this->majorVersion) ||
      !out->WriteU16(this->minorVersion) ||
      !out->WriteU16(this->designAxisSize) ||
      !out->WriteU16(this->designAxisCount) ||
      !out->WriteU32(this->designAxesOffset) ||
      !out->WriteU16(this->axisValueCount) ||
      !out->WriteU32(this->offsetToAxisValueOffsets) ||
      !(this->minorVersion < 1 || out->WriteU16(this->elidedFallbackNameID))) {
    return Error("Failed to write table header");
  }

  if (this->designAxisCount > 0) {
    if (out->Tell() - tableStart != this->designAxesOffset) {
      return Error("Error computing designAxesOffset");
    }
  }

  for (unsigned i = 0; i < this->designAxisCount; i++) {
    const auto& axis = this->designAxes[i];
    if (!out->WriteU32(axis.axisTag) ||
        !out->WriteU16(axis.axisNameID) ||
        !out->WriteU16(axis.axisOrdering)) {
      return Error("Failed to write design axis");
    }
  }

  if (this->axisValueCount > 0) {
    if (out->Tell() - tableStart != this->offsetToAxisValueOffsets) {
      return Error("Error computing offsetToAxisValueOffsets");
    }
  }

  uint32_t axisValueOffset = this->axisValueCount * sizeof(uint16_t);
  for (unsigned i = 0; i < this->axisValueCount; i++) {
    const auto& value = this->axisValues[i];
    if (!out->WriteU16(axisValueOffset)) {
      return Error("Failed to write axis value offset");
    }
    axisValueOffset += value.Length();
  }
  for (unsigned i = 0; i < this->axisValueCount; i++) {
    const auto& value = this->axisValues[i];
    if (!out->WriteU16(value.format)) {
      return Error("Failed to write axis value");
    }
    switch (value.format) {
    case 1:
      if (!out->WriteU16(value.format1.axisIndex) ||
          !out->WriteU16(value.format1.flags) ||
          !out->WriteU16(value.format1.valueNameID) ||
          !out->WriteS32(value.format1.value)) {
        return Error("Failed to write axis value");
      }
      break;
    case 2:
      if (!out->WriteU16(value.format2.axisIndex) ||
          !out->WriteU16(value.format2.flags) ||
          !out->WriteU16(value.format2.valueNameID) ||
          !out->WriteS32(value.format2.nominalValue) ||
          !out->WriteS32(value.format2.rangeMinValue) ||
          !out->WriteS32(value.format2.rangeMaxValue)) {
        return Error("Failed to write axis value");
      }
      break;
    case 3:
      if (!out->WriteU16(value.format3.axisIndex) ||
          !out->WriteU16(value.format3.flags) ||
          !out->WriteU16(value.format3.valueNameID) ||
          !out->WriteS32(value.format3.value) ||
          !out->WriteS32(value.format3.linkedValue)) {
        return Error("Failed to write axis value");
      }
      break;
    case 4:
      if (!out->WriteU16(value.format4.axisCount) ||
          !out->WriteU16(value.format4.flags) ||
          !out->WriteU16(value.format4.valueNameID)) {
        return Error("Failed to write axis value");
      }
      for (unsigned j = 0; j < value.format4.axisValues.size(); j++) {
        if (!out->WriteU16(value.format4.axisValues[j].axisIndex) ||
            !out->WriteS32(value.format4.axisValues[j].value)) {
          return Error("Failed to write axis value");
        }
      }
      break;
    default:
      return Error("Bad value format");
    }
  }

  return true;
}

}  // namespace ots


<|start_filename|>src/avar.h<|end_filename|>
// Copyright (c) 2018 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_AVAR_H_
#define OTS_AVAR_H_

#include "ots.h"

#include <vector>

namespace ots {

// -----------------------------------------------------------------------------
// OpenTypeAVAR Interface
// -----------------------------------------------------------------------------

class OpenTypeAVAR : public Table {
 public:
  explicit OpenTypeAVAR(Font* font, uint32_t tag)
      : Table(font, tag, tag) { }

  bool Parse(const uint8_t* data, size_t length);
  bool Serialize(OTSStream* out);

 private:
  uint16_t majorVersion;
  uint16_t minorVersion;
  uint16_t reserved;
  uint16_t axisCount;

  struct AxisValueMap {
    int16_t fromCoordinate;
    int16_t toCoordinate;
  };

  std::vector<std::vector<AxisValueMap>> axisSegmentMaps;
};

}  // namespace ots

#endif  // OTS_AVAR_H_


<|start_filename|>src/glat.h<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_GLAT_H_
#define OTS_GLAT_H_

#include <vector>

#include "ots.h"
#include "graphite.h"

namespace ots {

// -----------------------------------------------------------------------------
// OpenTypeGLAT_Basic Interface
// -----------------------------------------------------------------------------

class OpenTypeGLAT_Basic : public Table {
 public:
  explicit OpenTypeGLAT_Basic(Font* font, uint32_t tag)
      : Table(font, tag, tag) { }

  virtual bool Parse(const uint8_t* data, size_t length) = 0;
  virtual bool Serialize(OTSStream* out) = 0;
};

// -----------------------------------------------------------------------------
// OpenTypeGLAT_v1
// -----------------------------------------------------------------------------

class OpenTypeGLAT_v1 : public OpenTypeGLAT_Basic {
 public:
  explicit OpenTypeGLAT_v1(Font* font, uint32_t tag)
      : OpenTypeGLAT_Basic(font, tag) { }

  bool Parse(const uint8_t* data, size_t length);
  bool Serialize(OTSStream* out);

 private:
  struct GlatEntry : public TablePart<OpenTypeGLAT_v1> {
    explicit GlatEntry(OpenTypeGLAT_v1* parent)
        : TablePart<OpenTypeGLAT_v1>(parent) { }
    bool ParsePart(Buffer& table);
    bool SerializePart(OTSStream* out) const;
    uint8_t attNum;
    uint8_t num;
    std::vector<int16_t> attributes;
  };
  uint32_t version;
  std::vector<GlatEntry> entries;
};

// -----------------------------------------------------------------------------
// OpenTypeGLAT_v2
// -----------------------------------------------------------------------------

class OpenTypeGLAT_v2 : public OpenTypeGLAT_Basic {
 public:
  explicit OpenTypeGLAT_v2(Font* font, uint32_t tag)
      : OpenTypeGLAT_Basic(font, tag) { }

  bool Parse(const uint8_t* data, size_t length);
  bool Serialize(OTSStream* out);

 private:
 struct GlatEntry : public TablePart<OpenTypeGLAT_v2> {
   explicit GlatEntry(OpenTypeGLAT_v2* parent)
      : TablePart<OpenTypeGLAT_v2>(parent) { }
   bool ParsePart(Buffer& table);
   bool SerializePart(OTSStream* out) const;
   int16_t attNum;
   int16_t num;
   std::vector<int16_t> attributes;
  };
  uint32_t version;
  std::vector<GlatEntry> entries;
};

// -----------------------------------------------------------------------------
// OpenTypeGLAT_v3
// -----------------------------------------------------------------------------

class OpenTypeGLAT_v3 : public OpenTypeGLAT_Basic {
 public:
  explicit OpenTypeGLAT_v3(Font* font, uint32_t tag)
     : OpenTypeGLAT_Basic(font, tag) { }

  bool Parse(const uint8_t* data, size_t length) {
    return this->Parse(data, length, false);
  }
  bool Serialize(OTSStream* out);

 private:
  bool Parse(const uint8_t* data, size_t length, bool prevent_decompression);
  struct GlyphAttrs : public TablePart<OpenTypeGLAT_v3> {
    explicit GlyphAttrs(OpenTypeGLAT_v3* parent)
      : TablePart<OpenTypeGLAT_v3>(parent), octabox(parent) { }
    bool ParsePart(Buffer& table) { return false; }
    bool ParsePart(Buffer& table, const size_t size);
    bool SerializePart(OTSStream* out) const;
    struct OctaboxMetrics : public TablePart<OpenTypeGLAT_v3> {
      explicit OctaboxMetrics(OpenTypeGLAT_v3* parent)
          : TablePart<OpenTypeGLAT_v3>(parent) { }
      bool ParsePart(Buffer& table);
      bool SerializePart(OTSStream* out) const;
      struct SubboxEntry : public TablePart<OpenTypeGLAT_v3> {
        explicit SubboxEntry(OpenTypeGLAT_v3* parent)
            : TablePart<OpenTypeGLAT_v3>(parent) { }
        bool ParsePart(Buffer& table);
        bool SerializePart(OTSStream* out) const;
        uint8_t left;
        uint8_t right;
        uint8_t bottom;
        uint8_t top;
        uint8_t diag_pos_min;
        uint8_t diag_pos_max;
        uint8_t diag_neg_min;
        uint8_t diag_neg_max;
      };
      uint16_t subbox_bitmap;
      uint8_t diag_neg_min;
      uint8_t diag_neg_max;
      uint8_t diag_pos_min;
      uint8_t diag_pos_max;
      std::vector<SubboxEntry> subboxes;
    };
    struct GlatEntry : public TablePart<OpenTypeGLAT_v3> {
      explicit GlatEntry(OpenTypeGLAT_v3* parent)
          : TablePart<OpenTypeGLAT_v3>(parent) { }
      bool ParsePart(Buffer& table);
      bool SerializePart(OTSStream* out) const;
      int16_t attNum;
      int16_t num;
      std::vector<int16_t> attributes;
     };
    OctaboxMetrics octabox;
    std::vector<GlatEntry> entries;
  };
  uint32_t version;
  uint32_t compHead;  // compression header
  static const uint32_t SCHEME = 0xF8000000;
  static const uint32_t FULL_SIZE = 0x07FFFFFF;
  static const uint32_t RESERVED = 0x07FFFFFE;
  static const uint32_t OCTABOXES = 0x00000001;
  std::vector<GlyphAttrs> entries;
};

// -----------------------------------------------------------------------------
// OpenTypeGLAT
// -----------------------------------------------------------------------------

class OpenTypeGLAT : public Table {
 public:
  explicit OpenTypeGLAT(Font* font, uint32_t tag)
      : Table(font, tag, tag), font(font), tag(tag) { }
  OpenTypeGLAT(const OpenTypeGLAT& other) = delete;
  OpenTypeGLAT& operator=(const OpenTypeGLAT& other) = delete;
  ~OpenTypeGLAT() { delete handler; }

  bool Parse(const uint8_t* data, size_t length);
  bool Serialize(OTSStream* out);

 private:
  Font* font;
  uint32_t tag;
  OpenTypeGLAT_Basic* handler = nullptr;
};

}  // namespace ots

#endif  // OTS_GLAT_H_


<|start_filename|>src/prep.cc<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "prep.h"

// prep - Control Value Program
// http://www.microsoft.com/typography/otspec/prep.htm

namespace ots {

bool OpenTypePREP::Parse(const uint8_t *data, size_t length) {
  Buffer table(data, length);

  if (length >= 128 * 1024u) {
    // almost all prep tables are less than 9k bytes.
    return Error("Table length %ld > 120K", length);
  }

  if (!table.Skip(length)) {
    return Error("Failed to read table of length %ld", length);
  }

  this->m_data = data;
  this->m_length = length;
  return true;
}

bool OpenTypePREP::Serialize(OTSStream *out) {
  if (!out->Write(this->m_data, this->m_length)) {
    return Error("Failed to write table length");
  }

  return true;
}

bool OpenTypePREP::ShouldSerialize() {
  return Table::ShouldSerialize() &&
         // this table is not for CFF fonts.
         GetFont()->GetTable(OTS_TAG_GLYF) != NULL;
}

}  // namespace ots


<|start_filename|>src/metrics.h<|end_filename|>
// Copyright (c) 2011-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_METRICS_H_
#define OTS_METRICS_H_

#include <new>
#include <utility>
#include <vector>

#include "ots.h"

namespace ots {

class OpenTypeMetricsHeader : public Table {
 public:
  explicit OpenTypeMetricsHeader(Font *font, uint32_t tag, uint32_t type)
      : Table(font, tag, type) { }

  bool Parse(const uint8_t *data, size_t length);
  bool Serialize(OTSStream *out);

  uint32_t version;
  int16_t ascent;
  int16_t descent;
  int16_t linegap;
  uint16_t adv_width_max;
  int16_t min_sb1;
  int16_t min_sb2;
  int16_t max_extent;
  int16_t caret_slope_rise;
  int16_t caret_slope_run;
  int16_t caret_offset;
  uint16_t num_metrics;
};

struct OpenTypeMetricsTable : public Table {
 public:
  explicit OpenTypeMetricsTable(Font *font, uint32_t tag, uint32_t type,
                                uint32_t header_tag)
      : Table(font, tag, type), m_header_tag(header_tag) { }

  bool Parse(const uint8_t *data, size_t length);
  bool Serialize(OTSStream *out);

 private:
  uint32_t m_header_tag;

  std::vector<std::pair<uint16_t, int16_t> > entries;
  std::vector<int16_t> sbs;
};

}  // namespace ots

#endif  // OTS_METRICS_H_


<|start_filename|>src/vdmx.h<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_VDMX_H_
#define OTS_VDMX_H_

#include <vector>

#include "ots.h"

namespace ots {

struct OpenTypeVDMXRatioRecord {
  uint8_t charset;
  uint8_t x_ratio;
  uint8_t y_start_ratio;
  uint8_t y_end_ratio;
};

struct OpenTypeVDMXVTable {
  uint16_t y_pel_height;
  int16_t y_max;
  int16_t y_min;
};

struct OpenTypeVDMXGroup {
  uint16_t recs;
  uint8_t startsz;
  uint8_t endsz;
  std::vector<OpenTypeVDMXVTable> entries;
};

class OpenTypeVDMX : public Table {
 public:
  explicit OpenTypeVDMX(Font *font, uint32_t tag)
      : Table(font, tag, tag) { }

  bool Parse(const uint8_t *data, size_t length);
  bool Serialize(OTSStream *out);
  bool ShouldSerialize();

 private:
  uint16_t version;
  uint16_t num_recs;
  uint16_t num_ratios;
  std::vector<OpenTypeVDMXRatioRecord> rat_ranges;
  std::vector<uint16_t> offsets;
  std::vector<OpenTypeVDMXGroup> groups;
};

}  // namespace ots

#endif  // OTS_VDMX_H_


<|start_filename|>src/glyf.h<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_GLYF_H_
#define OTS_GLYF_H_

#include <new>
#include <utility>
#include <vector>

#include "ots.h"

namespace ots {
class OpenTypeMAXP;

class OpenTypeGLYF : public Table {
 public:
  explicit OpenTypeGLYF(Font *font, uint32_t tag)
      : Table(font, tag, tag), maxp(NULL) { }

  bool Parse(const uint8_t *data, size_t length);
  bool Serialize(OTSStream *out);

 private:
  bool ParseFlagsForSimpleGlyph(Buffer &glyph,
                                uint32_t num_flags,
                                uint32_t *flag_index,
                                uint32_t *coordinates_length);
  bool ParseSimpleGlyph(Buffer &glyph, int16_t num_contours);
  bool ParseCompositeGlyph(Buffer &glyph);

  OpenTypeMAXP* maxp;

  std::vector<std::pair<const uint8_t*, size_t> > iov;
};

}  // namespace ots

#endif  // OTS_GLYF_H_


<|start_filename|>src/head.h<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_HEAD_H_
#define OTS_HEAD_H_

#include "ots.h"

namespace ots {

class OpenTypeHEAD : public Table {
 public:
  explicit OpenTypeHEAD(Font *font, uint32_t tag)
      : Table(font, tag, tag) { }

  bool Parse(const uint8_t *data, size_t length);
  bool Serialize(OTSStream *out);

  uint32_t revision;
  uint16_t flags;
  uint16_t upem;
  uint64_t created;
  uint64_t modified;

  int16_t xmin, xmax;
  int16_t ymin, ymax;

  uint16_t mac_style;
  uint16_t min_ppem;
  int16_t index_to_loc_format;
};

}  // namespace ots

#endif  // OTS_HEAD_H_


<|start_filename|>src/gloc.h<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_GLOC_H_
#define OTS_GLOC_H_

#include <vector>

#include "ots.h"
#include "graphite.h"

namespace ots {

class OpenTypeGLOC : public Table {
 public:
  explicit OpenTypeGLOC(Font* font, uint32_t tag)
      : Table(font, tag, tag) { }

  bool Parse(const uint8_t* data, size_t length);
  bool Serialize(OTSStream* out);
  const std::vector<uint32_t>& GetLocations();

 private:
  uint32_t version;
  uint16_t flags;
  static const uint16_t LONG_FORMAT = 0b1;
  static const uint16_t ATTRIB_IDS = 0b10;
  uint16_t numAttribs;
  std::vector<uint32_t> locations;
  std::vector<uint16_t> attribIds;
};

}  // namespace ots

#endif  // OTS_GLOC_H_


<|start_filename|>src/kern.cc<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "kern.h"

// kern - Kerning
// http://www.microsoft.com/typography/otspec/kern.htm

namespace ots {

bool OpenTypeKERN::Parse(const uint8_t *data, size_t length) {
  Buffer table(data, length);

  uint16_t num_tables = 0;
  if (!table.ReadU16(&this->version) ||
      !table.ReadU16(&num_tables)) {
    return Error("Failed to read table header");
  }

  if (this->version > 0) {
    return Drop("Unsupported table version: %d", this->version);
  }

  if (num_tables == 0) {
    return Drop("nTables is zero");
  }

  this->subtables.reserve(num_tables);
  for (unsigned i = 0; i < num_tables; ++i) {
    OpenTypeKERNFormat0 subtable;
    uint16_t sub_length = 0;

    if (!table.ReadU16(&subtable.version) ||
        !table.ReadU16(&sub_length)) {
      return Error("Failed to read subtable %d header", i);
    }

    if (subtable.version > 0) {
      Warning("Ignoring subtable %d with unsupported version: %d",
              i, subtable.version);
      continue;
    }

    const size_t current_offset = table.offset();
    if (current_offset - 4 + sub_length > length) {
      return Error("Bad subtable %d offset %ld", i, current_offset);
    }

    if (!table.ReadU16(&subtable.coverage)) {
      return Error("Failed to read subtable %d coverage", i);
    }

    if (!(subtable.coverage & 0x1)) {
      Warning(
          "We don't support vertical data as the renderer doesn't support it.");
      continue;
    }
    if (subtable.coverage & 0xF0) {
      return Drop("Reserved fields should be zero");
    }
    const uint32_t format = (subtable.coverage & 0xFF00) >> 8;
    if (format != 0) {
      Warning("Ignoring subtable %d with unsupported format: %d", i, format);
      continue;
    }

    // Parse the format 0 field.
    uint16_t num_pairs = 0;
    if (!table.ReadU16(&num_pairs) ||
        !table.ReadU16(&subtable.search_range) ||
        !table.ReadU16(&subtable.entry_selector) ||
        !table.ReadU16(&subtable.range_shift)) {
      return Error("Failed to read subtable %d format 0 fields", i);
    }

    if (!num_pairs) {
      return Drop("Zero length subtable is found");
    }

    // Sanity checks for search_range, entry_selector, and range_shift. See the
    // comment in ots.cc for details.
    const size_t kFormat0PairSize = 6;  // left, right, and value. 2 bytes each.
    if (num_pairs > (65536 / kFormat0PairSize)) {
      // Some fonts (e.g. calibri.ttf, pykes_peak_zero.ttf) have pairs >= 10923.
      return Drop("Too large subtable");
    }
    unsigned max_pow2 = 0;
    while (1u << (max_pow2 + 1) <= num_pairs) {
      ++max_pow2;
    }
    const uint16_t expected_search_range = (1u << max_pow2) * kFormat0PairSize;
    if (subtable.search_range != expected_search_range) {
      Warning("bad search range");
      subtable.search_range = expected_search_range;
    }
    if (subtable.entry_selector != max_pow2) {
      return Error("Bad subtable %d entry selector %d", i, subtable.entry_selector);
    }
    const uint16_t expected_range_shift =
        kFormat0PairSize * num_pairs - subtable.search_range;
    if (subtable.range_shift != expected_range_shift) {
      Warning("bad range shift");
      subtable.range_shift = expected_range_shift;
    }

    // Read kerning pairs.
    subtable.pairs.reserve(num_pairs);
    uint32_t last_pair = 0;
    for (unsigned j = 0; j < num_pairs; ++j) {
      OpenTypeKERNFormat0Pair kerning_pair;
      if (!table.ReadU16(&kerning_pair.left) ||
          !table.ReadU16(&kerning_pair.right) ||
          !table.ReadS16(&kerning_pair.value)) {
        return Error("Failed to read subtable %d kerning pair %d", i, j);
      }
      const uint32_t current_pair
          = (kerning_pair.left << 16) + kerning_pair.right;
      if (j != 0 && current_pair <= last_pair) {
        // Many free fonts don't follow this rule, so we don't call OTS_FAILURE
        // in order to support these fonts.
        return Drop("Kerning pairs are not sorted");
      }
      last_pair = current_pair;
      subtable.pairs.push_back(kerning_pair);
    }

    this->subtables.push_back(subtable);
  }

  if (!this->subtables.size()) {
    return Drop("All subtables were removed");
  }

  return true;
}

bool OpenTypeKERN::Serialize(OTSStream *out) {
  const uint16_t num_subtables = static_cast<uint16_t>(this->subtables.size());
  if (num_subtables != this->subtables.size() ||
      !out->WriteU16(this->version) ||
      !out->WriteU16(num_subtables)) {
    return Error("Failed to write kern table header");
  }

  for (uint16_t i = 0; i < num_subtables; ++i) {
    const size_t length = 14 + (6 * this->subtables[i].pairs.size());
    if (length > std::numeric_limits<uint16_t>::max() ||
        !out->WriteU16(this->subtables[i].version) ||
        !out->WriteU16(static_cast<uint16_t>(length)) ||
        !out->WriteU16(this->subtables[i].coverage) ||
        !out->WriteU16(
            static_cast<uint16_t>(this->subtables[i].pairs.size())) ||
        !out->WriteU16(this->subtables[i].search_range) ||
        !out->WriteU16(this->subtables[i].entry_selector) ||
        !out->WriteU16(this->subtables[i].range_shift)) {
      return Error("Failed to write kern subtable %d", i);
    }
    for (unsigned j = 0; j < this->subtables[i].pairs.size(); ++j) {
      if (!out->WriteU16(this->subtables[i].pairs[j].left) ||
          !out->WriteU16(this->subtables[i].pairs[j].right) ||
          !out->WriteS16(this->subtables[i].pairs[j].value)) {
        return Error("Failed to write kern pair %d for subtable %d", j, i);
      }
    }
  }

  return true;
}

bool OpenTypeKERN::ShouldSerialize() {
  return Table::ShouldSerialize() &&
         // this table is not for CFF fonts.
         GetFont()->GetTable(OTS_TAG_GLYF) != NULL;
}

}  // namespace ots


<|start_filename|>src/sile.h<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_SILE_H_
#define OTS_SILE_H_

#include "ots.h"
#include "graphite.h"

#include <vector>

namespace ots {

class OpenTypeSILE : public Table {
 public:
  explicit OpenTypeSILE(Font* font, uint32_t tag)
      : Table(font, tag, tag) { }

  bool Parse(const uint8_t* data, size_t length);
  bool Serialize(OTSStream* out);

 private:
  uint32_t version;
  uint32_t checksum;
  uint32_t createTime[2];
  uint32_t modifyTime[2];
  uint16_t fontNameLength;
  std::vector<uint16_t> fontName;
  uint16_t fontFileLength;
  std::vector<uint16_t> baseFile;
};

}  // namespace ots

#endif  // OTS_SILE_H_


<|start_filename|>src/cvar.cc<|end_filename|>
// Copyright (c) 2018 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cvar.h"

#include "fvar.h"
#include "variations.h"

namespace ots {

// -----------------------------------------------------------------------------
// OpenTypeCVAR
// -----------------------------------------------------------------------------

bool OpenTypeCVAR::Parse(const uint8_t* data, size_t length) {
  Buffer table(data, length);

  uint16_t majorVersion;
  uint16_t minorVersion;

  if (!table.ReadU16(&majorVersion) ||
      !table.ReadU16(&minorVersion)) {
    return Drop("Failed to read table header");
  }

  if (majorVersion != 1) {
    return Drop("Unknown table version");
  }

  OpenTypeFVAR* fvar = static_cast<OpenTypeFVAR*>(
      GetFont()->GetTypedTable(OTS_TAG_FVAR));
  if (!fvar) {
    return DropVariations("Required fvar table is missing");
  }

  if (!ParseVariationData(GetFont(), data + table.offset(), length - table.offset(),
                          fvar->AxisCount(), 0)) {
    return Drop("Failed to parse variation data");
  }

  this->m_data = data;
  this->m_length = length;

  return true;
}

bool OpenTypeCVAR::Serialize(OTSStream* out) {
  if (!out->Write(this->m_data, this->m_length)) {
    return Error("Failed to write cvar table");
  }

  return true;
}

}  // namespace ots


<|start_filename|>src/cvt.cc<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cvt.h"

// cvt - Control Value Table
// http://www.microsoft.com/typography/otspec/cvt.htm

namespace ots {

bool OpenTypeCVT::Parse(const uint8_t *data, size_t length) {
  Buffer table(data, length);

  if (length >= 128 * 1024u) {
    return Error("Length (%d) > 120K");  // almost all cvt tables are less than 4k bytes.
  }

  if (length % 2 != 0) {
    return Error("Uneven table length (%d)", length);
  }

  if (!table.Skip(length)) {
    return Error("Table length too high");
  }

  this->data = data;
  this->length = length;
  return true;
}

bool OpenTypeCVT::Serialize(OTSStream *out) {
  if (!out->Write(this->data, this->length)) {
    return Error("Failed to write cvt table");
  }

  return true;
}

bool OpenTypeCVT::ShouldSerialize() {
  return Table::ShouldSerialize() &&
         // this table is not for CFF fonts.
         GetFont()->GetTable(OTS_TAG_GLYF) != NULL;
}

}  // namespace ots


<|start_filename|>src/stat.h<|end_filename|>
// Copyright (c) 2018 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_STAT_H_
#define OTS_STAT_H_

#include <vector>

#include "ots.h"

namespace ots {

// -----------------------------------------------------------------------------
// OpenTypeSTAT Interface
// -----------------------------------------------------------------------------

class OpenTypeSTAT : public Table {
 public:
  explicit OpenTypeSTAT(Font* font, uint32_t tag)
      : Table(font, tag, tag) { }

  bool Parse(const uint8_t* data, size_t length);
  bool Serialize(OTSStream* out);

 private:
  bool ValidateNameId(uint16_t nameid, bool allowPredefined = true);

  uint16_t majorVersion;
  uint16_t minorVersion;
  uint16_t designAxisSize;
  uint16_t designAxisCount;
  uint32_t designAxesOffset;
  uint16_t axisValueCount;
  uint32_t offsetToAxisValueOffsets;
  uint16_t elidedFallbackNameID;

  struct AxisRecord {
    uint32_t axisTag;
    uint16_t axisNameID;
    uint16_t axisOrdering;
  };
  std::vector<AxisRecord> designAxes;

  typedef int32_t Fixed; /* 16.16 fixed-point value */

  struct AxisValueFormat1 {
    uint16_t axisIndex;
    uint16_t flags;
    uint16_t valueNameID;
    Fixed    value;
    static size_t Length() {
      return 3 * sizeof(uint16_t) + sizeof(Fixed);
    }
  };

  struct AxisValueFormat2 {
    uint16_t axisIndex;
    uint16_t flags;
    uint16_t valueNameID;
    Fixed    nominalValue;
    Fixed    rangeMinValue;
    Fixed    rangeMaxValue;
    static size_t Length() {
      return 3 * sizeof(uint16_t) + 3 * sizeof(Fixed);
    }
  };

  struct AxisValueFormat3 {
    uint16_t axisIndex;
    uint16_t flags;
    uint16_t valueNameID;
    Fixed    value;
    Fixed    linkedValue;
    static size_t Length() {
      return 3 * sizeof(uint16_t) + 2 * sizeof(Fixed);
    }
  };

  struct AxisValueFormat4 {
    uint16_t axisCount;
    uint16_t flags;
    uint16_t valueNameID;
    struct AxisValue {
      uint16_t axisIndex;
      Fixed    value;
    };
    std::vector<AxisValue> axisValues;
    size_t Length() const {
      return 3 * sizeof(uint16_t) + axisValues.size() * (sizeof(uint16_t) + sizeof(Fixed));
    }
  };

  struct AxisValueRecord {
    uint16_t format;
    union {
      AxisValueFormat1 format1;
      AxisValueFormat2 format2;
      AxisValueFormat3 format3;
      AxisValueFormat4 format4;
    };
    explicit AxisValueRecord(uint16_t format_)
      : format(format_)
    {
      if (format == 4) {
        new (&this->format4) AxisValueFormat4();
      }
    }
    AxisValueRecord(const AxisValueRecord& other_)
      : format(other_.format)
    {
      switch (format) {
      case 1:
        format1 = other_.format1;
        break;
      case 2:
        format2 = other_.format2;
        break;
      case 3:
        format3 = other_.format3;
        break;
      case 4:
        new (&this->format4) AxisValueFormat4();
        format4 = other_.format4;
        break;
      }
    }
    ~AxisValueRecord() {
      if (format == 4) {
        this->format4.~AxisValueFormat4();
      }
    }
    uint32_t Length() const {
      switch (format) {
      case 1:
        return sizeof(uint16_t) + format1.Length();
      case 2:
        return sizeof(uint16_t) + format2.Length();
      case 3:
        return sizeof(uint16_t) + format3.Length();
      case 4:
        return sizeof(uint16_t) + format4.Length();
      default:
        // can't happen
        return 0;
      }
    }
  };

  std::vector<AxisValueRecord> axisValues;
};

}  // namespace ots

#endif  // OTS_STAT_H_


<|start_filename|>src/ltsh.cc<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ltsh.h"

#include "maxp.h"

// LTSH - Linear Threshold
// http://www.microsoft.com/typography/otspec/ltsh.htm

namespace ots {

bool OpenTypeLTSH::Parse(const uint8_t *data, size_t length) {
  Buffer table(data, length);

  OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>(
      GetFont()->GetTypedTable(OTS_TAG_MAXP));
  if (!maxp) {
    return Error("Required maxp table is missing");
  }

  uint16_t num_glyphs = 0;
  if (!table.ReadU16(&this->version) ||
      !table.ReadU16(&num_glyphs)) {
    return Error("Failed to read table header");
  }

  if (this->version != 0) {
    return Drop("Unsupported version: %u", this->version);
  }

  if (num_glyphs != maxp->num_glyphs) {
    return Drop("Bad numGlyphs: %u", num_glyphs);
  }

  this->ypels.reserve(num_glyphs);
  for (unsigned i = 0; i < num_glyphs; ++i) {
    uint8_t pel = 0;
    if (!table.ReadU8(&pel)) {
      return Error("Failed to read pixels for glyph %d", i);
    }
    this->ypels.push_back(pel);
  }

  return true;
}

bool OpenTypeLTSH::Serialize(OTSStream *out) {
  const uint16_t num_ypels = static_cast<uint16_t>(this->ypels.size());
  if (num_ypels != this->ypels.size() ||
      !out->WriteU16(this->version) ||
      !out->WriteU16(num_ypels)) {
    return Error("Failed to write table header");
  }
  for (uint16_t i = 0; i < num_ypels; ++i) {
    if (!out->Write(&(this->ypels[i]), 1)) {
      return Error("Failed to write pixel size for glyph %d", i);
    }
  }

  return true;
}

bool OpenTypeLTSH::ShouldSerialize() {
  return Table::ShouldSerialize() &&
         // this table is not for CFF fonts.
         GetFont()->GetTable(OTS_TAG_GLYF) != NULL;
}

}  // namespace ots


<|start_filename|>util/test-context.h<|end_filename|>
// Copyright (c) 2014-2015 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef OTS_TEST_CONTEXT_H_
#define OTS_TEST_CONTEXT_H_

#include <cstdarg>

#include "opentype-sanitiser.h"

namespace ots {

class TestContext: public ots::OTSContext {
 public:
  TestContext(int level)
    : level_(level)
  { }

  void Message(int level, const char *format, ...) {
    va_list va;

    if (level > level_)
      return;

    if (level == 0)
      std::fprintf(stderr, "ERROR: ");
    else
      std::fprintf(stderr, "WARNING: ");
    va_start(va, format);
    std::vfprintf(stderr, format, va);
    std::fprintf(stderr, "\n");
    va_end(va);
  }

  ots::TableAction GetTableAction(uint32_t tag) {
    switch (tag) {
      case OTS_TAG('C','B','D','T'):
      case OTS_TAG('C','B','L','C'):
      case OTS_TAG('s','b','i','x'):
        return ots::TABLE_ACTION_PASSTHRU;
      default:
        return ots::TABLE_ACTION_DEFAULT;
    }
  }

private:
  int level_;
};

}  // namespace ots

#endif  // OTS_TEST_CONTEXT_H_


<|start_filename|>util/ots-idempotent.cc<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"

#if defined(HAVE_CORETEXT)
#include <ApplicationServices/ApplicationServices.h>
#elif defined(HAVE_FREETYPE)
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#elif defined(HAVE_WIN32)
#define NOMINMAX
#include <Windows.h>
#endif

#include <fstream>
#include <iostream>
#include <memory>
#include <vector>

#include "test-context.h"
#include "ots-memory-stream.h"

namespace {

int Usage(const char *argv0) {
  std::fprintf(stderr, "Usage: %s <ttf file>\n", argv0);
  return 1;
}

bool DumpResults(const uint8_t *result1, const size_t len1,
                 const uint8_t *result2, const size_t len2) {
  std::ofstream out1("out1.ttf", std::ofstream::out | std::ofstream::binary);
  std::ofstream out2("out2.ttf", std::ofstream::out | std::ofstream::binary);
  if (!out1.good() || !out2.good())
    return false;

  out1.write(reinterpret_cast<const char*>(result1), len1);
  out2.write(reinterpret_cast<const char*>(result2), len2);
  if (!out1.good() || !out2.good())
    return false;

  return true;
}

// Platform specific implementations.
bool VerifyTranscodedFont(uint8_t *result, const size_t len);

#if defined(HAVE_CORETEXT)
bool VerifyTranscodedFont(uint8_t *result, const size_t len) {
  CFDataRef data = CFDataCreate(0, result, len);
  if (!data) {
    return false;
  }

  CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data);
  CGFontRef cgFontRef = CGFontCreateWithDataProvider(dataProvider);
  CGDataProviderRelease(dataProvider);
  CFRelease(data);
  if (!cgFontRef) {
    return false;
  }

  size_t numGlyphs = CGFontGetNumberOfGlyphs(cgFontRef);
  CGFontRelease(cgFontRef);
  if (!numGlyphs) {
    return false;
  }
  return true;
}

#elif defined(HAVE_FREETYPE)
bool VerifyTranscodedFont(uint8_t *result, const size_t len) {
  FT_Library library;
  FT_Error error = ::FT_Init_FreeType(&library);
  if (error) {
    return false;
  }
  FT_Face dummy;
  error = ::FT_New_Memory_Face(library, result, len, 0, &dummy);
  if (error) {
    return false;
  }
  ::FT_Done_Face(dummy);
  ::FT_Done_FreeType(library);
  return true;
}

#elif defined(HAVE_WIN32)
// Windows
bool VerifyTranscodedFont(uint8_t *result, const size_t len) {
  DWORD num_fonts = 0;
  HANDLE handle = AddFontMemResourceEx(result, len, 0, &num_fonts);
  if (!handle) {
    return false;
  }
  RemoveFontMemResourceEx(handle);
  return true;
}

#else
bool VerifyTranscodedFont(uint8_t *result, const size_t len) {
  std::fprintf(stderr, "Can't verify the transcoded font on this platform.\n");
  return false;
}

#endif

}  // namespace

int main(int argc, char **argv) {
  if (argc != 2) return Usage(argv[0]);

  std::ifstream ifs(argv[1], std::ifstream::binary);
  if (!ifs.good()) {
    std::fprintf(stderr, "Failed to read file!\n");
    return 1;
  }
  std::vector<uint8_t> in((std::istreambuf_iterator<char>(ifs)),
                          (std::istreambuf_iterator<char>()));

  // A transcoded font is usually smaller than an original font.
  // However, it can be slightly bigger than the original one due to
  // name table replacement and/or padding for glyf table.
  //
  // However, a WOFF font gets decompressed and so can be *much* larger than
  // the original.
  std::unique_ptr<uint8_t[]> result(new uint8_t[in.size() * 8]);
  ots::MemoryStream output(result.get(), in.size() * 8);

  ots::TestContext context(0);

  if (!context.Process(&output, in.data(), in.size())) {
    std::fprintf(stderr, "Failed to sanitize file!\n");
    return 1;
  }
  const size_t result_len = output.Tell();

  std::unique_ptr<uint8_t[]> result2(new uint8_t[result_len]);
  ots::MemoryStream output2(result2.get(), result_len);
  if (!context.Process(&output2, result.get(), result_len)) {
    std::fprintf(stderr, "Failed to sanitize previous output!\n");
    return 1;
  }
  const size_t result2_len = output2.Tell();

  bool dump_results = false;
  if (result2_len != result_len) {
    std::fprintf(stderr, "Outputs differ in length\n");
    dump_results = true;
  } else if (std::memcmp(result2.get(), result.get(), result_len)) {
    std::fprintf(stderr, "Outputs differ in content\n");
    dump_results = true;
  }

  if (dump_results) {
    std::fprintf(stderr, "Dumping results to out1.tff and out2.tff\n");
    if (!DumpResults(result.get(), result_len, result2.get(), result2_len)) {
      std::fprintf(stderr, "Failed to dump output files.\n");
      return 1;
    }
  }

  // Verify that original font can be opened by the font renderer. If this
  // fails then no point in verfying the transcoded font.
  if (!VerifyTranscodedFont(in.data(), in.size())) {
    std::fprintf(stderr, "Failed to verify the original font\n");
    return 0;
  }

  // Verify that the transcoded font can be opened by the font renderer for
  // Linux (FreeType2), Mac OS X, or Windows.
  if (!VerifyTranscodedFont(result.get(), result_len)) {
    std::fprintf(stderr, "Failed to verify the transcoded font\n");
    return 1;
  }

  return 0;
}


<|start_filename|>src/avar.cc<|end_filename|>
// Copyright (c) 2018 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "avar.h"

#include "fvar.h"

namespace ots {

// -----------------------------------------------------------------------------
// OpenTypeAVAR
// -----------------------------------------------------------------------------

bool OpenTypeAVAR::Parse(const uint8_t* data, size_t length) {
  Buffer table(data, length);
  if (!table.ReadU16(&this->majorVersion) ||
      !table.ReadU16(&this->minorVersion) ||
      !table.ReadU16(&this->reserved) ||
      !table.ReadU16(&this->axisCount)) {
    return Drop("Failed to read table header");
  }
  if (this->majorVersion != 1) {
    return Drop("Unknown table version");
  }
  if (this->minorVersion > 0) {
    // we only know how to serialize version 1.0
    Warning("Downgrading minor version to 0");
    this->minorVersion = 0;
  }
  if (this->reserved != 0) {
    Warning("Expected reserved=0");
    this->reserved = 0;
  }

  OpenTypeFVAR* fvar = static_cast<OpenTypeFVAR*>(
      GetFont()->GetTypedTable(OTS_TAG_FVAR));
  if (!fvar) {
    return DropVariations("Required fvar table is missing");
  }
  if (axisCount != fvar->AxisCount()) {
    return Drop("Axis count mismatch");
  }

  for (size_t i = 0; i < this->axisCount; i++) {
    this->axisSegmentMaps.emplace_back();
    uint16_t positionMapCount;
    if (!table.ReadU16(&positionMapCount)) {
      return Drop("Failed to read position map count");
    }
    int foundRequiredMappings = 0;
    for (size_t j = 0; j < positionMapCount; j++) {
      AxisValueMap map;
      if (!table.ReadS16(&map.fromCoordinate) ||
          !table.ReadS16(&map.toCoordinate)) {
        return Drop("Failed to read axis value map");
      }
      if (map.fromCoordinate < -0x4000 ||
          map.fromCoordinate > 0x4000 ||
          map.toCoordinate < -0x4000 ||
          map.toCoordinate > 0x4000) {
        return Drop("Axis value map coordinate out of range");
      }
      if (j > 0) {
        if (map.fromCoordinate <= this->axisSegmentMaps[i].back().fromCoordinate ||
            map.toCoordinate < this->axisSegmentMaps[i].back().toCoordinate) {
          return Drop("Axis value map out of order");
        }
      }
      if ((map.fromCoordinate == -0x4000 && map.toCoordinate == -0x4000) ||
          (map.fromCoordinate == 0 && map.toCoordinate == 0) ||
          (map.fromCoordinate == 0x4000 && map.toCoordinate == 0x4000)) {
        ++foundRequiredMappings;
      }
      this->axisSegmentMaps[i].push_back(map);
    }
    if (positionMapCount > 0 && foundRequiredMappings != 3) {
      return Drop("A required mapping (for -1, 0 or 1) is missing");
    }
  }

  return true;
}

bool OpenTypeAVAR::Serialize(OTSStream* out) {
  if (!out->WriteU16(this->majorVersion) ||
      !out->WriteU16(this->minorVersion) ||
      !out->WriteU16(this->reserved) ||
      !out->WriteU16(this->axisCount)) {
    return Error("Failed to write table");
  }

  for (size_t i = 0; i < this->axisCount; i++) {
    const auto& axisValueMap = this->axisSegmentMaps[i];
    if (!out->WriteU16(axisValueMap.size())) {
      return Error("Failed to write table");
    }
    for (size_t j = 0; j < axisValueMap.size(); j++) {
      if (!out->WriteS16(axisValueMap[j].fromCoordinate) ||
          !out->WriteS16(axisValueMap[j].toCoordinate)) {
        return Error("Failed to write table");
      }
    }
  }

  return true;
}

}  // namespace ots


<|start_filename|>src/gasp.cc<|end_filename|>
// Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gasp.h"

// gasp - Grid-fitting And Scan-conversion Procedure
// http://www.microsoft.com/typography/otspec/gasp.htm

namespace ots {

bool OpenTypeGASP::Parse(const uint8_t *data, size_t length) {
  Buffer table(data, length);

  uint16_t num_ranges = 0;
  if (!table.ReadU16(&this->version) ||
      !table.ReadU16(&num_ranges)) {
    return Error("Failed to read table header");
  }

  if (this->version > 1) {
    // Lots of Linux fonts have bad version numbers...
    return Drop("Unsupported version: %u", this->version);
  }

  if (num_ranges == 0) {
    return Drop("numRanges is zero");
  }

  this->gasp_ranges.reserve(num_ranges);
  for (unsigned i = 0; i < num_ranges; ++i) {
    uint16_t max_ppem = 0;
    uint16_t behavior = 0;
    if (!table.ReadU16(&max_ppem) ||
        !table.ReadU16(&behavior)) {
      return Error("Failed to read GASPRANGE %d", i);
    }
    if ((i > 0) && (this->gasp_ranges[i - 1].first >= max_ppem)) {
      // The records in the gaspRange[] array must be sorted in order of
      // increasing rangeMaxPPEM value.
      return Drop("Ranges are not sorted");
    }
    if ((i == num_ranges - 1u) &&  // never underflow.
        (max_ppem != 0xffffu)) {
      return Drop("The last record should be 0xFFFF as a sentinel value "
                  "for rangeMaxPPEM");
    }

    if (behavior >> 8) {
      Warning("Undefined bits are used: %x", behavior);
      // mask undefined bits.
      behavior &= 0x000fu;
    }

    if (this->version == 0 && (behavior >> 2) != 0) {
      Warning("Changed the version number to 1");
      this->version = 1;
    }

    this->gasp_ranges.push_back(std::make_pair(max_ppem, behavior));
  }

  return true;
}

bool OpenTypeGASP::Serialize(OTSStream *out) {
  const uint16_t num_ranges = static_cast<uint16_t>(this->gasp_ranges.size());
  if (num_ranges != this->gasp_ranges.size() ||
      !out->WriteU16(this->version) ||
      !out->WriteU16(num_ranges)) {
    return Error("Failed to write table header");
  }

  for (uint16_t i = 0; i < num_ranges; ++i) {
    if (!out->WriteU16(this->gasp_ranges[i].first) ||
        !out->WriteU16(this->gasp_ranges[i].second)) {
      return Error("Failed to write GASPRANGE %d", i);
    }
  }

  return true;
}

}  // namespace ots
