tor-browser

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

post.cc (5605B)


      1 // Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "post.h"
      6 
      7 #include "maxp.h"
      8 
      9 // post - PostScript
     10 // http://www.microsoft.com/typography/otspec/post.htm
     11 
     12 namespace ots {
     13 
     14 bool OpenTypePOST::Parse(const uint8_t *data, size_t length) {
     15  Buffer table(data, length);
     16 
     17  if (!table.ReadU32(&this->version)) {
     18    return Error("Failed to read table version");
     19  }
     20 
     21  if (this->version != 0x00010000 &&
     22      this->version != 0x00020000 &&
     23      this->version != 0x00030000) {
     24    // 0x00025000 is deprecated. We don't accept it.
     25    return Error("Unsupported table version 0x%x", this->version);
     26  }
     27 
     28  if (!table.ReadU32(&this->italic_angle) ||
     29      !table.ReadS16(&this->underline) ||
     30      !table.ReadS16(&this->underline_thickness) ||
     31      !table.ReadU32(&this->is_fixed_pitch) ||
     32      // We don't care about the memory usage fields. We'll set all these to
     33      // zero when serialising
     34      !table.Skip(16)) {
     35    return Error("Failed to read table header");
     36  }
     37 
     38  if (this->underline_thickness < 0) {
     39    this->underline_thickness = 1;
     40  }
     41 
     42  if (this->version == 0x00010000 || this->version == 0x00030000) {
     43    return true;
     44  }
     45 
     46  // We have a version 2 table with a list of Pascal strings at the end
     47 
     48  uint16_t num_glyphs = 0;
     49  if (!table.ReadU16(&num_glyphs)) {
     50    return Error("Failed to read numberOfGlyphs");
     51  }
     52 
     53  OpenTypeMAXP* maxp = static_cast<OpenTypeMAXP*>
     54    (GetFont()->GetTable(OTS_TAG_MAXP));
     55  if (!maxp) {
     56    return Error("Missing required maxp table");
     57  }
     58 
     59  if (num_glyphs == 0) {
     60    if (maxp->num_glyphs > 258) {
     61      return Error("Can't have no glyphs in the post table if there are more "
     62                   "than 258 glyphs in the font");
     63    }
     64    // workaround for fonts in http://www.fontsquirrel.com/fontface
     65    // (e.g., yataghan.ttf).
     66    this->version = 0x00010000;
     67    return Warning("Table version is 1, but no glyph names are found");
     68  }
     69 
     70  if (num_glyphs != maxp->num_glyphs) {
     71    // Note: Fixedsys500c.ttf seems to have inconsistent num_glyphs values.
     72    return Error("Bad number of glyphs: %d", num_glyphs);
     73  }
     74 
     75  this->glyph_name_index.resize(num_glyphs);
     76  for (unsigned i = 0; i < num_glyphs; ++i) {
     77    if (!table.ReadU16(&this->glyph_name_index[i])) {
     78      return Error("Failed to read glyph name %d", i);
     79    }
     80    // Note: A strict interpretation of the specification requires name indexes
     81    // are less than 32768. This, however, excludes fonts like unifont.ttf
     82    // which cover all of unicode.
     83  }
     84 
     85  // Now we have an array of Pascal strings. We have to check that they are all
     86  // valid and read them in.
     87  const size_t strings_offset = table.offset();
     88  const uint8_t *strings = data + strings_offset;
     89  const uint8_t *strings_end = data + length;
     90 
     91  for (;;) {
     92    if (strings == strings_end) break;
     93    const unsigned string_length = *strings;
     94    if (strings + 1 + string_length > strings_end) {
     95      return Error("Bad string length %d", string_length);
     96    }
     97    if (std::memchr(strings + 1, '\0', string_length)) {
     98      return Error("Bad string of length %d", string_length);
     99    }
    100    this->names.push_back(
    101        std::string(reinterpret_cast<const char*>(strings + 1), string_length));
    102    strings += 1 + string_length;
    103  }
    104  const unsigned num_strings = this->names.size();
    105 
    106  // check that all the references are within bounds
    107  for (unsigned i = 0; i < num_glyphs; ++i) {
    108    unsigned offset = this->glyph_name_index[i];
    109    if (offset < 258) {
    110      continue;
    111    }
    112 
    113    offset -= 258;
    114    if (offset >= num_strings) {
    115      return Error("Bad string index %d", offset);
    116    }
    117  }
    118 
    119  return true;
    120 }
    121 
    122 bool OpenTypePOST::Serialize(OTSStream *out) {
    123  // OpenType with CFF glyphs must have v3 post table.
    124  if (GetFont()->GetTable(OTS_TAG_CFF) && this->version != 0x00030000) {
    125    Warning("Only version supported for fonts with CFF table is 0x00030000"
    126            " not 0x%x", this->version);
    127    this->version = 0x00030000;
    128  }
    129 
    130  if (!out->WriteU32(this->version) ||
    131      !out->WriteU32(this->italic_angle) ||
    132      !out->WriteS16(this->underline) ||
    133      !out->WriteS16(this->underline_thickness) ||
    134      !out->WriteU32(this->is_fixed_pitch) ||
    135      !out->WriteU32(0) ||
    136      !out->WriteU32(0) ||
    137      !out->WriteU32(0) ||
    138      !out->WriteU32(0)) {
    139    return Error("Failed to write post header");
    140  }
    141 
    142  if (this->version != 0x00020000) {
    143    return true;  // v1.0 and v3.0 does not have glyph names.
    144  }
    145 
    146  const uint16_t num_indexes =
    147      static_cast<uint16_t>(this->glyph_name_index.size());
    148  if (num_indexes != this->glyph_name_index.size() ||
    149      !out->WriteU16(num_indexes)) {
    150    return Error("Failed to write number of indices");
    151  }
    152 
    153  for (uint16_t i = 0; i < num_indexes; ++i) {
    154    if (!out->WriteU16(this->glyph_name_index[i])) {
    155      return Error("Failed to write name index %d", i);
    156    }
    157  }
    158 
    159  // Now we just have to write out the strings in the correct order
    160  for (unsigned i = 0; i < this->names.size(); ++i) {
    161    const std::string& s = this->names[i];
    162    const uint8_t string_length = static_cast<uint8_t>(s.size());
    163    if (string_length != s.size() ||
    164        !out->Write(&string_length, 1)) {
    165      return Error("Failed to write string %d", i);
    166    }
    167    // Some ttf fonts (e.g., frank.ttf on Windows Vista) have zero-length name.
    168    // We allow them.
    169    if (string_length > 0 && !out->Write(s.data(), string_length)) {
    170      return Error("Failed to write string length for string %d", i);
    171    }
    172  }
    173 
    174  return true;
    175 }
    176 
    177 }  // namespace ots