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 |