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.
8 #include "mozilla/Compression.h"
14 bool OpenTypeSILF::Parse(const uint8_t* data
, size_t length
,
15 bool prevent_decompression
) {
16 Buffer
table(data
, length
);
18 if (!table
.ReadU32(&this->version
)) {
19 return DropGraphite("Failed to read version");
21 if (this->version
>> 16 != 1 &&
22 this->version
>> 16 != 2 &&
23 this->version
>> 16 != 3 &&
24 this->version
>> 16 != 4 &&
25 this->version
>> 16 != 5) {
26 return DropGraphite("Unsupported table version: %u", this->version
>> 16);
28 if (this->version
>> 16 >= 3 && !table
.ReadU32(&this->compHead
)) {
29 return DropGraphite("Failed to read compHead");
31 if (this->version
>> 16 >= 5) {
32 switch ((this->compHead
& SCHEME
) >> 27) {
33 case 0: // uncompressed
36 if (prevent_decompression
) {
37 return DropGraphite("Illegal nested compression");
39 size_t decompressed_size
= this->compHead
& FULL_SIZE
;
40 if (decompressed_size
< length
) {
41 return DropGraphite("Decompressed size is less than compressed size");
43 if (decompressed_size
== 0) {
44 return DropGraphite("Decompressed size is set to 0");
46 // decompressed table must be <= OTS_MAX_DECOMPRESSED_TABLE_SIZE
47 if (decompressed_size
> OTS_MAX_DECOMPRESSED_TABLE_SIZE
) {
48 return DropGraphite("Decompressed size exceeds %gMB: %gMB",
49 OTS_MAX_DECOMPRESSED_TABLE_SIZE
/ (1024.0 * 1024.0),
50 decompressed_size
/ (1024.0 * 1024.0));
52 std::unique_ptr
<uint8_t> decompressed(new uint8_t[decompressed_size
]());
53 size_t outputSize
= 0;
54 bool ret
= mozilla::Compression::LZ4::decompressPartial(
55 reinterpret_cast<const char*>(data
+ table
.offset()),
56 table
.remaining(), // input buffer size (input size + padding)
57 reinterpret_cast<char*>(decompressed
.get()),
58 decompressed_size
, // target output size
59 &outputSize
); // return output size
60 if (!ret
|| outputSize
!= decompressed_size
) {
61 return DropGraphite("Decompression failed");
63 return this->Parse(decompressed
.get(), decompressed_size
, true);
66 return DropGraphite("Unknown compression scheme");
69 if (!table
.ReadU16(&this->numSub
)) {
70 return DropGraphite("Failed to read numSub");
72 if (this->version
>> 16 >= 2 && !table
.ReadU16(&this->reserved
)) {
73 return DropGraphite("Failed to read reserved");
75 if (this->version
>> 16 >= 2 && this->reserved
!= 0) {
76 Warning("Nonzero reserved");
79 unsigned long last_offset
= 0;
80 //this->offset.resize(this->numSub);
81 for (unsigned i
= 0; i
< this->numSub
; ++i
) {
82 this->offset
.emplace_back();
83 if (!table
.ReadU32(&this->offset
[i
]) || this->offset
[i
] < last_offset
) {
84 return DropGraphite("Failed to read offset[%u]", i
);
86 last_offset
= this->offset
[i
];
89 for (unsigned i
= 0; i
< this->numSub
; ++i
) {
90 if (table
.offset() != this->offset
[i
]) {
91 return DropGraphite("Offset check failed for tables[%lu]", i
);
93 SILSub
subtable(this);
94 if (!subtable
.ParsePart(table
)) {
95 return DropGraphite("Failed to read tables[%u]", i
);
97 tables
.push_back(subtable
);
100 if (table
.remaining()) {
101 return Warning("%zu bytes unparsed", table
.remaining());
106 bool OpenTypeSILF::Serialize(OTSStream
* out
) {
107 if (!out
->WriteU32(this->version
) ||
108 (this->version
>> 16 >= 3 && !out
->WriteU32(this->compHead
)) ||
109 !out
->WriteU16(this->numSub
) ||
110 (this->version
>> 16 >= 2 && !out
->WriteU16(this->reserved
)) ||
111 !SerializeParts(this->offset
, out
) ||
112 !SerializeParts(this->tables
, out
)) {
113 return Error("Failed to write table");
118 bool OpenTypeSILF::SILSub::ParsePart(Buffer
& table
) {
119 size_t init_offset
= table
.offset();
120 if (parent
->version
>> 16 >= 3) {
121 if (!table
.ReadU32(&this->ruleVersion
)) {
122 return parent
->Error("SILSub: Failed to read ruleVersion");
124 if (!table
.ReadU16(&this->passOffset
)) {
125 return parent
->Error("SILSub: Failed to read passOffset");
127 if (!table
.ReadU16(&this->pseudosOffset
)) {
128 return parent
->Error("SILSub: Failed to read pseudosOffset");
131 if (!table
.ReadU16(&this->maxGlyphID
)) {
132 return parent
->Error("SILSub: Failed to read maxGlyphID");
134 if (!table
.ReadS16(&this->extraAscent
)) {
135 return parent
->Error("SILSub: Failed to read extraAscent");
137 if (!table
.ReadS16(&this->extraDescent
)) {
138 return parent
->Error("SILSub: Failed to read extraDescent");
140 if (!table
.ReadU8(&this->numPasses
)) {
141 return parent
->Error("SILSub: Failed to read numPasses");
143 if (!table
.ReadU8(&this->iSubst
) || this->iSubst
> this->numPasses
) {
144 return parent
->Error("SILSub: Failed to read valid iSubst");
146 if (!table
.ReadU8(&this->iPos
) || this->iPos
> this->numPasses
) {
147 return parent
->Error("SILSub: Failed to read valid iPos");
149 if (!table
.ReadU8(&this->iJust
) || this->iJust
> this->numPasses
) {
150 return parent
->Error("SILSub: Failed to read valid iJust");
152 if (!table
.ReadU8(&this->iBidi
) ||
153 !(iBidi
== 0xFF || this->iBidi
<= this->iPos
)) {
154 return parent
->Error("SILSub: Failed to read valid iBidi");
156 if (!table
.ReadU8(&this->flags
)) {
157 return parent
->Error("SILSub: Failed to read flags");
160 if (!table
.ReadU8(&this->maxPreContext
)) {
161 return parent
->Error("SILSub: Failed to read maxPreContext");
163 if (!table
.ReadU8(&this->maxPostContext
)) {
164 return parent
->Error("SILSub: Failed to read maxPostContext");
166 if (!table
.ReadU8(&this->attrPseudo
)) {
167 return parent
->Error("SILSub: Failed to read attrPseudo");
169 if (!table
.ReadU8(&this->attrBreakWeight
)) {
170 return parent
->Error("SILSub: Failed to read attrBreakWeight");
172 if (!table
.ReadU8(&this->attrDirectionality
)) {
173 return parent
->Error("SILSub: Failed to read attrDirectionality");
175 if (parent
->version
>> 16 >= 2) {
176 if (!table
.ReadU8(&this->attrMirroring
)) {
177 return parent
->Error("SILSub: Failed to read attrMirroring");
179 if (!table
.ReadU8(&this->attrSkipPasses
)) {
180 return parent
->Error("SILSub: Failed to read attrSkipPasses");
183 if (!table
.ReadU8(&this->numJLevels
)) {
184 return parent
->Error("SILSub: Failed to read numJLevels");
186 //this->jLevels.resize(this->numJLevels, parent);
187 for (unsigned i
= 0; i
< this->numJLevels
; ++i
) {
188 this->jLevels
.emplace_back(parent
);
189 if (!this->jLevels
[i
].ParsePart(table
)) {
190 return parent
->Error("SILSub: Failed to read jLevels[%u]", i
);
195 if (!table
.ReadU16(&this->numLigComp
)) {
196 return parent
->Error("SILSub: Failed to read numLigComp");
198 if (!table
.ReadU8(&this->numUserDefn
)) {
199 return parent
->Error("SILSub: Failed to read numUserDefn");
201 if (!table
.ReadU8(&this->maxCompPerLig
)) {
202 return parent
->Error("SILSub: Failed to read maxCompPerLig");
204 if (!table
.ReadU8(&this->direction
)) {
205 return parent
->Error("SILSub: Failed to read direction");
207 if (!table
.ReadU8(&this->attrCollisions
)) {
208 return parent
->Error("SILSub: Failed to read attrCollisions");
210 if (parent
->version
< 0x40001 && this->attrCollisions
!= 0) {
211 parent
->Warning("SILSub: Nonzero attrCollisions (reserved before v4.1)");
213 if (!table
.ReadU8(&this->reserved4
)) {
214 return parent
->Error("SILSub: Failed to read reserved4");
216 if (this->reserved4
!= 0) {
217 parent
->Warning("SILSub: Nonzero reserved4");
219 if (!table
.ReadU8(&this->reserved5
)) {
220 return parent
->Error("SILSub: Failed to read reserved5");
222 if (this->reserved5
!= 0) {
223 parent
->Warning("SILSub: Nonzero reserved5");
225 if (parent
->version
>> 16 >= 2) {
226 if (!table
.ReadU8(&this->reserved6
)) {
227 return parent
->Error("SILSub: Failed to read reserved6");
229 if (this->reserved6
!= 0) {
230 parent
->Warning("SILSub: Nonzero reserved6");
233 if (!table
.ReadU8(&this->numCritFeatures
)) {
234 return parent
->Error("SILSub: Failed to read numCritFeatures");
236 //this->critFeatures.resize(this->numCritFeatures);
237 for (unsigned i
= 0; i
< this->numCritFeatures
; ++i
) {
238 this->critFeatures
.emplace_back();
239 if (!table
.ReadU16(&this->critFeatures
[i
])) {
240 return parent
->Error("SILSub: Failed to read critFeatures[%u]", i
);
244 if (!table
.ReadU8(&this->reserved7
)) {
245 return parent
->Error("SILSub: Failed to read reserved7");
247 if (this->reserved7
!= 0) {
248 parent
->Warning("SILSub: Nonzero reserved7");
252 if (!table
.ReadU8(&this->numScriptTag
)) {
253 return parent
->Error("SILSub: Failed to read numScriptTag");
255 //this->scriptTag.resize(this->numScriptTag);
256 for (unsigned i
= 0; i
< this->numScriptTag
; ++i
) {
257 this->scriptTag
.emplace_back();
258 if (!table
.ReadU32(&this->scriptTag
[i
])) {
259 return parent
->Error("SILSub: Failed to read scriptTag[%u]", i
);
263 if (!table
.ReadU16(&this->lbGID
)) {
264 return parent
->Error("SILSub: Failed to read lbGID");
266 if (this->lbGID
> this->maxGlyphID
) {
267 parent
->Warning("SILSub: lbGID %u outside range 0..%u, replaced with 0",
268 this->lbGID
, this->maxGlyphID
);
272 if (parent
->version
>> 16 >= 3 &&
273 table
.offset() != init_offset
+ this->passOffset
) {
274 return parent
->Error("SILSub: passOffset check failed");
276 unsigned long last_oPass
= 0;
277 //this->oPasses.resize(static_cast<unsigned>(this->numPasses) + 1);
278 for (unsigned i
= 0; i
<= this->numPasses
; ++i
) {
279 this->oPasses
.emplace_back();
280 if (!table
.ReadU32(&this->oPasses
[i
]) || this->oPasses
[i
] < last_oPass
) {
283 last_oPass
= this->oPasses
[i
];
286 if (parent
->version
>> 16 >= 3 &&
287 table
.offset() != init_offset
+ this->pseudosOffset
) {
288 return parent
->Error("SILSub: pseudosOffset check failed");
290 if (!table
.ReadU16(&this->numPseudo
)) {
291 return parent
->Error("SILSub: Failed to read numPseudo");
294 // The following three fields are deprecated and ignored. We fix them up here
295 // just for internal consistency, but the Graphite engine doesn't care.
296 if (!table
.ReadU16(&this->searchPseudo
) ||
297 !table
.ReadU16(&this->pseudoSelector
) ||
298 !table
.ReadU16(&this->pseudoShift
)) {
299 return parent
->Error("SILSub: Failed to read searchPseudo..pseudoShift");
301 if (this->numPseudo
== 0) {
302 if (this->searchPseudo
!= 0 || this->pseudoSelector
!= 0 || this->pseudoShift
!= 0) {
303 this->searchPseudo
= this->pseudoSelector
= this->pseudoShift
= 0;
306 unsigned floorLog2
= std::floor(std::log2(this->numPseudo
));
307 if (this->searchPseudo
!= 6 * (unsigned)std::pow(2, floorLog2
) ||
308 this->pseudoSelector
!= floorLog2
||
309 this->pseudoShift
!= 6 * this->numPseudo
- this->searchPseudo
) {
310 this->searchPseudo
= 6 * (unsigned)std::pow(2, floorLog2
);
311 this->pseudoSelector
= floorLog2
;
312 this->pseudoShift
= 6 * this->numPseudo
- this->searchPseudo
;
316 //this->pMaps.resize(this->numPseudo, parent);
317 for (unsigned i
= 0; i
< numPseudo
; i
++) {
318 this->pMaps
.emplace_back(parent
);
319 if (!this->pMaps
[i
].ParsePart(table
)) {
320 return parent
->Error("SILSub: Failed to read pMaps[%u]", i
);
324 if (!this->classes
.ParsePart(table
)) {
325 return parent
->Error("SILSub: Failed to read classes");
328 //this->passes.resize(this->numPasses, parent);
329 for (unsigned i
= 0; i
< this->numPasses
; ++i
) {
330 this->passes
.emplace_back(parent
);
331 if (table
.offset() != init_offset
+ this->oPasses
[i
]) {
332 return parent
->Error("SILSub: Offset check failed for passes[%u]", i
);
334 if (!this->passes
[i
].ParsePart(table
, init_offset
, this->oPasses
[i
+1])) {
335 return parent
->Error("SILSub: Failed to read passes[%u]", i
);
341 bool OpenTypeSILF::SILSub::SerializePart(OTSStream
* out
) const {
342 if ((parent
->version
>> 16 >= 3 &&
343 (!out
->WriteU32(this->ruleVersion
) ||
344 !out
->WriteU16(this->passOffset
) ||
345 !out
->WriteU16(this->pseudosOffset
))) ||
346 !out
->WriteU16(this->maxGlyphID
) ||
347 !out
->WriteS16(this->extraAscent
) ||
348 !out
->WriteS16(this->extraDescent
) ||
349 !out
->WriteU8(this->numPasses
) ||
350 !out
->WriteU8(this->iSubst
) ||
351 !out
->WriteU8(this->iPos
) ||
352 !out
->WriteU8(this->iJust
) ||
353 !out
->WriteU8(this->iBidi
) ||
354 !out
->WriteU8(this->flags
) ||
355 !out
->WriteU8(this->maxPreContext
) ||
356 !out
->WriteU8(this->maxPostContext
) ||
357 !out
->WriteU8(this->attrPseudo
) ||
358 !out
->WriteU8(this->attrBreakWeight
) ||
359 !out
->WriteU8(this->attrDirectionality
) ||
360 (parent
->version
>> 16 >= 2 &&
361 (!out
->WriteU8(this->attrMirroring
) ||
362 !out
->WriteU8(this->attrSkipPasses
) ||
363 !out
->WriteU8(this->numJLevels
) ||
364 !SerializeParts(this->jLevels
, out
))) ||
365 !out
->WriteU16(this->numLigComp
) ||
366 !out
->WriteU8(this->numUserDefn
) ||
367 !out
->WriteU8(this->maxCompPerLig
) ||
368 !out
->WriteU8(this->direction
) ||
369 !out
->WriteU8(this->attrCollisions
) ||
370 !out
->WriteU8(this->reserved4
) ||
371 !out
->WriteU8(this->reserved5
) ||
372 (parent
->version
>> 16 >= 2 &&
373 (!out
->WriteU8(this->reserved6
) ||
374 !out
->WriteU8(this->numCritFeatures
) ||
375 !SerializeParts(this->critFeatures
, out
) ||
376 !out
->WriteU8(this->reserved7
))) ||
377 !out
->WriteU8(this->numScriptTag
) ||
378 !SerializeParts(this->scriptTag
, out
) ||
379 !out
->WriteU16(this->lbGID
) ||
380 !SerializeParts(this->oPasses
, out
) ||
381 !out
->WriteU16(this->numPseudo
) ||
382 !out
->WriteU16(this->searchPseudo
) ||
383 !out
->WriteU16(this->pseudoSelector
) ||
384 !out
->WriteU16(this->pseudoShift
) ||
385 !SerializeParts(this->pMaps
, out
) ||
386 !this->classes
.SerializePart(out
) ||
387 !SerializeParts(this->passes
, out
)) {
388 return parent
->Error("SILSub: Failed to write");
393 bool OpenTypeSILF::SILSub::
394 JustificationLevel::ParsePart(Buffer
& table
) {
395 if (!table
.ReadU8(&this->attrStretch
)) {
396 return parent
->Error("JustificationLevel: Failed to read attrStretch");
398 if (!table
.ReadU8(&this->attrShrink
)) {
399 return parent
->Error("JustificationLevel: Failed to read attrShrink");
401 if (!table
.ReadU8(&this->attrStep
)) {
402 return parent
->Error("JustificationLevel: Failed to read attrStep");
404 if (!table
.ReadU8(&this->attrWeight
)) {
405 return parent
->Error("JustificationLevel: Failed to read attrWeight");
407 if (!table
.ReadU8(&this->runto
)) {
408 return parent
->Error("JustificationLevel: Failed to read runto");
410 if (!table
.ReadU8(&this->reserved
)) {
411 return parent
->Error("JustificationLevel: Failed to read reserved");
413 if (this->reserved
!= 0) {
414 parent
->Warning("JustificationLevel: Nonzero reserved");
416 if (!table
.ReadU8(&this->reserved2
)) {
417 return parent
->Error("JustificationLevel: Failed to read reserved2");
419 if (this->reserved2
!= 0) {
420 parent
->Warning("JustificationLevel: Nonzero reserved2");
422 if (!table
.ReadU8(&this->reserved3
)) {
423 return parent
->Error("JustificationLevel: Failed to read reserved3");
425 if (this->reserved3
!= 0) {
426 parent
->Warning("JustificationLevel: Nonzero reserved3");
431 bool OpenTypeSILF::SILSub::
432 JustificationLevel::SerializePart(OTSStream
* out
) const {
433 if (!out
->WriteU8(this->attrStretch
) ||
434 !out
->WriteU8(this->attrShrink
) ||
435 !out
->WriteU8(this->attrStep
) ||
436 !out
->WriteU8(this->attrWeight
) ||
437 !out
->WriteU8(this->runto
) ||
438 !out
->WriteU8(this->reserved
) ||
439 !out
->WriteU8(this->reserved2
) ||
440 !out
->WriteU8(this->reserved3
)) {
441 return parent
->Error("JustificationLevel: Failed to write");
446 bool OpenTypeSILF::SILSub::
447 PseudoMap::ParsePart(Buffer
& table
) {
448 if (parent
->version
>> 16 >= 2 && !table
.ReadU32(&this->unicode
)) {
449 return parent
->Error("PseudoMap: Failed to read unicode");
451 if (parent
->version
>> 16 == 1) {
453 if (!table
.ReadU16(&unicode
)) {
454 return parent
->Error("PseudoMap: Failed to read unicode");
456 this->unicode
= unicode
;
458 if (!table
.ReadU16(&this->nPseudo
)) {
459 return parent
->Error("PseudoMap: Failed to read nPseudo");
464 bool OpenTypeSILF::SILSub::
465 PseudoMap::SerializePart(OTSStream
* out
) const {
466 if ((parent
->version
>> 16 >= 2 && !out
->WriteU32(this->unicode
)) ||
467 (parent
->version
>> 16 == 1 &&
468 !out
->WriteU16(static_cast<uint16_t>(this->unicode
))) ||
469 !out
->WriteU16(this->nPseudo
)) {
470 return parent
->Error("PseudoMap: Failed to write");
475 bool OpenTypeSILF::SILSub::
476 ClassMap::ParsePart(Buffer
& table
) {
477 size_t init_offset
= table
.offset();
478 if (!table
.ReadU16(&this->numClass
)) {
479 return parent
->Error("ClassMap: Failed to read numClass");
481 if (!table
.ReadU16(&this->numLinear
) || this->numLinear
> this->numClass
) {
482 return parent
->Error("ClassMap: Failed to read valid numLinear");
485 //this->oClass.resize(static_cast<unsigned long>(this->numClass) + 1);
486 if (parent
->version
>> 16 >= 4) {
487 unsigned long last_oClass
= 0;
488 for (unsigned long i
= 0; i
<= this->numClass
; ++i
) {
489 this->oClass
.emplace_back();
490 if (!table
.ReadU32(&this->oClass
[i
]) || this->oClass
[i
] < last_oClass
) {
491 return parent
->Error("ClassMap: Failed to read oClass[%lu]", i
);
493 last_oClass
= this->oClass
[i
];
496 if (parent
->version
>> 16 < 4) {
497 unsigned last_oClass
= 0;
498 for (unsigned long i
= 0; i
<= this->numClass
; ++i
) {
500 if (!table
.ReadU16(&offset
) || offset
< last_oClass
) {
501 return parent
->Error("ClassMap: Failed to read oClass[%lu]", i
);
503 last_oClass
= offset
;
504 this->oClass
.push_back(static_cast<uint32_t>(offset
));
508 if (table
.offset() - init_offset
> this->oClass
[this->numLinear
]) {
509 return parent
->Error("ClassMap: Failed to calculate length of glyphs");
511 unsigned long glyphs_len
= (this->oClass
[this->numLinear
] -
512 (table
.offset() - init_offset
))/2;
513 //this->glyphs.resize(glyphs_len);
514 for (unsigned long i
= 0; i
< glyphs_len
; ++i
) {
515 this->glyphs
.emplace_back();
516 if (!table
.ReadU16(&this->glyphs
[i
])) {
517 return parent
->Error("ClassMap: Failed to read glyphs[%lu]", i
);
521 unsigned lookups_len
= this->numClass
- this->numLinear
;
522 // this->numLinear <= this->numClass
523 //this->lookups.resize(lookups_len, parent);
524 for (unsigned i
= 0; i
< lookups_len
; ++i
) {
525 this->lookups
.emplace_back(parent
);
526 if (table
.offset() != init_offset
+ oClass
[this->numLinear
+ i
]) {
527 return parent
->Error("ClassMap: Offset check failed for lookups[%u]", i
);
529 if (!this->lookups
[i
].ParsePart(table
)) {
530 return parent
->Error("ClassMap: Failed to read lookups[%u]", i
);
536 bool OpenTypeSILF::SILSub::
537 ClassMap::SerializePart(OTSStream
* out
) const {
538 if (!out
->WriteU16(this->numClass
) ||
539 !out
->WriteU16(this->numLinear
) ||
540 (parent
->version
>> 16 >= 4 && !SerializeParts(this->oClass
, out
)) ||
541 (parent
->version
>> 16 < 4 &&
543 for (uint32_t offset
: this->oClass
) {
544 if (!out
->WriteU16(static_cast<uint16_t>(offset
))) {
550 !SerializeParts(this->glyphs
, out
) ||
551 !SerializeParts(this->lookups
, out
)) {
552 return parent
->Error("ClassMap: Failed to write");
557 bool OpenTypeSILF::SILSub::ClassMap::
558 LookupClass::ParsePart(Buffer
& table
) {
559 if (!table
.ReadU16(&this->numIDs
)) {
560 return parent
->Error("LookupClass: Failed to read numIDs");
562 if (!table
.ReadU16(&this->searchRange
) ||
563 !table
.ReadU16(&this->entrySelector
) ||
564 !table
.ReadU16(&this->rangeShift
)) {
565 return parent
->Error("LookupClass: Failed to read searchRange..rangeShift");
567 if (this->numIDs
== 0) {
568 if (this->searchRange
!= 0 || this->entrySelector
!= 0 || this->rangeShift
!= 0) {
569 parent
->Warning("LookupClass: Correcting binary-search header for zero-length LookupPair list");
570 this->searchRange
= this->entrySelector
= this->rangeShift
= 0;
573 unsigned floorLog2
= std::floor(std::log2(this->numIDs
));
574 if (this->searchRange
!= (unsigned)std::pow(2, floorLog2
) ||
575 this->entrySelector
!= floorLog2
||
576 this->rangeShift
!= this->numIDs
- this->searchRange
) {
577 parent
->Warning("LookupClass: Correcting binary-search header for LookupPair list");
578 this->searchRange
= (unsigned)std::pow(2, floorLog2
);
579 this->entrySelector
= floorLog2
;
580 this->rangeShift
= this->numIDs
- this->searchRange
;
584 //this->lookups.resize(this->numIDs, parent);
585 for (unsigned i
= 0; i
< numIDs
; ++i
) {
586 this->lookups
.emplace_back(parent
);
587 if (!this->lookups
[i
].ParsePart(table
)) {
588 return parent
->Error("LookupClass: Failed to read lookups[%u]", i
);
594 bool OpenTypeSILF::SILSub::ClassMap::
595 LookupClass::SerializePart(OTSStream
* out
) const {
596 if (!out
->WriteU16(this->numIDs
) ||
597 !out
->WriteU16(this->searchRange
) ||
598 !out
->WriteU16(this->entrySelector
) ||
599 !out
->WriteU16(this->rangeShift
) ||
600 !SerializeParts(this->lookups
, out
)) {
601 return parent
->Error("LookupClass: Failed to write");
606 bool OpenTypeSILF::SILSub::ClassMap::LookupClass::
607 LookupPair::ParsePart(Buffer
& table
) {
608 if (!table
.ReadU16(&this->glyphId
)) {
609 return parent
->Error("LookupPair: Failed to read glyphId");
611 if (!table
.ReadU16(&this->index
)) {
612 return parent
->Error("LookupPair: Failed to read index");
617 bool OpenTypeSILF::SILSub::ClassMap::LookupClass::
618 LookupPair::SerializePart(OTSStream
* out
) const {
619 if (!out
->WriteU16(this->glyphId
) ||
620 !out
->WriteU16(this->index
)) {
621 return parent
->Error("LookupPair: Failed to write");
626 bool OpenTypeSILF::SILSub::
627 SILPass::ParsePart(Buffer
& table
, const size_t SILSub_init_offset
,
628 const size_t next_pass_offset
) {
629 size_t init_offset
= table
.offset();
630 if (!table
.ReadU8(&this->flags
)) {
631 return parent
->Error("SILPass: Failed to read flags");
634 if (!table
.ReadU8(&this->maxRuleLoop
)) {
635 return parent
->Error("SILPass: Failed to read valid maxRuleLoop");
637 if (!table
.ReadU8(&this->maxRuleContext
)) {
638 return parent
->Error("SILPass: Failed to read maxRuleContext");
640 if (!table
.ReadU8(&this->maxBackup
)) {
641 return parent
->Error("SILPass: Failed to read maxBackup");
643 if (!table
.ReadU16(&this->numRules
)) {
644 return parent
->Error("SILPass: Failed to read numRules");
646 if (parent
->version
>> 16 >= 2) {
647 if (!table
.ReadU16(&this->fsmOffset
)) {
648 return parent
->Error("SILPass: Failed to read fsmOffset");
650 if (!table
.ReadU32(&this->pcCode
) ||
651 (parent
->version
>= 3 && this->pcCode
< this->fsmOffset
)) {
652 return parent
->Error("SILPass: Failed to read pcCode");
655 if (!table
.ReadU32(&this->rcCode
) ||
656 (parent
->version
>> 16 >= 2 && this->rcCode
< this->pcCode
)) {
657 return parent
->Error("SILPass: Failed to read valid rcCode");
659 if (!table
.ReadU32(&this->aCode
) || this->aCode
< this->rcCode
) {
660 return parent
->Error("SILPass: Failed to read valid aCode");
662 if (!table
.ReadU32(&this->oDebug
) ||
663 (this->oDebug
&& this->oDebug
< this->aCode
)) {
664 return parent
->Error("SILPass: Failed to read valid oDebug");
666 if (parent
->version
>> 16 >= 3 &&
667 table
.offset() != init_offset
+ this->fsmOffset
) {
668 return parent
->Error("SILPass: fsmOffset check failed");
670 if (!table
.ReadU16(&this->numRows
) ||
671 (this->oDebug
&& this->numRows
< this->numRules
)) {
672 return parent
->Error("SILPass: Failed to read valid numRows");
674 if (!table
.ReadU16(&this->numTransitional
)) {
675 return parent
->Error("SILPass: Failed to read numTransitional");
677 if (!table
.ReadU16(&this->numSuccess
)) {
678 return parent
->Error("SILPass: Failed to read numSuccess");
680 if (!table
.ReadU16(&this->numColumns
)) {
681 return parent
->Error("SILPass: Failed to read numColumns");
683 if (!table
.ReadU16(&this->numRange
)) {
684 return parent
->Error("SILPass: Failed to read numRange");
687 // The following three fields are deprecated and ignored. We fix them up here
688 // just for internal consistency, but the Graphite engine doesn't care.
689 if (!table
.ReadU16(&this->searchRange
) ||
690 !table
.ReadU16(&this->entrySelector
) ||
691 !table
.ReadU16(&this->rangeShift
)) {
692 return parent
->Error("SILPass: Failed to read searchRange..rangeShift");
694 if (this->numRange
== 0) {
695 if (this->searchRange
!= 0 || this->entrySelector
!= 0 || this->rangeShift
!= 0) {
696 this->searchRange
= this->entrySelector
= this->rangeShift
= 0;
699 unsigned floorLog2
= std::floor(std::log2(this->numRange
));
700 if (this->searchRange
!= 6 * (unsigned)std::pow(2, floorLog2
) ||
701 this->entrySelector
!= floorLog2
||
702 this->rangeShift
!= 6 * this->numRange
- this->searchRange
) {
703 this->searchRange
= 6 * (unsigned)std::pow(2, floorLog2
);
704 this->entrySelector
= floorLog2
;
705 this->rangeShift
= 6 * this->numRange
- this->searchRange
;
709 //this->ranges.resize(this->numRange, parent);
710 for (unsigned i
= 0 ; i
< this->numRange
; ++i
) {
711 this->ranges
.emplace_back(parent
);
712 if (!this->ranges
[i
].ParsePart(table
)) {
713 return parent
->Error("SILPass: Failed to read ranges[%u]", i
);
716 unsigned ruleMap_len
= 0; // maximum value in oRuleMap
717 //this->oRuleMap.resize(static_cast<unsigned long>(this->numSuccess) + 1);
718 for (unsigned long i
= 0; i
<= this->numSuccess
; ++i
) {
719 this->oRuleMap
.emplace_back();
720 if (!table
.ReadU16(&this->oRuleMap
[i
])) {
721 return parent
->Error("SILPass: Failed to read oRuleMap[%u]", i
);
723 if (oRuleMap
[i
] > ruleMap_len
) {
724 ruleMap_len
= oRuleMap
[i
];
728 //this->ruleMap.resize(ruleMap_len);
729 for (unsigned i
= 0; i
< ruleMap_len
; ++i
) {
730 this->ruleMap
.emplace_back();
731 if (!table
.ReadU16(&this->ruleMap
[i
])) {
732 return parent
->Error("SILPass: Failed to read ruleMap[%u]", i
);
736 if (!table
.ReadU8(&this->minRulePreContext
)) {
737 return parent
->Error("SILPass: Failed to read minRulePreContext");
739 if (!table
.ReadU8(&this->maxRulePreContext
) ||
740 this->maxRulePreContext
< this->minRulePreContext
) {
741 return parent
->Error("SILPass: Failed to read valid maxRulePreContext");
744 unsigned startStates_len
= this->maxRulePreContext
- this->minRulePreContext
746 // this->minRulePreContext <= this->maxRulePreContext
747 //this->startStates.resize(startStates_len);
748 for (unsigned i
= 0; i
< startStates_len
; ++i
) {
749 this->startStates
.emplace_back();
750 if (!table
.ReadS16(&this->startStates
[i
])) {
751 return parent
->Error("SILPass: Failed to read startStates[%u]", i
);
755 //this->ruleSortKeys.resize(this->numRules);
756 for (unsigned i
= 0; i
< this->numRules
; ++i
) {
757 this->ruleSortKeys
.emplace_back();
758 if (!table
.ReadU16(&this->ruleSortKeys
[i
])) {
759 return parent
->Error("SILPass: Failed to read ruleSortKeys[%u]", i
);
763 //this->rulePreContext.resize(this->numRules);
764 for (unsigned i
= 0; i
< this->numRules
; ++i
) {
765 this->rulePreContext
.emplace_back();
766 if (!table
.ReadU8(&this->rulePreContext
[i
])) {
767 return parent
->Error("SILPass: Failed to read rulePreContext[%u]", i
);
771 if (parent
->version
>> 16 >= 2) {
772 if (!table
.ReadU8(&this->collisionThreshold
)) {
773 return parent
->Error("SILPass: Failed to read collisionThreshold");
775 if (!table
.ReadU16(&this->pConstraint
)) {
776 return parent
->Error("SILPass: Failed to read pConstraint");
780 unsigned long ruleConstraints_len
= this->aCode
- this->rcCode
;
781 // this->rcCode <= this->aCode
782 //this->oConstraints.resize(static_cast<unsigned long>(this->numRules) + 1);
783 for (unsigned long i
= 0; i
<= this->numRules
; ++i
) {
784 this->oConstraints
.emplace_back();
785 if (!table
.ReadU16(&this->oConstraints
[i
]) ||
786 this->oConstraints
[i
] > ruleConstraints_len
) {
787 return parent
->Error("SILPass: Failed to read valid oConstraints[%lu]",
792 if (!this->oDebug
&& this->aCode
> next_pass_offset
) {
793 return parent
->Error("SILPass: Failed to calculate length of actions");
795 unsigned long actions_len
= this->oDebug
? this->oDebug
- this->aCode
:
796 next_pass_offset
- this->aCode
;
797 // if this->oDebug, then this->aCode <= this->oDebug
798 //this->oActions.resize(static_cast<unsigned long>(this->numRules) + 1);
799 for (unsigned long i
= 0; i
<= this->numRules
; ++i
) {
800 this->oActions
.emplace_back();
801 if (!table
.ReadU16(&this->oActions
[i
]) ||
802 (this->oActions
[i
] > actions_len
)) {
803 return parent
->Error("SILPass: Failed to read valid oActions[%lu]", i
);
807 //this->stateTrans.resize(this->numTransitional);
808 for (unsigned i
= 0; i
< this->numTransitional
; ++i
) {
809 this->stateTrans
.emplace_back();
810 //this->stateTrans[i].resize(this->numColumns);
811 for (unsigned j
= 0; j
< this->numColumns
; ++j
) {
812 this->stateTrans
[i
].emplace_back();
813 if (!table
.ReadU16(&stateTrans
[i
][j
])) {
814 return parent
->Error("SILPass: Failed to read stateTrans[%u][%u]",
820 if (parent
->version
>> 16 >= 2) {
821 if (!table
.ReadU8(&this->reserved2
)) {
822 return parent
->Error("SILPass: Failed to read reserved2");
824 if (this->reserved2
!= 0) {
825 parent
->Warning("SILPass: Nonzero reserved2");
828 if (table
.offset() != SILSub_init_offset
+ this->pcCode
) {
829 return parent
->Error("SILPass: pcCode check failed");
831 //this->passConstraints.resize(this->pConstraint);
832 for (unsigned i
= 0; i
< this->pConstraint
; ++i
) {
833 this->passConstraints
.emplace_back();
834 if (!table
.ReadU8(&this->passConstraints
[i
])) {
835 return parent
->Error("SILPass: Failed to read passConstraints[%u]", i
);
840 if (table
.offset() != SILSub_init_offset
+ this->rcCode
) {
841 return parent
->Error("SILPass: rcCode check failed");
843 //this->ruleConstraints.resize(ruleConstraints_len); // calculated above
844 for (unsigned long i
= 0; i
< ruleConstraints_len
; ++i
) {
845 this->ruleConstraints
.emplace_back();
846 if (!table
.ReadU8(&this->ruleConstraints
[i
])) {
847 return parent
->Error("SILPass: Failed to read ruleConstraints[%u]", i
);
851 if (table
.offset() != SILSub_init_offset
+ this->aCode
) {
852 return parent
->Error("SILPass: aCode check failed");
854 //this->actions.resize(actions_len); // calculated above
855 for (unsigned long i
= 0; i
< actions_len
; ++i
) {
856 this->actions
.emplace_back();
857 if (!table
.ReadU8(&this->actions
[i
])) {
858 return parent
->Error("SILPass: Failed to read actions[%u]", i
);
863 OpenTypeNAME
* name
= static_cast<OpenTypeNAME
*>(
864 parent
->GetFont()->GetTypedTable(OTS_TAG_NAME
));
866 return parent
->Error("SILPass: Required name table is missing");
869 if (table
.offset() != SILSub_init_offset
+ this->oDebug
) {
870 return parent
->Error("SILPass: oDebug check failed");
872 //this->dActions.resize(this->numRules);
873 for (unsigned i
= 0; i
< this->numRules
; ++i
) {
874 this->dActions
.emplace_back();
875 if (!table
.ReadU16(&this->dActions
[i
]) ||
876 !name
->IsValidNameId(this->dActions
[i
])) {
877 return parent
->Error("SILPass: Failed to read valid dActions[%u]", i
);
881 unsigned dStates_len
= this->numRows
- this->numRules
;
882 // this->numRules <= this->numRows
883 //this->dStates.resize(dStates_len);
884 for (unsigned i
= 0; i
< dStates_len
; ++i
) {
885 this->dStates
.emplace_back();
886 if (!table
.ReadU16(&this->dStates
[i
]) ||
887 !name
->IsValidNameId(this->dStates
[i
])) {
888 return parent
->Error("SILPass: Failed to read valid dStates[%u]", i
);
892 //this->dCols.resize(this->numRules);
893 for (unsigned i
= 0; i
< this->numRules
; ++i
) {
894 this->dCols
.emplace_back();
895 if (!table
.ReadU16(&this->dCols
[i
]) ||
896 !name
->IsValidNameId(this->dCols
[i
])) {
897 return parent
->Error("SILPass: Failed to read valid dCols[%u]");
904 bool OpenTypeSILF::SILSub::
905 SILPass::SerializePart(OTSStream
* out
) const {
906 if (!out
->WriteU8(this->flags
) ||
907 !out
->WriteU8(this->maxRuleLoop
) ||
908 !out
->WriteU8(this->maxRuleContext
) ||
909 !out
->WriteU8(this->maxBackup
) ||
910 !out
->WriteU16(this->numRules
) ||
911 (parent
->version
>> 16 >= 2 &&
912 (!out
->WriteU16(this->fsmOffset
) ||
913 !out
->WriteU32(this->pcCode
))) ||
914 !out
->WriteU32(this->rcCode
) ||
915 !out
->WriteU32(this->aCode
) ||
916 !out
->WriteU32(this->oDebug
) ||
917 !out
->WriteU16(this->numRows
) ||
918 !out
->WriteU16(this->numTransitional
) ||
919 !out
->WriteU16(this->numSuccess
) ||
920 !out
->WriteU16(this->numColumns
) ||
921 !out
->WriteU16(this->numRange
) ||
922 !out
->WriteU16(this->searchRange
) ||
923 !out
->WriteU16(this->entrySelector
) ||
924 !out
->WriteU16(this->rangeShift
) ||
925 !SerializeParts(this->ranges
, out
) ||
926 !SerializeParts(this->oRuleMap
, out
) ||
927 !SerializeParts(this->ruleMap
, out
) ||
928 !out
->WriteU8(this->minRulePreContext
) ||
929 !out
->WriteU8(this->maxRulePreContext
) ||
930 !SerializeParts(this->startStates
, out
) ||
931 !SerializeParts(this->ruleSortKeys
, out
) ||
932 !SerializeParts(this->rulePreContext
, out
) ||
933 (parent
->version
>> 16 >= 2 &&
934 (!out
->WriteU8(this->collisionThreshold
) ||
935 !out
->WriteU16(this->pConstraint
))) ||
936 !SerializeParts(this->oConstraints
, out
) ||
937 !SerializeParts(this->oActions
, out
) ||
938 !SerializeParts(this->stateTrans
, out
) ||
939 (parent
->version
>> 16 >= 2 &&
940 (!out
->WriteU8(this->reserved2
) ||
941 !SerializeParts(this->passConstraints
, out
))) ||
942 !SerializeParts(this->ruleConstraints
, out
) ||
943 !SerializeParts(this->actions
, out
) ||
944 !SerializeParts(this->dActions
, out
) ||
945 !SerializeParts(this->dStates
, out
) ||
946 !SerializeParts(this->dCols
, out
)) {
947 return parent
->Error("SILPass: Failed to write");
952 bool OpenTypeSILF::SILSub::SILPass::
953 PassRange::ParsePart(Buffer
& table
) {
954 if (!table
.ReadU16(&this->firstId
)) {
955 return parent
->Error("PassRange: Failed to read firstId");
957 if (!table
.ReadU16(&this->lastId
)) {
958 return parent
->Error("PassRange: Failed to read lastId");
960 if (!table
.ReadU16(&this->colId
)) {
961 return parent
->Error("PassRange: Failed to read colId");
966 bool OpenTypeSILF::SILSub::SILPass::
967 PassRange::SerializePart(OTSStream
* out
) const {
968 if (!out
->WriteU16(this->firstId
) ||
969 !out
->WriteU16(this->lastId
) ||
970 !out
->WriteU16(this->colId
)) {
971 return parent
->Error("PassRange: Failed to write");