Coverage Report

Created: 2026-11-12 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ots/src/cmap.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 "cmap.h"
6
7
#include <algorithm>
8
#include <set>
9
#include <utility>
10
#include <vector>
11
12
#include "maxp.h"
13
#include "os2.h"
14
15
// cmap - Character To Glyph Index Mapping Table
16
// http://www.microsoft.com/typography/otspec/cmap.htm
17
18
namespace {
19
20
struct CMAPSubtableHeader {
21
  uint16_t platform;
22
  uint16_t encoding;
23
  uint32_t offset;
24
  uint16_t format;
25
  uint32_t length;
26
  uint32_t language;
27
};
28
29
struct Subtable314Range {
30
  uint16_t start_range;
31
  uint16_t end_range;
32
  int16_t id_delta;
33
  uint16_t id_range_offset;
34
  uint32_t id_range_offset_offset;
35
};
36
37
// Glyph array size for the Mac Roman (format 0) table.
38
const size_t kFormat0ArraySize = 256;
39
40
// The upper limit of the Unicode code point.
41
const uint32_t kUnicodeUpperLimit = 0x10FFFF;
42
43
// The maximum number of UVS records (See below).
44
const uint32_t kMaxCMAPSelectorRecords = 259;
45
// The range of UVSes are:
46
//   0x180B-0x180D (3 code points)
47
//   0xFE00-0xFE0F (16 code points)
48
//   0xE0100-0xE01EF (240 code points)
49
const uint32_t kMongolianVSStart = 0x180B;
50
const uint32_t kMongolianVSEnd = 0x180D;
51
const uint32_t kVSStart = 0xFE00;
52
const uint32_t kVSEnd = 0xFE0F;
53
const uint32_t kIVSStart = 0xE0100;
54
const uint32_t kIVSEnd = 0xE01EF;
55
const uint32_t kUVSUpperLimit = 0xFFFFFF;
56
57
} // namespace
58
59
namespace ots {
60
61
// Parses Format 4 tables
62
bool OpenTypeCMAP::ParseFormat4(int platform, int encoding,
63
79.4k
              const uint8_t *data, size_t length, uint16_t num_glyphs) {
64
79.4k
  ots::Buffer subtable(data, length);
65
66
  // 0.3.4, 3.0.4 or 3.1.4 subtables are complex and, rather than expanding the
67
  // whole thing and recompacting it, we validate it and include it verbatim
68
  // in the output.
69
70
79.4k
  OpenTypeOS2 *os2 = static_cast<OpenTypeOS2*>(
71
79.4k
      GetFont()->GetTypedTable(OTS_TAG_OS2));
72
79.4k
  if (!os2) {
73
0
    return Error("Required OS/2 table missing");
74
0
  }
75
76
79.4k
  if (!subtable.Skip(4)) {
77
42
    return Error("Can't read 4 bytes at start of cmap format 4 subtable");
78
42
  }
79
79.4k
  uint16_t language = 0;
80
79.4k
  if (!subtable.ReadU16(&language)) {
81
43
    return Error("Can't read language");
82
43
  }
83
79.4k
  if (language) {
84
    // Platform ID 3 (windows) subtables should have language '0'.
85
45
    return Error("Languages should be 0 (%d)", language);
86
45
  }
87
88
79.3k
  uint16_t segcountx2, search_range, entry_selector, range_shift;
89
79.3k
  segcountx2 = search_range = entry_selector = range_shift = 0;
90
79.3k
  if (!subtable.ReadU16(&segcountx2) ||
91
79.3k
      !subtable.ReadU16(&search_range) ||
92
79.3k
      !subtable.ReadU16(&entry_selector) ||
93
79.2k
      !subtable.ReadU16(&range_shift)) {
94
118
    return Error("Failed to read subcmap structure");
95
118
  }
96
97
79.2k
  if (segcountx2 & 1 || search_range & 1) {
98
86
    return Error("Bad subcmap structure");
99
86
  }
100
79.1k
  const uint16_t segcount = segcountx2 >> 1;
101
  // There must be at least one segment according the spec.
102
79.1k
  if (segcount < 1) {
103
42
    return Error("Segcount < 1 (%d)", segcount);
104
42
  }
105
106
  // log2segcount is the maximal x s.t. 2^x < segcount
107
79.1k
  unsigned log2segcount = 0;
108
236k
  while (1u << (log2segcount + 1) <= segcount) {
109
157k
    log2segcount++;
110
157k
  }
111
112
79.1k
  const uint16_t expected_search_range = 2 * 1u << log2segcount;
113
79.1k
  if (expected_search_range != search_range) {
114
54
    return Error("expected search range != search range (%d != %d)", expected_search_range, search_range);
115
54
  }
116
117
79.0k
  if (entry_selector != log2segcount) {
118
50
    return Error("entry selector != log2(segement count) (%d != %d)", entry_selector, log2segcount);
119
50
  }
120
121
79.0k
  const uint16_t expected_range_shift = segcountx2 - search_range;
122
79.0k
  if (range_shift != expected_range_shift) {
123
50
    return Error("unexpected range shift (%d != %d)", range_shift, expected_range_shift);
124
50
  }
125
126
78.9k
  std::vector<Subtable314Range> ranges(segcount);
127
128
513k
  for (unsigned i = 0; i < segcount; ++i) {
129
434k
    if (!subtable.ReadU16(&ranges[i].end_range)) {
130
26
      return Error("Failed to read segment %d", i);
131
26
    }
132
434k
  }
133
134
78.9k
  uint16_t padding;
135
78.9k
  if (!subtable.ReadU16(&padding)) {
136
38
    return Error("Failed to read cmap subtable segment padding");
137
38
  }
138
78.8k
  if (padding) {
139
44
    return Error("Non zero cmap subtable segment padding (%d)", padding);
140
44
  }
141
142
513k
  for (unsigned i = 0; i < segcount; ++i) {
143
434k
    if (!subtable.ReadU16(&ranges[i].start_range)) {
144
43
      return Error("Failed to read segment start range %d", i);
145
43
    }
146
434k
  }
147
513k
  for (unsigned i = 0; i < segcount; ++i) {
148
434k
    if (!subtable.ReadS16(&ranges[i].id_delta)) {
149
42
      return Error("Failed to read segment delta %d", i);
150
42
    }
151
434k
  }
152
512k
  for (unsigned i = 0; i < segcount; ++i) {
153
433k
    ranges[i].id_range_offset_offset = subtable.offset();
154
433k
    if (!subtable.ReadU16(&ranges[i].id_range_offset)) {
155
40
      return Error("Failed to read segment range offset %d", i);
156
40
    }
157
158
433k
    if (ranges[i].id_range_offset & 1) {
159
      // Some font generators seem to put 65535 on id_range_offset
160
      // for 0xFFFF-0xFFFF range.
161
      // (e.g., many fonts in http://www.princexml.com/fonts/)
162
35.0k
      if (i == segcount - 1u) {
163
34.9k
        Warning("bad id_range_offset");
164
34.9k
        ranges[i].id_range_offset = 0;
165
        // The id_range_offset value in the transcoded font will not change
166
        // since this table is not actually "transcoded" yet.
167
34.9k
      } else {
168
43
        return Error("Bad segment offset (%d)", ranges[i].id_range_offset);
169
43
      }
170
35.0k
    }
171
433k
  }
172
173
  // ranges must be ascending order, based on the end_code. Ranges may not
174
  // overlap.
175
433k
  for (unsigned i = 1; i < segcount; ++i) {
176
354k
    if ((i == segcount - 1u) &&
177
78.4k
        (ranges[i - 1].start_range == 0xffff) &&
178
3.16k
        (ranges[i - 1].end_range == 0xffff) &&
179
84
        (ranges[i].start_range == 0xffff) &&
180
51
        (ranges[i].end_range == 0xffff)) {
181
      // Some fonts (e.g., Germania.ttf) have multiple 0xffff terminators.
182
      // We'll accept them as an exception.
183
33
      Warning("multiple 0xffff terminators found");
184
33
      continue;
185
33
    }
186
187
    // Note: some Linux fonts (e.g., LucidaSansOblique.ttf, bsmi00lp.ttf) have
188
    // unsorted table...
189
354k
    if (ranges[i].end_range <= ranges[i - 1].end_range) {
190
94
      return Error("Out of order end range (%d <= %d)", ranges[i].end_range, ranges[i-1].end_range);
191
94
    }
192
354k
    if (ranges[i].start_range <= ranges[i - 1].end_range) {
193
44
      return Error("out of order start range (%d <= %d)", ranges[i].start_range, ranges[i-1].end_range);
194
44
    }
195
196
    // On many fonts, the value of {first, last}_char_index are incorrect.
197
    // Fix them.
198
354k
    if (os2->table.first_char_index != 0xFFFF &&
199
341k
        ranges[i].start_range != 0xFFFF &&
200
251k
        os2->table.first_char_index > ranges[i].start_range) {
201
36.1k
      os2->table.first_char_index = ranges[i].start_range;
202
36.1k
    }
203
354k
    if (os2->table.last_char_index != 0xFFFF &&
204
290k
        ranges[i].end_range != 0xFFFF &&
205
221k
        os2->table.last_char_index < ranges[i].end_range) {
206
79.5k
      os2->table.last_char_index = ranges[i].end_range;
207
79.5k
    }
208
354k
  }
209
210
  // The last range must end at 0xffff
211
78.5k
  if (ranges[segcount - 1].start_range != 0xffff || ranges[segcount - 1].end_range != 0xffff) {
212
119
    return Error("Final segment start and end must be 0xFFFF (0x%04X-0x%04X)",
213
119
                           ranges[segcount - 1].start_range, ranges[segcount - 1].end_range);
214
119
  }
215
216
  // A format 4 CMAP subtable is complex. To be safe we simulate a lookup of
217
  // each code-point defined in the table and make sure that they are all valid
218
  // glyphs and that we don't access anything out-of-bounds.
219
510k
  for (unsigned i = 0; i < segcount; ++i) {
220
2.62M
    for (unsigned cp = ranges[i].start_range; cp <= ranges[i].end_range; ++cp) {
221
2.18M
      const uint16_t code_point = static_cast<uint16_t>(cp);
222
2.18M
      if (ranges[i].id_range_offset == 0) {
223
        // this is explictly allowed to overflow in the spec
224
1.80M
        const uint16_t glyph = code_point + ranges[i].id_delta;
225
1.80M
        if (glyph >= num_glyphs) {
226
86
          return Error("Range glyph reference too high (%d > %d)", glyph, num_glyphs - 1);
227
86
        }
228
1.80M
      } else {
229
389k
        const uint16_t range_delta = code_point - ranges[i].start_range;
230
        // this might seem odd, but it's true. The offset is relative to the
231
        // location of the offset value itself.
232
389k
        const uint32_t glyph_id_offset = ranges[i].id_range_offset_offset +
233
389k
                                         ranges[i].id_range_offset +
234
389k
                                         range_delta * 2;
235
        // We need to be able to access a 16-bit value from this offset
236
389k
        if (glyph_id_offset + 1 >= length) {
237
40
          return Error("bad glyph id offset (%d > %ld)", glyph_id_offset, length);
238
40
        }
239
389k
        uint16_t glyph;
240
389k
        std::memcpy(&glyph, data + glyph_id_offset, 2);
241
389k
        glyph = ots_ntohs(glyph);
242
389k
        if (glyph >= num_glyphs) {
243
45
          return Error("Range glyph reference too high (%d > %d)", glyph, num_glyphs - 1);
244
45
        }
245
389k
      }
246
2.18M
    }
247
432k
  }
248
249
  // We accept the table.
250
  // TODO(yusukes): transcode the subtable.
251
78.2k
  if (platform == 3 && encoding == 0) {
252
1.60k
    this->subtable_3_0_4_data = data;
253
1.60k
    this->subtable_3_0_4_length = length;
254
76.6k
  } else if (platform == 3 && encoding == 1) {
255
68.2k
    this->subtable_3_1_4_data = data;
256
68.2k
    this->subtable_3_1_4_length = length;
257
68.2k
  } else if (platform == 0 && encoding == 3) {
258
8.36k
    this->subtable_0_3_4_data = data;
259
8.36k
    this->subtable_0_3_4_length = length;
260
8.36k
  } else {
261
0
    return Error("Unknown cmap subtable type (platform=%d, encoding=%d)", platform, encoding);
262
0
  }
263
264
78.2k
  return true;
265
78.2k
}
266
267
bool OpenTypeCMAP::Parse31012(const uint8_t *data, size_t length,
268
2.46k
                              uint16_t num_glyphs) {
269
2.46k
  ots::Buffer subtable(data, length);
270
271
  // Format 12 tables are simple. We parse these and fully serialise them
272
  // later.
273
274
2.46k
  if (!subtable.Skip(8)) {
275
60
    return Error("failed to skip the first 8 bytes of format 12 subtable");
276
60
  }
277
2.40k
  uint32_t language = 0;
278
2.40k
  if (!subtable.ReadU32(&language)) {
279
38
    return Error("can't read format 12 subtable language");
280
38
  }
281
2.36k
  if (language) {
282
68
    return Error("format 12 subtable language should be zero (%d)", language);
283
68
  }
284
285
2.29k
  uint32_t num_groups = 0;
286
2.29k
  if (!subtable.ReadU32(&num_groups)) {
287
20
    return Error("can't read number of format 12 subtable groups");
288
20
  }
289
2.27k
  if (num_groups == 0 || subtable.remaining() / 12 < num_groups) {
290
134
    return Error("Bad format 12 subtable group count %d", num_groups);
291
134
  }
292
293
2.14k
  std::vector<ots::OpenTypeCMAPSubtableRange> &groups
294
2.14k
      = this->subtable_3_10_12;
295
2.14k
  groups.resize(num_groups);
296
297
111k
  for (unsigned i = 0; i < num_groups; ++i) {
298
109k
    if (!subtable.ReadU32(&groups[i].start_range) ||
299
109k
        !subtable.ReadU32(&groups[i].end_range) ||
300
109k
        !subtable.ReadU32(&groups[i].start_glyph_id)) {
301
0
      return Error("can't read format 12 subtable group");
302
0
    }
303
304
109k
    if (groups[i].start_range > kUnicodeUpperLimit ||
305
109k
        groups[i].end_range > kUnicodeUpperLimit ||
306
109k
        groups[i].start_glyph_id > 0xFFFF) {
307
177
      return Error("bad format 12 subtable group (startCharCode=0x%4X, endCharCode=0x%4X, startGlyphID=%d)",
308
177
                             groups[i].start_range, groups[i].end_range, groups[i].start_glyph_id);
309
177
    }
310
311
    // We assert that the glyph value is within range. Because of the range
312
    // limits, above, we don't need to worry about overflow.
313
109k
    if (groups[i].end_range < groups[i].start_range) {
314
44
      return Error("format 12 subtable group endCharCode before startCharCode (0x%4X < 0x%4X)",
315
44
                             groups[i].end_range, groups[i].start_range);
316
44
    }
317
109k
    if ((groups[i].end_range - groups[i].start_range) +
318
109k
        groups[i].start_glyph_id >= num_glyphs) {
319
56
      return Error("bad format 12 subtable group startGlyphID (%d)", groups[i].start_glyph_id);
320
56
    }
321
109k
  }
322
323
  // the groups must be sorted by start code and may not overlap
324
109k
  for (unsigned i = 1; i < num_groups; ++i) {
325
107k
    if (groups[i].start_range <= groups[i - 1].start_range) {
326
22
      return Error("out of order format 12 subtable group (startCharCode=0x%4X <= startCharCode=0x%4X of previous group)",
327
22
                             groups[i].start_range, groups[i-1].start_range);
328
22
    }
329
107k
    if (groups[i].start_range <= groups[i - 1].end_range) {
330
6
      return Error("overlapping format 12 subtable groups (startCharCode=0x%4X <= endCharCode=0x%4X of previous group)",
331
6
                             groups[i].start_range, groups[i-1].end_range);
332
6
    }
333
107k
  }
334
335
1.83k
  return true;
336
1.86k
}
337
338
bool OpenTypeCMAP::Parse31013(const uint8_t *data, size_t length,
339
729
                              uint16_t num_glyphs) {
340
729
  ots::Buffer subtable(data, length);
341
342
  // Format 13 tables are simple. We parse these and fully serialise them
343
  // later.
344
345
729
  if (!subtable.Skip(8)) {
346
41
    return Error("Bad cmap subtable length");
347
41
  }
348
688
  uint32_t language = 0;
349
688
  if (!subtable.ReadU32(&language)) {
350
39
    return Error("Can't read cmap subtable language");
351
39
  }
352
649
  if (language) {
353
78
    return Error("Cmap subtable language should be zero but is %d", language);
354
78
  }
355
356
571
  uint32_t num_groups = 0;
357
571
  if (!subtable.ReadU32(&num_groups)) {
358
46
    return Error("Can't read number of groups in a cmap subtable");
359
46
  }
360
361
  // We limit the number of groups in the same way as in 3.10.12 tables. See
362
  // the comment there in
363
525
  if (num_groups == 0 || subtable.remaining() / 12 < num_groups) {
364
136
    return Error("Bad format 13 subtable group count %d", num_groups);
365
136
  }
366
367
389
  std::vector<ots::OpenTypeCMAPSubtableRange> &groups = this->subtable_3_10_13;
368
389
  groups.resize(num_groups);
369
370
1.56k
  for (unsigned i = 0; i < num_groups; ++i) {
371
1.39k
    if (!subtable.ReadU32(&groups[i].start_range) ||
372
1.39k
        !subtable.ReadU32(&groups[i].end_range) ||
373
1.39k
        !subtable.ReadU32(&groups[i].start_glyph_id)) {
374
0
      return Error("Can't read subrange structure in a cmap subtable");
375
0
    }
376
377
    // We conservatively limit all of the values to protect some parsers from
378
    // overflows
379
1.39k
    if (groups[i].start_range > kUnicodeUpperLimit ||
380
1.34k
        groups[i].end_range > kUnicodeUpperLimit ||
381
1.28k
        groups[i].start_glyph_id > 0xFFFF) {
382
176
      return Error("Bad subrange with start_range=%d, end_range=%d, start_glyph_id=%d", groups[i].start_range, groups[i].end_range, groups[i].start_glyph_id);
383
176
    }
384
385
1.21k
    if (groups[i].start_glyph_id >= num_glyphs) {
386
48
      return Error("Subrange starting glyph id too high (%d > %d)", groups[i].start_glyph_id, num_glyphs);
387
48
    }
388
1.21k
  }
389
390
  // the groups must be sorted by start code and may not overlap
391
796
  for (unsigned i = 1; i < num_groups; ++i) {
392
677
    if (groups[i].start_range <= groups[i - 1].start_range) {
393
24
      return Error("Overlapping subrange starts (%d >= %d)", groups[i]. start_range, groups[i-1].start_range);
394
24
    }
395
653
    if (groups[i].start_range <= groups[i - 1].end_range) {
396
22
      return Error("Overlapping subranges (%d <= %d)", groups[i].start_range, groups[i-1].end_range);
397
22
    }
398
653
  }
399
400
119
  return true;
401
165
}
402
403
1.39k
bool OpenTypeCMAP::Parse0514(const uint8_t *data, size_t length) {
404
  // Unicode Variation Selector table
405
1.39k
  ots::Buffer subtable(data, length);
406
407
  // Format 14 tables are simple. We parse these and fully serialise them
408
  // later.
409
410
  // Skip format (USHORT) and length (ULONG)
411
1.39k
  if (!subtable.Skip(6)) {
412
36
    return Error("Can't read start of cmap subtable");
413
36
  }
414
415
1.36k
  uint32_t num_records = 0;
416
1.36k
  if (!subtable.ReadU32(&num_records)) {
417
16
    return Error("Can't read number of records in cmap subtable");
418
16
  }
419
1.34k
  if (num_records == 0 || num_records > kMaxCMAPSelectorRecords) {
420
109
    return Error("Bad format 14 subtable records count %d", num_records);
421
109
  }
422
423
1.23k
  std::vector<ots::OpenTypeCMAPSubtableVSRecord>& records
424
1.23k
      = this->subtable_0_5_14;
425
1.23k
  records.resize(num_records);
426
427
5.72k
  for (unsigned i = 0; i < num_records; ++i) {
428
4.95k
    if (!subtable.ReadU24(&records[i].var_selector) ||
429
4.95k
        !subtable.ReadU32(&records[i].default_offset) ||
430
4.91k
        !subtable.ReadU32(&records[i].non_default_offset)) {
431
76
      return Error("Can't read record structure of record %d in cmap subtale", i);
432
76
    }
433
    // Checks the value of variation selector
434
4.88k
    if (!((records[i].var_selector >= kMongolianVSStart &&
435
4.82k
           records[i].var_selector <= kMongolianVSEnd) ||
436
4.85k
          (records[i].var_selector >= kVSStart &&
437
4.79k
           records[i].var_selector <= kVSEnd) ||
438
4.40k
          (records[i].var_selector >= kIVSStart &&
439
4.31k
           records[i].var_selector <= kIVSEnd))) {
440
156
      return Error("Bad record variation selector (%04X) in record %i", records[i].var_selector, i);
441
156
    }
442
4.72k
    if (i > 0 &&
443
3.65k
        records[i-1].var_selector >= records[i].var_selector) {
444
38
      return Error("Out of order variation selector (%04X >= %04X) in record %d", records[i-1].var_selector, records[i].var_selector, i);
445
38
    }
446
447
    // Checks offsets
448
4.68k
    if (!records[i].default_offset && !records[i].non_default_offset) {
449
42
      return Error("No default aoffset in variation selector record %d", i);
450
42
    }
451
4.64k
    if (records[i].default_offset &&
452
1.92k
        records[i].default_offset >= length) {
453
64
      return Error("Default offset too high (%d >= %ld) in record %d", records[i].default_offset, length, i);
454
64
    }
455
4.58k
    if (records[i].non_default_offset &&
456
3.58k
        records[i].non_default_offset >= length) {
457
92
      return Error("Non default offset too high (%d >= %ld) in record %d", records[i].non_default_offset, length, i);
458
92
    }
459
4.58k
  }
460
461
1.91k
  for (unsigned i = 0; i < num_records; ++i) {
462
    // Checks default UVS table
463
1.69k
    if (records[i].default_offset) {
464
680
      subtable.set_offset(records[i].default_offset);
465
680
      uint32_t num_ranges = 0;
466
680
      if (!subtable.ReadU32(&num_ranges)) {
467
37
        return Error("Can't read number of ranges in record %d", i);
468
37
      }
469
643
      if (num_ranges == 0 || subtable.remaining() / 4 < num_ranges) {
470
92
        return Error("Bad number of ranges (%d) in record %d", num_ranges, i);
471
92
      }
472
473
551
      uint32_t last_unicode_value = 0;
474
551
      std::vector<ots::OpenTypeCMAPSubtableVSRange>& ranges
475
551
          = records[i].ranges;
476
551
      ranges.resize(num_ranges);
477
478
1.15k
      for (unsigned j = 0; j < num_ranges; ++j) {
479
745
        if (!subtable.ReadU24(&ranges[j].unicode_value) ||
480
745
            !subtable.ReadU8(&ranges[j].additional_count)) {
481
0
          return Error("Can't read range info in variation selector record %d", i);
482
0
        }
483
745
        const uint32_t check_value =
484
745
            ranges[j].unicode_value + ranges[j].additional_count;
485
745
        if (ranges[j].unicode_value == 0 ||
486
704
            ranges[j].unicode_value > kUnicodeUpperLimit ||
487
655
            check_value > kUVSUpperLimit ||
488
655
            (last_unicode_value &&
489
162
             ranges[j].unicode_value <= last_unicode_value)) {
490
144
          return Error("Bad Unicode value *%04X) in variation selector range %d record %d", ranges[j].unicode_value, j, i);
491
144
        }
492
601
        last_unicode_value = check_value;
493
601
      }
494
551
    }
495
496
    // Checks non default UVS table
497
1.42k
    if (records[i].non_default_offset) {
498
1.14k
      subtable.set_offset(records[i].non_default_offset);
499
1.14k
      uint32_t num_mappings = 0;
500
1.14k
      if (!subtable.ReadU32(&num_mappings)) {
501
34
        return Error("Can't read number of mappings in variation selector record %d", i);
502
34
      }
503
1.10k
      if (num_mappings == 0 || subtable.remaining() / 5 < num_mappings) {
504
90
        return Error("Bad number of mappings (%d) in variation selector record %d", num_mappings, i);
505
90
      }
506
507
1.01k
      uint32_t last_unicode_value = 0;
508
1.01k
      std::vector<ots::OpenTypeCMAPSubtableVSMapping>& mappings
509
1.01k
          = records[i].mappings;
510
1.01k
      mappings.resize(num_mappings);
511
512
2.11k
      for (unsigned j = 0; j < num_mappings; ++j) {
513
1.25k
        if (!subtable.ReadU24(&mappings[j].unicode_value) ||
514
1.25k
            !subtable.ReadU16(&mappings[j].glyph_id)) {
515
0
          return Error("Can't read mapping %d in variation selector record %d", j, i);
516
0
        }
517
1.25k
        if (mappings[j].glyph_id == 0 || mappings[j].unicode_value == 0) {
518
86
          return Error("Bad mapping (%04X -> %d) in mapping %d of variation selector %d", mappings[j].unicode_value, mappings[j].glyph_id, j, i);
519
86
        }
520
1.16k
        if (mappings[j].unicode_value > kUnicodeUpperLimit) {
521
44
          return Error("Invalid Unicode value (%04X > %04X) in mapping %d of variation selector %d", mappings[j].unicode_value, kUnicodeUpperLimit, j, i);
522
44
        }
523
1.12k
        if (last_unicode_value &&
524
192
            mappings[j].unicode_value <= last_unicode_value) {
525
28
          return Error("Out of order Unicode value (%04X <= %04X) in mapping %d of variation selector %d", mappings[j].unicode_value, last_unicode_value, j, i);
526
28
        }
527
1.09k
        last_unicode_value = mappings[j].unicode_value;
528
1.09k
      }
529
1.01k
    }
530
1.42k
  }
531
532
213
  if (subtable.offset() != length) {
533
22
    return Error("Bad subtable offset (%ld != %ld)", subtable.offset(), length);
534
22
  }
535
191
  this->subtable_0_5_14_length = subtable.offset();
536
191
  return true;
537
213
}
538
539
485
bool OpenTypeCMAP::Parse100(const uint8_t *data, size_t length) {
540
  // Mac Roman table
541
485
  ots::Buffer subtable(data, length);
542
543
485
  if (!subtable.Skip(4)) {
544
105
    return Error("Bad cmap subtable");
545
105
  }
546
380
  uint16_t language = 0;
547
380
  if (!subtable.ReadU16(&language)) {
548
42
    return Error("Can't read language in cmap subtable");
549
42
  }
550
338
  if (language) {
551
    // simsun.ttf has non-zero language id.
552
164
    Warning("language id should be zero: %u", language);
553
164
  }
554
555
338
  this->subtable_1_0_0.reserve(kFormat0ArraySize);
556
55.6k
  for (size_t i = 0; i < kFormat0ArraySize; ++i) {
557
55.4k
    uint8_t glyph_id = 0;
558
55.4k
    if (!subtable.ReadU8(&glyph_id)) {
559
175
      return Error("Can't read glyph id at array[%ld] in cmap subtable", i);
560
175
    }
561
55.3k
    this->subtable_1_0_0.push_back(glyph_id);
562
55.3k
  }
563
564
163
  return true;
565
338
}
566
567
94.6k
bool OpenTypeCMAP::Parse(const uint8_t *data, size_t length) {
568
94.6k
  Buffer table(data, length);
569
570
94.6k
  uint16_t version = 0;
571
94.6k
  uint16_t num_tables = 0;
572
94.6k
  if (!table.ReadU16(&version) ||
573
94.5k
      !table.ReadU16(&num_tables)) {
574
87
    return Error("Can't read structure of cmap");
575
87
  }
576
577
94.5k
  if (version != 0) {
578
73
    return Error("Non zero cmap version (%d)", version);
579
73
  }
580
94.4k
  if (!num_tables) {
581
75
    return Error("No subtables in cmap!");
582
75
  }
583
584
94.3k
  std::vector<CMAPSubtableHeader> subtable_headers;
585
586
  // read the subtable headers
587
94.3k
  subtable_headers.reserve(num_tables);
588
261k
  for (unsigned i = 0; i < num_tables; ++i) {
589
167k
    CMAPSubtableHeader subt;
590
591
167k
    if (!table.ReadU16(&subt.platform) ||
592
167k
        !table.ReadU16(&subt.encoding) ||
593
167k
        !table.ReadU32(&subt.offset)) {
594
131
      return Error("Can't read subtable information cmap subtable %d", i);
595
131
    }
596
597
167k
    subtable_headers.push_back(subt);
598
167k
  }
599
600
94.2k
  const size_t data_offset = table.offset();
601
602
  // make sure that all the offsets are valid.
603
256k
  for (unsigned i = 0; i < num_tables; ++i) {
604
162k
    if (subtable_headers[i].offset > 1024 * 1024 * 1024) {
605
47
      return Error("Bad subtable offset in cmap subtable %d", i);
606
47
    }
607
162k
    if (subtable_headers[i].offset < data_offset ||
608
162k
        subtable_headers[i].offset >= length) {
609
127
      return Error("Bad subtable offset (%d) in cmap subtable %d", subtable_headers[i].offset, i);
610
127
    }
611
162k
  }
612
613
  // the format of the table is the first couple of bytes in the table. The
614
  // length of the table is stored in a format-specific way.
615
255k
  for (unsigned i = 0; i < num_tables; ++i) {
616
161k
    table.set_offset(subtable_headers[i].offset);
617
161k
    if (!table.ReadU16(&subtable_headers[i].format)) {
618
36
      return Error("Can't read cmap subtable header format %d", i);
619
36
    }
620
621
161k
    uint16_t len = 0;
622
161k
    uint16_t lang = 0;
623
161k
    switch (subtable_headers[i].format) {
624
16.0k
      case 0:
625
100k
      case 4:
626
100k
        if (!table.ReadU16(&len)) {
627
40
          return Error("Can't read cmap subtable %d length", i);
628
40
        }
629
100k
        if (!table.ReadU16(&lang)) {
630
42
          return Error("Can't read cmap subtable %d language", i);
631
42
        }
632
100k
        subtable_headers[i].length = len;
633
100k
        subtable_headers[i].language = lang;
634
100k
        break;
635
3.84k
      case 12:
636
6.22k
      case 13:
637
6.22k
        if (!table.Skip(2)) {
638
37
          return Error("Bad cmap subtable %d structure", i);
639
37
        }
640
6.18k
        if (!table.ReadU32(&subtable_headers[i].length)) {
641
39
          return Error("Can read cmap subtable %d length", i);
642
39
        }
643
6.14k
        if (!table.ReadU32(&subtable_headers[i].language)) {
644
7
          return Error("Can't read cmap subtable %d language", i);
645
7
        }
646
6.14k
        break;
647
6.14k
      case 14:
648
1.96k
        if (!table.ReadU32(&subtable_headers[i].length)) {
649
34
          return Error("Can't read cmap subtable %d length", i);
650
34
        }
651
1.93k
        subtable_headers[i].language = 0;
652
1.93k
        break;
653
53.3k
      default:
654
53.3k
        subtable_headers[i].length = 0;
655
53.3k
        subtable_headers[i].language = 0;
656
53.3k
        break;
657
161k
    }
658
161k
  }
659
660
  // check if the table is sorted first by platform ID, then by encoding ID.
661
160k
  for (unsigned i = 1; i < num_tables; ++i) {
662
66.9k
    if (subtable_headers[i - 1].platform > subtable_headers[i].platform ||
663
41.4k
        (subtable_headers[i - 1].platform == subtable_headers[i].platform &&
664
11.2k
         (subtable_headers[i - 1].encoding > subtable_headers[i].encoding ||
665
7.75k
          (subtable_headers[i - 1].encoding == subtable_headers[i].encoding &&
666
1.15k
           subtable_headers[i - 1].language > subtable_headers[i].language))))
667
29.2k
      Warning("subtable %d with platform ID %d, encoding ID %d, language ID %d "
668
29.2k
                  "following subtable with platform ID %d, encoding ID %d, language ID %d",
669
29.2k
                  i,
670
29.2k
                  subtable_headers[i].platform,
671
29.2k
                  subtable_headers[i].encoding,
672
29.2k
                  subtable_headers[i].language,
673
29.2k
                  subtable_headers[i - 1].platform,
674
29.2k
                  subtable_headers[i - 1].encoding,
675
29.2k
                  subtable_headers[i - 1].language);
676
66.9k
  }
677
678
  // Now, verify that all the lengths are sane
679
253k
  for (unsigned i = 0; i < num_tables; ++i) {
680
159k
    if (!subtable_headers[i].length) continue;
681
97.3k
    if (subtable_headers[i].length > 1024 * 1024 * 1024) {
682
92
      return Error("Bad cmap subtable %d length", i);
683
92
    }
684
    // We know that both the offset and length are < 1GB, so the following
685
    // addition doesn't overflow
686
97.2k
    const uint32_t end_byte
687
97.2k
        = subtable_headers[i].offset + subtable_headers[i].length;
688
97.2k
    if (end_byte > length) {
689
189
      return Error("Over long cmap subtable %d @ %d for %d", i, subtable_headers[i].offset, subtable_headers[i].length);
690
189
    }
691
97.2k
  }
692
693
  // check that the cmap subtables are not overlapping.
694
93.5k
  std::set<std::pair<uint32_t, uint32_t> > uniq_checker;
695
93.5k
  std::vector<std::pair<uint32_t, uint8_t> > overlap_checker;
696
252k
  for (unsigned i = 0; i < num_tables; ++i) {
697
159k
    const uint32_t end_byte
698
159k
        = subtable_headers[i].offset + subtable_headers[i].length;
699
700
159k
    if (!uniq_checker.insert(std::make_pair(subtable_headers[i].offset,
701
159k
                                            end_byte)).second) {
702
      // Sometimes Unicode table and MS table share exactly the same data.
703
      // We'll allow this.
704
13.6k
      continue;
705
13.6k
    }
706
145k
    overlap_checker.push_back(
707
145k
        std::make_pair(subtable_headers[i].offset,
708
145k
                       static_cast<uint8_t>(1) /* start */));
709
145k
    overlap_checker.push_back(
710
145k
        std::make_pair(end_byte, static_cast<uint8_t>(0) /* end */));
711
145k
  }
712
93.5k
  std::sort(overlap_checker.begin(), overlap_checker.end());
713
93.5k
  int overlap_count = 0;
714
342k
  for (unsigned i = 0; i < overlap_checker.size(); ++i) {
715
249k
    overlap_count += (overlap_checker[i].second ? 1 : -1);
716
249k
    if (overlap_count > 1) {
717
906
      return Error("Excessive overlap count %d", overlap_count);
718
906
    }
719
249k
  }
720
721
  // we grab the number of glyphs in the file from the maxp table to make sure
722
  // that the character map isn't referencing anything beyound this range.
723
92.6k
  OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>(
724
92.6k
      GetFont()->GetTypedTable(OTS_TAG_MAXP));
725
92.6k
  if (!maxp) {
726
0
    return Error("No maxp table in font! Needed by cmap.");
727
0
  }
728
92.6k
  const uint16_t num_glyphs = maxp->num_glyphs;
729
730
  // We only support a subset of the possible character map tables. Microsoft
731
  // 'strongly recommends' that everyone supports the Unicode BMP table with
732
  // the UCS-4 table for non-BMP glyphs. We'll pass the following subtables:
733
  //   Platform ID   Encoding ID  Format
734
  //   0             0            4       (Unicode Default)
735
  //   0             1            4       (Unicode 1.1)
736
  //   0             3            4       (Unicode BMP)
737
  //   0             3            12      (Unicode UCS-4)
738
  //   0             5            14      (Unicode Variation Sequences)
739
  //   1             0            0       (Mac Roman)
740
  //   3             0            4       (MS Symbol)
741
  //   3             1            4       (MS Unicode BMP)
742
  //   3             10           12      (MS Unicode UCS-4)
743
  //   3             10           13      (MS UCS-4 Fallback mapping)
744
  //
745
  // Note:
746
  //  * 0-0-4 and 0-1-4 tables are (usually) written as a 3-1-4 table. If 3-1-4 table
747
  //    also exists, the 0-0-4 or 0-1-4 tables are ignored.
748
  //  * Unlike 0-0-4 table, 0-3-4 table is written as a 0-3-4 table.
749
  //    Some fonts which include 0-5-14 table seems to be required 0-3-4
750
  //    table. The 0-3-4 table will be wriiten even if 3-1-4 table also exists.
751
  //  * 0-3-12 table is written as a 3-10-12 table. If 3-10-12 table also
752
  //    exists, the 0-3-12 table is ignored.
753
  //
754
755
209k
  for (unsigned i = 0; i < num_tables; ++i) {
756
121k
    if (subtable_headers[i].platform == 0) {
757
      // Unicode platform
758
759
83.8k
      if ((subtable_headers[i].encoding == 0 || subtable_headers[i].encoding == 1) &&
760
66.0k
          (subtable_headers[i].format == 4)) {
761
        // parse and output the 0-0-4 and 0-1-4 tables as 3-1-4 table. Sometimes the 0-0-4
762
        // table actually points to MS symbol data and thus should be parsed as
763
        // 3-0-4 table (e.g., marqueem.ttf and quixotic.ttf). This error will be
764
        // recovered in ots_cmap_serialise().
765
65.4k
        if (!ParseFormat4(3, 1, data + subtable_headers[i].offset,
766
65.4k
                      subtable_headers[i].length, num_glyphs)) {
767
490
          return Error("Failed to parse format 4 cmap subtable %d", i);
768
490
        }
769
65.4k
      } else if ((subtable_headers[i].encoding == 3) &&
770
10.5k
                 (subtable_headers[i].format == 4)) {
771
        // parse and output the 0-3-4 table as 0-3-4 table.
772
8.55k
        if (!ParseFormat4(0, 3, data + subtable_headers[i].offset,
773
8.55k
                      subtable_headers[i].length, num_glyphs)) {
774
182
          return Error("Failed to parse format 4 cmap subtable %d", i);
775
182
        }
776
9.90k
      } else if ((subtable_headers[i].encoding == 3 ||
777
7.91k
                  subtable_headers[i].encoding == 4) &&
778
4.10k
                 (subtable_headers[i].format == 12)) {
779
        // parse and output the 0-3-12 or 0-4-12 tables as 3-10-12 table.
780
1.31k
        if (!Parse31012(data + subtable_headers[i].offset,
781
1.31k
                        subtable_headers[i].length, num_glyphs)) {
782
462
          return Error("Failed to parse format 12 cmap subtable %d", i);
783
462
        }
784
8.59k
      } else if ((subtable_headers[i].encoding == 5) &&
785
1.64k
                 (subtable_headers[i].format == 14)) {
786
1.39k
        if (!Parse0514(data + subtable_headers[i].offset,
787
1.39k
                       subtable_headers[i].length)) {
788
1.20k
          return Error("Failed to parse format 14 cmap subtable %d", i);
789
1.20k
        }
790
1.39k
      }
791
83.8k
    } else if (subtable_headers[i].platform == 1) {
792
      // Mac platform
793
794
2.30k
      if ((subtable_headers[i].encoding == 0) &&
795
1.35k
          (subtable_headers[i].format == 0)) {
796
        // parse and output the 1-0-0 table.
797
485
        if (!Parse100(data + subtable_headers[i].offset,
798
485
                      subtable_headers[i].length)) {
799
322
          return OTS_FAILURE();
800
322
        }
801
485
      }
802
35.0k
    } else if (subtable_headers[i].platform == 3) {
803
      // MS platform
804
805
12.0k
      switch (subtable_headers[i].encoding) {
806
1.98k
        case 0:
807
7.64k
        case 1:
808
7.64k
          if (subtable_headers[i].format == 4) {
809
            // parse 3-0-4 or 3-1-4 table.
810
5.50k
            if (!ParseFormat4(subtable_headers[i].platform,
811
5.50k
                          subtable_headers[i].encoding,
812
5.50k
                          data + subtable_headers[i].offset,
813
5.50k
                          subtable_headers[i].length, num_glyphs)) {
814
562
              return OTS_FAILURE();
815
562
            }
816
5.50k
          }
817
7.08k
          break;
818
7.08k
        case 10:
819
2.61k
          if (subtable_headers[i].format == 12) {
820
1.15k
            this->subtable_3_10_12.clear();
821
1.15k
            if (!Parse31012(data + subtable_headers[i].offset,
822
1.15k
                            subtable_headers[i].length, num_glyphs)) {
823
163
              return OTS_FAILURE();
824
163
            }
825
1.46k
          } else if (subtable_headers[i].format == 13) {
826
729
            this->subtable_3_10_13.clear();
827
729
            if (!Parse31013(data + subtable_headers[i].offset,
828
729
                            subtable_headers[i].length, num_glyphs)) {
829
610
              return OTS_FAILURE();
830
610
            }
831
729
          }
832
1.83k
          break;
833
12.0k
      }
834
12.0k
    }
835
121k
  }
836
837
88.6k
  return true;
838
92.6k
}
839
840
47.0k
bool OpenTypeCMAP::Serialize(OTSStream *out) {
841
47.0k
  const bool have_034 = this->subtable_0_3_4_data != NULL;
842
47.0k
  const bool have_0514 = this->subtable_0_5_14.size() != 0;
843
47.0k
  const bool have_100 = this->subtable_1_0_0.size() != 0;
844
47.0k
  const bool have_304 = this->subtable_3_0_4_data != NULL;
845
  // MS Symbol and MS Unicode tables should not co-exist.
846
  // See the comment above in 0-0-4 parser.
847
47.0k
  const bool have_314 = (!have_304) && this->subtable_3_1_4_data;
848
47.0k
  const bool have_31012 = this->subtable_3_10_12.size() != 0;
849
47.0k
  const bool have_31013 = this->subtable_3_10_13.size() != 0;
850
47.0k
  const uint16_t num_subtables = static_cast<uint16_t>(have_034) +
851
47.0k
                                 static_cast<uint16_t>(have_0514) +
852
47.0k
                                 static_cast<uint16_t>(have_100) +
853
47.0k
                                 static_cast<uint16_t>(have_304) +
854
47.0k
                                 static_cast<uint16_t>(have_314) +
855
47.0k
                                 static_cast<uint16_t>(have_31012) +
856
47.0k
                                 static_cast<uint16_t>(have_31013);
857
47.0k
  const off_t table_start = out->Tell();
858
859
  // Some fonts don't have 3-0-4 MS Symbol nor 3-1-4 Unicode BMP tables
860
  // (e.g., old fonts for Mac). We don't support them.
861
47.0k
  if (!have_304 && !have_314 && !have_034 && !have_31012 && !have_31013) {
862
744
    return Error("no supported subtables were found");
863
744
  }
864
865
46.2k
  if (!out->WriteU16(0) ||
866
46.2k
      !out->WriteU16(num_subtables)) {
867
0
    return OTS_FAILURE();
868
0
  }
869
870
46.2k
  const off_t record_offset = out->Tell();
871
46.2k
  if (!out->Pad(num_subtables * 8)) {
872
0
    return OTS_FAILURE();
873
0
  }
874
875
46.2k
  const off_t offset_034 = out->Tell();
876
46.2k
  if (have_034) {
877
4.34k
    if (!out->Write(this->subtable_0_3_4_data,
878
4.34k
                    this->subtable_0_3_4_length)) {
879
0
      return OTS_FAILURE();
880
0
    }
881
4.34k
  }
882
883
46.2k
  const off_t offset_0514 = out->Tell();
884
46.2k
  if (have_0514) {
885
82
    const std::vector<ots::OpenTypeCMAPSubtableVSRecord> &records
886
82
        = this->subtable_0_5_14;
887
82
    const unsigned num_records = records.size();
888
82
    if (!out->WriteU16(14) ||
889
82
        !out->WriteU32(this->subtable_0_5_14_length) ||
890
82
        !out->WriteU32(num_records)) {
891
0
      return OTS_FAILURE();
892
0
    }
893
333
    for (unsigned i = 0; i < num_records; ++i) {
894
251
      if (!out->WriteU24(records[i].var_selector) ||
895
251
          !out->WriteU32(records[i].default_offset) ||
896
251
          !out->WriteU32(records[i].non_default_offset)) {
897
0
        return OTS_FAILURE();
898
0
      }
899
251
    }
900
333
    for (unsigned i = 0; i < num_records; ++i) {
901
251
      if (records[i].default_offset) {
902
61
        const std::vector<ots::OpenTypeCMAPSubtableVSRange> &ranges
903
61
            = records[i].ranges;
904
61
        const unsigned num_ranges = ranges.size();
905
61
        if (!out->Seek(records[i].default_offset + offset_0514) ||
906
61
            !out->WriteU32(num_ranges)) {
907
0
          return OTS_FAILURE();
908
0
        }
909
124
        for (unsigned j = 0; j < num_ranges; ++j) {
910
63
          if (!out->WriteU24(ranges[j].unicode_value) ||
911
63
              !out->WriteU8(ranges[j].additional_count)) {
912
0
            return OTS_FAILURE();
913
0
          }
914
63
        }
915
61
      }
916
251
      if (records[i].non_default_offset) {
917
208
        const std::vector<ots::OpenTypeCMAPSubtableVSMapping> &mappings
918
208
            = records[i].mappings;
919
208
        const unsigned num_mappings = mappings.size();
920
208
        if (!out->Seek(records[i].non_default_offset + offset_0514) ||
921
208
            !out->WriteU32(num_mappings)) {
922
0
          return OTS_FAILURE();
923
0
        }
924
491
        for (unsigned j = 0; j < num_mappings; ++j) {
925
283
          if (!out->WriteU24(mappings[j].unicode_value) ||
926
283
              !out->WriteU16(mappings[j].glyph_id)) {
927
0
            return OTS_FAILURE();
928
0
          }
929
283
        }
930
208
      }
931
251
    }
932
82
  }
933
934
46.2k
  const off_t offset_100 = out->Tell();
935
46.2k
  if (have_100) {
936
35
    if (!out->WriteU16(0) ||  // format
937
35
        !out->WriteU16(6 + kFormat0ArraySize) ||  // length
938
35
        !out->WriteU16(0)) {  // language
939
0
      return OTS_FAILURE();
940
0
    }
941
35
    if (!out->Write(&(this->subtable_1_0_0[0]), kFormat0ArraySize)) {
942
0
      return OTS_FAILURE();
943
0
    }
944
35
  }
945
946
46.2k
  const off_t offset_304 = out->Tell();
947
46.2k
  if (have_304) {
948
968
    if (!out->Write(this->subtable_3_0_4_data,
949
968
                    this->subtable_3_0_4_length)) {
950
0
      return OTS_FAILURE();
951
0
    }
952
968
  }
953
954
46.2k
  const off_t offset_314 = out->Tell();
955
46.2k
  if (have_314) {
956
41.0k
    if (!out->Write(this->subtable_3_1_4_data,
957
41.0k
                    this->subtable_3_1_4_length)) {
958
0
      return OTS_FAILURE();
959
0
    }
960
41.0k
  }
961
962
46.2k
  const off_t offset_31012 = out->Tell();
963
46.2k
  if (have_31012) {
964
160
    std::vector<OpenTypeCMAPSubtableRange> &groups
965
160
        = this->subtable_3_10_12;
966
160
    const unsigned num_groups = groups.size();
967
160
    if (!out->WriteU16(12) ||
968
160
        !out->WriteU16(0) ||
969
160
        !out->WriteU32(num_groups * 12 + 16) ||
970
160
        !out->WriteU32(0) ||
971
160
        !out->WriteU32(num_groups)) {
972
0
      return OTS_FAILURE();
973
0
    }
974
975
5.17k
    for (unsigned i = 0; i < num_groups; ++i) {
976
5.01k
      if (!out->WriteU32(groups[i].start_range) ||
977
5.01k
          !out->WriteU32(groups[i].end_range) ||
978
5.01k
          !out->WriteU32(groups[i].start_glyph_id)) {
979
0
        return OTS_FAILURE();
980
0
      }
981
5.01k
    }
982
160
  }
983
984
46.2k
  const off_t offset_31013 = out->Tell();
985
46.2k
  if (have_31013) {
986
82
    std::vector<OpenTypeCMAPSubtableRange> &groups
987
82
        = this->subtable_3_10_13;
988
82
    const unsigned num_groups = groups.size();
989
82
    if (!out->WriteU16(13) ||
990
82
        !out->WriteU16(0) ||
991
82
        !out->WriteU32(num_groups * 12 + 16) ||
992
82
        !out->WriteU32(0) ||
993
82
        !out->WriteU32(num_groups)) {
994
0
      return OTS_FAILURE();
995
0
    }
996
997
496
    for (unsigned i = 0; i < num_groups; ++i) {
998
414
      if (!out->WriteU32(groups[i].start_range) ||
999
414
          !out->WriteU32(groups[i].end_range) ||
1000
414
          !out->WriteU32(groups[i].start_glyph_id)) {
1001
0
        return OTS_FAILURE();
1002
0
      }
1003
414
    }
1004
82
  }
1005
1006
46.2k
  const off_t table_end = out->Tell();
1007
1008
  // Now seek back and write the table of offsets
1009
46.2k
  if (!out->Seek(record_offset)) {
1010
0
    return OTS_FAILURE();
1011
0
  }
1012
1013
46.2k
  if (have_034) {
1014
4.34k
    if (!out->WriteU16(0) ||
1015
4.34k
        !out->WriteU16(3) ||
1016
4.34k
        !out->WriteU32(offset_034 - table_start)) {
1017
0
      return OTS_FAILURE();
1018
0
    }
1019
4.34k
  }
1020
1021
46.2k
  if (have_0514) {
1022
82
    if (!out->WriteU16(0) ||
1023
82
        !out->WriteU16(5) ||
1024
82
        !out->WriteU32(offset_0514 - table_start)) {
1025
0
      return OTS_FAILURE();
1026
0
    }
1027
82
  }
1028
1029
46.2k
  if (have_100) {
1030
35
    if (!out->WriteU16(1) ||
1031
35
        !out->WriteU16(0) ||
1032
35
        !out->WriteU32(offset_100 - table_start)) {
1033
0
      return OTS_FAILURE();
1034
0
    }
1035
35
  }
1036
1037
46.2k
  if (have_304) {
1038
968
    if (!out->WriteU16(3) ||
1039
968
        !out->WriteU16(0) ||
1040
968
        !out->WriteU32(offset_304 - table_start)) {
1041
0
      return OTS_FAILURE();
1042
0
    }
1043
968
  }
1044
1045
46.2k
  if (have_314) {
1046
41.0k
    if (!out->WriteU16(3) ||
1047
41.0k
        !out->WriteU16(1) ||
1048
41.0k
        !out->WriteU32(offset_314 - table_start)) {
1049
0
      return OTS_FAILURE();
1050
0
    }
1051
41.0k
  }
1052
1053
46.2k
  if (have_31012) {
1054
160
    if (!out->WriteU16(3) ||
1055
160
        !out->WriteU16(10) ||
1056
160
        !out->WriteU32(offset_31012 - table_start)) {
1057
0
      return OTS_FAILURE();
1058
0
    }
1059
160
  }
1060
1061
46.2k
  if (have_31013) {
1062
82
    if (!out->WriteU16(3) ||
1063
82
        !out->WriteU16(10) ||
1064
82
        !out->WriteU32(offset_31013 - table_start)) {
1065
0
      return OTS_FAILURE();
1066
0
    }
1067
82
  }
1068
1069
46.2k
  if (!out->Seek(table_end)) {
1070
0
    return OTS_FAILURE();
1071
0
  }
1072
1073
46.2k
  return true;
1074
46.2k
}
1075
1076
}  // namespace ots