tor-browser

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

glat.cc (15304B)


      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 "glat.h"
      6 
      7 #include "gloc.h"
      8 #include "mozilla/Compression.h"
      9 #include <list>
     10 #include <memory>
     11 
     12 namespace ots {
     13 
     14 // -----------------------------------------------------------------------------
     15 // OpenTypeGLAT_v1
     16 // -----------------------------------------------------------------------------
     17 
     18 bool OpenTypeGLAT_v1::Parse(const uint8_t* data, size_t length) {
     19  Buffer table(data, length);
     20  OpenTypeGLOC* gloc = static_cast<OpenTypeGLOC*>(
     21      GetFont()->GetTypedTable(OTS_TAG_GLOC));
     22  if (!gloc) {
     23    return DropGraphite("Required Gloc table is missing");
     24  }
     25 
     26  if (!table.ReadU32(&this->version) || this->version >> 16 != 1) {
     27    return DropGraphite("Failed to read version");
     28  }
     29 
     30  const std::vector<uint32_t>& locations = gloc->GetLocations();
     31  if (locations.empty()) {
     32    return DropGraphite("No locations from Gloc table");
     33  }
     34  std::list<uint32_t> unverified(locations.begin(), locations.end());
     35  while (table.remaining()) {
     36    GlatEntry entry(this);
     37    if (table.offset() > unverified.front()) {
     38      return DropGraphite("Offset check failed for a GlatEntry");
     39    }
     40    if (table.offset() == unverified.front()) {
     41      unverified.pop_front();
     42    }
     43    if (unverified.empty()) {
     44      return DropGraphite("Expected more locations");
     45    }
     46    if (!entry.ParsePart(table)) {
     47      return DropGraphite("Failed to read a GlatEntry");
     48    }
     49    this->entries.push_back(entry);
     50  }
     51 
     52  if (unverified.size() != 1 || unverified.front() != table.offset()) {
     53    return DropGraphite("%zu location(s) could not be verified", unverified.size());
     54  }
     55  if (table.remaining()) {
     56    return Warning("%zu bytes unparsed", table.remaining());
     57  }
     58  return true;
     59 }
     60 
     61 bool OpenTypeGLAT_v1::Serialize(OTSStream* out) {
     62  assert(ShouldSerialize());
     63  if (!out->WriteU32(this->version) ||
     64      !SerializeParts(this->entries, out)) {
     65    return Error("Failed to write table");
     66  }
     67  return true;
     68 }
     69 
     70 bool OpenTypeGLAT_v1::GlatEntry::ParsePart(Buffer& table) {
     71  if (!table.ReadU8(&this->attNum)) {
     72    return parent->Error("GlatEntry: Failed to read attNum");
     73  }
     74  if (!table.ReadU8(&this->num)) {
     75    return parent->Error("GlatEntry: Failed to read num");
     76  }
     77 
     78  //this->attributes.resize(this->num);
     79  for (int i = 0; i < this->num; ++i) {
     80    this->attributes.emplace_back();
     81    if (!table.ReadS16(&this->attributes[i])) {
     82      return parent->Error("GlatEntry: Failed to read attribute %u", i);
     83    }
     84  }
     85  return true;
     86 }
     87 
     88 bool OpenTypeGLAT_v1::GlatEntry::SerializePart(OTSStream* out) const {
     89  if (!out->WriteU8(this->attNum) ||
     90      !out->WriteU8(this->num) ||
     91      !SerializeParts(this->attributes, out)) {
     92    return parent->Error("GlatEntry: Failed to write");
     93  }
     94  return true;
     95 }
     96 
     97 // -----------------------------------------------------------------------------
     98 // OpenTypeGLAT_v2
     99 // -----------------------------------------------------------------------------
    100 
    101 bool OpenTypeGLAT_v2::Parse(const uint8_t* data, size_t length) {
    102  Buffer table(data, length);
    103  OpenTypeGLOC* gloc = static_cast<OpenTypeGLOC*>(
    104      GetFont()->GetTypedTable(OTS_TAG_GLOC));
    105  if (!gloc) {
    106    return DropGraphite("Required Gloc table is missing");
    107  }
    108 
    109  if (!table.ReadU32(&this->version) || this->version >> 16 != 1) {
    110    return DropGraphite("Failed to read version");
    111  }
    112 
    113  const std::vector<uint32_t>& locations = gloc->GetLocations();
    114  if (locations.empty()) {
    115    return DropGraphite("No locations from Gloc table");
    116  }
    117  std::list<uint32_t> unverified(locations.begin(), locations.end());
    118  while (table.remaining()) {
    119    GlatEntry entry(this);
    120    if (table.offset() > unverified.front()) {
    121      return DropGraphite("Offset check failed for a GlatEntry");
    122    }
    123    if (table.offset() == unverified.front()) {
    124      unverified.pop_front();
    125    }
    126    if (unverified.empty()) {
    127      return DropGraphite("Expected more locations");
    128    }
    129    if (!entry.ParsePart(table)) {
    130      return DropGraphite("Failed to read a GlatEntry");
    131    }
    132    this->entries.push_back(entry);
    133  }
    134 
    135  if (unverified.size() != 1 || unverified.front() != table.offset()) {
    136    return DropGraphite("%zu location(s) could not be verified", unverified.size());
    137  }
    138  if (table.remaining()) {
    139    return Warning("%zu bytes unparsed", table.remaining());
    140  }
    141  return true;
    142 }
    143 
    144 bool OpenTypeGLAT_v2::Serialize(OTSStream* out) {
    145  assert(ShouldSerialize());
    146  if (!out->WriteU32(this->version) ||
    147      !SerializeParts(this->entries, out)) {
    148    return Error("Failed to write table");
    149  }
    150  return true;
    151 }
    152 
    153 bool OpenTypeGLAT_v2::GlatEntry::ParsePart(Buffer& table) {
    154  if (!table.ReadS16(&this->attNum)) {
    155    return parent->Error("GlatEntry: Failed to read attNum");
    156  }
    157  if (!table.ReadS16(&this->num) || this->num < 0) {
    158    return parent->Error("GlatEntry: Failed to read valid num");
    159  }
    160 
    161  //this->attributes.resize(this->num);
    162  for (int i = 0; i < this->num; ++i) {
    163    this->attributes.emplace_back();
    164    if (!table.ReadS16(&this->attributes[i])) {
    165      return parent->Error("GlatEntry: Failed to read attribute %u", i);
    166    }
    167  }
    168  return true;
    169 }
    170 
    171 bool OpenTypeGLAT_v2::GlatEntry::SerializePart(OTSStream* out) const {
    172  if (!out->WriteS16(this->attNum) ||
    173      !out->WriteS16(this->num) ||
    174      !SerializeParts(this->attributes, out)) {
    175    return parent->Error("GlatEntry: Failed to write");
    176  }
    177  return true;
    178 }
    179 
    180 // -----------------------------------------------------------------------------
    181 // OpenTypeGLAT_v3
    182 // -----------------------------------------------------------------------------
    183 
    184 bool OpenTypeGLAT_v3::Parse(const uint8_t* data, size_t length,
    185                            bool prevent_decompression) {
    186  Buffer table(data, length);
    187  OpenTypeGLOC* gloc = static_cast<OpenTypeGLOC*>(
    188      GetFont()->GetTypedTable(OTS_TAG_GLOC));
    189  if (!gloc) {
    190    return DropGraphite("Required Gloc table is missing");
    191  }
    192 
    193  if (!table.ReadU32(&this->version) || this->version >> 16 != 3) {
    194    return DropGraphite("Failed to read version");
    195  }
    196  if (!table.ReadU32(&this->compHead)) {
    197    return DropGraphite("Failed to read compression header");
    198  }
    199  switch ((this->compHead & SCHEME) >> 27) {
    200    case 0:  // uncompressed
    201      break;
    202    case 1: {  // lz4
    203      if (prevent_decompression) {
    204        return DropGraphite("Illegal nested compression");
    205      }
    206      size_t decompressed_size = this->compHead & FULL_SIZE;
    207      if (decompressed_size < length) {
    208        return DropGraphite("Decompressed size is less than compressed size");
    209      }
    210      if (decompressed_size == 0) {
    211        return DropGraphite("Decompressed size is set to 0");
    212      }
    213      // decompressed table must be <= OTS_MAX_DECOMPRESSED_TABLE_SIZE
    214      if (decompressed_size > OTS_MAX_DECOMPRESSED_TABLE_SIZE) {
    215        return DropGraphite("Decompressed size exceeds %gMB: %gMB",
    216                            OTS_MAX_DECOMPRESSED_TABLE_SIZE / (1024.0 * 1024.0),
    217                            decompressed_size / (1024.0 * 1024.0));
    218      }
    219      std::unique_ptr<uint8_t> decompressed(new uint8_t[decompressed_size]());
    220      size_t outputSize = 0;
    221      bool ret = mozilla::Compression::LZ4::decompressPartial(
    222          reinterpret_cast<const char*>(data + table.offset()),
    223          table.remaining(),  // input buffer size (input size + padding)
    224          reinterpret_cast<char*>(decompressed.get()),
    225          decompressed_size,  // target output size
    226          &outputSize);  // return output size
    227      if (!ret || outputSize != decompressed_size) {
    228        return DropGraphite("Decompression failed");
    229      }
    230      return this->Parse(decompressed.get(), decompressed_size, true);
    231    }
    232    default:
    233      return DropGraphite("Unknown compression scheme");
    234  }
    235  if (this->compHead & RESERVED) {
    236    Warning("Nonzero reserved");
    237  }
    238 
    239  const std::vector<uint32_t>& locations = gloc->GetLocations();
    240  if (locations.empty()) {
    241    return DropGraphite("No locations from Gloc table");
    242  }
    243  std::list<uint32_t> unverified(locations.begin(), locations.end());
    244  //this->entries.resize(locations.size() - 1, this);
    245  for (size_t i = 0; i < locations.size() - 1; ++i) {
    246    this->entries.emplace_back(this);
    247    if (table.offset() != unverified.front()) {
    248      return DropGraphite("Offset check failed for a GlyphAttrs");
    249    }
    250    unverified.pop_front();
    251    if (!this->entries[i].ParsePart(table,
    252                                    unverified.front() - table.offset())) {
    253        // unverified.front() is guaranteed to exist because of the number of
    254        // iterations of this loop
    255      return DropGraphite("Failed to read a GlyphAttrs");
    256    }
    257  }
    258 
    259  if (unverified.size() != 1 || unverified.front() != table.offset()) {
    260    return DropGraphite("%zu location(s) could not be verified", unverified.size());
    261  }
    262  if (table.remaining()) {
    263    return Warning("%zu bytes unparsed", table.remaining());
    264  }
    265  return true;
    266 }
    267 
    268 bool OpenTypeGLAT_v3::Serialize(OTSStream* out) {
    269  assert(ShouldSerialize());
    270  if (!out->WriteU32(this->version) ||
    271      !out->WriteU32(this->compHead) ||
    272      !SerializeParts(this->entries, out)) {
    273    return Error("Failed to write table");
    274  }
    275  return true;
    276 }
    277 
    278 bool OpenTypeGLAT_v3::GlyphAttrs::ParsePart(Buffer& table, const size_t size) {
    279  size_t init_offset = table.offset();
    280  if (parent->compHead & OCTABOXES && !octabox.ParsePart(table)) {
    281    // parent->flags & 0b1: octaboxes are present flag
    282    return parent->Error("GlyphAttrs: Failed to read octabox");
    283  }
    284 
    285  while (table.offset() < init_offset + size) {
    286    GlatEntry entry(parent);
    287    if (!entry.ParsePart(table)) {
    288      return parent->Error("GlyphAttrs: Failed to read a GlatEntry");
    289    }
    290    this->entries.push_back(entry);
    291  }
    292  return true;
    293 }
    294 
    295 bool OpenTypeGLAT_v3::GlyphAttrs::SerializePart(OTSStream* out) const {
    296  if ((parent->compHead & OCTABOXES && !octabox.SerializePart(out)) ||
    297      !SerializeParts(this->entries, out)) {
    298    return parent->Error("GlyphAttrs: Failed to write");
    299  }
    300  return true;
    301 }
    302 
    303 bool OpenTypeGLAT_v3::GlyphAttrs::
    304 OctaboxMetrics::ParsePart(Buffer& table) {
    305  if (!table.ReadU16(&this->subbox_bitmap)) {
    306    return parent->Error("OctaboxMetrics: Failed to read subbox_bitmap");
    307  }
    308  if (!table.ReadU8(&this->diag_neg_min)) {
    309    return parent->Error("OctaboxMetrics: Failed to read diag_neg_min");
    310  }
    311  if (!table.ReadU8(&this->diag_neg_max) ||
    312      this->diag_neg_max < this->diag_neg_min) {
    313    return parent->Error("OctaboxMetrics: Failed to read valid diag_neg_max");
    314  }
    315  if (!table.ReadU8(&this->diag_pos_min)) {
    316    return parent->Error("OctaboxMetrics: Failed to read diag_pos_min");
    317  }
    318  if (!table.ReadU8(&this->diag_pos_max) ||
    319      this->diag_pos_max < this->diag_pos_min) {
    320    return parent->Error("OctaboxMetrics: Failed to read valid diag_pos_max");
    321  }
    322 
    323  unsigned subboxes_len = 0;  // count of 1's in this->subbox_bitmap
    324  for (uint16_t i = this->subbox_bitmap; i; i >>= 1) {
    325    if (i & 0b1) {
    326      ++subboxes_len;
    327    }
    328  }
    329  //this->subboxes.resize(subboxes_len, parent);
    330  for (unsigned i = 0; i < subboxes_len; i++) {
    331    this->subboxes.emplace_back(parent);
    332    if (!this->subboxes[i].ParsePart(table)) {
    333      return parent->Error("OctaboxMetrics: Failed to read subbox[%u]", i);
    334    }
    335  }
    336  return true;
    337 }
    338 
    339 bool OpenTypeGLAT_v3::GlyphAttrs::
    340 OctaboxMetrics::SerializePart(OTSStream* out) const {
    341  if (!out->WriteU16(this->subbox_bitmap) ||
    342      !out->WriteU8(this->diag_neg_min) ||
    343      !out->WriteU8(this->diag_neg_max) ||
    344      !out->WriteU8(this->diag_pos_min) ||
    345      !out->WriteU8(this->diag_pos_max) ||
    346      !SerializeParts(this->subboxes, out)) {
    347    return parent->Error("OctaboxMetrics: Failed to write");
    348  }
    349  return true;
    350 }
    351 
    352 bool OpenTypeGLAT_v3::GlyphAttrs::OctaboxMetrics::
    353 SubboxEntry::ParsePart(Buffer& table) {
    354  if (!table.ReadU8(&this->left)) {
    355    return parent->Error("SubboxEntry: Failed to read left");
    356  }
    357  if (!table.ReadU8(&this->right) || this->right < this->left) {
    358    return parent->Error("SubboxEntry: Failed to read valid right");
    359  }
    360  if (!table.ReadU8(&this->bottom)) {
    361    return parent->Error("SubboxEntry: Failed to read bottom");
    362  }
    363  if (!table.ReadU8(&this->top) || this->top < this->bottom) {
    364    return parent->Error("SubboxEntry: Failed to read valid top");
    365  }
    366  if (!table.ReadU8(&this->diag_pos_min)) {
    367    return parent->Error("SubboxEntry: Failed to read diag_pos_min");
    368  }
    369  if (!table.ReadU8(&this->diag_pos_max) ||
    370      this->diag_pos_max < this->diag_pos_min) {
    371    return parent->Error("SubboxEntry: Failed to read valid diag_pos_max");
    372  }
    373  if (!table.ReadU8(&this->diag_neg_min)) {
    374    return parent->Error("SubboxEntry: Failed to read diag_neg_min");
    375  }
    376  if (!table.ReadU8(&this->diag_neg_max) ||
    377      this->diag_neg_max < this->diag_neg_min) {
    378    return parent->Error("SubboxEntry: Failed to read valid diag_neg_max");
    379  }
    380  return true;
    381 }
    382 
    383 bool OpenTypeGLAT_v3::GlyphAttrs::OctaboxMetrics::
    384 SubboxEntry::SerializePart(OTSStream* out) const {
    385  if (!out->WriteU8(this->left) ||
    386      !out->WriteU8(this->right) ||
    387      !out->WriteU8(this->bottom) ||
    388      !out->WriteU8(this->top) ||
    389      !out->WriteU8(this->diag_pos_min) ||
    390      !out->WriteU8(this->diag_pos_max) ||
    391      !out->WriteU8(this->diag_neg_min) ||
    392      !out->WriteU8(this->diag_neg_max)) {
    393    return parent->Error("SubboxEntry: Failed to write");
    394  }
    395  return true;
    396 }
    397 
    398 bool OpenTypeGLAT_v3::GlyphAttrs::
    399 GlatEntry::ParsePart(Buffer& table) {
    400  if (!table.ReadS16(&this->attNum)) {
    401    return parent->Error("GlatEntry: Failed to read attNum");
    402  }
    403  if (!table.ReadS16(&this->num) || this->num < 0) {
    404    return parent->Error("GlatEntry: Failed to read valid num");
    405  }
    406 
    407  //this->attributes.resize(this->num);
    408  for (int i = 0; i < this->num; ++i) {
    409    this->attributes.emplace_back();
    410    if (!table.ReadS16(&this->attributes[i])) {
    411      return parent->Error("GlatEntry: Failed to read attribute %u", i);
    412    }
    413  }
    414  return true;
    415 }
    416 
    417 bool OpenTypeGLAT_v3::GlyphAttrs::
    418 GlatEntry::SerializePart(OTSStream* out) const {
    419  if (!out->WriteS16(this->attNum) ||
    420      !out->WriteS16(this->num) ||
    421      !SerializeParts(this->attributes, out)) {
    422    return parent->Error("GlatEntry: Failed to write");
    423  }
    424  return true;
    425 }
    426 
    427 // -----------------------------------------------------------------------------
    428 // OpenTypeGLAT
    429 // -----------------------------------------------------------------------------
    430 
    431 bool OpenTypeGLAT::Parse(const uint8_t* data, size_t length) {
    432  Buffer table(data, length);
    433  uint32_t version;
    434  if (!table.ReadU32(&version)) {
    435    return DropGraphite("Failed to read version");
    436  }
    437  switch (version >> 16) {
    438    case 1:
    439      this->handler = new OpenTypeGLAT_v1(this->font, this->tag);
    440      break;
    441    case 2:
    442      this->handler = new OpenTypeGLAT_v2(this->font, this->tag);
    443      break;
    444    case 3: {
    445      this->handler = new OpenTypeGLAT_v3(this->font, this->tag);
    446      break;
    447    }
    448    default:
    449      return DropGraphite("Unsupported table version: %u", version >> 16);
    450  }
    451  return this->handler->Parse(data, length);
    452 }
    453 
    454 bool OpenTypeGLAT::Serialize(OTSStream* out) {
    455  if (!this->handler) {
    456    return Error("No Glat table parsed");
    457  }
    458  return this->handler->Serialize(out);
    459 }
    460 
    461 }  // namespace ots