Coverage Report

Created: 2026-06-09 06:03

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