Coverage Report

Created: 2026-11-12 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ots/src/ots.h
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
#ifndef OTS_H_
6
#define OTS_H_
7
8
#ifdef HAVE_CONFIG_H
9
#include "config.h"
10
#endif
11
12
#include <stddef.h>
13
#include <cstdarg>
14
#include <cstddef>
15
#include <cstdio>
16
#include <cstdlib>
17
#include <cstring>
18
#include <limits>
19
#include <map>
20
21
#include "opentype-sanitiser.h"
22
23
// arraysize borrowed from base/basictypes.h
24
template <typename T, size_t N>
25
char (&ArraySizeHelper(T (&array)[N]))[N];
26
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
27
28
namespace ots {
29
30
#if !defined(OTS_DEBUG)
31
9.09k
#define OTS_FAILURE() false
32
#else
33
#define OTS_FAILURE() \
34
1.29M
  (\
35
1.29M
    std::fprintf(stderr, "ERROR at %s:%d (%s)\n", \
36
1.29M
                 __FILE__, __LINE__, __FUNCTION__) \
37
1.29M
    && false\
38
1.29M
  )
39
#endif
40
41
// All OTS_FAILURE_* macros ultimately evaluate to 'false', just like the original
42
// message-less OTS_FAILURE(), so that the current parser will return 'false' as
43
// its result (indicating a failure).
44
45
#if !defined(OTS_DEBUG)
46
#define OTS_MESSAGE_(level,otf_,...) \
47
  (otf_)->context->Message(level,__VA_ARGS__)
48
#else
49
#define OTS_MESSAGE_(level,otf_,...) \
50
1.23M
  OTS_FAILURE(), \
51
1.23M
  (otf_)->context->Message(level,__VA_ARGS__)
52
#endif
53
54
// Generate a simple message
55
#define OTS_FAILURE_MSG_(otf_,...) \
56
34.0k
  (OTS_MESSAGE_(0,otf_,__VA_ARGS__), false)
57
58
#define OTS_WARNING_MSG_(otf_,...) \
59
1.14M
  OTS_MESSAGE_(1,otf_,__VA_ARGS__)
60
61
// Convenience macros for use in files that only handle a single table tag,
62
// defined as TABLE_NAME at the top of the file; the 'file' variable is
63
// expected to be the current FontFile pointer.
64
23.4k
#define OTS_FAILURE_MSG(...) OTS_FAILURE_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__)
65
66
65.1k
#define OTS_WARNING(...) OTS_WARNING_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__)
67
68
// -----------------------------------------------------------------------------
69
// Buffer helper class
70
//
71
// This class perform some trival buffer operations while checking for
72
// out-of-bounds errors. As a family they return false if anything is amiss,
73
// updating the current offset otherwise.
74
// -----------------------------------------------------------------------------
75
class Buffer {
76
 public:
77
  Buffer(const uint8_t *buf, size_t len)
78
173M
      : buffer_(buf),
79
173M
        length_(len),
80
173M
        offset_(0) { }
81
82
165M
  bool Skip(size_t n_bytes) {
83
165M
    return Read(NULL, n_bytes);
84
165M
  }
85
86
165M
  bool Read(uint8_t *buf, size_t n_bytes) {
87
165M
    if (n_bytes > 1024 * 1024 * 1024) {
88
0
      return OTS_FAILURE();
89
0
    }
90
165M
    if (length_ < n_bytes || offset_ > length_ - n_bytes) {
91
0
      return OTS_FAILURE();
92
0
    }
93
165M
    if (buf) {
94
165M
      std::memcpy(buf, buffer_ + offset_, n_bytes);
95
165M
    }
96
165M
    offset_ += n_bytes;
97
165M
    return true;
98
165M
  }
99
100
117M
  inline bool ReadU8(uint8_t *value) {
101
117M
    if (length_ < 1 || offset_ > length_ - 1) {
102
3.13k
      return OTS_FAILURE();
103
3.13k
    }
104
117M
    *value = buffer_[offset_];
105
117M
    ++offset_;
106
117M
    return true;
107
117M
  }
108
109
318M
  bool ReadU16(uint16_t *value) {
110
318M
    if (length_ < 2 || offset_ > length_ - 2) {
111
44.1k
      return OTS_FAILURE();
112
44.1k
    }
113
318M
    std::memcpy(value, buffer_ + offset_, sizeof(uint16_t));
114
318M
    *value = ots_ntohs(*value);
115
318M
    offset_ += 2;
116
318M
    return true;
117
318M
  }
118
119
36.4M
  bool ReadS16(int16_t *value) {
120
36.4M
    return ReadU16(reinterpret_cast<uint16_t*>(value));
121
36.4M
  }
122
123
232k
  bool ReadU24(uint32_t *value) {
124
232k
    if (length_ < 3 || offset_ > length_ - 3) {
125
27
      return OTS_FAILURE();
126
27
    }
127
232k
    *value = static_cast<uint32_t>(buffer_[offset_]) << 16 |
128
232k
        static_cast<uint32_t>(buffer_[offset_ + 1]) << 8 |
129
232k
        static_cast<uint32_t>(buffer_[offset_ + 2]);
130
232k
    offset_ += 3;
131
232k
    return true;
132
232k
  }
133
134
16.3M
  bool ReadU32(uint32_t *value) {
135
16.3M
    if (length_ < 4 || offset_ > length_ - 4) {
136
9.09k
      return OTS_FAILURE();
137
9.09k
    }
138
16.3M
    std::memcpy(value, buffer_ + offset_, sizeof(uint32_t));
139
16.3M
    *value = ots_ntohl(*value);
140
16.3M
    offset_ += 4;
141
16.3M
    return true;
142
16.3M
  }
143
144
248k
  bool ReadS32(int32_t *value) {
145
248k
    return ReadU32(reinterpret_cast<uint32_t*>(value));
146
248k
  }
147
148
194k
  bool ReadR64(uint64_t *value) {
149
194k
    if (length_ < 8 || offset_ > length_ - 8) {
150
110
      return OTS_FAILURE();
151
110
    }
152
194k
    std::memcpy(value, buffer_ + offset_, sizeof(uint64_t));
153
194k
    offset_ += 8;
154
194k
    return true;
155
194k
  }
156
157
100M
  const uint8_t *buffer() const { return buffer_; }
158
92.6M
  size_t offset() const { return offset_; }
159
104M
  size_t length() const { return length_; }
160
372k
  size_t remaining() const { return length_ - offset_; }
161
162
27.7M
  void set_offset(size_t newoffset) { offset_ = newoffset; }
163
164
 private:
165
  const uint8_t * const buffer_;
166
  const size_t length_;
167
  size_t offset_;
168
};
169
170
// Round a value up to the nearest multiple of 4. Don't round the value in the
171
// case that rounding up overflows.
172
12.5k
template<typename T> T Round4(T value) {
173
12.5k
  if (std::numeric_limits<T>::max() - value < 3) {
174
2
    return value;
175
2
  }
176
12.5k
  return (value + 3) & ~3;
177
12.5k
}
unsigned int ots::Round4<unsigned int>(unsigned int)
Line
Count
Source
172
11.1k
template<typename T> T Round4(T value) {
173
11.1k
  if (std::numeric_limits<T>::max() - value < 3) {
174
2
    return value;
175
2
  }
176
11.1k
  return (value + 3) & ~3;
177
11.1k
}
unsigned long ots::Round4<unsigned long>(unsigned long)
Line
Count
Source
172
1.32k
template<typename T> T Round4(T value) {
173
1.32k
  if (std::numeric_limits<T>::max() - value < 3) {
174
0
    return value;
175
0
  }
176
1.32k
  return (value + 3) & ~3;
177
1.32k
}
178
179
template<typename T> T Round2(T value) {
180
  if (value == std::numeric_limits<T>::max()) {
181
    return value;
182
  }
183
  return (value + 1) & ~1;
184
}
185
186
// Check that a tag consists entirely of printable ASCII characters
187
bool CheckTag(uint32_t tag_value);
188
189
172k
#define OTS_TAG_CFF  OTS_TAG('C','F','F',' ')
190
125k
#define OTS_TAG_CFF2 OTS_TAG('C','F','F','2')
191
94.6k
#define OTS_TAG_CMAP OTS_TAG('c','m','a','p')
192
990
#define OTS_TAG_COLR OTS_TAG('C','O','L','R')
193
3.84k
#define OTS_TAG_CPAL OTS_TAG('C','P','A','L')
194
1.55k
#define OTS_TAG_CVT  OTS_TAG('c','v','t',' ')
195
450k
#define OTS_TAG_FEAT OTS_TAG('F','e','a','t')
196
3.68k
#define OTS_TAG_FPGM OTS_TAG('f','p','g','m')
197
1.56k
#define OTS_TAG_GASP OTS_TAG('g','a','s','p')
198
8.01k
#define OTS_TAG_GDEF OTS_TAG('G','D','E','F')
199
369k
#define OTS_TAG_GLAT OTS_TAG('G','l','a','t')
200
373k
#define OTS_TAG_GLOC OTS_TAG('G','l','o','c')
201
235k
#define OTS_TAG_GLYF OTS_TAG('g','l','y','f')
202
15.9k
#define OTS_TAG_GPOS OTS_TAG('G','P','O','S')
203
8.00k
#define OTS_TAG_GSUB OTS_TAG('G','S','U','B')
204
1.18k
#define OTS_TAG_HDMX OTS_TAG('h','d','m','x')
205
396k
#define OTS_TAG_HEAD OTS_TAG('h','e','a','d')
206
176k
#define OTS_TAG_HHEA OTS_TAG('h','h','e','a')
207
87.7k
#define OTS_TAG_HMTX OTS_TAG('h','m','t','x')
208
11.0k
#define OTS_TAG_KERN OTS_TAG('k','e','r','n')
209
280k
#define OTS_TAG_LOCA OTS_TAG('l','o','c','a')
210
1.22k
#define OTS_TAG_LTSH OTS_TAG('L','T','S','H')
211
4.27k
#define OTS_TAG_MATH OTS_TAG('M','A','T','H')
212
692k
#define OTS_TAG_MAXP OTS_TAG('m','a','x','p')
213
374k
#define OTS_TAG_NAME OTS_TAG('n','a','m','e')
214
175k
#define OTS_TAG_OS2  OTS_TAG('O','S','/','2')
215
85.5k
#define OTS_TAG_POST OTS_TAG('p','o','s','t')
216
3.61k
#define OTS_TAG_PREP OTS_TAG('p','r','e','p')
217
357k
#define OTS_TAG_SILE OTS_TAG('S','i','l','e')
218
361k
#define OTS_TAG_SILF OTS_TAG('S','i','l','f')
219
346k
#define OTS_TAG_SILL OTS_TAG('S','i','l','l')
220
4.03k
#define OTS_TAG_VDMX OTS_TAG('V','D','M','X')
221
618
#define OTS_TAG_VHEA OTS_TAG('v','h','e','a')
222
46
#define OTS_TAG_VMTX OTS_TAG('v','m','t','x')
223
2.22k
#define OTS_TAG_VORG OTS_TAG('V','O','R','G')
224
225
175k
#define OTS_TAG_AVAR OTS_TAG('a','v','a','r')
226
174k
#define OTS_TAG_CVAR OTS_TAG('c','v','a','r')
227
306k
#define OTS_TAG_FVAR OTS_TAG('f','v','a','r')
228
175k
#define OTS_TAG_GVAR OTS_TAG('g','v','a','r')
229
169k
#define OTS_TAG_HVAR OTS_TAG('H','V','A','R')
230
160k
#define OTS_TAG_MVAR OTS_TAG('M','V','A','R')
231
158k
#define OTS_TAG_VVAR OTS_TAG('V','V','A','R')
232
160k
#define OTS_TAG_STAT OTS_TAG('S','T','A','T')
233
234
// See https://github.com/khaledhosny/ots/issues/219
235
175k
#define OTS_MAX_DECOMPRESSED_FILE_SIZE 300 * 1024 * 1024
236
4.87k
#define OTS_MAX_DECOMPRESSED_TABLE_SIZE 150 * 1024 * 1024
237
238
struct Font;
239
struct FontFile;
240
struct TableEntry;
241
struct Arena;
242
243
class Table {
244
 public:
245
  explicit Table(Font *font, uint32_t tag, uint32_t type)
246
1.02M
      : m_tag(tag),
247
1.02M
        m_type(type),
248
1.02M
        m_font(font),
249
1.02M
        m_shouldSerialize(true) {
250
1.02M
  }
251
252
1.02M
  virtual ~Table() { }
253
254
  virtual bool Parse(const uint8_t *data, size_t length) = 0;
255
  virtual bool Serialize(OTSStream *out) = 0;
256
  virtual bool ShouldSerialize();
257
258
  // Return the tag (table type) this Table was parsed as, to support
259
  // "poor man's RTTI" so that we know if we can safely down-cast to
260
  // a specific Table subclass. The m_type field is initialized to the
261
  // appropriate tag when a subclass is constructed, or to zero for
262
  // TablePassthru (indicating unparsed data).
263
1.48M
  uint32_t Type() { return m_type; }
264
265
  // Return the tag assigned when this table was constructed.
266
1.97M
  uint32_t Tag() { return m_tag; }
267
268
57.3M
  Font* GetFont() { return m_font; }
269
270
  bool Error(const char *format, ...);
271
  bool Warning(const char *format, ...);
272
  bool Drop(const char *format, ...);
273
  bool DropGraphite(const char *format, ...);
274
  bool DropVariations(const char *format, ...);
275
276
 private:
277
  void Message(int level, const char *format, va_list va);
278
279
  uint32_t m_tag;
280
  uint32_t m_type;
281
  Font *m_font;
282
  bool m_shouldSerialize;
283
};
284
285
class TablePassthru : public Table {
286
 public:
287
  explicit TablePassthru(Font *font, uint32_t tag)
288
0
      : Table(font, tag, 0),
289
0
        m_data(NULL),
290
0
        m_length(0) {
291
0
  }
292
293
  bool Parse(const uint8_t *data, size_t length);
294
  bool Serialize(OTSStream *out);
295
296
 private:
297
  const uint8_t *m_data;
298
  size_t m_length;
299
};
300
301
struct Font {
302
  explicit Font(FontFile *f)
303
193k
      : file(f),
304
193k
        version(0),
305
193k
        num_tables(0),
306
193k
        search_range(0),
307
193k
        entry_selector(0),
308
193k
        range_shift(0) {
309
193k
  }
310
311
  bool ParseTable(const TableEntry& tableinfo, const uint8_t* data,
312
                  Arena &arena);
313
  Table* GetTable(uint32_t tag) const;
314
315
  // This checks that the returned Table is actually of the correct subclass
316
  // for |tag|, so it can safely be downcast to the corresponding OpenTypeXXXX;
317
  // if not (i.e. if the table was treated as Passthru), it will return NULL.
318
  Table* GetTypedTable(uint32_t tag) const;
319
320
  // Insert a new table. Asserts if a table with the same tag already exists.
321
  void AddTable(TableEntry entry, Table* table);
322
323
  // Drop all Graphite tables and don't parse new ones.
324
  void DropGraphite();
325
326
  // Drop all Variations tables and don't parse new ones.
327
  void DropVariations();
328
329
  FontFile *file;
330
331
  uint32_t version;
332
  uint16_t num_tables;
333
  uint16_t search_range;
334
  uint16_t entry_selector;
335
  uint16_t range_shift;
336
337
 private:
338
  std::map<uint32_t, Table*> m_tables;
339
};
340
341
struct TableEntry {
342
  uint32_t tag;
343
  uint32_t offset;
344
  uint32_t length;
345
  uint32_t uncompressed_length;
346
  uint32_t chksum;
347
348
13.3M
  bool operator<(const TableEntry& other) const {
349
13.3M
    return tag < other.tag;
350
13.3M
  }
351
};
352
353
struct FontFile {
354
  ~FontFile();
355
356
  OTSContext *context;
357
  std::map<TableEntry, Table*> tables;
358
  std::map<uint32_t, TableEntry> table_entries;
359
};
360
361
}  // namespace ots
362
363
#endif  // OTS_H_