Coverage Report

Created: 2026-01-25 07:03

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