Line data Source code
1 : // Copyright (c) 2011 The Chromium 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 "layout.h"
6 :
7 : #include <limits>
8 : #include <vector>
9 :
10 : #include "gdef.h"
11 :
12 : // OpenType Layout Common Table Formats
13 : // http://www.microsoft.com/typography/otspec/chapter2.htm
14 :
15 : #define TABLE_NAME "Layout" // XXX: use individual table names
16 :
17 : namespace {
18 :
19 : // The 'DFLT' tag of script table.
20 : const uint32_t kScriptTableTagDflt = 0x44464c54;
21 : // The value which represents there is no required feature index.
22 : const uint16_t kNoRequiredFeatureIndexDefined = 0xFFFF;
23 : // The lookup flag bit which indicates existence of MarkFilteringSet.
24 : const uint16_t kUseMarkFilteringSetBit = 0x0010;
25 : // The lookup flags which require GDEF table.
26 : const uint16_t kGdefRequiredFlags = 0x0002 | 0x0004 | 0x0008;
27 : // The mask for MarkAttachmentType.
28 : const uint16_t kMarkAttachmentTypeMask = 0xFF00;
29 : // The maximum type number of format for device tables.
30 : const uint16_t kMaxDeltaFormatType = 3;
31 : // The maximum number of class value.
32 : const uint16_t kMaxClassDefValue = 0xFFFF;
33 :
34 : struct ScriptRecord {
35 : uint32_t tag;
36 : uint16_t offset;
37 : };
38 :
39 : struct LangSysRecord {
40 : uint32_t tag;
41 : uint16_t offset;
42 : };
43 :
44 : struct FeatureRecord {
45 : uint32_t tag;
46 : uint16_t offset;
47 : };
48 :
49 0 : bool ParseLangSysTable(const ots::Font *font,
50 : ots::Buffer *subtable, const uint32_t tag,
51 : const uint16_t num_features) {
52 0 : uint16_t offset_lookup_order = 0;
53 0 : uint16_t req_feature_index = 0;
54 0 : uint16_t feature_count = 0;
55 0 : if (!subtable->ReadU16(&offset_lookup_order) ||
56 0 : !subtable->ReadU16(&req_feature_index) ||
57 0 : !subtable->ReadU16(&feature_count)) {
58 0 : return OTS_FAILURE_MSG("Failed to read langsys header for tag %c%c%c%c", OTS_UNTAG(tag));
59 : }
60 : // |offset_lookup_order| is reserved and should be NULL.
61 0 : if (offset_lookup_order != 0) {
62 0 : return OTS_FAILURE_MSG("Bad lookup offset order %d for langsys tag %c%c%c%c", offset_lookup_order, OTS_UNTAG(tag));
63 : }
64 0 : if (req_feature_index != kNoRequiredFeatureIndexDefined &&
65 0 : req_feature_index >= num_features) {
66 0 : return OTS_FAILURE_MSG("Bad required features index %d for langsys tag %c%c%c%c", req_feature_index, OTS_UNTAG(tag));
67 : }
68 0 : if (feature_count > num_features) {
69 0 : return OTS_FAILURE_MSG("Bad feature count %d for langsys tag %c%c%c%c", feature_count, OTS_UNTAG(tag));
70 : }
71 :
72 0 : for (unsigned i = 0; i < feature_count; ++i) {
73 0 : uint16_t feature_index = 0;
74 0 : if (!subtable->ReadU16(&feature_index)) {
75 0 : return OTS_FAILURE_MSG("Failed to read feature index %d for langsys tag %c%c%c%c", i, OTS_UNTAG(tag));
76 : }
77 0 : if (feature_index >= num_features) {
78 0 : return OTS_FAILURE_MSG("Bad feature index %d for feature %d for langsys tag %c%c%c%c", feature_index, i, OTS_UNTAG(tag));
79 : }
80 : }
81 0 : return true;
82 : }
83 :
84 0 : bool ParseScriptTable(const ots::Font *font,
85 : const uint8_t *data, const size_t length,
86 : const uint32_t tag, const uint16_t num_features) {
87 0 : ots::Buffer subtable(data, length);
88 :
89 0 : uint16_t offset_default_lang_sys = 0;
90 0 : uint16_t lang_sys_count = 0;
91 0 : if (!subtable.ReadU16(&offset_default_lang_sys) ||
92 0 : !subtable.ReadU16(&lang_sys_count)) {
93 0 : return OTS_FAILURE_MSG("Failed to read script header for script tag %c%c%c%c", OTS_UNTAG(tag));
94 : }
95 :
96 : // The spec requires a script table for 'DFLT' tag must contain non-NULL
97 : // |offset_default_lang_sys| and |lang_sys_count| == 0
98 : // https://www.microsoft.com/typography/otspec/chapter2.htm
99 0 : if (tag == kScriptTableTagDflt) {
100 0 : if (offset_default_lang_sys == 0) {
101 0 : return OTS_FAILURE_MSG("DFLT script doesn't satisfy the spec. DefaultLangSys is NULL");
102 : }
103 0 : if (lang_sys_count != 0) {
104 0 : return OTS_FAILURE_MSG("DFLT script doesn't satisfy the spec. LangSysCount is not zero: %d", lang_sys_count);
105 : }
106 : }
107 :
108 : const unsigned lang_sys_record_end =
109 0 : 6 * static_cast<unsigned>(lang_sys_count) + 4;
110 0 : if (lang_sys_record_end > std::numeric_limits<uint16_t>::max()) {
111 0 : return OTS_FAILURE_MSG("Bad end of langsys record %d for script tag %c%c%c%c", lang_sys_record_end, OTS_UNTAG(tag));
112 : }
113 :
114 0 : std::vector<LangSysRecord> lang_sys_records;
115 0 : lang_sys_records.resize(lang_sys_count);
116 0 : uint32_t last_tag = 0;
117 0 : for (unsigned i = 0; i < lang_sys_count; ++i) {
118 0 : if (!subtable.ReadU32(&lang_sys_records[i].tag) ||
119 0 : !subtable.ReadU16(&lang_sys_records[i].offset)) {
120 0 : return OTS_FAILURE_MSG("Failed to read langsys record header %d for script tag %c%c%c%c", i, OTS_UNTAG(tag));
121 : }
122 : // The record array must store the records alphabetically by tag
123 0 : if (last_tag != 0 && last_tag > lang_sys_records[i].tag) {
124 0 : return OTS_FAILURE_MSG("Bad last tag %d for langsys record %d for script tag %c%c%c%c", last_tag, i, OTS_UNTAG(tag));
125 : }
126 0 : if (lang_sys_records[i].offset < lang_sys_record_end ||
127 0 : lang_sys_records[i].offset >= length) {
128 0 : return OTS_FAILURE_MSG("bad offset to lang sys table: %x",
129 : lang_sys_records[i].offset);
130 : }
131 0 : last_tag = lang_sys_records[i].tag;
132 : }
133 :
134 : // Check lang sys tables
135 0 : for (unsigned i = 0; i < lang_sys_count; ++i) {
136 0 : subtable.set_offset(lang_sys_records[i].offset);
137 0 : if (!ParseLangSysTable(font, &subtable, lang_sys_records[i].tag, num_features)) {
138 0 : return OTS_FAILURE_MSG("Failed to parse langsys table %d (%c%c%c%c) for script tag %c%c%c%c", i, OTS_UNTAG(lang_sys_records[i].tag), OTS_UNTAG(tag));
139 : }
140 : }
141 :
142 0 : return true;
143 : }
144 :
145 0 : bool ParseFeatureTable(const ots::Font *font,
146 : const uint8_t *data, const size_t length,
147 : const uint16_t num_lookups) {
148 0 : ots::Buffer subtable(data, length);
149 :
150 0 : uint16_t offset_feature_params = 0;
151 0 : uint16_t lookup_count = 0;
152 0 : if (!subtable.ReadU16(&offset_feature_params) ||
153 0 : !subtable.ReadU16(&lookup_count)) {
154 0 : return OTS_FAILURE_MSG("Failed to read feature table header");
155 : }
156 :
157 : const unsigned feature_table_end =
158 0 : 2 * static_cast<unsigned>(lookup_count) + 4;
159 0 : if (feature_table_end > std::numeric_limits<uint16_t>::max()) {
160 0 : return OTS_FAILURE_MSG("Bad end of feature table %d", feature_table_end);
161 : }
162 : // |offset_feature_params| is generally set to NULL.
163 0 : if (offset_feature_params != 0 &&
164 0 : (offset_feature_params < feature_table_end ||
165 0 : offset_feature_params >= length)) {
166 0 : return OTS_FAILURE_MSG("Bad feature params offset %d", offset_feature_params);
167 : }
168 :
169 0 : for (unsigned i = 0; i < lookup_count; ++i) {
170 0 : uint16_t lookup_index = 0;
171 0 : if (!subtable.ReadU16(&lookup_index)) {
172 0 : return OTS_FAILURE_MSG("Failed to read lookup index for lookup %d", i);
173 : }
174 : // lookup index starts with 0.
175 0 : if (lookup_index >= num_lookups) {
176 0 : return OTS_FAILURE_MSG("Bad lookup index %d for lookup %d", lookup_index, i);
177 : }
178 : }
179 0 : return true;
180 : }
181 :
182 0 : bool ParseLookupTable(ots::Font *font, const uint8_t *data,
183 : const size_t length,
184 : const ots::LookupSubtableParser* parser) {
185 0 : ots::Buffer subtable(data, length);
186 :
187 0 : uint16_t lookup_type = 0;
188 0 : uint16_t lookup_flag = 0;
189 0 : uint16_t subtable_count = 0;
190 0 : if (!subtable.ReadU16(&lookup_type) ||
191 0 : !subtable.ReadU16(&lookup_flag) ||
192 0 : !subtable.ReadU16(&subtable_count)) {
193 0 : return OTS_FAILURE_MSG("Failed to read lookup table header");
194 : }
195 :
196 0 : if (lookup_type == 0 || lookup_type > parser->num_types) {
197 0 : return OTS_FAILURE_MSG("Bad lookup type %d", lookup_type);
198 : }
199 :
200 : // Check lookup flags.
201 0 : if ((lookup_flag & kGdefRequiredFlags) &&
202 0 : (!font->gdef || !font->gdef->has_glyph_class_def)) {
203 0 : return OTS_FAILURE_MSG("Lookup flags require GDEF table, "
204 : "but none was found: %d", lookup_flag);
205 : }
206 0 : if ((lookup_flag & kMarkAttachmentTypeMask) &&
207 0 : (!font->gdef || !font->gdef->has_mark_attachment_class_def)) {
208 0 : return OTS_FAILURE_MSG("Lookup flags ask for mark attachment, "
209 : "but there is no GDEF table or it has no "
210 : "mark attachment classes: %d", lookup_flag);
211 : }
212 0 : bool use_mark_filtering_set = false;
213 0 : if (lookup_flag & kUseMarkFilteringSetBit) {
214 0 : if (!font->gdef || !font->gdef->has_mark_glyph_sets_def) {
215 0 : return OTS_FAILURE_MSG("Lookup flags ask for mark filtering, "
216 : "but there is no GDEF table or it has no "
217 : "mark filtering sets: %d", lookup_flag);
218 : }
219 0 : use_mark_filtering_set = true;
220 : }
221 :
222 0 : std::vector<uint16_t> subtables;
223 0 : subtables.reserve(subtable_count);
224 : // If the |kUseMarkFilteringSetBit| of |lookup_flag| is set,
225 : // extra 2 bytes will follow after subtable offset array.
226 0 : const unsigned lookup_table_end = 2 * static_cast<unsigned>(subtable_count) +
227 0 : (use_mark_filtering_set ? 8 : 6);
228 0 : if (lookup_table_end > std::numeric_limits<uint16_t>::max()) {
229 0 : return OTS_FAILURE_MSG("Bad end of lookup %d", lookup_table_end);
230 : }
231 0 : for (unsigned i = 0; i < subtable_count; ++i) {
232 0 : uint16_t offset_subtable = 0;
233 0 : if (!subtable.ReadU16(&offset_subtable)) {
234 0 : return OTS_FAILURE_MSG("Failed to read subtable offset %d", i);
235 : }
236 0 : if (offset_subtable < lookup_table_end ||
237 0 : offset_subtable >= length) {
238 0 : return OTS_FAILURE_MSG("Bad subtable offset %d for subtable %d", offset_subtable, i);
239 : }
240 0 : subtables.push_back(offset_subtable);
241 : }
242 0 : if (subtables.size() != subtable_count) {
243 0 : return OTS_FAILURE_MSG("Bad subtable size %ld", subtables.size());
244 : }
245 :
246 0 : if (use_mark_filtering_set) {
247 0 : uint16_t mark_filtering_set = 0;
248 0 : if (!subtable.ReadU16(&mark_filtering_set)) {
249 0 : return OTS_FAILURE_MSG("Failed to read mark filtering set");
250 : }
251 0 : if (font->gdef->num_mark_glyph_sets == 0 ||
252 0 : mark_filtering_set >= font->gdef->num_mark_glyph_sets) {
253 0 : return OTS_FAILURE_MSG("Bad mark filtering set %d", mark_filtering_set);
254 : }
255 : }
256 :
257 : // Parse lookup subtables for this lookup type.
258 0 : for (unsigned i = 0; i < subtable_count; ++i) {
259 0 : if (!parser->Parse(font, data + subtables[i], length - subtables[i],
260 : lookup_type)) {
261 0 : return OTS_FAILURE_MSG("Failed to parse subtable %d", i);
262 : }
263 : }
264 0 : return true;
265 : }
266 :
267 0 : bool ParseClassDefFormat1(const ots::Font *font,
268 : const uint8_t *data, size_t length,
269 : const uint16_t num_glyphs,
270 : const uint16_t num_classes) {
271 0 : ots::Buffer subtable(data, length);
272 :
273 : // Skip format field.
274 0 : if (!subtable.Skip(2)) {
275 0 : return OTS_FAILURE_MSG("Failed to skip class definition header");
276 : }
277 :
278 0 : uint16_t start_glyph = 0;
279 0 : if (!subtable.ReadU16(&start_glyph)) {
280 0 : return OTS_FAILURE_MSG("Failed to read starting glyph of class definition");
281 : }
282 0 : if (start_glyph > num_glyphs) {
283 0 : return OTS_FAILURE_MSG("Bad starting glyph %d in class definition", start_glyph);
284 : }
285 :
286 0 : uint16_t glyph_count = 0;
287 0 : if (!subtable.ReadU16(&glyph_count)) {
288 0 : return OTS_FAILURE_MSG("Failed to read glyph count in class definition");
289 : }
290 0 : if (glyph_count > num_glyphs) {
291 0 : return OTS_FAILURE_MSG("bad glyph count: %u", glyph_count);
292 : }
293 0 : for (unsigned i = 0; i < glyph_count; ++i) {
294 0 : uint16_t class_value = 0;
295 0 : if (!subtable.ReadU16(&class_value)) {
296 0 : return OTS_FAILURE_MSG("Failed to read class value for glyph %d in class definition", i);
297 : }
298 0 : if (class_value > num_classes) {
299 0 : return OTS_FAILURE_MSG("Bad class value %d for glyph %d in class definition", class_value, i);
300 : }
301 : }
302 :
303 0 : return true;
304 : }
305 :
306 0 : bool ParseClassDefFormat2(const ots::Font *font,
307 : const uint8_t *data, size_t length,
308 : const uint16_t num_glyphs,
309 : const uint16_t num_classes) {
310 0 : ots::Buffer subtable(data, length);
311 :
312 : // Skip format field.
313 0 : if (!subtable.Skip(2)) {
314 0 : return OTS_FAILURE_MSG("Failed to skip format of class defintion header");
315 : }
316 :
317 0 : uint16_t range_count = 0;
318 0 : if (!subtable.ReadU16(&range_count)) {
319 0 : return OTS_FAILURE_MSG("Failed to read range count in class definition");
320 : }
321 0 : if (range_count > num_glyphs) {
322 0 : return OTS_FAILURE_MSG("bad range count: %u", range_count);
323 : }
324 :
325 0 : uint16_t last_end = 0;
326 0 : for (unsigned i = 0; i < range_count; ++i) {
327 0 : uint16_t start = 0;
328 0 : uint16_t end = 0;
329 0 : uint16_t class_value = 0;
330 0 : if (!subtable.ReadU16(&start) ||
331 0 : !subtable.ReadU16(&end) ||
332 0 : !subtable.ReadU16(&class_value)) {
333 0 : return OTS_FAILURE_MSG("Failed to read class definition reange %d", i);
334 : }
335 0 : if (start > end || (last_end && start <= last_end)) {
336 0 : return OTS_FAILURE_MSG("glyph range is overlapping.in range %d", i);
337 : }
338 0 : if (class_value > num_classes) {
339 0 : return OTS_FAILURE_MSG("bad class value: %u", class_value);
340 : }
341 0 : last_end = end;
342 : }
343 :
344 0 : return true;
345 : }
346 :
347 0 : bool ParseCoverageFormat1(const ots::Font *font,
348 : const uint8_t *data, size_t length,
349 : const uint16_t num_glyphs,
350 : const uint16_t expected_num_glyphs) {
351 0 : ots::Buffer subtable(data, length);
352 :
353 : // Skip format field.
354 0 : if (!subtable.Skip(2)) {
355 0 : return OTS_FAILURE_MSG("Failed to skip coverage format");
356 : }
357 :
358 0 : uint16_t glyph_count = 0;
359 0 : if (!subtable.ReadU16(&glyph_count)) {
360 0 : return OTS_FAILURE_MSG("Failed to read glyph count in coverage");
361 : }
362 0 : if (glyph_count > num_glyphs) {
363 0 : return OTS_FAILURE_MSG("bad glyph count: %u", glyph_count);
364 : }
365 0 : for (unsigned i = 0; i < glyph_count; ++i) {
366 0 : uint16_t glyph = 0;
367 0 : if (!subtable.ReadU16(&glyph)) {
368 0 : return OTS_FAILURE_MSG("Failed to read glyph %d in coverage", i);
369 : }
370 0 : if (glyph > num_glyphs) {
371 0 : return OTS_FAILURE_MSG("bad glyph ID: %u", glyph);
372 : }
373 : }
374 :
375 0 : if (expected_num_glyphs && expected_num_glyphs != glyph_count) {
376 0 : return OTS_FAILURE_MSG("unexpected number of glyphs: %u", glyph_count);
377 : }
378 :
379 0 : return true;
380 : }
381 :
382 0 : bool ParseCoverageFormat2(const ots::Font *font,
383 : const uint8_t *data, size_t length,
384 : const uint16_t num_glyphs,
385 : const uint16_t expected_num_glyphs) {
386 0 : ots::Buffer subtable(data, length);
387 :
388 : // Skip format field.
389 0 : if (!subtable.Skip(2)) {
390 0 : return OTS_FAILURE_MSG("Failed to skip format of coverage type 2");
391 : }
392 :
393 0 : uint16_t range_count = 0;
394 0 : if (!subtable.ReadU16(&range_count)) {
395 0 : return OTS_FAILURE_MSG("Failed to read range count in coverage");
396 : }
397 0 : if (range_count > num_glyphs) {
398 0 : return OTS_FAILURE_MSG("bad range count: %u", range_count);
399 : }
400 0 : uint16_t last_end = 0;
401 0 : uint16_t last_start_coverage_index = 0;
402 0 : for (unsigned i = 0; i < range_count; ++i) {
403 0 : uint16_t start = 0;
404 0 : uint16_t end = 0;
405 0 : uint16_t start_coverage_index = 0;
406 0 : if (!subtable.ReadU16(&start) ||
407 0 : !subtable.ReadU16(&end) ||
408 0 : !subtable.ReadU16(&start_coverage_index)) {
409 0 : return OTS_FAILURE_MSG("Failed to read range %d in coverage", i);
410 : }
411 :
412 : // Some of the Adobe Pro fonts have ranges that overlap by one element: the
413 : // start of one range is equal to the end of the previous range. Therefore
414 : // the < in the following condition should be <= were it not for this.
415 : // See crbug.com/134135.
416 0 : if (start > end || (last_end && start < last_end)) {
417 0 : return OTS_FAILURE_MSG("glyph range is overlapping.");
418 : }
419 0 : if (start_coverage_index != last_start_coverage_index) {
420 0 : return OTS_FAILURE_MSG("bad start coverage index.");
421 : }
422 0 : last_end = end;
423 0 : last_start_coverage_index += end - start + 1;
424 : }
425 :
426 0 : if (expected_num_glyphs &&
427 : expected_num_glyphs != last_start_coverage_index) {
428 0 : return OTS_FAILURE_MSG("unexpected number of glyphs: %u", last_start_coverage_index);
429 : }
430 :
431 0 : return true;
432 : }
433 :
434 : // Parsers for Contextual subtables in GSUB/GPOS tables.
435 :
436 0 : bool ParseLookupRecord(const ots::Font *font,
437 : ots::Buffer *subtable, const uint16_t num_glyphs,
438 : const uint16_t num_lookups) {
439 0 : uint16_t sequence_index = 0;
440 0 : uint16_t lookup_list_index = 0;
441 0 : if (!subtable->ReadU16(&sequence_index) ||
442 0 : !subtable->ReadU16(&lookup_list_index)) {
443 0 : return OTS_FAILURE_MSG("Failed to read header for lookup record");
444 : }
445 0 : if (sequence_index >= num_glyphs) {
446 0 : return OTS_FAILURE_MSG("Bad sequence index %d in lookup record", sequence_index);
447 : }
448 0 : if (lookup_list_index >= num_lookups) {
449 0 : return OTS_FAILURE_MSG("Bad lookup list index %d in lookup record", lookup_list_index);
450 : }
451 0 : return true;
452 : }
453 :
454 0 : bool ParseRuleSubtable(const ots::Font *font,
455 : const uint8_t *data, const size_t length,
456 : const uint16_t num_glyphs,
457 : const uint16_t num_lookups) {
458 0 : ots::Buffer subtable(data, length);
459 :
460 0 : uint16_t glyph_count = 0;
461 0 : uint16_t lookup_count = 0;
462 0 : if (!subtable.ReadU16(&glyph_count) ||
463 0 : !subtable.ReadU16(&lookup_count)) {
464 0 : return OTS_FAILURE_MSG("Failed to read rule subtable header");
465 : }
466 :
467 0 : if (glyph_count == 0 || glyph_count >= num_glyphs) {
468 0 : return OTS_FAILURE_MSG("Bad glyph count %d in rule subtable", glyph_count);
469 : }
470 0 : for (unsigned i = 0; i < glyph_count - static_cast<unsigned>(1); ++i) {
471 0 : uint16_t glyph_id = 0;
472 0 : if (!subtable.ReadU16(&glyph_id)) {
473 0 : return OTS_FAILURE_MSG("Failed to read glyph %d", i);
474 : }
475 0 : if (glyph_id > num_glyphs) {
476 0 : return OTS_FAILURE_MSG("Bad glyph %d for entry %d", glyph_id, i);
477 : }
478 : }
479 :
480 0 : for (unsigned i = 0; i < lookup_count; ++i) {
481 0 : if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) {
482 0 : return OTS_FAILURE_MSG("Failed to parse lookup record %d", i);
483 : }
484 : }
485 0 : return true;
486 : }
487 :
488 0 : bool ParseRuleSetTable(const ots::Font *font,
489 : const uint8_t *data, const size_t length,
490 : const uint16_t num_glyphs,
491 : const uint16_t num_lookups) {
492 0 : ots::Buffer subtable(data, length);
493 :
494 0 : uint16_t rule_count = 0;
495 0 : if (!subtable.ReadU16(&rule_count)) {
496 0 : return OTS_FAILURE_MSG("Failed to read rule count in rule set");
497 : }
498 0 : const unsigned rule_end = 2 * static_cast<unsigned>(rule_count) + 2;
499 0 : if (rule_end > std::numeric_limits<uint16_t>::max()) {
500 0 : return OTS_FAILURE_MSG("Bad end of rule %d in rule set", rule_end);
501 : }
502 :
503 0 : for (unsigned i = 0; i < rule_count; ++i) {
504 0 : uint16_t offset_rule = 0;
505 0 : if (!subtable.ReadU16(&offset_rule)) {
506 0 : return OTS_FAILURE_MSG("Failed to read rule offset for rule set %d", i);
507 : }
508 0 : if (offset_rule < rule_end || offset_rule >= length) {
509 0 : return OTS_FAILURE_MSG("Bad rule offset %d in set %d", offset_rule, i);
510 : }
511 0 : if (!ParseRuleSubtable(font, data + offset_rule, length - offset_rule,
512 : num_glyphs, num_lookups)) {
513 0 : return OTS_FAILURE_MSG("Failed to parse rule set %d", i);
514 : }
515 : }
516 :
517 0 : return true;
518 : }
519 :
520 0 : bool ParseContextFormat1(const ots::Font *font,
521 : const uint8_t *data, const size_t length,
522 : const uint16_t num_glyphs,
523 : const uint16_t num_lookups) {
524 0 : ots::Buffer subtable(data, length);
525 :
526 0 : uint16_t offset_coverage = 0;
527 0 : uint16_t rule_set_count = 0;
528 : // Skip format field.
529 0 : if (!subtable.Skip(2) ||
530 0 : !subtable.ReadU16(&offset_coverage) ||
531 0 : !subtable.ReadU16(&rule_set_count)) {
532 0 : return OTS_FAILURE_MSG("Failed to read header of context format 1");
533 : }
534 :
535 : const unsigned rule_set_end = static_cast<unsigned>(6) +
536 0 : rule_set_count * 2;
537 0 : if (rule_set_end > std::numeric_limits<uint16_t>::max()) {
538 0 : return OTS_FAILURE_MSG("Bad end of rule set %d of context format 1", rule_set_end);
539 : }
540 0 : if (offset_coverage < rule_set_end || offset_coverage >= length) {
541 0 : return OTS_FAILURE_MSG("Bad coverage offset %d in context format 1", offset_coverage);
542 : }
543 0 : if (!ots::ParseCoverageTable(font, data + offset_coverage,
544 : length - offset_coverage, num_glyphs)) {
545 0 : return OTS_FAILURE_MSG("Failed to parse coverage table in context format 1");
546 : }
547 :
548 0 : for (unsigned i = 0; i < rule_set_count; ++i) {
549 0 : uint16_t offset_rule = 0;
550 0 : if (!subtable.ReadU16(&offset_rule)) {
551 0 : return OTS_FAILURE_MSG("Failed to read rule offset %d in context format 1", i);
552 : }
553 0 : if (offset_rule < rule_set_end || offset_rule >= length) {
554 0 : return OTS_FAILURE_MSG("Bad rule offset %d in rule %d in context format 1", offset_rule, i);
555 : }
556 0 : if (!ParseRuleSetTable(font, data + offset_rule, length - offset_rule,
557 : num_glyphs, num_lookups)) {
558 0 : return OTS_FAILURE_MSG("Failed to parse rule set %d in context format 1", i);
559 : }
560 : }
561 :
562 0 : return true;
563 : }
564 :
565 0 : bool ParseClassRuleTable(const ots::Font *font,
566 : const uint8_t *data, const size_t length,
567 : const uint16_t num_glyphs,
568 : const uint16_t num_lookups) {
569 0 : ots::Buffer subtable(data, length);
570 :
571 0 : uint16_t glyph_count = 0;
572 0 : uint16_t lookup_count = 0;
573 0 : if (!subtable.ReadU16(&glyph_count) ||
574 0 : !subtable.ReadU16(&lookup_count)) {
575 0 : return OTS_FAILURE_MSG("Failed to read header of class rule table");
576 : }
577 :
578 0 : if (glyph_count == 0 || glyph_count >= num_glyphs) {
579 0 : return OTS_FAILURE_MSG("Bad glyph count %d in class rule table", glyph_count);
580 : }
581 :
582 : // ClassRule table contains an array of classes. Each value of classes
583 : // could take arbitrary values including zero so we don't check these value.
584 0 : const unsigned num_classes = glyph_count - static_cast<unsigned>(1);
585 0 : if (!subtable.Skip(2 * num_classes)) {
586 0 : return OTS_FAILURE_MSG("Failed to skip classes in class rule table");
587 : }
588 :
589 0 : for (unsigned i = 0; i < lookup_count; ++i) {
590 0 : if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) {
591 0 : return OTS_FAILURE_MSG("Failed to parse lookup record %d in class rule table", i);
592 : }
593 : }
594 0 : return true;
595 : }
596 :
597 0 : bool ParseClassSetTable(const ots::Font *font,
598 : const uint8_t *data, const size_t length,
599 : const uint16_t num_glyphs,
600 : const uint16_t num_lookups) {
601 0 : ots::Buffer subtable(data, length);
602 :
603 0 : uint16_t class_rule_count = 0;
604 0 : if (!subtable.ReadU16(&class_rule_count)) {
605 0 : return OTS_FAILURE_MSG("Failed to read class rule count in class set table");
606 : }
607 : const unsigned class_rule_end =
608 0 : 2 * static_cast<unsigned>(class_rule_count) + 2;
609 0 : if (class_rule_end > std::numeric_limits<uint16_t>::max()) {
610 0 : return OTS_FAILURE_MSG("bad class rule end %d in class set table", class_rule_end);
611 : }
612 0 : for (unsigned i = 0; i < class_rule_count; ++i) {
613 0 : uint16_t offset_class_rule = 0;
614 0 : if (!subtable.ReadU16(&offset_class_rule)) {
615 0 : return OTS_FAILURE_MSG("Failed to read class rule offset %d in class set table", i);
616 : }
617 0 : if (offset_class_rule < class_rule_end || offset_class_rule >= length) {
618 0 : return OTS_FAILURE_MSG("Bad class rule offset %d in class %d", offset_class_rule, i);
619 : }
620 0 : if (!ParseClassRuleTable(font, data + offset_class_rule,
621 : length - offset_class_rule, num_glyphs,
622 : num_lookups)) {
623 0 : return OTS_FAILURE_MSG("Failed to parse class rule table %d", i);
624 : }
625 : }
626 :
627 0 : return true;
628 : }
629 :
630 0 : bool ParseContextFormat2(const ots::Font *font,
631 : const uint8_t *data, const size_t length,
632 : const uint16_t num_glyphs,
633 : const uint16_t num_lookups) {
634 0 : ots::Buffer subtable(data, length);
635 :
636 0 : uint16_t offset_coverage = 0;
637 0 : uint16_t offset_class_def = 0;
638 0 : uint16_t class_set_cnt = 0;
639 : // Skip format field.
640 0 : if (!subtable.Skip(2) ||
641 0 : !subtable.ReadU16(&offset_coverage) ||
642 0 : !subtable.ReadU16(&offset_class_def) ||
643 0 : !subtable.ReadU16(&class_set_cnt)) {
644 0 : return OTS_FAILURE_MSG("Failed to read header for context format 2");
645 : }
646 :
647 0 : const unsigned class_set_end = 2 * static_cast<unsigned>(class_set_cnt) + 8;
648 0 : if (class_set_end > std::numeric_limits<uint16_t>::max()) {
649 0 : return OTS_FAILURE_MSG("Bad end of class set %d for context format 2", class_set_end);
650 : }
651 0 : if (offset_coverage < class_set_end || offset_coverage >= length) {
652 0 : return OTS_FAILURE_MSG("Bad coverage offset %d in context format 2", offset_coverage);
653 : }
654 0 : if (!ots::ParseCoverageTable(font, data + offset_coverage,
655 : length - offset_coverage, num_glyphs)) {
656 0 : return OTS_FAILURE_MSG("Failed to parse coverage table in context format 2");
657 : }
658 :
659 0 : if (offset_class_def < class_set_end || offset_class_def >= length) {
660 0 : return OTS_FAILURE_MSG("bad class definition offset %d in context format 2", offset_class_def);
661 : }
662 0 : if (!ots::ParseClassDefTable(font, data + offset_class_def,
663 : length - offset_class_def,
664 : num_glyphs, kMaxClassDefValue)) {
665 0 : return OTS_FAILURE_MSG("Failed to parse class definition table in context format 2");
666 : }
667 :
668 0 : for (unsigned i = 0; i < class_set_cnt; ++i) {
669 0 : uint16_t offset_class_rule = 0;
670 0 : if (!subtable.ReadU16(&offset_class_rule)) {
671 0 : return OTS_FAILURE_MSG("Failed to read class rule offset %d in context format 2", i);
672 : }
673 0 : if (offset_class_rule) {
674 0 : if (offset_class_rule < class_set_end || offset_class_rule >= length) {
675 0 : return OTS_FAILURE_MSG("Bad class rule offset %d for rule %d in context format 2", offset_class_rule, i);
676 : }
677 0 : if (!ParseClassSetTable(font, data + offset_class_rule,
678 : length - offset_class_rule, num_glyphs,
679 : num_lookups)) {
680 0 : return OTS_FAILURE_MSG("Failed to parse class set %d in context format 2", i);
681 : }
682 : }
683 : }
684 :
685 0 : return true;
686 : }
687 :
688 0 : bool ParseContextFormat3(const ots::Font *font,
689 : const uint8_t *data, const size_t length,
690 : const uint16_t num_glyphs,
691 : const uint16_t num_lookups) {
692 0 : ots::Buffer subtable(data, length);
693 :
694 0 : uint16_t glyph_count = 0;
695 0 : uint16_t lookup_count = 0;
696 : // Skip format field.
697 0 : if (!subtable.Skip(2) ||
698 0 : !subtable.ReadU16(&glyph_count) ||
699 0 : !subtable.ReadU16(&lookup_count)) {
700 0 : return OTS_FAILURE_MSG("Failed to read header in context format 3");
701 : }
702 :
703 0 : if (glyph_count >= num_glyphs) {
704 0 : return OTS_FAILURE_MSG("Bad glyph count %d in context format 3", glyph_count);
705 : }
706 0 : const unsigned lookup_record_end = 2 * static_cast<unsigned>(glyph_count) +
707 0 : 4 * static_cast<unsigned>(lookup_count) + 6;
708 0 : if (lookup_record_end > std::numeric_limits<uint16_t>::max()) {
709 0 : return OTS_FAILURE_MSG("Bad end of lookup %d in context format 3", lookup_record_end);
710 : }
711 0 : for (unsigned i = 0; i < glyph_count; ++i) {
712 0 : uint16_t offset_coverage = 0;
713 0 : if (!subtable.ReadU16(&offset_coverage)) {
714 0 : return OTS_FAILURE_MSG("Failed to read coverage offset %d in conxtext format 3", i);
715 : }
716 0 : if (offset_coverage < lookup_record_end || offset_coverage >= length) {
717 0 : return OTS_FAILURE_MSG("Bad coverage offset %d for glyph %d in context format 3", offset_coverage, i);
718 : }
719 0 : if (!ots::ParseCoverageTable(font, data + offset_coverage,
720 : length - offset_coverage, num_glyphs)) {
721 0 : return OTS_FAILURE_MSG("Failed to parse coverage table for glyph %d in context format 3", i);
722 : }
723 : }
724 :
725 0 : for (unsigned i = 0; i < lookup_count; ++i) {
726 0 : if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) {
727 0 : return OTS_FAILURE_MSG("Failed to parse lookup record %d in context format 3", i);
728 : }
729 : }
730 :
731 0 : return true;
732 : }
733 :
734 : // Parsers for Chaning Contextual subtables in GSUB/GPOS tables.
735 :
736 0 : bool ParseChainRuleSubtable(const ots::Font *font,
737 : const uint8_t *data, const size_t length,
738 : const uint16_t num_glyphs,
739 : const uint16_t num_lookups) {
740 0 : ots::Buffer subtable(data, length);
741 :
742 0 : uint16_t backtrack_count = 0;
743 0 : if (!subtable.ReadU16(&backtrack_count)) {
744 0 : return OTS_FAILURE_MSG("Failed to read backtrack count in chain rule subtable");
745 : }
746 0 : if (backtrack_count >= num_glyphs) {
747 0 : return OTS_FAILURE_MSG("Bad backtrack count %d in chain rule subtable", backtrack_count);
748 : }
749 0 : for (unsigned i = 0; i < backtrack_count; ++i) {
750 0 : uint16_t glyph_id = 0;
751 0 : if (!subtable.ReadU16(&glyph_id)) {
752 0 : return OTS_FAILURE_MSG("Failed to read backtrack glyph %d in chain rule subtable", i);
753 : }
754 0 : if (glyph_id > num_glyphs) {
755 0 : return OTS_FAILURE_MSG("Bad glyph id %d for bactrack glyph %d in chain rule subtable", glyph_id, i);
756 : }
757 : }
758 :
759 0 : uint16_t input_count = 0;
760 0 : if (!subtable.ReadU16(&input_count)) {
761 0 : return OTS_FAILURE_MSG("Failed to read input count in chain rule subtable");
762 : }
763 0 : if (input_count == 0 || input_count >= num_glyphs) {
764 0 : return OTS_FAILURE_MSG("Bad input count %d in chain rule subtable", input_count);
765 : }
766 0 : for (unsigned i = 0; i < input_count - static_cast<unsigned>(1); ++i) {
767 0 : uint16_t glyph_id = 0;
768 0 : if (!subtable.ReadU16(&glyph_id)) {
769 0 : return OTS_FAILURE_MSG("Failed to read input glyph %d in chain rule subtable", i);
770 : }
771 0 : if (glyph_id > num_glyphs) {
772 0 : return OTS_FAILURE_MSG("Bad glyph id %d for input glyph %d in chain rule subtable", glyph_id, i);
773 : }
774 : }
775 :
776 0 : uint16_t lookahead_count = 0;
777 0 : if (!subtable.ReadU16(&lookahead_count)) {
778 0 : return OTS_FAILURE_MSG("Failed to read lookahead count in chain rule subtable");
779 : }
780 0 : if (lookahead_count >= num_glyphs) {
781 0 : return OTS_FAILURE_MSG("Bad lookahead count %d in chain rule subtable", lookahead_count);
782 : }
783 0 : for (unsigned i = 0; i < lookahead_count; ++i) {
784 0 : uint16_t glyph_id = 0;
785 0 : if (!subtable.ReadU16(&glyph_id)) {
786 0 : return OTS_FAILURE_MSG("Failed to read lookahead glyph %d in chain rule subtable", i);
787 : }
788 0 : if (glyph_id > num_glyphs) {
789 0 : return OTS_FAILURE_MSG("Bad glyph id %d for lookadhead glyph %d in chain rule subtable", glyph_id, i);
790 : }
791 : }
792 :
793 0 : uint16_t lookup_count = 0;
794 0 : if (!subtable.ReadU16(&lookup_count)) {
795 0 : return OTS_FAILURE_MSG("Failed to read lookup count in chain rule subtable");
796 : }
797 0 : for (unsigned i = 0; i < lookup_count; ++i) {
798 0 : if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) {
799 0 : return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain rule subtable", i);
800 : }
801 : }
802 :
803 0 : return true;
804 : }
805 :
806 0 : bool ParseChainRuleSetTable(const ots::Font *font,
807 : const uint8_t *data, const size_t length,
808 : const uint16_t num_glyphs,
809 : const uint16_t num_lookups) {
810 0 : ots::Buffer subtable(data, length);
811 :
812 0 : uint16_t chain_rule_count = 0;
813 0 : if (!subtable.ReadU16(&chain_rule_count)) {
814 0 : return OTS_FAILURE_MSG("Failed to read rule count in chain rule set");
815 : }
816 : const unsigned chain_rule_end =
817 0 : 2 * static_cast<unsigned>(chain_rule_count) + 2;
818 0 : if (chain_rule_end > std::numeric_limits<uint16_t>::max()) {
819 0 : return OTS_FAILURE_MSG("Bad end of chain rule %d in chain rule set", chain_rule_end);
820 : }
821 0 : for (unsigned i = 0; i < chain_rule_count; ++i) {
822 0 : uint16_t offset_chain_rule = 0;
823 0 : if (!subtable.ReadU16(&offset_chain_rule)) {
824 0 : return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain rule set", i);
825 : }
826 0 : if (offset_chain_rule < chain_rule_end || offset_chain_rule >= length) {
827 0 : return OTS_FAILURE_MSG("Bad chain rule offset %d for chain rule %d in chain rule set", offset_chain_rule, i);
828 : }
829 0 : if (!ParseChainRuleSubtable(font, data + offset_chain_rule,
830 : length - offset_chain_rule,
831 : num_glyphs, num_lookups)) {
832 0 : return OTS_FAILURE_MSG("Failed to parse chain rule %d in chain rule set", i);
833 : }
834 : }
835 :
836 0 : return true;
837 : }
838 :
839 0 : bool ParseChainContextFormat1(const ots::Font *font,
840 : const uint8_t *data, const size_t length,
841 : const uint16_t num_glyphs,
842 : const uint16_t num_lookups) {
843 0 : ots::Buffer subtable(data, length);
844 :
845 0 : uint16_t offset_coverage = 0;
846 0 : uint16_t chain_rule_set_count = 0;
847 : // Skip format field.
848 0 : if (!subtable.Skip(2) ||
849 0 : !subtable.ReadU16(&offset_coverage) ||
850 0 : !subtable.ReadU16(&chain_rule_set_count)) {
851 0 : return OTS_FAILURE_MSG("Failed to read header of chain context format 1");
852 : }
853 :
854 : const unsigned chain_rule_set_end =
855 0 : 2 * static_cast<unsigned>(chain_rule_set_count) + 6;
856 0 : if (chain_rule_set_end > std::numeric_limits<uint16_t>::max()) {
857 0 : return OTS_FAILURE_MSG("Bad chain rule end %d in chain context format 1", chain_rule_set_end);
858 : }
859 0 : if (offset_coverage < chain_rule_set_end || offset_coverage >= length) {
860 0 : return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 1", chain_rule_set_end);
861 : }
862 0 : if (!ots::ParseCoverageTable(font, data + offset_coverage,
863 : length - offset_coverage, num_glyphs)) {
864 0 : return OTS_FAILURE_MSG("Failed to parse coverage table for chain context format 1");
865 : }
866 :
867 0 : for (unsigned i = 0; i < chain_rule_set_count; ++i) {
868 0 : uint16_t offset_chain_rule_set = 0;
869 0 : if (!subtable.ReadU16(&offset_chain_rule_set)) {
870 0 : return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain context format 1", i);
871 : }
872 0 : if (offset_chain_rule_set < chain_rule_set_end ||
873 0 : offset_chain_rule_set >= length) {
874 0 : return OTS_FAILURE_MSG("Bad chain rule set offset %d for chain rule set %d in chain context format 1", offset_chain_rule_set, i);
875 : }
876 0 : if (!ParseChainRuleSetTable(font, data + offset_chain_rule_set,
877 : length - offset_chain_rule_set,
878 : num_glyphs, num_lookups)) {
879 0 : return OTS_FAILURE_MSG("Failed to parse chain rule set %d in chain context format 1", i);
880 : }
881 : }
882 :
883 0 : return true;
884 : }
885 :
886 0 : bool ParseChainClassRuleSubtable(const ots::Font *font,
887 : const uint8_t *data, const size_t length,
888 : const uint16_t num_glyphs,
889 : const uint16_t num_lookups) {
890 0 : ots::Buffer subtable(data, length);
891 :
892 : // In this subtable, we don't check the value of classes for now since
893 : // these could take arbitrary values.
894 :
895 0 : uint16_t backtrack_count = 0;
896 0 : if (!subtable.ReadU16(&backtrack_count)) {
897 0 : return OTS_FAILURE_MSG("Failed to read backtrack count in chain class rule subtable");
898 : }
899 0 : if (backtrack_count >= num_glyphs) {
900 0 : return OTS_FAILURE_MSG("Bad backtrack count %d in chain class rule subtable", backtrack_count);
901 : }
902 0 : if (!subtable.Skip(2 * backtrack_count)) {
903 0 : return OTS_FAILURE_MSG("Failed to skip backtrack offsets in chain class rule subtable");
904 : }
905 :
906 0 : uint16_t input_count = 0;
907 0 : if (!subtable.ReadU16(&input_count)) {
908 0 : return OTS_FAILURE_MSG("Failed to read input count in chain class rule subtable");
909 : }
910 0 : if (input_count == 0 || input_count >= num_glyphs) {
911 0 : return OTS_FAILURE_MSG("Bad input count %d in chain class rule subtable", input_count);
912 : }
913 0 : if (!subtable.Skip(2 * (input_count - 1))) {
914 0 : return OTS_FAILURE_MSG("Failed to skip input offsets in chain class rule subtable");
915 : }
916 :
917 0 : uint16_t lookahead_count = 0;
918 0 : if (!subtable.ReadU16(&lookahead_count)) {
919 0 : return OTS_FAILURE_MSG("Failed to read lookahead count in chain class rule subtable");
920 : }
921 0 : if (lookahead_count >= num_glyphs) {
922 0 : return OTS_FAILURE_MSG("Bad lookahead count %d in chain class rule subtable", lookahead_count);
923 : }
924 0 : if (!subtable.Skip(2 * lookahead_count)) {
925 0 : return OTS_FAILURE_MSG("Failed to skip lookahead offsets in chain class rule subtable");
926 : }
927 :
928 0 : uint16_t lookup_count = 0;
929 0 : if (!subtable.ReadU16(&lookup_count)) {
930 0 : return OTS_FAILURE_MSG("Failed to read lookup count in chain class rule subtable");
931 : }
932 0 : for (unsigned i = 0; i < lookup_count; ++i) {
933 0 : if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) {
934 0 : return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain class rule subtable", i);
935 : }
936 : }
937 :
938 0 : return true;
939 : }
940 :
941 0 : bool ParseChainClassSetTable(const ots::Font *font,
942 : const uint8_t *data, const size_t length,
943 : const uint16_t num_glyphs,
944 : const uint16_t num_lookups) {
945 0 : ots::Buffer subtable(data, length);
946 :
947 0 : uint16_t chain_class_rule_count = 0;
948 0 : if (!subtable.ReadU16(&chain_class_rule_count)) {
949 0 : return OTS_FAILURE_MSG("Failed to read rule count in chain class set");
950 : }
951 : const unsigned chain_class_rule_end =
952 0 : 2 * static_cast<unsigned>(chain_class_rule_count) + 2;
953 0 : if (chain_class_rule_end > std::numeric_limits<uint16_t>::max()) {
954 0 : return OTS_FAILURE_MSG("Bad end of chain class set %d in chain class set", chain_class_rule_end);
955 : }
956 0 : for (unsigned i = 0; i < chain_class_rule_count; ++i) {
957 0 : uint16_t offset_chain_class_rule = 0;
958 0 : if (!subtable.ReadU16(&offset_chain_class_rule)) {
959 0 : return OTS_FAILURE_MSG("Failed to read chain class rule offset %d in chain class set", i);
960 : }
961 0 : if (offset_chain_class_rule < chain_class_rule_end ||
962 0 : offset_chain_class_rule >= length) {
963 0 : return OTS_FAILURE_MSG("Bad chain class rule offset %d for chain class %d in chain class set", offset_chain_class_rule, i);
964 : }
965 0 : if (!ParseChainClassRuleSubtable(font, data + offset_chain_class_rule,
966 : length - offset_chain_class_rule,
967 : num_glyphs, num_lookups)) {
968 0 : return OTS_FAILURE_MSG("Failed to parse chain class rule %d in chain class set", i);
969 : }
970 : }
971 :
972 0 : return true;
973 : }
974 :
975 0 : bool ParseChainContextFormat2(const ots::Font *font,
976 : const uint8_t *data, const size_t length,
977 : const uint16_t num_glyphs,
978 : const uint16_t num_lookups) {
979 0 : ots::Buffer subtable(data, length);
980 :
981 0 : uint16_t offset_coverage = 0;
982 0 : uint16_t offset_backtrack_class_def = 0;
983 0 : uint16_t offset_input_class_def = 0;
984 0 : uint16_t offset_lookahead_class_def = 0;
985 0 : uint16_t chain_class_set_count = 0;
986 : // Skip format field.
987 0 : if (!subtable.Skip(2) ||
988 0 : !subtable.ReadU16(&offset_coverage) ||
989 0 : !subtable.ReadU16(&offset_backtrack_class_def) ||
990 0 : !subtable.ReadU16(&offset_input_class_def) ||
991 0 : !subtable.ReadU16(&offset_lookahead_class_def) ||
992 0 : !subtable.ReadU16(&chain_class_set_count)) {
993 0 : return OTS_FAILURE_MSG("Failed to read header of chain context format 2");
994 : }
995 :
996 : const unsigned chain_class_set_end =
997 0 : 2 * static_cast<unsigned>(chain_class_set_count) + 12;
998 0 : if (chain_class_set_end > std::numeric_limits<uint16_t>::max()) {
999 0 : return OTS_FAILURE_MSG("Bad chain class set end %d in chain context format 2", chain_class_set_end);
1000 : }
1001 0 : if (offset_coverage < chain_class_set_end || offset_coverage >= length) {
1002 0 : return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 2", offset_coverage);
1003 : }
1004 0 : if (!ots::ParseCoverageTable(font, data + offset_coverage,
1005 : length - offset_coverage, num_glyphs)) {
1006 0 : return OTS_FAILURE_MSG("Failed to parse coverage table in chain context format 2");
1007 : }
1008 :
1009 : // Classes for backtrack/lookahead sequences might not be defined.
1010 0 : if (offset_backtrack_class_def) {
1011 0 : if (offset_backtrack_class_def < chain_class_set_end ||
1012 0 : offset_backtrack_class_def >= length) {
1013 0 : return OTS_FAILURE_MSG("Bad backtrack class offset %d in chain context format 2", offset_backtrack_class_def);
1014 : }
1015 0 : if (!ots::ParseClassDefTable(font, data + offset_backtrack_class_def,
1016 : length - offset_backtrack_class_def,
1017 : num_glyphs, kMaxClassDefValue)) {
1018 0 : return OTS_FAILURE_MSG("Failed to parse backtrack class defn table in chain context format 2");
1019 : }
1020 : }
1021 :
1022 0 : if (offset_input_class_def < chain_class_set_end ||
1023 0 : offset_input_class_def >= length) {
1024 0 : return OTS_FAILURE_MSG("Bad input class defn offset %d in chain context format 2", offset_input_class_def);
1025 : }
1026 0 : if (!ots::ParseClassDefTable(font, data + offset_input_class_def,
1027 : length - offset_input_class_def,
1028 : num_glyphs, kMaxClassDefValue)) {
1029 0 : return OTS_FAILURE_MSG("Failed to parse input class defn in chain context format 2");
1030 : }
1031 :
1032 0 : if (offset_lookahead_class_def) {
1033 0 : if (offset_lookahead_class_def < chain_class_set_end ||
1034 0 : offset_lookahead_class_def >= length) {
1035 0 : return OTS_FAILURE_MSG("Bad lookahead class defn offset %d in chain context format 2", offset_lookahead_class_def);
1036 : }
1037 0 : if (!ots::ParseClassDefTable(font, data + offset_lookahead_class_def,
1038 : length - offset_lookahead_class_def,
1039 : num_glyphs, kMaxClassDefValue)) {
1040 0 : return OTS_FAILURE_MSG("Failed to parse lookahead class defn in chain context format 2");
1041 : }
1042 : }
1043 :
1044 0 : for (unsigned i = 0; i < chain_class_set_count; ++i) {
1045 0 : uint16_t offset_chain_class_set = 0;
1046 0 : if (!subtable.ReadU16(&offset_chain_class_set)) {
1047 0 : return OTS_FAILURE_MSG("Failed to read chain class set offset %d", i);
1048 : }
1049 : // |offset_chain_class_set| could be NULL.
1050 0 : if (offset_chain_class_set) {
1051 0 : if (offset_chain_class_set < chain_class_set_end ||
1052 0 : offset_chain_class_set >= length) {
1053 0 : return OTS_FAILURE_MSG("Bad chain set class offset %d for chain set %d in chain context format 2", offset_chain_class_set, i);
1054 : }
1055 0 : if (!ParseChainClassSetTable(font, data + offset_chain_class_set,
1056 : length - offset_chain_class_set,
1057 : num_glyphs, num_lookups)) {
1058 0 : return OTS_FAILURE_MSG("Failed to parse chain class set table %d in chain context format 2", i);
1059 : }
1060 : }
1061 : }
1062 :
1063 0 : return true;
1064 : }
1065 :
1066 0 : bool ParseChainContextFormat3(const ots::Font *font,
1067 : const uint8_t *data, const size_t length,
1068 : const uint16_t num_glyphs,
1069 : const uint16_t num_lookups) {
1070 0 : ots::Buffer subtable(data, length);
1071 :
1072 0 : uint16_t backtrack_count = 0;
1073 : // Skip format field.
1074 0 : if (!subtable.Skip(2) ||
1075 0 : !subtable.ReadU16(&backtrack_count)) {
1076 0 : return OTS_FAILURE_MSG("Failed to read backtrack count in chain context format 3");
1077 : }
1078 :
1079 0 : if (backtrack_count >= num_glyphs) {
1080 0 : return OTS_FAILURE_MSG("Bad backtrack count %d in chain context format 3", backtrack_count);
1081 : }
1082 0 : std::vector<uint16_t> offsets_backtrack;
1083 0 : offsets_backtrack.reserve(backtrack_count);
1084 0 : for (unsigned i = 0; i < backtrack_count; ++i) {
1085 0 : uint16_t offset = 0;
1086 0 : if (!subtable.ReadU16(&offset)) {
1087 0 : return OTS_FAILURE_MSG("Failed to read backtrack offset %d in chain context format 3", i);
1088 : }
1089 0 : offsets_backtrack.push_back(offset);
1090 : }
1091 0 : if (offsets_backtrack.size() != backtrack_count) {
1092 0 : return OTS_FAILURE_MSG("Bad backtrack offsets size %ld in chain context format 3", offsets_backtrack.size());
1093 : }
1094 :
1095 0 : uint16_t input_count = 0;
1096 0 : if (!subtable.ReadU16(&input_count)) {
1097 0 : return OTS_FAILURE_MSG("Failed to read input count in chain context format 3");
1098 : }
1099 0 : if (input_count >= num_glyphs) {
1100 0 : return OTS_FAILURE_MSG("Bad input count %d in chain context format 3", input_count);
1101 : }
1102 0 : std::vector<uint16_t> offsets_input;
1103 0 : offsets_input.reserve(input_count);
1104 0 : for (unsigned i = 0; i < input_count; ++i) {
1105 0 : uint16_t offset = 0;
1106 0 : if (!subtable.ReadU16(&offset)) {
1107 0 : return OTS_FAILURE_MSG("Failed to read input offset %d in chain context format 3", i);
1108 : }
1109 0 : offsets_input.push_back(offset);
1110 : }
1111 0 : if (offsets_input.size() != input_count) {
1112 0 : return OTS_FAILURE_MSG("Bad input offsets size %ld in chain context format 3", offsets_input.size());
1113 : }
1114 :
1115 0 : uint16_t lookahead_count = 0;
1116 0 : if (!subtable.ReadU16(&lookahead_count)) {
1117 0 : return OTS_FAILURE_MSG("Failed ot read lookahead count in chain context format 3");
1118 : }
1119 0 : if (lookahead_count >= num_glyphs) {
1120 0 : return OTS_FAILURE_MSG("Bad lookahead count %d in chain context format 3", lookahead_count);
1121 : }
1122 0 : std::vector<uint16_t> offsets_lookahead;
1123 0 : offsets_lookahead.reserve(lookahead_count);
1124 0 : for (unsigned i = 0; i < lookahead_count; ++i) {
1125 0 : uint16_t offset = 0;
1126 0 : if (!subtable.ReadU16(&offset)) {
1127 0 : return OTS_FAILURE_MSG("Failed to read lookahead offset %d in chain context format 3", i);
1128 : }
1129 0 : offsets_lookahead.push_back(offset);
1130 : }
1131 0 : if (offsets_lookahead.size() != lookahead_count) {
1132 0 : return OTS_FAILURE_MSG("Bad lookahead offsets size %ld in chain context format 3", offsets_lookahead.size());
1133 : }
1134 :
1135 0 : uint16_t lookup_count = 0;
1136 0 : if (!subtable.ReadU16(&lookup_count)) {
1137 0 : return OTS_FAILURE_MSG("Failed to read lookup count in chain context format 3");
1138 : }
1139 0 : for (unsigned i = 0; i < lookup_count; ++i) {
1140 0 : if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) {
1141 0 : return OTS_FAILURE_MSG("Failed to parse lookup %d in chain context format 3", i);
1142 : }
1143 : }
1144 :
1145 : const unsigned lookup_record_end =
1146 0 : 2 * (static_cast<unsigned>(backtrack_count) +
1147 0 : static_cast<unsigned>(input_count) +
1148 0 : static_cast<unsigned>(lookahead_count)) +
1149 0 : 4 * static_cast<unsigned>(lookup_count) + 10;
1150 0 : if (lookup_record_end > std::numeric_limits<uint16_t>::max()) {
1151 0 : return OTS_FAILURE_MSG("Bad end of lookup record %d in chain context format 3", lookup_record_end);
1152 : }
1153 0 : for (unsigned i = 0; i < backtrack_count; ++i) {
1154 0 : if (offsets_backtrack[i] < lookup_record_end ||
1155 0 : offsets_backtrack[i] >= length) {
1156 0 : return OTS_FAILURE_MSG("Bad backtrack offset of %d for backtrack %d in chain context format 3", offsets_backtrack[i], i);
1157 : }
1158 0 : if (!ots::ParseCoverageTable(font, data + offsets_backtrack[i],
1159 0 : length - offsets_backtrack[i], num_glyphs)) {
1160 0 : return OTS_FAILURE_MSG("Failed to parse backtrack coverage %d in chain context format 3", i);
1161 : }
1162 : }
1163 0 : for (unsigned i = 0; i < input_count; ++i) {
1164 0 : if (offsets_input[i] < lookup_record_end || offsets_input[i] >= length) {
1165 0 : return OTS_FAILURE_MSG("Bad input offset %d for input %d in chain context format 3", offsets_input[i], i);
1166 : }
1167 0 : if (!ots::ParseCoverageTable(font, data + offsets_input[i],
1168 0 : length - offsets_input[i], num_glyphs)) {
1169 0 : return OTS_FAILURE_MSG("Failed to parse input coverage table %d in chain context format 3", i);
1170 : }
1171 : }
1172 0 : for (unsigned i = 0; i < lookahead_count; ++i) {
1173 0 : if (offsets_lookahead[i] < lookup_record_end ||
1174 0 : offsets_lookahead[i] >= length) {
1175 0 : return OTS_FAILURE_MSG("Bad lookadhead offset %d for lookahead %d in chain context format 3", offsets_lookahead[i], i);
1176 : }
1177 0 : if (!ots::ParseCoverageTable(font, data + offsets_lookahead[i],
1178 0 : length - offsets_lookahead[i], num_glyphs)) {
1179 0 : return OTS_FAILURE_MSG("Failed to parse lookahead coverage table %d in chain context format 3", i);
1180 : }
1181 : }
1182 :
1183 0 : return true;
1184 : }
1185 :
1186 : } // namespace
1187 :
1188 : namespace ots {
1189 :
1190 0 : bool LookupSubtableParser::Parse(const Font *font, const uint8_t *data,
1191 : const size_t length,
1192 : const uint16_t lookup_type) const {
1193 0 : for (unsigned i = 0; i < num_types; ++i) {
1194 0 : if (parsers[i].type == lookup_type && parsers[i].parse) {
1195 0 : if (!parsers[i].parse(font, data, length)) {
1196 0 : return OTS_FAILURE_MSG("Failed to parse lookup subtable %d", i);
1197 : }
1198 0 : return true;
1199 : }
1200 : }
1201 0 : return OTS_FAILURE_MSG("No lookup subtables to parse");
1202 : }
1203 :
1204 : // Parsing ScriptListTable requires number of features so we need to
1205 : // parse FeatureListTable before calling this function.
1206 0 : bool ParseScriptListTable(const ots::Font *font,
1207 : const uint8_t *data, const size_t length,
1208 : const uint16_t num_features) {
1209 0 : Buffer subtable(data, length);
1210 :
1211 0 : uint16_t script_count = 0;
1212 0 : if (!subtable.ReadU16(&script_count)) {
1213 0 : return OTS_FAILURE_MSG("Failed to read script count in script list table");
1214 : }
1215 :
1216 : const unsigned script_record_end =
1217 0 : 6 * static_cast<unsigned>(script_count) + 2;
1218 0 : if (script_record_end > std::numeric_limits<uint16_t>::max()) {
1219 0 : return OTS_FAILURE_MSG("Bad end of script record %d in script list table", script_record_end);
1220 : }
1221 0 : std::vector<ScriptRecord> script_list;
1222 0 : script_list.reserve(script_count);
1223 0 : uint32_t last_tag = 0;
1224 0 : for (unsigned i = 0; i < script_count; ++i) {
1225 : ScriptRecord record;
1226 0 : if (!subtable.ReadU32(&record.tag) ||
1227 0 : !subtable.ReadU16(&record.offset)) {
1228 0 : return OTS_FAILURE_MSG("Failed to read script record %d in script list table", i);
1229 : }
1230 : // Script tags should be arranged alphabetically by tag
1231 0 : if (last_tag != 0 && last_tag > record.tag) {
1232 : // Several fonts don't arrange tags alphabetically.
1233 : // It seems that the order of tags might not be a security issue
1234 : // so we just warn it.
1235 0 : OTS_WARNING("tags aren't arranged alphabetically.");
1236 : }
1237 0 : last_tag = record.tag;
1238 0 : if (record.offset < script_record_end || record.offset >= length) {
1239 0 : return OTS_FAILURE_MSG("Bad record offset %d for script %c%c%c%c entry %d in script list table", record.offset, OTS_UNTAG(record.tag), i);
1240 : }
1241 0 : script_list.push_back(record);
1242 : }
1243 0 : if (script_list.size() != script_count) {
1244 0 : return OTS_FAILURE_MSG("Bad script list size %ld in script list table", script_list.size());
1245 : }
1246 :
1247 : // Check script records.
1248 0 : for (unsigned i = 0; i < script_count; ++i) {
1249 0 : if (!ParseScriptTable(font, data + script_list[i].offset,
1250 0 : length - script_list[i].offset,
1251 0 : script_list[i].tag, num_features)) {
1252 0 : return OTS_FAILURE_MSG("Failed to parse script table %d", i);
1253 : }
1254 : }
1255 :
1256 0 : return true;
1257 : }
1258 :
1259 : // Parsing FeatureListTable requires number of lookups so we need to parse
1260 : // LookupListTable before calling this function.
1261 0 : bool ParseFeatureListTable(const ots::Font *font,
1262 : const uint8_t *data, const size_t length,
1263 : const uint16_t num_lookups,
1264 : uint16_t* num_features) {
1265 0 : Buffer subtable(data, length);
1266 :
1267 0 : uint16_t feature_count = 0;
1268 0 : if (!subtable.ReadU16(&feature_count)) {
1269 0 : return OTS_FAILURE_MSG("Failed to read feature count");
1270 : }
1271 :
1272 0 : std::vector<FeatureRecord> feature_records;
1273 0 : feature_records.resize(feature_count);
1274 : const unsigned feature_record_end =
1275 0 : 6 * static_cast<unsigned>(feature_count) + 2;
1276 0 : if (feature_record_end > std::numeric_limits<uint16_t>::max()) {
1277 0 : return OTS_FAILURE_MSG("Bad end of feature record %d", feature_record_end);
1278 : }
1279 0 : uint32_t last_tag = 0;
1280 0 : for (unsigned i = 0; i < feature_count; ++i) {
1281 0 : if (!subtable.ReadU32(&feature_records[i].tag) ||
1282 0 : !subtable.ReadU16(&feature_records[i].offset)) {
1283 0 : return OTS_FAILURE_MSG("Failed to read feature header %d", i);
1284 : }
1285 : // Feature record array should be arranged alphabetically by tag
1286 0 : if (last_tag != 0 && last_tag > feature_records[i].tag) {
1287 : // Several fonts don't arrange tags alphabetically.
1288 : // It seems that the order of tags might not be a security issue
1289 : // so we just warn it.
1290 0 : OTS_WARNING("tags aren't arranged alphabetically.");
1291 : }
1292 0 : last_tag = feature_records[i].tag;
1293 0 : if (feature_records[i].offset < feature_record_end ||
1294 0 : feature_records[i].offset >= length) {
1295 0 : return OTS_FAILURE_MSG("Bad feature offset %d for feature %d %c%c%c%c", feature_records[i].offset, i, OTS_UNTAG(feature_records[i].tag));
1296 : }
1297 : }
1298 :
1299 0 : for (unsigned i = 0; i < feature_count; ++i) {
1300 0 : if (!ParseFeatureTable(font, data + feature_records[i].offset,
1301 0 : length - feature_records[i].offset, num_lookups)) {
1302 0 : return OTS_FAILURE_MSG("Failed to parse feature table %d", i);
1303 : }
1304 : }
1305 0 : *num_features = feature_count;
1306 0 : return true;
1307 : }
1308 :
1309 : // For parsing GPOS/GSUB tables, this function should be called at first to
1310 : // obtain the number of lookups because parsing FeatureTableList requires
1311 : // the number.
1312 0 : bool ParseLookupListTable(Font *font, const uint8_t *data,
1313 : const size_t length,
1314 : const LookupSubtableParser* parser,
1315 : uint16_t *num_lookups) {
1316 0 : Buffer subtable(data, length);
1317 :
1318 0 : if (!subtable.ReadU16(num_lookups)) {
1319 0 : return OTS_FAILURE_MSG("Failed to read number of lookups");
1320 : }
1321 :
1322 0 : std::vector<uint16_t> lookups;
1323 0 : lookups.reserve(*num_lookups);
1324 : const unsigned lookup_end =
1325 0 : 2 * static_cast<unsigned>(*num_lookups) + 2;
1326 0 : if (lookup_end > std::numeric_limits<uint16_t>::max()) {
1327 0 : return OTS_FAILURE_MSG("Bad end of lookups %d", lookup_end);
1328 : }
1329 0 : for (unsigned i = 0; i < *num_lookups; ++i) {
1330 0 : uint16_t offset = 0;
1331 0 : if (!subtable.ReadU16(&offset)) {
1332 0 : return OTS_FAILURE_MSG("Failed to read lookup offset %d", i);
1333 : }
1334 0 : if (offset < lookup_end || offset >= length) {
1335 0 : return OTS_FAILURE_MSG("Bad lookup offset %d for lookup %d", offset, i);
1336 : }
1337 0 : lookups.push_back(offset);
1338 : }
1339 0 : if (lookups.size() != *num_lookups) {
1340 0 : return OTS_FAILURE_MSG("Bad lookup offsets list size %ld", lookups.size());
1341 : }
1342 :
1343 0 : for (unsigned i = 0; i < *num_lookups; ++i) {
1344 0 : if (!ParseLookupTable(font, data + lookups[i], length - lookups[i],
1345 : parser)) {
1346 0 : return OTS_FAILURE_MSG("Failed to parse lookup %d", i);
1347 : }
1348 : }
1349 :
1350 0 : return true;
1351 : }
1352 :
1353 0 : bool ParseClassDefTable(const ots::Font *font,
1354 : const uint8_t *data, size_t length,
1355 : const uint16_t num_glyphs,
1356 : const uint16_t num_classes) {
1357 0 : Buffer subtable(data, length);
1358 :
1359 0 : uint16_t format = 0;
1360 0 : if (!subtable.ReadU16(&format)) {
1361 0 : return OTS_FAILURE_MSG("Failed to read class defn format");
1362 : }
1363 0 : if (format == 1) {
1364 0 : return ParseClassDefFormat1(font, data, length, num_glyphs, num_classes);
1365 0 : } else if (format == 2) {
1366 0 : return ParseClassDefFormat2(font, data, length, num_glyphs, num_classes);
1367 : }
1368 :
1369 0 : return OTS_FAILURE_MSG("Bad class defn format %d", format);
1370 : }
1371 :
1372 0 : bool ParseCoverageTable(const ots::Font *font,
1373 : const uint8_t *data, size_t length,
1374 : const uint16_t num_glyphs,
1375 : const uint16_t expected_num_glyphs) {
1376 0 : Buffer subtable(data, length);
1377 :
1378 0 : uint16_t format = 0;
1379 0 : if (!subtable.ReadU16(&format)) {
1380 0 : return OTS_FAILURE_MSG("Failed to read coverage table format");
1381 : }
1382 0 : if (format == 1) {
1383 0 : return ParseCoverageFormat1(font, data, length, num_glyphs, expected_num_glyphs);
1384 0 : } else if (format == 2) {
1385 0 : return ParseCoverageFormat2(font, data, length, num_glyphs, expected_num_glyphs);
1386 : }
1387 :
1388 0 : return OTS_FAILURE_MSG("Bad coverage table format %d", format);
1389 : }
1390 :
1391 0 : bool ParseDeviceTable(const ots::Font *font,
1392 : const uint8_t *data, size_t length) {
1393 0 : Buffer subtable(data, length);
1394 :
1395 0 : uint16_t start_size = 0;
1396 0 : uint16_t end_size = 0;
1397 0 : uint16_t delta_format = 0;
1398 0 : if (!subtable.ReadU16(&start_size) ||
1399 0 : !subtable.ReadU16(&end_size) ||
1400 0 : !subtable.ReadU16(&delta_format)) {
1401 0 : return OTS_FAILURE_MSG("Failed to read device table header");
1402 : }
1403 0 : if (start_size > end_size) {
1404 0 : return OTS_FAILURE_MSG("bad size range: %u > %u", start_size, end_size);
1405 : }
1406 0 : if (delta_format == 0 || delta_format > kMaxDeltaFormatType) {
1407 0 : return OTS_FAILURE_MSG("bad delta format: %u", delta_format);
1408 : }
1409 : // The number of delta values per uint16. The device table should contain
1410 : // at least |num_units| * 2 bytes compressed data.
1411 0 : const unsigned num_units = (end_size - start_size) /
1412 0 : (1 << (4 - delta_format)) + 1;
1413 : // Just skip |num_units| * 2 bytes since the compressed data could take
1414 : // arbitrary values.
1415 0 : if (!subtable.Skip(num_units * 2)) {
1416 0 : return OTS_FAILURE_MSG("Failed to skip data in device table");
1417 : }
1418 0 : return true;
1419 : }
1420 :
1421 0 : bool ParseContextSubtable(const ots::Font *font,
1422 : const uint8_t *data, const size_t length,
1423 : const uint16_t num_glyphs,
1424 : const uint16_t num_lookups) {
1425 0 : Buffer subtable(data, length);
1426 :
1427 0 : uint16_t format = 0;
1428 0 : if (!subtable.ReadU16(&format)) {
1429 0 : return OTS_FAILURE_MSG("Failed to read context subtable format");
1430 : }
1431 :
1432 0 : if (format == 1) {
1433 0 : if (!ParseContextFormat1(font, data, length, num_glyphs, num_lookups)) {
1434 0 : return OTS_FAILURE_MSG("Failed to parse context format 1 subtable");
1435 : }
1436 0 : } else if (format == 2) {
1437 0 : if (!ParseContextFormat2(font, data, length, num_glyphs, num_lookups)) {
1438 0 : return OTS_FAILURE_MSG("Failed to parse context format 2 subtable");
1439 : }
1440 0 : } else if (format == 3) {
1441 0 : if (!ParseContextFormat3(font, data, length, num_glyphs, num_lookups)) {
1442 0 : return OTS_FAILURE_MSG("Failed to parse context format 3 subtable");
1443 : }
1444 : } else {
1445 0 : return OTS_FAILURE_MSG("Bad context subtable format %d", format);
1446 : }
1447 :
1448 0 : return true;
1449 : }
1450 :
1451 0 : bool ParseChainingContextSubtable(const ots::Font *font,
1452 : const uint8_t *data, const size_t length,
1453 : const uint16_t num_glyphs,
1454 : const uint16_t num_lookups) {
1455 0 : Buffer subtable(data, length);
1456 :
1457 0 : uint16_t format = 0;
1458 0 : if (!subtable.ReadU16(&format)) {
1459 0 : return OTS_FAILURE_MSG("Failed to read chaining context subtable format");
1460 : }
1461 :
1462 0 : if (format == 1) {
1463 0 : if (!ParseChainContextFormat1(font, data, length, num_glyphs, num_lookups)) {
1464 0 : return OTS_FAILURE_MSG("Failed to parse chaining context format 1 subtable");
1465 : }
1466 0 : } else if (format == 2) {
1467 0 : if (!ParseChainContextFormat2(font, data, length, num_glyphs, num_lookups)) {
1468 0 : return OTS_FAILURE_MSG("Failed to parse chaining context format 2 subtable");
1469 : }
1470 0 : } else if (format == 3) {
1471 0 : if (!ParseChainContextFormat3(font, data, length, num_glyphs, num_lookups)) {
1472 0 : return OTS_FAILURE_MSG("Failed to parse chaining context format 3 subtable");
1473 : }
1474 : } else {
1475 0 : return OTS_FAILURE_MSG("Bad chaining context subtable format %d", format);
1476 : }
1477 :
1478 0 : return true;
1479 : }
1480 :
1481 0 : bool ParseExtensionSubtable(const Font *font,
1482 : const uint8_t *data, const size_t length,
1483 : const LookupSubtableParser* parser) {
1484 0 : Buffer subtable(data, length);
1485 :
1486 0 : uint16_t format = 0;
1487 0 : uint16_t lookup_type = 0;
1488 0 : uint32_t offset_extension = 0;
1489 0 : if (!subtable.ReadU16(&format) ||
1490 0 : !subtable.ReadU16(&lookup_type) ||
1491 0 : !subtable.ReadU32(&offset_extension)) {
1492 0 : return OTS_FAILURE_MSG("Failed to read extension table header");
1493 : }
1494 :
1495 0 : if (format != 1) {
1496 0 : return OTS_FAILURE_MSG("Bad extension table format %d", format);
1497 : }
1498 : // |lookup_type| should be other than |parser->extension_type|.
1499 0 : if (lookup_type < 1 || lookup_type > parser->num_types ||
1500 0 : lookup_type == parser->extension_type) {
1501 0 : return OTS_FAILURE_MSG("Bad lookup type %d in extension table", lookup_type);
1502 : }
1503 :
1504 0 : const unsigned format_end = static_cast<unsigned>(8);
1505 0 : if (offset_extension < format_end ||
1506 0 : offset_extension >= length) {
1507 0 : return OTS_FAILURE_MSG("Bad extension offset %d", offset_extension);
1508 : }
1509 :
1510 : // Parse the extension subtable of |lookup_type|.
1511 0 : if (!parser->Parse(font, data + offset_extension, length - offset_extension,
1512 : lookup_type)) {
1513 0 : return OTS_FAILURE_MSG("Failed to parse lookup from extension lookup");
1514 : }
1515 :
1516 0 : return true;
1517 : }
1518 :
1519 : } // namespace ots
1520 :
1521 : #undef TABLE_NAME
|