sill.cc (5229B)
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 bool OpenTypeSILL::Parse(const uint8_t* data, size_t length) { 14 Buffer table(data, length); 15 16 if (!table.ReadU32(&this->version) || this->version >> 16 != 1) { 17 return Drop("Failed to read valid version"); 18 } 19 if (!table.ReadU16(&this->numLangs)) { 20 return Drop("Failed to read numLangs"); 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 if (!table.ReadU16(&this->searchRange) || 26 !table.ReadU16(&this->entrySelector) || 27 !table.ReadU16(&this->rangeShift)) { 28 return Drop("Failed to read searchRange..rangeShift"); 29 } 30 if (this->numLangs == 0) { 31 if (this->searchRange != 0 || this->entrySelector != 0 || this->rangeShift != 0) { 32 this->searchRange = this->entrySelector = this->rangeShift = 0; 33 } 34 } else { 35 unsigned floorLog2 = std::floor(std::log2(this->numLangs)); 36 if (this->searchRange != (unsigned)std::pow(2, floorLog2) || 37 this->entrySelector != floorLog2 || 38 this->rangeShift != this->numLangs - this->searchRange) { 39 this->searchRange = (unsigned)std::pow(2, floorLog2); 40 this->entrySelector = floorLog2; 41 this->rangeShift = this->numLangs - this->searchRange; 42 } 43 } 44 45 std::unordered_set<size_t> unverified; 46 //this->entries.resize(static_cast<unsigned long>(this->numLangs) + 1, this); 47 for (unsigned long i = 0; i <= this->numLangs; ++i) { 48 this->entries.emplace_back(this); 49 LanguageEntry& entry = this->entries[i]; 50 if (!entry.ParsePart(table)) { 51 return Drop("Failed to read entries[%u]", i); 52 } 53 for (unsigned j = 0; j < entry.numSettings; ++j) { 54 size_t offset = entry.offset + j * 8; 55 if (offset < entry.offset || offset > length) { 56 return DropGraphite("Invalid LangFeatureSetting offset %zu/%zu", 57 offset, length); 58 } 59 unverified.insert(offset); 60 // need to verify that this LanguageEntry points to valid 61 // LangFeatureSetting 62 } 63 } 64 65 while (table.remaining()) { 66 unverified.erase(table.offset()); 67 LangFeatureSetting setting(this); 68 if (!setting.ParsePart(table)) { 69 return Drop("Failed to read a LangFeatureSetting"); 70 } 71 settings.push_back(setting); 72 } 73 74 if (!unverified.empty()) { 75 return Drop("%zu incorrect offsets into settings", unverified.size()); 76 } 77 if (table.remaining()) { 78 return Warning("%zu bytes unparsed", table.remaining()); 79 } 80 return true; 81 } 82 83 bool OpenTypeSILL::Serialize(OTSStream* out) { 84 if (!out->WriteU32(this->version) || 85 !out->WriteU16(this->numLangs) || 86 !out->WriteU16(this->searchRange) || 87 !out->WriteU16(this->entrySelector) || 88 !out->WriteU16(this->rangeShift) || 89 !SerializeParts(this->entries, out) || 90 !SerializeParts(this->settings, out)) { 91 return Error("Failed to write table"); 92 } 93 return true; 94 } 95 96 bool OpenTypeSILL::LanguageEntry::ParsePart(Buffer& table) { 97 if (!table.ReadU8(&this->langcode[0]) || 98 !table.ReadU8(&this->langcode[1]) || 99 !table.ReadU8(&this->langcode[2]) || 100 !table.ReadU8(&this->langcode[3])) { 101 return parent->Error("LanguageEntry: Failed to read langcode"); 102 } 103 if (!table.ReadU16(&this->numSettings)) { 104 return parent->Error("LanguageEntry: Failed to read numSettings"); 105 } 106 if (!table.ReadU16(&this->offset)) { 107 return parent->Error("LanguageEntry: Failed to read offset"); 108 } 109 return true; 110 } 111 112 bool OpenTypeSILL::LanguageEntry::SerializePart(OTSStream* out) const { 113 if (!out->WriteU8(this->langcode[0]) || 114 !out->WriteU8(this->langcode[1]) || 115 !out->WriteU8(this->langcode[2]) || 116 !out->WriteU8(this->langcode[3]) || 117 !out->WriteU16(this->numSettings) || 118 !out->WriteU16(this->offset)) { 119 return parent->Error("LanguageEntry: Failed to write"); 120 } 121 return true; 122 } 123 124 bool OpenTypeSILL::LangFeatureSetting::ParsePart(Buffer& table) { 125 OpenTypeFEAT* feat = static_cast<OpenTypeFEAT*>( 126 parent->GetFont()->GetTypedTable(OTS_TAG_FEAT)); 127 if (!feat) { 128 return parent->Error("FeatureDefn: Required Feat table is missing"); 129 } 130 131 if (!table.ReadU32(&this->featureId) || 132 !feat->IsValidFeatureId(this->featureId)) { 133 return parent->Error("LangFeatureSetting: Failed to read valid featureId"); 134 } 135 if (!table.ReadS16(&this->value)) { 136 return parent->Error("LangFeatureSetting: Failed to read value"); 137 } 138 if (!table.ReadU16(&this->reserved)) { 139 return parent->Error("LangFeatureSetting: Failed to read reserved"); 140 } 141 if (this->reserved != 0) { 142 parent->Warning("LangFeatureSetting: Nonzero reserved"); 143 } 144 return true; 145 } 146 147 bool OpenTypeSILL::LangFeatureSetting::SerializePart(OTSStream* out) const { 148 if (!out->WriteU32(this->featureId) || 149 !out->WriteS16(this->value) || 150 !out->WriteU16(this->reserved)) { 151 return parent->Error("LangFeatureSetting: Failed to read reserved"); 152 } 153 return true; 154 } 155 156 } // namespace ots