stat.cc (11971B)
1 // Copyright (c) 2018 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 "stat.h" 6 #include "name.h" 7 8 namespace ots { 9 10 // ----------------------------------------------------------------------------- 11 // OpenTypeSTAT 12 // ----------------------------------------------------------------------------- 13 14 bool OpenTypeSTAT::ValidateNameId(uint16_t nameid) { 15 OpenTypeNAME* name = static_cast<OpenTypeNAME*>( 16 GetFont()->GetTypedTable(OTS_TAG_NAME)); 17 18 if (!name || !name->IsValidNameId(nameid)) { 19 Drop("Invalid nameID: %d", nameid); 20 return false; 21 } 22 23 if ((nameid >= 26 && nameid <= 255) || nameid >= 32768) { 24 Warning("nameID out of range: %d", nameid); 25 return true; 26 } 27 28 return true; 29 } 30 31 bool OpenTypeSTAT::Parse(const uint8_t* data, size_t length) { 32 Buffer table(data, length); 33 if (!table.ReadU16(&this->majorVersion) || 34 !table.ReadU16(&this->minorVersion) || 35 !table.ReadU16(&this->designAxisSize) || 36 !table.ReadU16(&this->designAxisCount) || 37 !table.ReadU32(&this->designAxesOffset) || 38 !table.ReadU16(&this->axisValueCount) || 39 !table.ReadU32(&this->offsetToAxisValueOffsets) || 40 !(this->minorVersion < 1 || table.ReadU16(&this->elidedFallbackNameID))) { 41 return Drop("Failed to read table header"); 42 } 43 if (this->majorVersion != 1) { 44 return Drop("Unknown table version"); 45 } 46 if (this->minorVersion > 2) { 47 Warning("Unknown minor version, downgrading to 2"); 48 this->minorVersion = 2; 49 } 50 51 size_t headerEnd = table.offset(); 52 53 if (this->designAxisCount == 0) { 54 if (this->designAxesOffset != 0) { 55 Warning("Unexpected non-zero designAxesOffset"); 56 this->designAxesOffset = 0; 57 } 58 } else { 59 if (this->designAxisSize < sizeof(AxisRecord)) { 60 return Drop("Invalid designAxisSize"); 61 } 62 if (this->designAxesOffset < headerEnd || 63 size_t(this->designAxesOffset) > length || 64 size_t(this->designAxisCount) * size_t(this->designAxisSize) > 65 length - size_t(this->designAxesOffset)) { 66 return Drop("Invalid designAxesOffset"); 67 } 68 } 69 70 for (size_t i = 0; i < this->designAxisCount; i++) { 71 table.set_offset(this->designAxesOffset + i * this->designAxisSize); 72 this->designAxes.emplace_back(); 73 auto& axis = this->designAxes[i]; 74 if (!table.ReadU32(&axis.axisTag) || 75 !table.ReadU16(&axis.axisNameID) || 76 !table.ReadU16(&axis.axisOrdering)) { 77 return Drop("Failed to read design axis"); 78 } 79 if (!CheckTag(axis.axisTag)) { 80 return Drop("Bad design axis tag"); 81 } 82 if (!ValidateNameId(axis.axisNameID)) { 83 return true; 84 } 85 } 86 87 // TODO 88 // - check that all axes defined in fvar are covered by STAT 89 // - check that axisOrdering values are not duplicated (warn only) 90 91 if (this->axisValueCount == 0) { 92 if (this->offsetToAxisValueOffsets != 0) { 93 Warning("Unexpected non-zero offsetToAxisValueOffsets"); 94 this->offsetToAxisValueOffsets = 0; 95 } 96 } else { 97 if (this->offsetToAxisValueOffsets < headerEnd || 98 size_t(this->offsetToAxisValueOffsets) > length || 99 size_t(this->axisValueCount) * sizeof(uint16_t) > 100 length - size_t(this->offsetToAxisValueOffsets)) { 101 return Drop("Invalid offsetToAxisValueOffsets"); 102 } 103 } 104 105 for (size_t i = 0; i < this->axisValueCount; i++) { 106 table.set_offset(this->offsetToAxisValueOffsets + i * sizeof(uint16_t)); 107 uint16_t axisValueOffset; 108 if (!table.ReadU16(&axisValueOffset)) { 109 return Drop("Failed to read axis value offset"); 110 } 111 // We already checked that offsetToAxisValueOffsets doesn't exceed length, 112 // so this subtraction will not underflow. 113 if (axisValueOffset > length - this->offsetToAxisValueOffsets) { 114 return Drop("Invalid axis value offset"); 115 } 116 table.set_offset(this->offsetToAxisValueOffsets + axisValueOffset); 117 uint16_t format; 118 if (!table.ReadU16(&format)) { 119 return Drop("Failed to read axis value format"); 120 } 121 this->axisValues.emplace_back(format); 122 auto& axisValue = axisValues[i]; 123 switch (format) { 124 case 1: 125 if (!table.ReadU16(&axisValue.format1.axisIndex) || 126 !table.ReadU16(&axisValue.format1.flags) || 127 !table.ReadU16(&axisValue.format1.valueNameID) || 128 !table.ReadS32(&axisValue.format1.value)) { 129 return Drop("Failed to read axis value (format 1)"); 130 } 131 if (axisValue.format1.axisIndex >= this->designAxisCount) { 132 return Drop("Axis index out of range"); 133 } 134 if ((axisValue.format1.flags & 0xFFFCu) != 0) { 135 Warning("Unexpected axis value flags"); 136 axisValue.format1.flags &= ~0xFFFCu; 137 } 138 if (!ValidateNameId(axisValue.format1.valueNameID)) { 139 return true; 140 } 141 break; 142 case 2: 143 if (!table.ReadU16(&axisValue.format2.axisIndex) || 144 !table.ReadU16(&axisValue.format2.flags) || 145 !table.ReadU16(&axisValue.format2.valueNameID) || 146 !table.ReadS32(&axisValue.format2.nominalValue) || 147 !table.ReadS32(&axisValue.format2.rangeMinValue) || 148 !table.ReadS32(&axisValue.format2.rangeMaxValue)) { 149 return Drop("Failed to read axis value (format 2)"); 150 } 151 if (axisValue.format2.axisIndex >= this->designAxisCount) { 152 return Drop("Axis index out of range"); 153 } 154 if ((axisValue.format2.flags & 0xFFFCu) != 0) { 155 Warning("Unexpected axis value flags"); 156 axisValue.format1.flags &= ~0xFFFCu; 157 } 158 if (!ValidateNameId(axisValue.format2.valueNameID)) { 159 return true; 160 } 161 if (!(axisValue.format2.rangeMinValue <= axisValue.format2.nominalValue && 162 axisValue.format2.nominalValue <= axisValue.format2.rangeMaxValue)) { 163 Warning("Bad axis value range or nominal value"); 164 } 165 break; 166 case 3: 167 if (!table.ReadU16(&axisValue.format3.axisIndex) || 168 !table.ReadU16(&axisValue.format3.flags) || 169 !table.ReadU16(&axisValue.format3.valueNameID) || 170 !table.ReadS32(&axisValue.format3.value) || 171 !table.ReadS32(&axisValue.format3.linkedValue)) { 172 return Drop("Failed to read axis value (format 3)"); 173 } 174 if (axisValue.format3.axisIndex >= this->designAxisCount) { 175 return Drop("Axis index out of range"); 176 } 177 if ((axisValue.format3.flags & 0xFFFCu) != 0) { 178 Warning("Unexpected axis value flags"); 179 axisValue.format3.flags &= ~0xFFFCu; 180 } 181 if (!ValidateNameId(axisValue.format3.valueNameID)) { 182 return true; 183 } 184 break; 185 case 4: 186 if (this->minorVersion < 2) { 187 return Drop("Invalid table minorVersion for format 4 axis values: %d", this->minorVersion); 188 } 189 if (!table.ReadU16(&axisValue.format4.axisCount) || 190 !table.ReadU16(&axisValue.format4.flags) || 191 !table.ReadU16(&axisValue.format4.valueNameID)) { 192 return Drop("Failed to read axis value (format 4)"); 193 } 194 if (axisValue.format4.axisCount > this->designAxisCount) { 195 return Drop("Axis count out of range"); 196 } 197 if ((axisValue.format4.flags & 0xFFFCu) != 0) { 198 Warning("Unexpected axis value flags"); 199 axisValue.format4.flags &= ~0xFFFCu; 200 } 201 if (!ValidateNameId(axisValue.format4.valueNameID)) { 202 return true; 203 } 204 for (unsigned j = 0; j < axisValue.format4.axisCount; j++) { 205 axisValue.format4.axisValues.emplace_back(); 206 auto& v = axisValue.format4.axisValues[j]; 207 if (!table.ReadU16(&v.axisIndex) || 208 !table.ReadS32(&v.value)) { 209 return Drop("Failed to read axis value"); 210 } 211 if (v.axisIndex >= this->designAxisCount) { 212 return Drop("Axis index out of range"); 213 } 214 } 215 break; 216 default: 217 return Drop("Unknown axis value format"); 218 } 219 } 220 221 return true; 222 } 223 224 bool OpenTypeSTAT::Serialize(OTSStream* out) { 225 off_t tableStart = out->Tell(); 226 227 size_t headerSize = 5 * sizeof(uint16_t) + 2 * sizeof(uint32_t); 228 if (this->minorVersion >= 1) { 229 headerSize += sizeof(uint16_t); 230 } 231 232 if (this->designAxisCount == 0) { 233 this->designAxesOffset = 0; 234 } else { 235 this->designAxesOffset = headerSize; 236 } 237 238 this->designAxisSize = sizeof(AxisRecord); 239 240 if (this->axisValueCount == 0) { 241 this->offsetToAxisValueOffsets = 0; 242 } else { 243 if (this->designAxesOffset == 0) { 244 this->offsetToAxisValueOffsets = headerSize; 245 } else { 246 this->offsetToAxisValueOffsets = this->designAxesOffset + this->designAxisCount * this->designAxisSize; 247 } 248 } 249 250 if (!out->WriteU16(this->majorVersion) || 251 !out->WriteU16(this->minorVersion) || 252 !out->WriteU16(this->designAxisSize) || 253 !out->WriteU16(this->designAxisCount) || 254 !out->WriteU32(this->designAxesOffset) || 255 !out->WriteU16(this->axisValueCount) || 256 !out->WriteU32(this->offsetToAxisValueOffsets) || 257 !(this->minorVersion < 1 || out->WriteU16(this->elidedFallbackNameID))) { 258 return Error("Failed to write table header"); 259 } 260 261 if (this->designAxisCount > 0) { 262 if (out->Tell() - tableStart != this->designAxesOffset) { 263 return Error("Error computing designAxesOffset"); 264 } 265 } 266 267 for (unsigned i = 0; i < this->designAxisCount; i++) { 268 const auto& axis = this->designAxes[i]; 269 if (!out->WriteU32(axis.axisTag) || 270 !out->WriteU16(axis.axisNameID) || 271 !out->WriteU16(axis.axisOrdering)) { 272 return Error("Failed to write design axis"); 273 } 274 } 275 276 if (this->axisValueCount > 0) { 277 if (out->Tell() - tableStart != this->offsetToAxisValueOffsets) { 278 return Error("Error computing offsetToAxisValueOffsets"); 279 } 280 } 281 282 uint32_t axisValueOffset = this->axisValueCount * sizeof(uint16_t); 283 for (unsigned i = 0; i < this->axisValueCount; i++) { 284 const auto& value = this->axisValues[i]; 285 if (!out->WriteU16(axisValueOffset)) { 286 return Error("Failed to write axis value offset"); 287 } 288 axisValueOffset += value.Length(); 289 } 290 for (unsigned i = 0; i < this->axisValueCount; i++) { 291 const auto& value = this->axisValues[i]; 292 if (!out->WriteU16(value.format)) { 293 return Error("Failed to write axis value"); 294 } 295 switch (value.format) { 296 case 1: 297 if (!out->WriteU16(value.format1.axisIndex) || 298 !out->WriteU16(value.format1.flags) || 299 !out->WriteU16(value.format1.valueNameID) || 300 !out->WriteS32(value.format1.value)) { 301 return Error("Failed to write axis value"); 302 } 303 break; 304 case 2: 305 if (!out->WriteU16(value.format2.axisIndex) || 306 !out->WriteU16(value.format2.flags) || 307 !out->WriteU16(value.format2.valueNameID) || 308 !out->WriteS32(value.format2.nominalValue) || 309 !out->WriteS32(value.format2.rangeMinValue) || 310 !out->WriteS32(value.format2.rangeMaxValue)) { 311 return Error("Failed to write axis value"); 312 } 313 break; 314 case 3: 315 if (!out->WriteU16(value.format3.axisIndex) || 316 !out->WriteU16(value.format3.flags) || 317 !out->WriteU16(value.format3.valueNameID) || 318 !out->WriteS32(value.format3.value) || 319 !out->WriteS32(value.format3.linkedValue)) { 320 return Error("Failed to write axis value"); 321 } 322 break; 323 case 4: 324 if (!out->WriteU16(value.format4.axisCount) || 325 !out->WriteU16(value.format4.flags) || 326 !out->WriteU16(value.format4.valueNameID)) { 327 return Error("Failed to write axis value"); 328 } 329 for (unsigned j = 0; j < value.format4.axisValues.size(); j++) { 330 if (!out->WriteU16(value.format4.axisValues[j].axisIndex) || 331 !out->WriteS32(value.format4.axisValues[j].value)) { 332 return Error("Failed to write axis value"); 333 } 334 } 335 break; 336 default: 337 return Error("Bad value format"); 338 } 339 } 340 341 return true; 342 } 343 344 } // namespace ots