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