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