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 "silf.h"
6
7 #include "name.h"
8 #include "lz4.h"
9 #include <cmath>
10
11 namespace ots {
12
Parse(const uint8_t * data,size_t length,bool prevent_decompression)13 bool OpenTypeSILF::Parse(const uint8_t* data, size_t length,
14 bool prevent_decompression) {
15 if (GetFont()->dropped_graphite) {
16 return Drop("Skipping Graphite table");
17 }
18 Buffer table(data, length);
19
20 if (!table.ReadU32(&this->version)) {
21 return DropGraphite("Failed to read version");
22 }
23 if (this->version >> 16 != 1 &&
24 this->version >> 16 != 2 &&
25 this->version >> 16 != 3 &&
26 this->version >> 16 != 4 &&
27 this->version >> 16 != 5) {
28 return DropGraphite("Unsupported table version: %u", this->version >> 16);
29 }
30 if (this->version >> 16 >= 3 && !table.ReadU32(&this->compHead)) {
31 return DropGraphite("Failed to read compHead");
32 }
33 if (this->version >> 16 >= 5) {
34 switch ((this->compHead & SCHEME) >> 27) {
35 case 0: // uncompressed
36 break;
37 case 1: { // lz4
38 if (prevent_decompression) {
39 return DropGraphite("Illegal nested compression");
40 }
41 std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE);
42 int ret = LZ4_decompress_safe_partial(
43 reinterpret_cast<const char*>(data + table.offset()),
44 reinterpret_cast<char*>(decompressed.data()),
45 table.remaining(), // input buffer size (input size + padding)
46 decompressed.size(), // target output size
47 decompressed.size()); // output buffer size
48 if (ret != decompressed.size()) {
49 return DropGraphite("Decompression failed with error code %d", ret);
50 }
51 return this->Parse(decompressed.data(), decompressed.size(), true);
52 }
53 default:
54 return DropGraphite("Unknown compression scheme");
55 }
56 }
57 if (!table.ReadU16(&this->numSub)) {
58 return DropGraphite("Failed to read numSub");
59 }
60 if (this->version >> 16 >= 2 && !table.ReadU16(&this->reserved)) {
61 return DropGraphite("Failed to read reserved");
62 }
63 if (this->version >> 16 >= 2 && this->reserved != 0) {
64 Warning("Nonzero reserved");
65 }
66
67 unsigned long last_offset = 0;
68 //this->offset.resize(this->numSub);
69 for (unsigned i = 0; i < this->numSub; ++i) {
70 this->offset.emplace_back();
71 if (!table.ReadU32(&this->offset[i]) || this->offset[i] < last_offset) {
72 return DropGraphite("Failed to read offset[%u]", i);
73 }
74 last_offset = this->offset[i];
75 }
76
77 for (unsigned i = 0; i < this->numSub; ++i) {
78 if (table.offset() != this->offset[i]) {
79 return DropGraphite("Offset check failed for tables[%lu]", i);
80 }
81 SILSub subtable(this);
82 if (!subtable.ParsePart(table)) {
83 return DropGraphite("Failed to read tables[%u]", i);
84 }
85 tables.push_back(subtable);
86 }
87
88 if (table.remaining()) {
89 return Warning("%zu bytes unparsed", table.remaining());
90 }
91 return true;
92 }
93
Serialize(OTSStream * out)94 bool OpenTypeSILF::Serialize(OTSStream* out) {
95 if (!out->WriteU32(this->version) ||
96 (this->version >> 16 >= 3 && !out->WriteU32(this->compHead)) ||
97 !out->WriteU16(this->numSub) ||
98 (this->version >> 16 >= 2 && !out->WriteU16(this->reserved)) ||
99 !SerializeParts(this->offset, out) ||
100 !SerializeParts(this->tables, out)) {
101 return Error("Failed to write table");
102 }
103 return true;
104 }
105
ParsePart(Buffer & table)106 bool OpenTypeSILF::SILSub::ParsePart(Buffer& table) {
107 size_t init_offset = table.offset();
108 if (parent->version >> 16 >= 3) {
109 if (!table.ReadU32(&this->ruleVersion)) {
110 return parent->Error("SILSub: Failed to read ruleVersion");
111 }
112 if (!table.ReadU16(&this->passOffset)) {
113 return parent->Error("SILSub: Failed to read passOffset");
114 }
115 if (!table.ReadU16(&this->pseudosOffset)) {
116 return parent->Error("SILSub: Failed to read pseudosOffset");
117 }
118 }
119 if (!table.ReadU16(&this->maxGlyphID)) {
120 return parent->Error("SILSub: Failed to read maxGlyphID");
121 }
122 if (!table.ReadS16(&this->extraAscent)) {
123 return parent->Error("SILSub: Failed to read extraAscent");
124 }
125 if (!table.ReadS16(&this->extraDescent)) {
126 return parent->Error("SILSub: Failed to read extraDescent");
127 }
128 if (!table.ReadU8(&this->numPasses)) {
129 return parent->Error("SILSub: Failed to read numPasses");
130 }
131 if (!table.ReadU8(&this->iSubst) || this->iSubst > this->numPasses) {
132 return parent->Error("SILSub: Failed to read valid iSubst");
133 }
134 if (!table.ReadU8(&this->iPos) || this->iPos > this->numPasses) {
135 return parent->Error("SILSub: Failed to read valid iPos");
136 }
137 if (!table.ReadU8(&this->iJust) || this->iJust > this->numPasses) {
138 return parent->Error("SILSub: Failed to read valid iJust");
139 }
140 if (!table.ReadU8(&this->iBidi) ||
141 !(iBidi == 0xFF || this->iBidi <= this->iPos)) {
142 return parent->Error("SILSub: Failed to read valid iBidi");
143 }
144 if (!table.ReadU8(&this->flags)) {
145 return parent->Error("SILSub: Failed to read flags");
146 // checks omitted
147 }
148 if (!table.ReadU8(&this->maxPreContext)) {
149 return parent->Error("SILSub: Failed to read maxPreContext");
150 }
151 if (!table.ReadU8(&this->maxPostContext)) {
152 return parent->Error("SILSub: Failed to read maxPostContext");
153 }
154 if (!table.ReadU8(&this->attrPseudo)) {
155 return parent->Error("SILSub: Failed to read attrPseudo");
156 }
157 if (!table.ReadU8(&this->attrBreakWeight)) {
158 return parent->Error("SILSub: Failed to read attrBreakWeight");
159 }
160 if (!table.ReadU8(&this->attrDirectionality)) {
161 return parent->Error("SILSub: Failed to read attrDirectionality");
162 }
163 if (parent->version >> 16 >= 2) {
164 if (!table.ReadU8(&this->attrMirroring)) {
165 return parent->Error("SILSub: Failed to read attrMirroring");
166 }
167 if (parent->version >> 16 < 4 && this->attrMirroring != 0) {
168 parent->Warning("SILSub: Nonzero attrMirroring (reserved before v4)");
169 }
170 if (!table.ReadU8(&this->attrSkipPasses)) {
171 return parent->Error("SILSub: Failed to read attrSkipPasses");
172 }
173 if (parent->version >> 16 < 4 && this->attrSkipPasses != 0) {
174 parent->Warning("SILSub: Nonzero attrSkipPasses (reserved2 before v4)");
175 }
176
177 if (!table.ReadU8(&this->numJLevels)) {
178 return parent->Error("SILSub: Failed to read numJLevels");
179 }
180 //this->jLevels.resize(this->numJLevels, parent);
181 for (unsigned i = 0; i < this->numJLevels; ++i) {
182 this->jLevels.emplace_back(parent);
183 if (!this->jLevels[i].ParsePart(table)) {
184 return parent->Error("SILSub: Failed to read jLevels[%u]", i);
185 }
186 }
187 }
188
189 if (!table.ReadU16(&this->numLigComp)) {
190 return parent->Error("SILSub: Failed to read numLigComp");
191 }
192 if (!table.ReadU8(&this->numUserDefn)) {
193 return parent->Error("SILSub: Failed to read numUserDefn");
194 }
195 if (!table.ReadU8(&this->maxCompPerLig)) {
196 return parent->Error("SILSub: Failed to read maxCompPerLig");
197 }
198 if (!table.ReadU8(&this->direction)) {
199 return parent->Error("SILSub: Failed to read direction");
200 }
201 if (!table.ReadU8(&this->attCollisions)) {
202 return parent->Error("SILSub: Failed to read attCollisions");
203 }
204 if (parent->version >> 16 < 5 && this->attCollisions != 0) {
205 parent->Warning("SILSub: Nonzero attCollisions (reserved before v5)");
206 }
207 if (!table.ReadU8(&this->reserved4)) {
208 return parent->Error("SILSub: Failed to read reserved4");
209 }
210 if (this->reserved4 != 0) {
211 parent->Warning("SILSub: Nonzero reserved4");
212 }
213 if (!table.ReadU8(&this->reserved5)) {
214 return parent->Error("SILSub: Failed to read reserved5");
215 }
216 if (this->reserved5 != 0) {
217 parent->Warning("SILSub: Nonzero reserved5");
218 }
219 if (parent->version >> 16 >= 2) {
220 if (!table.ReadU8(&this->reserved6)) {
221 return parent->Error("SILSub: Failed to read reserved6");
222 }
223 if (this->reserved6 != 0) {
224 parent->Warning("SILSub: Nonzero reserved6");
225 }
226
227 if (!table.ReadU8(&this->numCritFeatures)) {
228 return parent->Error("SILSub: Failed to read numCritFeatures");
229 }
230 //this->critFeatures.resize(this->numCritFeatures);
231 for (unsigned i = 0; i < this->numCritFeatures; ++i) {
232 this->critFeatures.emplace_back();
233 if (!table.ReadU16(&this->critFeatures[i])) {
234 return parent->Error("SILSub: Failed to read critFeatures[%u]", i);
235 }
236 }
237
238 if (!table.ReadU8(&this->reserved7)) {
239 return parent->Error("SILSub: Failed to read reserved7");
240 }
241 if (this->reserved7 != 0) {
242 parent->Warning("SILSub: Nonzero reserved7");
243 }
244 }
245
246 if (!table.ReadU8(&this->numScriptTag)) {
247 return parent->Error("SILSub: Failed to read numScriptTag");
248 }
249 //this->scriptTag.resize(this->numScriptTag);
250 for (unsigned i = 0; i < this->numScriptTag; ++i) {
251 this->scriptTag.emplace_back();
252 if (!table.ReadU32(&this->scriptTag[i])) {
253 return parent->Error("SILSub: Failed to read scriptTag[%u]", i);
254 }
255 }
256
257 if (!table.ReadU16(&this->lbGID)) {
258 return parent->Error("SILSub: Failed to read lbGID");
259 }
260 if (this->lbGID > this->maxGlyphID) {
261 parent->Warning("SILSub: lbGID %u outside range 0..%u, replaced with 0",
262 this->lbGID, this->maxGlyphID);
263 this->lbGID = 0;
264 }
265
266 if (parent->version >> 16 >= 3 &&
267 table.offset() != init_offset + this->passOffset) {
268 return parent->Error("SILSub: passOffset check failed");
269 }
270 unsigned long last_oPass = 0;
271 //this->oPasses.resize(static_cast<unsigned>(this->numPasses) + 1);
272 for (unsigned i = 0; i <= this->numPasses; ++i) {
273 this->oPasses.emplace_back();
274 if (!table.ReadU32(&this->oPasses[i]) || this->oPasses[i] < last_oPass) {
275 return false;
276 }
277 last_oPass = this->oPasses[i];
278 }
279
280 if (parent->version >> 16 >= 3 &&
281 table.offset() != init_offset + this->pseudosOffset) {
282 return parent->Error("SILSub: pseudosOffset check failed");
283 }
284 if (!table.ReadU16(&this->numPseudo)) {
285 return parent->Error("SILSub: Failed to read numPseudo");
286 }
287
288 // The following three fields are deprecated and ignored. We fix them up here
289 // just for internal consistency, but the Graphite engine doesn't care.
290 if (!table.ReadU16(&this->searchPseudo) ||
291 !table.ReadU16(&this->pseudoSelector) ||
292 !table.ReadU16(&this->pseudoShift)) {
293 return parent->Error("SILSub: Failed to read searchPseudo..pseudoShift");
294 }
295 if (this->numPseudo == 0) {
296 if (this->searchPseudo != 0 || this->pseudoSelector != 0 || this->pseudoShift != 0) {
297 this->searchPseudo = this->pseudoSelector = this->pseudoShift = 0;
298 }
299 } else {
300 unsigned floorLog2 = std::floor(std::log2(this->numPseudo));
301 if (this->searchPseudo != 6 * (unsigned)std::pow(2, floorLog2) ||
302 this->pseudoSelector != floorLog2 ||
303 this->pseudoShift != 6 * this->numPseudo - this->searchPseudo) {
304 this->searchPseudo = 6 * (unsigned)std::pow(2, floorLog2);
305 this->pseudoSelector = floorLog2;
306 this->pseudoShift = 6 * this->numPseudo - this->searchPseudo;
307 }
308 }
309
310 //this->pMaps.resize(this->numPseudo, parent);
311 for (unsigned i = 0; i < numPseudo; i++) {
312 this->pMaps.emplace_back(parent);
313 if (!this->pMaps[i].ParsePart(table)) {
314 return parent->Error("SILSub: Failed to read pMaps[%u]", i);
315 }
316 }
317
318 if (!this->classes.ParsePart(table)) {
319 return parent->Error("SILSub: Failed to read classes");
320 }
321
322 //this->passes.resize(this->numPasses, parent);
323 for (unsigned i = 0; i < this->numPasses; ++i) {
324 this->passes.emplace_back(parent);
325 if (table.offset() != init_offset + this->oPasses[i]) {
326 return parent->Error("SILSub: Offset check failed for passes[%u]", i);
327 }
328 if (!this->passes[i].ParsePart(table, init_offset, this->oPasses[i+1])) {
329 return parent->Error("SILSub: Failed to read passes[%u]", i);
330 }
331 }
332 return true;
333 }
334
SerializePart(OTSStream * out) const335 bool OpenTypeSILF::SILSub::SerializePart(OTSStream* out) const {
336 if ((parent->version >> 16 >= 3 &&
337 (!out->WriteU32(this->ruleVersion) ||
338 !out->WriteU16(this->passOffset) ||
339 !out->WriteU16(this->pseudosOffset))) ||
340 !out->WriteU16(this->maxGlyphID) ||
341 !out->WriteS16(this->extraAscent) ||
342 !out->WriteS16(this->extraDescent) ||
343 !out->WriteU8(this->numPasses) ||
344 !out->WriteU8(this->iSubst) ||
345 !out->WriteU8(this->iPos) ||
346 !out->WriteU8(this->iJust) ||
347 !out->WriteU8(this->iBidi) ||
348 !out->WriteU8(this->flags) ||
349 !out->WriteU8(this->maxPreContext) ||
350 !out->WriteU8(this->maxPostContext) ||
351 !out->WriteU8(this->attrPseudo) ||
352 !out->WriteU8(this->attrBreakWeight) ||
353 !out->WriteU8(this->attrDirectionality) ||
354 (parent->version >> 16 >= 2 &&
355 (!out->WriteU8(this->attrMirroring) ||
356 !out->WriteU8(this->attrSkipPasses) ||
357 !out->WriteU8(this->numJLevels) ||
358 !SerializeParts(this->jLevels, out))) ||
359 !out->WriteU16(this->numLigComp) ||
360 !out->WriteU8(this->numUserDefn) ||
361 !out->WriteU8(this->maxCompPerLig) ||
362 !out->WriteU8(this->direction) ||
363 !out->WriteU8(this->attCollisions) ||
364 !out->WriteU8(this->reserved4) ||
365 !out->WriteU8(this->reserved5) ||
366 (parent->version >> 16 >= 2 &&
367 (!out->WriteU8(this->reserved6) ||
368 !out->WriteU8(this->numCritFeatures) ||
369 !SerializeParts(this->critFeatures, out) ||
370 !out->WriteU8(this->reserved7))) ||
371 !out->WriteU8(this->numScriptTag) ||
372 !SerializeParts(this->scriptTag, out) ||
373 !out->WriteU16(this->lbGID) ||
374 !SerializeParts(this->oPasses, out) ||
375 !out->WriteU16(this->numPseudo) ||
376 !out->WriteU16(this->searchPseudo) ||
377 !out->WriteU16(this->pseudoSelector) ||
378 !out->WriteU16(this->pseudoShift) ||
379 !SerializeParts(this->pMaps, out) ||
380 !this->classes.SerializePart(out) ||
381 !SerializeParts(this->passes, out)) {
382 return parent->Error("SILSub: Failed to write");
383 }
384 return true;
385 }
386
387 bool OpenTypeSILF::SILSub::
ParsePart(Buffer & table)388 JustificationLevel::ParsePart(Buffer& table) {
389 if (!table.ReadU8(&this->attrStretch)) {
390 return parent->Error("JustificationLevel: Failed to read attrStretch");
391 }
392 if (!table.ReadU8(&this->attrShrink)) {
393 return parent->Error("JustificationLevel: Failed to read attrShrink");
394 }
395 if (!table.ReadU8(&this->attrStep)) {
396 return parent->Error("JustificationLevel: Failed to read attrStep");
397 }
398 if (!table.ReadU8(&this->attrWeight)) {
399 return parent->Error("JustificationLevel: Failed to read attrWeight");
400 }
401 if (!table.ReadU8(&this->runto)) {
402 return parent->Error("JustificationLevel: Failed to read runto");
403 }
404 if (!table.ReadU8(&this->reserved)) {
405 return parent->Error("JustificationLevel: Failed to read reserved");
406 }
407 if (this->reserved != 0) {
408 parent->Warning("JustificationLevel: Nonzero reserved");
409 }
410 if (!table.ReadU8(&this->reserved2)) {
411 return parent->Error("JustificationLevel: Failed to read reserved2");
412 }
413 if (this->reserved2 != 0) {
414 parent->Warning("JustificationLevel: Nonzero reserved2");
415 }
416 if (!table.ReadU8(&this->reserved3)) {
417 return parent->Error("JustificationLevel: Failed to read reserved3");
418 }
419 if (this->reserved3 != 0) {
420 parent->Warning("JustificationLevel: Nonzero reserved3");
421 }
422 return true;
423 }
424
425 bool OpenTypeSILF::SILSub::
SerializePart(OTSStream * out) const426 JustificationLevel::SerializePart(OTSStream* out) const {
427 if (!out->WriteU8(this->attrStretch) ||
428 !out->WriteU8(this->attrShrink) ||
429 !out->WriteU8(this->attrStep) ||
430 !out->WriteU8(this->attrWeight) ||
431 !out->WriteU8(this->runto) ||
432 !out->WriteU8(this->reserved) ||
433 !out->WriteU8(this->reserved2) ||
434 !out->WriteU8(this->reserved3)) {
435 return parent->Error("JustificationLevel: Failed to write");
436 }
437 return true;
438 }
439
440 bool OpenTypeSILF::SILSub::
ParsePart(Buffer & table)441 PseudoMap::ParsePart(Buffer& table) {
442 if (parent->version >> 16 >= 2 && !table.ReadU32(&this->unicode)) {
443 return parent->Error("PseudoMap: Failed to read unicode");
444 }
445 if (parent->version >> 16 == 1) {
446 uint16_t unicode;
447 if (!table.ReadU16(&unicode)) {
448 return parent->Error("PseudoMap: Failed to read unicode");
449 }
450 this->unicode = unicode;
451 }
452 if (!table.ReadU16(&this->nPseudo)) {
453 return parent->Error("PseudoMap: Failed to read nPseudo");
454 }
455 return true;
456 }
457
458 bool OpenTypeSILF::SILSub::
SerializePart(OTSStream * out) const459 PseudoMap::SerializePart(OTSStream* out) const {
460 if ((parent->version >> 16 >= 2 && !out->WriteU32(this->unicode)) ||
461 (parent->version >> 16 == 1 &&
462 !out->WriteU16(static_cast<uint16_t>(this->unicode))) ||
463 !out->WriteU16(this->nPseudo)) {
464 return parent->Error("PseudoMap: Failed to write");
465 }
466 return true;
467 }
468
469 bool OpenTypeSILF::SILSub::
ParsePart(Buffer & table)470 ClassMap::ParsePart(Buffer& table) {
471 size_t init_offset = table.offset();
472 if (!table.ReadU16(&this->numClass)) {
473 return parent->Error("ClassMap: Failed to read numClass");
474 }
475 if (!table.ReadU16(&this->numLinear) || this->numLinear > this->numClass) {
476 return parent->Error("ClassMap: Failed to read valid numLinear");
477 }
478
479 //this->oClass.resize(static_cast<unsigned long>(this->numClass) + 1);
480 if (parent->version >> 16 >= 4) {
481 unsigned long last_oClass = 0;
482 for (unsigned long i = 0; i <= this->numClass; ++i) {
483 this->oClass.emplace_back();
484 if (!table.ReadU32(&this->oClass[i]) || this->oClass[i] < last_oClass) {
485 return parent->Error("ClassMap: Failed to read oClass[%lu]", i);
486 }
487 last_oClass = this->oClass[i];
488 }
489 }
490 if (parent->version >> 16 < 4) {
491 unsigned last_oClass = 0;
492 for (unsigned long i = 0; i <= this->numClass; ++i) {
493 uint16_t offset;
494 if (!table.ReadU16(&offset) || offset < last_oClass) {
495 return parent->Error("ClassMap: Failed to read oClass[%lu]", i);
496 }
497 last_oClass = offset;
498 this->oClass.push_back(static_cast<uint32_t>(offset));
499 }
500 }
501
502 if (table.offset() - init_offset > this->oClass[this->numLinear]) {
503 return parent->Error("ClassMap: Failed to calculate length of glyphs");
504 }
505 unsigned long glyphs_len = (this->oClass[this->numLinear] -
506 (table.offset() - init_offset))/2;
507 //this->glyphs.resize(glyphs_len);
508 for (unsigned long i = 0; i < glyphs_len; ++i) {
509 this->glyphs.emplace_back();
510 if (!table.ReadU16(&this->glyphs[i])) {
511 return parent->Error("ClassMap: Failed to read glyphs[%lu]", i);
512 }
513 }
514
515 unsigned lookups_len = this->numClass - this->numLinear;
516 // this->numLinear <= this->numClass
517 //this->lookups.resize(lookups_len, parent);
518 for (unsigned i = 0; i < lookups_len; ++i) {
519 this->lookups.emplace_back(parent);
520 if (table.offset() != init_offset + oClass[this->numLinear + i]) {
521 return parent->Error("ClassMap: Offset check failed for lookups[%u]", i);
522 }
523 if (!this->lookups[i].ParsePart(table)) {
524 return parent->Error("ClassMap: Failed to read lookups[%u]", i);
525 }
526 }
527 return true;
528 }
529
530 bool OpenTypeSILF::SILSub::
SerializePart(OTSStream * out) const531 ClassMap::SerializePart(OTSStream* out) const {
532 if (!out->WriteU16(this->numClass) ||
533 !out->WriteU16(this->numLinear) ||
534 (parent->version >> 16 >= 4 && !SerializeParts(this->oClass, out)) ||
535 (parent->version >> 16 < 4 &&
536 ![&] {
537 for (uint32_t offset : this->oClass) {
538 if (!out->WriteU16(static_cast<uint16_t>(offset))) {
539 return false;
540 }
541 }
542 return true;
543 }()) ||
544 !SerializeParts(this->glyphs, out) ||
545 !SerializeParts(this->lookups, out)) {
546 return parent->Error("ClassMap: Failed to write");
547 }
548 return true;
549 }
550
551 bool OpenTypeSILF::SILSub::ClassMap::
ParsePart(Buffer & table)552 LookupClass::ParsePart(Buffer& table) {
553 if (!table.ReadU16(&this->numIDs)) {
554 return parent->Error("LookupClass: Failed to read numIDs");
555 }
556 if (!table.ReadU16(&this->searchRange) ||
557 !table.ReadU16(&this->entrySelector) ||
558 !table.ReadU16(&this->rangeShift)) {
559 return parent->Error("LookupClass: Failed to read searchRange..rangeShift");
560 }
561 if (this->numIDs == 0) {
562 if (this->searchRange != 0 || this->entrySelector != 0 || this->rangeShift != 0) {
563 parent->Warning("LookupClass: Correcting binary-search header for zero-length LookupPair list");
564 this->searchRange = this->entrySelector = this->rangeShift = 0;
565 }
566 } else {
567 unsigned floorLog2 = std::floor(std::log2(this->numIDs));
568 if (this->searchRange != (unsigned)std::pow(2, floorLog2) ||
569 this->entrySelector != floorLog2 ||
570 this->rangeShift != this->numIDs - this->searchRange) {
571 parent->Warning("LookupClass: Correcting binary-search header for LookupPair list");
572 this->searchRange = (unsigned)std::pow(2, floorLog2);
573 this->entrySelector = floorLog2;
574 this->rangeShift = this->numIDs - this->searchRange;
575 }
576 }
577
578 //this->lookups.resize(this->numIDs, parent);
579 for (unsigned i = 0; i < numIDs; ++i) {
580 this->lookups.emplace_back(parent);
581 if (!this->lookups[i].ParsePart(table)) {
582 return parent->Error("LookupClass: Failed to read lookups[%u]", i);
583 }
584 }
585 return true;
586 }
587
588 bool OpenTypeSILF::SILSub::ClassMap::
SerializePart(OTSStream * out) const589 LookupClass::SerializePart(OTSStream* out) const {
590 if (!out->WriteU16(this->numIDs) ||
591 !out->WriteU16(this->searchRange) ||
592 !out->WriteU16(this->entrySelector) ||
593 !out->WriteU16(this->rangeShift) ||
594 !SerializeParts(this->lookups, out)) {
595 return parent->Error("LookupClass: Failed to write");
596 }
597 return true;
598 }
599
600 bool OpenTypeSILF::SILSub::ClassMap::LookupClass::
ParsePart(Buffer & table)601 LookupPair::ParsePart(Buffer& table) {
602 if (!table.ReadU16(&this->glyphId)) {
603 return parent->Error("LookupPair: Failed to read glyphId");
604 }
605 if (!table.ReadU16(&this->index)) {
606 return parent->Error("LookupPair: Failed to read index");
607 }
608 return true;
609 }
610
611 bool OpenTypeSILF::SILSub::ClassMap::LookupClass::
SerializePart(OTSStream * out) const612 LookupPair::SerializePart(OTSStream* out) const {
613 if (!out->WriteU16(this->glyphId) ||
614 !out->WriteU16(this->index)) {
615 return parent->Error("LookupPair: Failed to write");
616 }
617 return true;
618 }
619
620 bool OpenTypeSILF::SILSub::
ParsePart(Buffer & table,const size_t SILSub_init_offset,const size_t next_pass_offset)621 SILPass::ParsePart(Buffer& table, const size_t SILSub_init_offset,
622 const size_t next_pass_offset) {
623 size_t init_offset = table.offset();
624 if (!table.ReadU8(&this->flags)) {
625 return parent->Error("SILPass: Failed to read flags");
626 // checks omitted
627 }
628 if (!table.ReadU8(&this->maxRuleLoop)) {
629 return parent->Error("SILPass: Failed to read valid maxRuleLoop");
630 }
631 if (!table.ReadU8(&this->maxRuleContext)) {
632 return parent->Error("SILPass: Failed to read maxRuleContext");
633 }
634 if (!table.ReadU8(&this->maxBackup)) {
635 return parent->Error("SILPass: Failed to read maxBackup");
636 }
637 if (!table.ReadU16(&this->numRules)) {
638 return parent->Error("SILPass: Failed to read numRules");
639 }
640 if (parent->version >> 16 >= 2) {
641 if (!table.ReadU16(&this->fsmOffset)) {
642 return parent->Error("SILPass: Failed to read fsmOffset");
643 }
644 if (parent->version >> 16 == 2 && this->fsmOffset != 0) {
645 parent->Warning("SILPass: Nonzero fsmOffset (reserved in SILSub v2)");
646 }
647 if (!table.ReadU32(&this->pcCode) ||
648 (parent->version >= 3 && this->pcCode < this->fsmOffset)) {
649 return parent->Error("SILPass: Failed to read pcCode");
650 }
651 }
652 if (!table.ReadU32(&this->rcCode) ||
653 (parent->version >> 16 >= 2 && this->rcCode < this->pcCode)) {
654 return parent->Error("SILPass: Failed to read valid rcCode");
655 }
656 if (!table.ReadU32(&this->aCode) || this->aCode < this->rcCode) {
657 return parent->Error("SILPass: Failed to read valid aCode");
658 }
659 if (!table.ReadU32(&this->oDebug) ||
660 (this->oDebug && this->oDebug < this->aCode)) {
661 return parent->Error("SILPass: Failed to read valid oDebug");
662 }
663 if (parent->version >> 16 >= 3 &&
664 table.offset() != init_offset + this->fsmOffset) {
665 return parent->Error("SILPass: fsmOffset check failed");
666 }
667 if (!table.ReadU16(&this->numRows) ||
668 (this->oDebug && this->numRows < this->numRules)) {
669 return parent->Error("SILPass: Failed to read valid numRows");
670 }
671 if (!table.ReadU16(&this->numTransitional)) {
672 return parent->Error("SILPass: Failed to read numTransitional");
673 }
674 if (!table.ReadU16(&this->numSuccess)) {
675 return parent->Error("SILPass: Failed to read numSuccess");
676 }
677 if (!table.ReadU16(&this->numColumns)) {
678 return parent->Error("SILPass: Failed to read numColumns");
679 }
680 if (!table.ReadU16(&this->numRange)) {
681 return parent->Error("SILPass: Failed to read numRange");
682 }
683
684 // The following three fields are deprecated and ignored. We fix them up here
685 // just for internal consistency, but the Graphite engine doesn't care.
686 if (!table.ReadU16(&this->searchRange) ||
687 !table.ReadU16(&this->entrySelector) ||
688 !table.ReadU16(&this->rangeShift)) {
689 return parent->Error("SILPass: Failed to read searchRange..rangeShift");
690 }
691 if (this->numRange == 0) {
692 if (this->searchRange != 0 || this->entrySelector != 0 || this->rangeShift != 0) {
693 this->searchRange = this->entrySelector = this->rangeShift = 0;
694 }
695 } else {
696 unsigned floorLog2 = std::floor(std::log2(this->numRange));
697 if (this->searchRange != 6 * (unsigned)std::pow(2, floorLog2) ||
698 this->entrySelector != floorLog2 ||
699 this->rangeShift != 6 * this->numRange - this->searchRange) {
700 this->searchRange = 6 * (unsigned)std::pow(2, floorLog2);
701 this->entrySelector = floorLog2;
702 this->rangeShift = 6 * this->numRange - this->searchRange;
703 }
704 }
705
706 //this->ranges.resize(this->numRange, parent);
707 for (unsigned i = 0 ; i < this->numRange; ++i) {
708 this->ranges.emplace_back(parent);
709 if (!this->ranges[i].ParsePart(table)) {
710 return parent->Error("SILPass: Failed to read ranges[%u]", i);
711 }
712 }
713 unsigned ruleMap_len = 0; // maximum value in oRuleMap
714 //this->oRuleMap.resize(static_cast<unsigned long>(this->numSuccess) + 1);
715 for (unsigned long i = 0; i <= this->numSuccess; ++i) {
716 this->oRuleMap.emplace_back();
717 if (!table.ReadU16(&this->oRuleMap[i])) {
718 return parent->Error("SILPass: Failed to read oRuleMap[%u]", i);
719 }
720 if (oRuleMap[i] > ruleMap_len) {
721 ruleMap_len = oRuleMap[i];
722 }
723 }
724
725 //this->ruleMap.resize(ruleMap_len);
726 for (unsigned i = 0; i < ruleMap_len; ++i) {
727 this->ruleMap.emplace_back();
728 if (!table.ReadU16(&this->ruleMap[i])) {
729 return parent->Error("SILPass: Failed to read ruleMap[%u]", i);
730 }
731 }
732
733 if (!table.ReadU8(&this->minRulePreContext)) {
734 return parent->Error("SILPass: Failed to read minRulePreContext");
735 }
736 if (!table.ReadU8(&this->maxRulePreContext) ||
737 this->maxRulePreContext < this->minRulePreContext) {
738 return parent->Error("SILPass: Failed to read valid maxRulePreContext");
739 }
740
741 unsigned startStates_len = this->maxRulePreContext - this->minRulePreContext
742 + 1;
743 // this->minRulePreContext <= this->maxRulePreContext
744 //this->startStates.resize(startStates_len);
745 for (unsigned i = 0; i < startStates_len; ++i) {
746 this->startStates.emplace_back();
747 if (!table.ReadS16(&this->startStates[i])) {
748 return parent->Error("SILPass: Failed to read startStates[%u]", i);
749 }
750 }
751
752 //this->ruleSortKeys.resize(this->numRules);
753 for (unsigned i = 0; i < this->numRules; ++i) {
754 this->ruleSortKeys.emplace_back();
755 if (!table.ReadU16(&this->ruleSortKeys[i])) {
756 return parent->Error("SILPass: Failed to read ruleSortKeys[%u]", i);
757 }
758 }
759
760 //this->rulePreContext.resize(this->numRules);
761 for (unsigned i = 0; i < this->numRules; ++i) {
762 this->rulePreContext.emplace_back();
763 if (!table.ReadU8(&this->rulePreContext[i])) {
764 return parent->Error("SILPass: Failed to read rulePreContext[%u]", i);
765 }
766 }
767
768 if (parent->version >> 16 >= 2) {
769 if (!table.ReadU8(&this->collisionThreshold)) {
770 return parent->Error("SILPass: Failed to read collisionThreshold");
771 }
772 if (parent->version >> 16 < 5 && this->collisionThreshold != 0) {
773 parent->Warning("SILPass: Nonzero collisionThreshold"
774 " (reserved before v5)");
775 }
776 if (!table.ReadU16(&this->pConstraint)) {
777 return parent->Error("SILPass: Failed to read pConstraint");
778 }
779 }
780
781 unsigned long ruleConstraints_len = this->aCode - this->rcCode;
782 // this->rcCode <= this->aCode
783 //this->oConstraints.resize(static_cast<unsigned long>(this->numRules) + 1);
784 for (unsigned long i = 0; i <= this->numRules; ++i) {
785 this->oConstraints.emplace_back();
786 if (!table.ReadU16(&this->oConstraints[i]) ||
787 this->oConstraints[i] > ruleConstraints_len) {
788 return parent->Error("SILPass: Failed to read valid oConstraints[%lu]",
789 i);
790 }
791 }
792
793 if (!this->oDebug && this->aCode > next_pass_offset) {
794 return parent->Error("SILPass: Failed to calculate length of actions");
795 }
796 unsigned long actions_len = this->oDebug ? this->oDebug - this->aCode :
797 next_pass_offset - this->aCode;
798 // if this->oDebug, then this->aCode <= this->oDebug
799 //this->oActions.resize(static_cast<unsigned long>(this->numRules) + 1);
800 for (unsigned long i = 0; i <= this->numRules; ++i) {
801 this->oActions.emplace_back();
802 if (!table.ReadU16(&this->oActions[i]) ||
803 (this->oActions[i] > actions_len)) {
804 return parent->Error("SILPass: Failed to read valid oActions[%lu]", i);
805 }
806 }
807
808 //this->stateTrans.resize(this->numTransitional);
809 for (unsigned i = 0; i < this->numTransitional; ++i) {
810 this->stateTrans.emplace_back();
811 //this->stateTrans[i].resize(this->numColumns);
812 for (unsigned j = 0; j < this->numColumns; ++j) {
813 this->stateTrans[i].emplace_back();
814 if (!table.ReadU16(&stateTrans[i][j])) {
815 return parent->Error("SILPass: Failed to read stateTrans[%u][%u]",
816 i, j);
817 }
818 }
819 }
820
821 if (parent->version >> 16 >= 2) {
822 if (!table.ReadU8(&this->reserved2)) {
823 return parent->Error("SILPass: Failed to read reserved2");
824 }
825 if (this->reserved2 != 0) {
826 parent->Warning("SILPass: Nonzero reserved2");
827 }
828
829 if (table.offset() != SILSub_init_offset + this->pcCode) {
830 return parent->Error("SILPass: pcCode check failed");
831 }
832 //this->passConstraints.resize(this->pConstraint);
833 for (unsigned i = 0; i < this->pConstraint; ++i) {
834 this->passConstraints.emplace_back();
835 if (!table.ReadU8(&this->passConstraints[i])) {
836 return parent->Error("SILPass: Failed to read passConstraints[%u]", i);
837 }
838 }
839 }
840
841 if (table.offset() != SILSub_init_offset + this->rcCode) {
842 return parent->Error("SILPass: rcCode check failed");
843 }
844 //this->ruleConstraints.resize(ruleConstraints_len); // calculated above
845 for (unsigned long i = 0; i < ruleConstraints_len; ++i) {
846 this->ruleConstraints.emplace_back();
847 if (!table.ReadU8(&this->ruleConstraints[i])) {
848 return parent->Error("SILPass: Failed to read ruleConstraints[%u]", i);
849 }
850 }
851
852 if (table.offset() != SILSub_init_offset + this->aCode) {
853 return parent->Error("SILPass: aCode check failed");
854 }
855 //this->actions.resize(actions_len); // calculated above
856 for (unsigned long i = 0; i < actions_len; ++i) {
857 this->actions.emplace_back();
858 if (!table.ReadU8(&this->actions[i])) {
859 return parent->Error("SILPass: Failed to read actions[%u]", i);
860 }
861 }
862
863 if (this->oDebug) {
864 OpenTypeNAME* name = static_cast<OpenTypeNAME*>(
865 parent->GetFont()->GetTypedTable(OTS_TAG_NAME));
866 if (!name) {
867 return parent->Error("SILPass: Required name table is missing");
868 }
869
870 if (table.offset() != SILSub_init_offset + this->oDebug) {
871 return parent->Error("SILPass: oDebug check failed");
872 }
873 //this->dActions.resize(this->numRules);
874 for (unsigned i = 0; i < this->numRules; ++i) {
875 this->dActions.emplace_back();
876 if (!table.ReadU16(&this->dActions[i]) ||
877 !name->IsValidNameId(this->dActions[i])) {
878 return parent->Error("SILPass: Failed to read valid dActions[%u]", i);
879 }
880 }
881
882 unsigned dStates_len = this->numRows - this->numRules;
883 // this->numRules <= this->numRows
884 //this->dStates.resize(dStates_len);
885 for (unsigned i = 0; i < dStates_len; ++i) {
886 this->dStates.emplace_back();
887 if (!table.ReadU16(&this->dStates[i]) ||
888 !name->IsValidNameId(this->dStates[i])) {
889 return parent->Error("SILPass: Failed to read valid dStates[%u]", i);
890 }
891 }
892
893 //this->dCols.resize(this->numRules);
894 for (unsigned i = 0; i < this->numRules; ++i) {
895 this->dCols.emplace_back();
896 if (!table.ReadU16(&this->dCols[i]) ||
897 !name->IsValidNameId(this->dCols[i])) {
898 return parent->Error("SILPass: Failed to read valid dCols[%u]");
899 }
900 }
901 }
902 return true;
903 }
904
905 bool OpenTypeSILF::SILSub::
SerializePart(OTSStream * out) const906 SILPass::SerializePart(OTSStream* out) const {
907 if (!out->WriteU8(this->flags) ||
908 !out->WriteU8(this->maxRuleLoop) ||
909 !out->WriteU8(this->maxRuleContext) ||
910 !out->WriteU8(this->maxBackup) ||
911 !out->WriteU16(this->numRules) ||
912 (parent->version >> 16 >= 2 &&
913 (!out->WriteU16(this->fsmOffset) ||
914 !out->WriteU32(this->pcCode))) ||
915 !out->WriteU32(this->rcCode) ||
916 !out->WriteU32(this->aCode) ||
917 !out->WriteU32(this->oDebug) ||
918 !out->WriteU16(this->numRows) ||
919 !out->WriteU16(this->numTransitional) ||
920 !out->WriteU16(this->numSuccess) ||
921 !out->WriteU16(this->numColumns) ||
922 !out->WriteU16(this->numRange) ||
923 !out->WriteU16(this->searchRange) ||
924 !out->WriteU16(this->entrySelector) ||
925 !out->WriteU16(this->rangeShift) ||
926 !SerializeParts(this->ranges, out) ||
927 !SerializeParts(this->oRuleMap, out) ||
928 !SerializeParts(this->ruleMap, out) ||
929 !out->WriteU8(this->minRulePreContext) ||
930 !out->WriteU8(this->maxRulePreContext) ||
931 !SerializeParts(this->startStates, out) ||
932 !SerializeParts(this->ruleSortKeys, out) ||
933 !SerializeParts(this->rulePreContext, out) ||
934 (parent->version >> 16 >= 2 &&
935 (!out->WriteU8(this->collisionThreshold) ||
936 !out->WriteU16(this->pConstraint))) ||
937 !SerializeParts(this->oConstraints, out) ||
938 !SerializeParts(this->oActions, out) ||
939 !SerializeParts(this->stateTrans, out) ||
940 (parent->version >> 16 >= 2 &&
941 (!out->WriteU8(this->reserved2) ||
942 !SerializeParts(this->passConstraints, out))) ||
943 !SerializeParts(this->ruleConstraints, out) ||
944 !SerializeParts(this->actions, out) ||
945 !SerializeParts(this->dActions, out) ||
946 !SerializeParts(this->dStates, out) ||
947 !SerializeParts(this->dCols, out)) {
948 return parent->Error("SILPass: Failed to write");
949 }
950 return true;
951 }
952
953 bool OpenTypeSILF::SILSub::SILPass::
ParsePart(Buffer & table)954 PassRange::ParsePart(Buffer& table) {
955 if (!table.ReadU16(&this->firstId)) {
956 return parent->Error("PassRange: Failed to read firstId");
957 }
958 if (!table.ReadU16(&this->lastId)) {
959 return parent->Error("PassRange: Failed to read lastId");
960 }
961 if (!table.ReadU16(&this->colId)) {
962 return parent->Error("PassRange: Failed to read colId");
963 }
964 return true;
965 }
966
967 bool OpenTypeSILF::SILSub::SILPass::
SerializePart(OTSStream * out) const968 PassRange::SerializePart(OTSStream* out) const {
969 if (!out->WriteU16(this->firstId) ||
970 !out->WriteU16(this->lastId) ||
971 !out->WriteU16(this->colId)) {
972 return parent->Error("PassRange: Failed to write");
973 }
974 return true;
975 }
976
977 } // namespace ots
978