Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / third_party / ots / src / layout.cc
blob856152c18ac12666315a17acd60c3f4bd944cf81
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;
39 struct LangSysRecord {
40 uint32_t tag;
41 uint16_t offset;
44 struct FeatureRecord {
45 uint32_t tag;
46 uint16_t offset;
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);
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);
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);
68 if (feature_count > num_features) {
69 return OTS_FAILURE_MSG("Bad feature count %d for langsys tag %4.4s", feature_count, (char *)&tag);
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);
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);
81 return true;
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);
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);
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);
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);
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);
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);
126 last_tag = lang_sys_records[i].tag;
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);
137 return true;
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");
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);
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);
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);
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);
174 return true;
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");
191 if (lookup_type == 0 || lookup_type > parser->num_types) {
192 return OTS_FAILURE_MSG("Bad lookup type %d", lookup_type);
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);
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);
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);
209 use_mark_filtering_set = true;
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);
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);
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);
230 subtables.push_back(offset_subtable);
232 if (subtables.size() != subtable_count) {
233 return OTS_FAILURE_MSG("Bad subtable size %ld", subtables.size());
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");
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);
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);
254 return true;
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");
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");
272 if (start_glyph > num_glyphs) {
273 return OTS_FAILURE_MSG("Bad starting glyph %d in class definition", start_glyph);
276 uint16_t glyph_count = 0;
277 if (!subtable.ReadU16(&glyph_count)) {
278 return OTS_FAILURE_MSG("Failed to read glyph count in class definition");
280 if (glyph_count > num_glyphs) {
281 return OTS_FAILURE_MSG("bad glyph count: %u", glyph_count);
283 for (unsigned i = 0; i < glyph_count; ++i) {
284 uint16_t class_value = 0;
285 if (!subtable.ReadU16(&class_value)) {
286 return OTS_FAILURE_MSG("Failed to read class value for glyph %d in class definition", i);
288 if (class_value > num_classes) {
289 return OTS_FAILURE_MSG("Bad class value %d for glyph %d in class definition", class_value, i);
293 return true;
296 bool ParseClassDefFormat2(const ots::OpenTypeFile *file,
297 const uint8_t *data, size_t length,
298 const uint16_t num_glyphs,
299 const uint16_t num_classes) {
300 ots::Buffer subtable(data, length);
302 // Skip format field.
303 if (!subtable.Skip(2)) {
304 return OTS_FAILURE_MSG("Failed to skip format of class defintion header");
307 uint16_t range_count = 0;
308 if (!subtable.ReadU16(&range_count)) {
309 return OTS_FAILURE_MSG("Failed to read range count in class definition");
311 if (range_count > num_glyphs) {
312 return OTS_FAILURE_MSG("bad range count: %u", range_count);
315 uint16_t last_end = 0;
316 for (unsigned i = 0; i < range_count; ++i) {
317 uint16_t start = 0;
318 uint16_t end = 0;
319 uint16_t class_value = 0;
320 if (!subtable.ReadU16(&start) ||
321 !subtable.ReadU16(&end) ||
322 !subtable.ReadU16(&class_value)) {
323 return OTS_FAILURE_MSG("Failed to read class definition reange %d", i);
325 if (start > end || (last_end && start <= last_end)) {
326 return OTS_FAILURE_MSG("glyph range is overlapping.in range %d", i);
328 if (class_value > num_classes) {
329 return OTS_FAILURE_MSG("bad class value: %u", class_value);
331 last_end = end;
334 return true;
337 bool ParseCoverageFormat1(const ots::OpenTypeFile *file,
338 const uint8_t *data, size_t length,
339 const uint16_t num_glyphs,
340 const uint16_t expected_num_glyphs) {
341 ots::Buffer subtable(data, length);
343 // Skip format field.
344 if (!subtable.Skip(2)) {
345 return OTS_FAILURE_MSG("Failed to skip coverage format");
348 uint16_t glyph_count = 0;
349 if (!subtable.ReadU16(&glyph_count)) {
350 return OTS_FAILURE_MSG("Failed to read glyph count in coverage");
352 if (glyph_count > num_glyphs) {
353 return OTS_FAILURE_MSG("bad glyph count: %u", glyph_count);
355 for (unsigned i = 0; i < glyph_count; ++i) {
356 uint16_t glyph = 0;
357 if (!subtable.ReadU16(&glyph)) {
358 return OTS_FAILURE_MSG("Failed to read glyph %d in coverage", i);
360 if (glyph > num_glyphs) {
361 return OTS_FAILURE_MSG("bad glyph ID: %u", glyph);
365 if (expected_num_glyphs && expected_num_glyphs != glyph_count) {
366 return OTS_FAILURE_MSG("unexpected number of glyphs: %u", glyph_count);
369 return true;
372 bool ParseCoverageFormat2(const ots::OpenTypeFile *file,
373 const uint8_t *data, size_t length,
374 const uint16_t num_glyphs,
375 const uint16_t expected_num_glyphs) {
376 ots::Buffer subtable(data, length);
378 // Skip format field.
379 if (!subtable.Skip(2)) {
380 return OTS_FAILURE_MSG("Failed to skip format of coverage type 2");
383 uint16_t range_count = 0;
384 if (!subtable.ReadU16(&range_count)) {
385 return OTS_FAILURE_MSG("Failed to read range count in coverage");
387 if (range_count > num_glyphs) {
388 return OTS_FAILURE_MSG("bad range count: %u", range_count);
390 uint16_t last_end = 0;
391 uint16_t last_start_coverage_index = 0;
392 for (unsigned i = 0; i < range_count; ++i) {
393 uint16_t start = 0;
394 uint16_t end = 0;
395 uint16_t start_coverage_index = 0;
396 if (!subtable.ReadU16(&start) ||
397 !subtable.ReadU16(&end) ||
398 !subtable.ReadU16(&start_coverage_index)) {
399 return OTS_FAILURE_MSG("Failed to read range %d in coverage", i);
402 // Some of the Adobe Pro fonts have ranges that overlap by one element: the
403 // start of one range is equal to the end of the previous range. Therefore
404 // the < in the following condition should be <= were it not for this.
405 // See crbug.com/134135.
406 if (start > end || (last_end && start < last_end)) {
407 return OTS_FAILURE_MSG("glyph range is overlapping.");
409 if (start_coverage_index != last_start_coverage_index) {
410 return OTS_FAILURE_MSG("bad start coverage index.");
412 last_end = end;
413 last_start_coverage_index += end - start + 1;
416 if (expected_num_glyphs &&
417 expected_num_glyphs != last_start_coverage_index) {
418 return OTS_FAILURE_MSG("unexpected number of glyphs: %u", last_start_coverage_index);
421 return true;
424 // Parsers for Contextual subtables in GSUB/GPOS tables.
426 bool ParseLookupRecord(const ots::OpenTypeFile *file,
427 ots::Buffer *subtable, const uint16_t num_glyphs,
428 const uint16_t num_lookups) {
429 uint16_t sequence_index = 0;
430 uint16_t lookup_list_index = 0;
431 if (!subtable->ReadU16(&sequence_index) ||
432 !subtable->ReadU16(&lookup_list_index)) {
433 return OTS_FAILURE_MSG("Failed to read header for lookup record");
435 if (sequence_index >= num_glyphs) {
436 return OTS_FAILURE_MSG("Bad sequence index %d in lookup record", sequence_index);
438 if (lookup_list_index >= num_lookups) {
439 return OTS_FAILURE_MSG("Bad lookup list index %d in lookup record", lookup_list_index);
441 return true;
444 bool ParseRuleSubtable(const ots::OpenTypeFile *file,
445 const uint8_t *data, const size_t length,
446 const uint16_t num_glyphs,
447 const uint16_t num_lookups) {
448 ots::Buffer subtable(data, length);
450 uint16_t glyph_count = 0;
451 uint16_t lookup_count = 0;
452 if (!subtable.ReadU16(&glyph_count) ||
453 !subtable.ReadU16(&lookup_count)) {
454 return OTS_FAILURE_MSG("Failed to read rule subtable header");
457 if (glyph_count == 0 || glyph_count >= num_glyphs) {
458 return OTS_FAILURE_MSG("Bad glyph count %d in rule subtable", glyph_count);
460 for (unsigned i = 0; i < glyph_count - static_cast<unsigned>(1); ++i) {
461 uint16_t glyph_id = 0;
462 if (!subtable.ReadU16(&glyph_id)) {
463 return OTS_FAILURE_MSG("Failed to read glyph %d", i);
465 if (glyph_id > num_glyphs) {
466 return OTS_FAILURE_MSG("Bad glyph %d for entry %d", glyph_id, i);
470 for (unsigned i = 0; i < lookup_count; ++i) {
471 if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
472 return OTS_FAILURE_MSG("Failed to parse lookup record %d", i);
475 return true;
478 bool ParseRuleSetTable(const ots::OpenTypeFile *file,
479 const uint8_t *data, const size_t length,
480 const uint16_t num_glyphs,
481 const uint16_t num_lookups) {
482 ots::Buffer subtable(data, length);
484 uint16_t rule_count = 0;
485 if (!subtable.ReadU16(&rule_count)) {
486 return OTS_FAILURE_MSG("Failed to read rule count in rule set");
488 const unsigned rule_end = 2 * static_cast<unsigned>(rule_count) + 2;
489 if (rule_end > std::numeric_limits<uint16_t>::max()) {
490 return OTS_FAILURE_MSG("Bad end of rule %d in rule set", rule_end);
493 for (unsigned i = 0; i < rule_count; ++i) {
494 uint16_t offset_rule = 0;
495 if (!subtable.ReadU16(&offset_rule)) {
496 return OTS_FAILURE_MSG("Failed to read rule offset for rule set %d", i);
498 if (offset_rule < rule_end || offset_rule >= length) {
499 return OTS_FAILURE_MSG("Bad rule offset %d in set %d", offset_rule, i);
501 if (!ParseRuleSubtable(file, data + offset_rule, length - offset_rule,
502 num_glyphs, num_lookups)) {
503 return OTS_FAILURE_MSG("Failed to parse rule set %d", i);
507 return true;
510 bool ParseContextFormat1(const ots::OpenTypeFile *file,
511 const uint8_t *data, const size_t length,
512 const uint16_t num_glyphs,
513 const uint16_t num_lookups) {
514 ots::Buffer subtable(data, length);
516 uint16_t offset_coverage = 0;
517 uint16_t rule_set_count = 0;
518 // Skip format field.
519 if (!subtable.Skip(2) ||
520 !subtable.ReadU16(&offset_coverage) ||
521 !subtable.ReadU16(&rule_set_count)) {
522 return OTS_FAILURE_MSG("Failed to read header of context format 1");
525 const unsigned rule_set_end = static_cast<unsigned>(6) +
526 rule_set_count * 2;
527 if (rule_set_end > std::numeric_limits<uint16_t>::max()) {
528 return OTS_FAILURE_MSG("Bad end of rule set %d of context format 1", rule_set_end);
530 if (offset_coverage < rule_set_end || offset_coverage >= length) {
531 return OTS_FAILURE_MSG("Bad coverage offset %d in context format 1", offset_coverage);
533 if (!ots::ParseCoverageTable(file, data + offset_coverage,
534 length - offset_coverage, num_glyphs)) {
535 return OTS_FAILURE_MSG("Failed to parse coverage table in context format 1");
538 for (unsigned i = 0; i < rule_set_count; ++i) {
539 uint16_t offset_rule = 0;
540 if (!subtable.ReadU16(&offset_rule)) {
541 return OTS_FAILURE_MSG("Failed to read rule offset %d in context format 1", i);
543 if (offset_rule < rule_set_end || offset_rule >= length) {
544 return OTS_FAILURE_MSG("Bad rule offset %d in rule %d in context format 1", offset_rule, i);
546 if (!ParseRuleSetTable(file, data + offset_rule, length - offset_rule,
547 num_glyphs, num_lookups)) {
548 return OTS_FAILURE_MSG("Failed to parse rule set %d in context format 1", i);
552 return true;
555 bool ParseClassRuleTable(const ots::OpenTypeFile *file,
556 const uint8_t *data, const size_t length,
557 const uint16_t num_glyphs,
558 const uint16_t num_lookups) {
559 ots::Buffer subtable(data, length);
561 uint16_t glyph_count = 0;
562 uint16_t lookup_count = 0;
563 if (!subtable.ReadU16(&glyph_count) ||
564 !subtable.ReadU16(&lookup_count)) {
565 return OTS_FAILURE_MSG("Failed to read header of class rule table");
568 if (glyph_count == 0 || glyph_count >= num_glyphs) {
569 return OTS_FAILURE_MSG("Bad glyph count %d in class rule table", glyph_count);
572 // ClassRule table contains an array of classes. Each value of classes
573 // could take arbitrary values including zero so we don't check these value.
574 const unsigned num_classes = glyph_count - static_cast<unsigned>(1);
575 if (!subtable.Skip(2 * num_classes)) {
576 return OTS_FAILURE_MSG("Failed to skip classes in class rule table");
579 for (unsigned i = 0; i < lookup_count; ++i) {
580 if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
581 return OTS_FAILURE_MSG("Failed to parse lookup record %d in class rule table", i);
584 return true;
587 bool ParseClassSetTable(const ots::OpenTypeFile *file,
588 const uint8_t *data, const size_t length,
589 const uint16_t num_glyphs,
590 const uint16_t num_lookups) {
591 ots::Buffer subtable(data, length);
593 uint16_t class_rule_count = 0;
594 if (!subtable.ReadU16(&class_rule_count)) {
595 return OTS_FAILURE_MSG("Failed to read class rule count in class set table");
597 const unsigned class_rule_end =
598 2 * static_cast<unsigned>(class_rule_count) + 2;
599 if (class_rule_end > std::numeric_limits<uint16_t>::max()) {
600 return OTS_FAILURE_MSG("bad class rule end %d in class set table", class_rule_end);
602 for (unsigned i = 0; i < class_rule_count; ++i) {
603 uint16_t offset_class_rule = 0;
604 if (!subtable.ReadU16(&offset_class_rule)) {
605 return OTS_FAILURE_MSG("Failed to read class rule offset %d in class set table", i);
607 if (offset_class_rule < class_rule_end || offset_class_rule >= length) {
608 return OTS_FAILURE_MSG("Bad class rule offset %d in class %d", offset_class_rule, i);
610 if (!ParseClassRuleTable(file, data + offset_class_rule,
611 length - offset_class_rule, num_glyphs,
612 num_lookups)) {
613 return OTS_FAILURE_MSG("Failed to parse class rule table %d", i);
617 return true;
620 bool ParseContextFormat2(const ots::OpenTypeFile *file,
621 const uint8_t *data, const size_t length,
622 const uint16_t num_glyphs,
623 const uint16_t num_lookups) {
624 ots::Buffer subtable(data, length);
626 uint16_t offset_coverage = 0;
627 uint16_t offset_class_def = 0;
628 uint16_t class_set_cnt = 0;
629 // Skip format field.
630 if (!subtable.Skip(2) ||
631 !subtable.ReadU16(&offset_coverage) ||
632 !subtable.ReadU16(&offset_class_def) ||
633 !subtable.ReadU16(&class_set_cnt)) {
634 return OTS_FAILURE_MSG("Failed to read header for context format 2");
637 const unsigned class_set_end = 2 * static_cast<unsigned>(class_set_cnt) + 8;
638 if (class_set_end > std::numeric_limits<uint16_t>::max()) {
639 return OTS_FAILURE_MSG("Bad end of class set %d for context format 2", class_set_end);
641 if (offset_coverage < class_set_end || offset_coverage >= length) {
642 return OTS_FAILURE_MSG("Bad coverage offset %d in context format 2", offset_coverage);
644 if (!ots::ParseCoverageTable(file, data + offset_coverage,
645 length - offset_coverage, num_glyphs)) {
646 return OTS_FAILURE_MSG("Failed to parse coverage table in context format 2");
649 if (offset_class_def < class_set_end || offset_class_def >= length) {
650 return OTS_FAILURE_MSG("bad class definition offset %d in context format 2", offset_class_def);
652 if (!ots::ParseClassDefTable(file, data + offset_class_def,
653 length - offset_class_def,
654 num_glyphs, kMaxClassDefValue)) {
655 return OTS_FAILURE_MSG("Failed to parse class definition table in context format 2");
658 for (unsigned i = 0; i < class_set_cnt; ++i) {
659 uint16_t offset_class_rule = 0;
660 if (!subtable.ReadU16(&offset_class_rule)) {
661 return OTS_FAILURE_MSG("Failed to read class rule offset %d in context format 2", i);
663 if (offset_class_rule) {
664 if (offset_class_rule < class_set_end || offset_class_rule >= length) {
665 return OTS_FAILURE_MSG("Bad class rule offset %d for rule %d in context format 2", offset_class_rule, i);
667 if (!ParseClassSetTable(file, data + offset_class_rule,
668 length - offset_class_rule, num_glyphs,
669 num_lookups)) {
670 return OTS_FAILURE_MSG("Failed to parse class set %d in context format 2", i);
675 return true;
678 bool ParseContextFormat3(const ots::OpenTypeFile *file,
679 const uint8_t *data, const size_t length,
680 const uint16_t num_glyphs,
681 const uint16_t num_lookups) {
682 ots::Buffer subtable(data, length);
684 uint16_t glyph_count = 0;
685 uint16_t lookup_count = 0;
686 // Skip format field.
687 if (!subtable.Skip(2) ||
688 !subtable.ReadU16(&glyph_count) ||
689 !subtable.ReadU16(&lookup_count)) {
690 return OTS_FAILURE_MSG("Failed to read header in context format 3");
693 if (glyph_count >= num_glyphs) {
694 return OTS_FAILURE_MSG("Bad glyph count %d in context format 3", glyph_count);
696 const unsigned lookup_record_end = 2 * static_cast<unsigned>(glyph_count) +
697 4 * static_cast<unsigned>(lookup_count) + 6;
698 if (lookup_record_end > std::numeric_limits<uint16_t>::max()) {
699 return OTS_FAILURE_MSG("Bad end of lookup %d in context format 3", lookup_record_end);
701 for (unsigned i = 0; i < glyph_count; ++i) {
702 uint16_t offset_coverage = 0;
703 if (!subtable.ReadU16(&offset_coverage)) {
704 return OTS_FAILURE_MSG("Failed to read coverage offset %d in conxtext format 3", i);
706 if (offset_coverage < lookup_record_end || offset_coverage >= length) {
707 return OTS_FAILURE_MSG("Bad coverage offset %d for glyph %d in context format 3", offset_coverage, i);
709 if (!ots::ParseCoverageTable(file, data + offset_coverage,
710 length - offset_coverage, num_glyphs)) {
711 return OTS_FAILURE_MSG("Failed to parse coverage table for glyph %d in context format 3", i);
715 for (unsigned i = 0; i < lookup_count; ++i) {
716 if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
717 return OTS_FAILURE_MSG("Failed to parse lookup record %d in context format 3", i);
721 return true;
724 // Parsers for Chaning Contextual subtables in GSUB/GPOS tables.
726 bool ParseChainRuleSubtable(const ots::OpenTypeFile *file,
727 const uint8_t *data, const size_t length,
728 const uint16_t num_glyphs,
729 const uint16_t num_lookups) {
730 ots::Buffer subtable(data, length);
732 uint16_t backtrack_count = 0;
733 if (!subtable.ReadU16(&backtrack_count)) {
734 return OTS_FAILURE_MSG("Failed to read backtrack count in chain rule subtable");
736 if (backtrack_count >= num_glyphs) {
737 return OTS_FAILURE_MSG("Bad backtrack count %d in chain rule subtable", backtrack_count);
739 for (unsigned i = 0; i < backtrack_count; ++i) {
740 uint16_t glyph_id = 0;
741 if (!subtable.ReadU16(&glyph_id)) {
742 return OTS_FAILURE_MSG("Failed to read backtrack glyph %d in chain rule subtable", i);
744 if (glyph_id > num_glyphs) {
745 return OTS_FAILURE_MSG("Bad glyph id %d for bactrack glyph %d in chain rule subtable", glyph_id, i);
749 uint16_t input_count = 0;
750 if (!subtable.ReadU16(&input_count)) {
751 return OTS_FAILURE_MSG("Failed to read input count in chain rule subtable");
753 if (input_count == 0 || input_count >= num_glyphs) {
754 return OTS_FAILURE_MSG("Bad input count %d in chain rule subtable", input_count);
756 for (unsigned i = 0; i < input_count - static_cast<unsigned>(1); ++i) {
757 uint16_t glyph_id = 0;
758 if (!subtable.ReadU16(&glyph_id)) {
759 return OTS_FAILURE_MSG("Failed to read input glyph %d in chain rule subtable", i);
761 if (glyph_id > num_glyphs) {
762 return OTS_FAILURE_MSG("Bad glyph id %d for input glyph %d in chain rule subtable", glyph_id, i);
766 uint16_t lookahead_count = 0;
767 if (!subtable.ReadU16(&lookahead_count)) {
768 return OTS_FAILURE_MSG("Failed to read lookahead count in chain rule subtable");
770 if (lookahead_count >= num_glyphs) {
771 return OTS_FAILURE_MSG("Bad lookahead count %d in chain rule subtable", lookahead_count);
773 for (unsigned i = 0; i < lookahead_count; ++i) {
774 uint16_t glyph_id = 0;
775 if (!subtable.ReadU16(&glyph_id)) {
776 return OTS_FAILURE_MSG("Failed to read lookahead glyph %d in chain rule subtable", i);
778 if (glyph_id > num_glyphs) {
779 return OTS_FAILURE_MSG("Bad glyph id %d for lookadhead glyph %d in chain rule subtable", glyph_id, i);
783 uint16_t lookup_count = 0;
784 if (!subtable.ReadU16(&lookup_count)) {
785 return OTS_FAILURE_MSG("Failed to read lookup count in chain rule subtable");
787 for (unsigned i = 0; i < lookup_count; ++i) {
788 if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
789 return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain rule subtable", i);
793 return true;
796 bool ParseChainRuleSetTable(const ots::OpenTypeFile *file,
797 const uint8_t *data, const size_t length,
798 const uint16_t num_glyphs,
799 const uint16_t num_lookups) {
800 ots::Buffer subtable(data, length);
802 uint16_t chain_rule_count = 0;
803 if (!subtable.ReadU16(&chain_rule_count)) {
804 return OTS_FAILURE_MSG("Failed to read rule count in chain rule set");
806 const unsigned chain_rule_end =
807 2 * static_cast<unsigned>(chain_rule_count) + 2;
808 if (chain_rule_end > std::numeric_limits<uint16_t>::max()) {
809 return OTS_FAILURE_MSG("Bad end of chain rule %d in chain rule set", chain_rule_end);
811 for (unsigned i = 0; i < chain_rule_count; ++i) {
812 uint16_t offset_chain_rule = 0;
813 if (!subtable.ReadU16(&offset_chain_rule)) {
814 return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain rule set", i);
816 if (offset_chain_rule < chain_rule_end || offset_chain_rule >= length) {
817 return OTS_FAILURE_MSG("Bad chain rule offset %d for chain rule %d in chain rule set", offset_chain_rule, i);
819 if (!ParseChainRuleSubtable(file, data + offset_chain_rule,
820 length - offset_chain_rule,
821 num_glyphs, num_lookups)) {
822 return OTS_FAILURE_MSG("Failed to parse chain rule %d in chain rule set", i);
826 return true;
829 bool ParseChainContextFormat1(const ots::OpenTypeFile *file,
830 const uint8_t *data, const size_t length,
831 const uint16_t num_glyphs,
832 const uint16_t num_lookups) {
833 ots::Buffer subtable(data, length);
835 uint16_t offset_coverage = 0;
836 uint16_t chain_rule_set_count = 0;
837 // Skip format field.
838 if (!subtable.Skip(2) ||
839 !subtable.ReadU16(&offset_coverage) ||
840 !subtable.ReadU16(&chain_rule_set_count)) {
841 return OTS_FAILURE_MSG("Failed to read header of chain context format 1");
844 const unsigned chain_rule_set_end =
845 2 * static_cast<unsigned>(chain_rule_set_count) + 6;
846 if (chain_rule_set_end > std::numeric_limits<uint16_t>::max()) {
847 return OTS_FAILURE_MSG("Bad chain rule end %d in chain context format 1", chain_rule_set_end);
849 if (offset_coverage < chain_rule_set_end || offset_coverage >= length) {
850 return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 1", chain_rule_set_end);
852 if (!ots::ParseCoverageTable(file, data + offset_coverage,
853 length - offset_coverage, num_glyphs)) {
854 return OTS_FAILURE_MSG("Failed to parse coverage table for chain context format 1");
857 for (unsigned i = 0; i < chain_rule_set_count; ++i) {
858 uint16_t offset_chain_rule_set = 0;
859 if (!subtable.ReadU16(&offset_chain_rule_set)) {
860 return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain context format 1", i);
862 if (offset_chain_rule_set < chain_rule_set_end ||
863 offset_chain_rule_set >= length) {
864 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);
866 if (!ParseChainRuleSetTable(file, data + offset_chain_rule_set,
867 length - offset_chain_rule_set,
868 num_glyphs, num_lookups)) {
869 return OTS_FAILURE_MSG("Failed to parse chain rule set %d in chain context format 1", i);
873 return true;
876 bool ParseChainClassRuleSubtable(const ots::OpenTypeFile *file,
877 const uint8_t *data, const size_t length,
878 const uint16_t num_glyphs,
879 const uint16_t num_lookups) {
880 ots::Buffer subtable(data, length);
882 // In this subtable, we don't check the value of classes for now since
883 // these could take arbitrary values.
885 uint16_t backtrack_count = 0;
886 if (!subtable.ReadU16(&backtrack_count)) {
887 return OTS_FAILURE_MSG("Failed to read backtrack count in chain class rule subtable");
889 if (backtrack_count >= num_glyphs) {
890 return OTS_FAILURE_MSG("Bad backtrack count %d in chain class rule subtable", backtrack_count);
892 if (!subtable.Skip(2 * backtrack_count)) {
893 return OTS_FAILURE_MSG("Failed to skip backtrack offsets in chain class rule subtable");
896 uint16_t input_count = 0;
897 if (!subtable.ReadU16(&input_count)) {
898 return OTS_FAILURE_MSG("Failed to read input count in chain class rule subtable");
900 if (input_count == 0 || input_count >= num_glyphs) {
901 return OTS_FAILURE_MSG("Bad input count %d in chain class rule subtable", input_count);
903 if (!subtable.Skip(2 * (input_count - 1))) {
904 return OTS_FAILURE_MSG("Failed to skip input offsets in chain class rule subtable");
907 uint16_t lookahead_count = 0;
908 if (!subtable.ReadU16(&lookahead_count)) {
909 return OTS_FAILURE_MSG("Failed to read lookahead count in chain class rule subtable");
911 if (lookahead_count >= num_glyphs) {
912 return OTS_FAILURE_MSG("Bad lookahead count %d in chain class rule subtable", lookahead_count);
914 if (!subtable.Skip(2 * lookahead_count)) {
915 return OTS_FAILURE_MSG("Failed to skip lookahead offsets in chain class rule subtable");
918 uint16_t lookup_count = 0;
919 if (!subtable.ReadU16(&lookup_count)) {
920 return OTS_FAILURE_MSG("Failed to read lookup count in chain class rule subtable");
922 for (unsigned i = 0; i < lookup_count; ++i) {
923 if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
924 return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain class rule subtable", i);
928 return true;
931 bool ParseChainClassSetTable(const ots::OpenTypeFile *file,
932 const uint8_t *data, const size_t length,
933 const uint16_t num_glyphs,
934 const uint16_t num_lookups) {
935 ots::Buffer subtable(data, length);
937 uint16_t chain_class_rule_count = 0;
938 if (!subtable.ReadU16(&chain_class_rule_count)) {
939 return OTS_FAILURE_MSG("Failed to read rule count in chain class set");
941 const unsigned chain_class_rule_end =
942 2 * static_cast<unsigned>(chain_class_rule_count) + 2;
943 if (chain_class_rule_end > std::numeric_limits<uint16_t>::max()) {
944 return OTS_FAILURE_MSG("Bad end of chain class set %d in chain class set", chain_class_rule_end);
946 for (unsigned i = 0; i < chain_class_rule_count; ++i) {
947 uint16_t offset_chain_class_rule = 0;
948 if (!subtable.ReadU16(&offset_chain_class_rule)) {
949 return OTS_FAILURE_MSG("Failed to read chain class rule offset %d in chain class set", i);
951 if (offset_chain_class_rule < chain_class_rule_end ||
952 offset_chain_class_rule >= length) {
953 return OTS_FAILURE_MSG("Bad chain class rule offset %d for chain class %d in chain class set", offset_chain_class_rule, i);
955 if (!ParseChainClassRuleSubtable(file, data + offset_chain_class_rule,
956 length - offset_chain_class_rule,
957 num_glyphs, num_lookups)) {
958 return OTS_FAILURE_MSG("Failed to parse chain class rule %d in chain class set", i);
962 return true;
965 bool ParseChainContextFormat2(const ots::OpenTypeFile *file,
966 const uint8_t *data, const size_t length,
967 const uint16_t num_glyphs,
968 const uint16_t num_lookups) {
969 ots::Buffer subtable(data, length);
971 uint16_t offset_coverage = 0;
972 uint16_t offset_backtrack_class_def = 0;
973 uint16_t offset_input_class_def = 0;
974 uint16_t offset_lookahead_class_def = 0;
975 uint16_t chain_class_set_count = 0;
976 // Skip format field.
977 if (!subtable.Skip(2) ||
978 !subtable.ReadU16(&offset_coverage) ||
979 !subtable.ReadU16(&offset_backtrack_class_def) ||
980 !subtable.ReadU16(&offset_input_class_def) ||
981 !subtable.ReadU16(&offset_lookahead_class_def) ||
982 !subtable.ReadU16(&chain_class_set_count)) {
983 return OTS_FAILURE_MSG("Failed to read header of chain context format 2");
986 const unsigned chain_class_set_end =
987 2 * static_cast<unsigned>(chain_class_set_count) + 12;
988 if (chain_class_set_end > std::numeric_limits<uint16_t>::max()) {
989 return OTS_FAILURE_MSG("Bad chain class set end %d in chain context format 2", chain_class_set_end);
991 if (offset_coverage < chain_class_set_end || offset_coverage >= length) {
992 return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 2", offset_coverage);
994 if (!ots::ParseCoverageTable(file, data + offset_coverage,
995 length - offset_coverage, num_glyphs)) {
996 return OTS_FAILURE_MSG("Failed to parse coverage table in chain context format 2");
999 // Classes for backtrack/lookahead sequences might not be defined.
1000 if (offset_backtrack_class_def) {
1001 if (offset_backtrack_class_def < chain_class_set_end ||
1002 offset_backtrack_class_def >= length) {
1003 return OTS_FAILURE_MSG("Bad backtrack class offset %d in chain context format 2", offset_backtrack_class_def);
1005 if (!ots::ParseClassDefTable(file, data + offset_backtrack_class_def,
1006 length - offset_backtrack_class_def,
1007 num_glyphs, kMaxClassDefValue)) {
1008 return OTS_FAILURE_MSG("Failed to parse backtrack class defn table in chain context format 2");
1012 if (offset_input_class_def < chain_class_set_end ||
1013 offset_input_class_def >= length) {
1014 return OTS_FAILURE_MSG("Bad input class defn offset %d in chain context format 2", offset_input_class_def);
1016 if (!ots::ParseClassDefTable(file, data + offset_input_class_def,
1017 length - offset_input_class_def,
1018 num_glyphs, kMaxClassDefValue)) {
1019 return OTS_FAILURE_MSG("Failed to parse input class defn in chain context format 2");
1022 if (offset_lookahead_class_def) {
1023 if (offset_lookahead_class_def < chain_class_set_end ||
1024 offset_lookahead_class_def >= length) {
1025 return OTS_FAILURE_MSG("Bad lookahead class defn offset %d in chain context format 2", offset_lookahead_class_def);
1027 if (!ots::ParseClassDefTable(file, data + offset_lookahead_class_def,
1028 length - offset_lookahead_class_def,
1029 num_glyphs, kMaxClassDefValue)) {
1030 return OTS_FAILURE_MSG("Failed to parse lookahead class defn in chain context format 2");
1034 for (unsigned i = 0; i < chain_class_set_count; ++i) {
1035 uint16_t offset_chain_class_set = 0;
1036 if (!subtable.ReadU16(&offset_chain_class_set)) {
1037 return OTS_FAILURE_MSG("Failed to read chain class set offset %d", i);
1039 // |offset_chain_class_set| could be NULL.
1040 if (offset_chain_class_set) {
1041 if (offset_chain_class_set < chain_class_set_end ||
1042 offset_chain_class_set >= length) {
1043 return OTS_FAILURE_MSG("Bad chain set class offset %d for chain set %d in chain context format 2", offset_chain_class_set, i);
1045 if (!ParseChainClassSetTable(file, data + offset_chain_class_set,
1046 length - offset_chain_class_set,
1047 num_glyphs, num_lookups)) {
1048 return OTS_FAILURE_MSG("Failed to parse chain class set table %d in chain context format 2", i);
1053 return true;
1056 bool ParseChainContextFormat3(const ots::OpenTypeFile *file,
1057 const uint8_t *data, const size_t length,
1058 const uint16_t num_glyphs,
1059 const uint16_t num_lookups) {
1060 ots::Buffer subtable(data, length);
1062 uint16_t backtrack_count = 0;
1063 // Skip format field.
1064 if (!subtable.Skip(2) ||
1065 !subtable.ReadU16(&backtrack_count)) {
1066 return OTS_FAILURE_MSG("Failed to read backtrack count in chain context format 3");
1069 if (backtrack_count >= num_glyphs) {
1070 return OTS_FAILURE_MSG("Bad backtrack count %d in chain context format 3", backtrack_count);
1072 std::vector<uint16_t> offsets_backtrack;
1073 offsets_backtrack.reserve(backtrack_count);
1074 for (unsigned i = 0; i < backtrack_count; ++i) {
1075 uint16_t offset = 0;
1076 if (!subtable.ReadU16(&offset)) {
1077 return OTS_FAILURE_MSG("Failed to read backtrack offset %d in chain context format 3", i);
1079 offsets_backtrack.push_back(offset);
1081 if (offsets_backtrack.size() != backtrack_count) {
1082 return OTS_FAILURE_MSG("Bad backtrack offsets size %ld in chain context format 3", offsets_backtrack.size());
1085 uint16_t input_count = 0;
1086 if (!subtable.ReadU16(&input_count)) {
1087 return OTS_FAILURE_MSG("Failed to read input count in chain context format 3");
1089 if (input_count >= num_glyphs) {
1090 return OTS_FAILURE_MSG("Bad input count %d in chain context format 3", input_count);
1092 std::vector<uint16_t> offsets_input;
1093 offsets_input.reserve(input_count);
1094 for (unsigned i = 0; i < input_count; ++i) {
1095 uint16_t offset = 0;
1096 if (!subtable.ReadU16(&offset)) {
1097 return OTS_FAILURE_MSG("Failed to read input offset %d in chain context format 3", i);
1099 offsets_input.push_back(offset);
1101 if (offsets_input.size() != input_count) {
1102 return OTS_FAILURE_MSG("Bad input offsets size %ld in chain context format 3", offsets_input.size());
1105 uint16_t lookahead_count = 0;
1106 if (!subtable.ReadU16(&lookahead_count)) {
1107 return OTS_FAILURE_MSG("Failed ot read lookahead count in chain context format 3");
1109 if (lookahead_count >= num_glyphs) {
1110 return OTS_FAILURE_MSG("Bad lookahead count %d in chain context format 3", lookahead_count);
1112 std::vector<uint16_t> offsets_lookahead;
1113 offsets_lookahead.reserve(lookahead_count);
1114 for (unsigned i = 0; i < lookahead_count; ++i) {
1115 uint16_t offset = 0;
1116 if (!subtable.ReadU16(&offset)) {
1117 return OTS_FAILURE_MSG("Failed to read lookahead offset %d in chain context format 3", i);
1119 offsets_lookahead.push_back(offset);
1121 if (offsets_lookahead.size() != lookahead_count) {
1122 return OTS_FAILURE_MSG("Bad lookahead offsets size %ld in chain context format 3", offsets_lookahead.size());
1125 uint16_t lookup_count = 0;
1126 if (!subtable.ReadU16(&lookup_count)) {
1127 return OTS_FAILURE_MSG("Failed to read lookup count in chain context format 3");
1129 for (unsigned i = 0; i < lookup_count; ++i) {
1130 if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
1131 return OTS_FAILURE_MSG("Failed to parse lookup %d in chain context format 3", i);
1135 const unsigned lookup_record_end =
1136 2 * (static_cast<unsigned>(backtrack_count) +
1137 static_cast<unsigned>(input_count) +
1138 static_cast<unsigned>(lookahead_count)) +
1139 4 * static_cast<unsigned>(lookup_count) + 10;
1140 if (lookup_record_end > std::numeric_limits<uint16_t>::max()) {
1141 return OTS_FAILURE_MSG("Bad end of lookup record %d in chain context format 3", lookup_record_end);
1143 for (unsigned i = 0; i < backtrack_count; ++i) {
1144 if (offsets_backtrack[i] < lookup_record_end ||
1145 offsets_backtrack[i] >= length) {
1146 return OTS_FAILURE_MSG("Bad backtrack offset of %d for backtrack %d in chain context format 3", offsets_backtrack[i], i);
1148 if (!ots::ParseCoverageTable(file, data + offsets_backtrack[i],
1149 length - offsets_backtrack[i], num_glyphs)) {
1150 return OTS_FAILURE_MSG("Failed to parse backtrack coverage %d in chain context format 3", i);
1153 for (unsigned i = 0; i < input_count; ++i) {
1154 if (offsets_input[i] < lookup_record_end || offsets_input[i] >= length) {
1155 return OTS_FAILURE_MSG("Bad input offset %d for input %d in chain context format 3", offsets_input[i], i);
1157 if (!ots::ParseCoverageTable(file, data + offsets_input[i],
1158 length - offsets_input[i], num_glyphs)) {
1159 return OTS_FAILURE_MSG("Failed to parse input coverage table %d in chain context format 3", i);
1162 for (unsigned i = 0; i < lookahead_count; ++i) {
1163 if (offsets_lookahead[i] < lookup_record_end ||
1164 offsets_lookahead[i] >= length) {
1165 return OTS_FAILURE_MSG("Bad lookadhead offset %d for lookahead %d in chain context format 3", offsets_lookahead[i], i);
1167 if (!ots::ParseCoverageTable(file, data + offsets_lookahead[i],
1168 length - offsets_lookahead[i], num_glyphs)) {
1169 return OTS_FAILURE_MSG("Failed to parse lookahead coverage table %d in chain context format 3", i);
1173 return true;
1176 } // namespace
1178 namespace ots {
1180 bool LookupSubtableParser::Parse(const OpenTypeFile *file, const uint8_t *data,
1181 const size_t length,
1182 const uint16_t lookup_type) const {
1183 for (unsigned i = 0; i < num_types; ++i) {
1184 if (parsers[i].type == lookup_type && parsers[i].parse) {
1185 if (!parsers[i].parse(file, data, length)) {
1186 return OTS_FAILURE_MSG("Failed to parse lookup subtable %d", i);
1188 return true;
1191 return OTS_FAILURE_MSG("No lookup subtables to parse");
1194 // Parsing ScriptListTable requires number of features so we need to
1195 // parse FeatureListTable before calling this function.
1196 bool ParseScriptListTable(const ots::OpenTypeFile *file,
1197 const uint8_t *data, const size_t length,
1198 const uint16_t num_features) {
1199 Buffer subtable(data, length);
1201 uint16_t script_count = 0;
1202 if (!subtable.ReadU16(&script_count)) {
1203 return OTS_FAILURE_MSG("Failed to read script count in script list table");
1206 const unsigned script_record_end =
1207 6 * static_cast<unsigned>(script_count) + 2;
1208 if (script_record_end > std::numeric_limits<uint16_t>::max()) {
1209 return OTS_FAILURE_MSG("Bad end of script record %d in script list table", script_record_end);
1211 std::vector<ScriptRecord> script_list;
1212 script_list.reserve(script_count);
1213 uint32_t last_tag = 0;
1214 for (unsigned i = 0; i < script_count; ++i) {
1215 ScriptRecord record;
1216 if (!subtable.ReadU32(&record.tag) ||
1217 !subtable.ReadU16(&record.offset)) {
1218 return OTS_FAILURE_MSG("Failed to read script record %d in script list table", i);
1220 // Script tags should be arranged alphabetically by tag
1221 if (last_tag != 0 && last_tag > record.tag) {
1222 // Several fonts don't arrange tags alphabetically.
1223 // It seems that the order of tags might not be a security issue
1224 // so we just warn it.
1225 OTS_WARNING("tags aren't arranged alphabetically.");
1227 last_tag = record.tag;
1228 if (record.offset < script_record_end || record.offset >= length) {
1229 return OTS_FAILURE_MSG("Bad record offset %d for script %4.4s entry %d in script list table", record.offset, (char *)&record.tag, i);
1231 script_list.push_back(record);
1233 if (script_list.size() != script_count) {
1234 return OTS_FAILURE_MSG("Bad script list size %ld in script list table", script_list.size());
1237 // Check script records.
1238 for (unsigned i = 0; i < script_count; ++i) {
1239 if (!ParseScriptTable(file, data + script_list[i].offset,
1240 length - script_list[i].offset,
1241 script_list[i].tag, num_features)) {
1242 return OTS_FAILURE_MSG("Failed to parse script table %d", i);
1246 return true;
1249 // Parsing FeatureListTable requires number of lookups so we need to parse
1250 // LookupListTable before calling this function.
1251 bool ParseFeatureListTable(const ots::OpenTypeFile *file,
1252 const uint8_t *data, const size_t length,
1253 const uint16_t num_lookups,
1254 uint16_t* num_features) {
1255 Buffer subtable(data, length);
1257 uint16_t feature_count = 0;
1258 if (!subtable.ReadU16(&feature_count)) {
1259 return OTS_FAILURE_MSG("Failed to read feature count");
1262 std::vector<FeatureRecord> feature_records;
1263 feature_records.resize(feature_count);
1264 const unsigned feature_record_end =
1265 6 * static_cast<unsigned>(feature_count) + 2;
1266 if (feature_record_end > std::numeric_limits<uint16_t>::max()) {
1267 return OTS_FAILURE_MSG("Bad end of feature record %d", feature_record_end);
1269 uint32_t last_tag = 0;
1270 for (unsigned i = 0; i < feature_count; ++i) {
1271 if (!subtable.ReadU32(&feature_records[i].tag) ||
1272 !subtable.ReadU16(&feature_records[i].offset)) {
1273 return OTS_FAILURE_MSG("Failed to read feature header %d", i);
1275 // Feature record array should be arranged alphabetically by tag
1276 if (last_tag != 0 && last_tag > feature_records[i].tag) {
1277 // Several fonts don't arrange tags alphabetically.
1278 // It seems that the order of tags might not be a security issue
1279 // so we just warn it.
1280 OTS_WARNING("tags aren't arranged alphabetically.");
1282 last_tag = feature_records[i].tag;
1283 if (feature_records[i].offset < feature_record_end ||
1284 feature_records[i].offset >= length) {
1285 return OTS_FAILURE_MSG("Bad feature offset %d for feature %d %4.4s", feature_records[i].offset, i, (char *)&feature_records[i].tag);
1289 for (unsigned i = 0; i < feature_count; ++i) {
1290 if (!ParseFeatureTable(file, data + feature_records[i].offset,
1291 length - feature_records[i].offset, num_lookups)) {
1292 return OTS_FAILURE_MSG("Failed to parse feature table %d", i);
1295 *num_features = feature_count;
1296 return true;
1299 // For parsing GPOS/GSUB tables, this function should be called at first to
1300 // obtain the number of lookups because parsing FeatureTableList requires
1301 // the number.
1302 bool ParseLookupListTable(OpenTypeFile *file, const uint8_t *data,
1303 const size_t length,
1304 const LookupSubtableParser* parser,
1305 uint16_t *num_lookups) {
1306 Buffer subtable(data, length);
1308 if (!subtable.ReadU16(num_lookups)) {
1309 return OTS_FAILURE_MSG("Failed to read number of lookups");
1312 std::vector<uint16_t> lookups;
1313 lookups.reserve(*num_lookups);
1314 const unsigned lookup_end =
1315 2 * static_cast<unsigned>(*num_lookups) + 2;
1316 if (lookup_end > std::numeric_limits<uint16_t>::max()) {
1317 return OTS_FAILURE_MSG("Bad end of lookups %d", lookup_end);
1319 for (unsigned i = 0; i < *num_lookups; ++i) {
1320 uint16_t offset = 0;
1321 if (!subtable.ReadU16(&offset)) {
1322 return OTS_FAILURE_MSG("Failed to read lookup offset %d", i);
1324 if (offset < lookup_end || offset >= length) {
1325 return OTS_FAILURE_MSG("Bad lookup offset %d for lookup %d", offset, i);
1327 lookups.push_back(offset);
1329 if (lookups.size() != *num_lookups) {
1330 return OTS_FAILURE_MSG("Bad lookup offsets list size %ld", lookups.size());
1333 for (unsigned i = 0; i < *num_lookups; ++i) {
1334 if (!ParseLookupTable(file, data + lookups[i], length - lookups[i],
1335 parser)) {
1336 return OTS_FAILURE_MSG("Failed to parse lookup %d", i);
1340 return true;
1343 bool ParseClassDefTable(const ots::OpenTypeFile *file,
1344 const uint8_t *data, size_t length,
1345 const uint16_t num_glyphs,
1346 const uint16_t num_classes) {
1347 Buffer subtable(data, length);
1349 uint16_t format = 0;
1350 if (!subtable.ReadU16(&format)) {
1351 return OTS_FAILURE_MSG("Failed to read class defn format");
1353 if (format == 1) {
1354 return ParseClassDefFormat1(file, data, length, num_glyphs, num_classes);
1355 } else if (format == 2) {
1356 return ParseClassDefFormat2(file, data, length, num_glyphs, num_classes);
1359 return OTS_FAILURE_MSG("Bad class defn format %d", format);
1362 bool ParseCoverageTable(const ots::OpenTypeFile *file,
1363 const uint8_t *data, size_t length,
1364 const uint16_t num_glyphs,
1365 const uint16_t expected_num_glyphs) {
1366 Buffer subtable(data, length);
1368 uint16_t format = 0;
1369 if (!subtable.ReadU16(&format)) {
1370 return OTS_FAILURE_MSG("Failed to read coverage table format");
1372 if (format == 1) {
1373 return ParseCoverageFormat1(file, data, length, num_glyphs, expected_num_glyphs);
1374 } else if (format == 2) {
1375 return ParseCoverageFormat2(file, data, length, num_glyphs, expected_num_glyphs);
1378 return OTS_FAILURE_MSG("Bad coverage table format %d", format);
1381 bool ParseDeviceTable(const ots::OpenTypeFile *file,
1382 const uint8_t *data, size_t length) {
1383 Buffer subtable(data, length);
1385 uint16_t start_size = 0;
1386 uint16_t end_size = 0;
1387 uint16_t delta_format = 0;
1388 if (!subtable.ReadU16(&start_size) ||
1389 !subtable.ReadU16(&end_size) ||
1390 !subtable.ReadU16(&delta_format)) {
1391 return OTS_FAILURE_MSG("Failed to read device table header");
1393 if (start_size > end_size) {
1394 return OTS_FAILURE_MSG("bad size range: %u > %u", start_size, end_size);
1396 if (delta_format == 0 || delta_format > kMaxDeltaFormatType) {
1397 return OTS_FAILURE_MSG("bad delta format: %u", delta_format);
1399 // The number of delta values per uint16. The device table should contain
1400 // at least |num_units| * 2 bytes compressed data.
1401 const unsigned num_units = (end_size - start_size) /
1402 (1 << (4 - delta_format)) + 1;
1403 // Just skip |num_units| * 2 bytes since the compressed data could take
1404 // arbitrary values.
1405 if (!subtable.Skip(num_units * 2)) {
1406 return OTS_FAILURE_MSG("Failed to skip data in device table");
1408 return true;
1411 bool ParseContextSubtable(const ots::OpenTypeFile *file,
1412 const uint8_t *data, const size_t length,
1413 const uint16_t num_glyphs,
1414 const uint16_t num_lookups) {
1415 Buffer subtable(data, length);
1417 uint16_t format = 0;
1418 if (!subtable.ReadU16(&format)) {
1419 return OTS_FAILURE_MSG("Failed to read context subtable format");
1422 if (format == 1) {
1423 if (!ParseContextFormat1(file, data, length, num_glyphs, num_lookups)) {
1424 return OTS_FAILURE_MSG("Failed to parse context format 1 subtable");
1426 } else if (format == 2) {
1427 if (!ParseContextFormat2(file, data, length, num_glyphs, num_lookups)) {
1428 return OTS_FAILURE_MSG("Failed to parse context format 2 subtable");
1430 } else if (format == 3) {
1431 if (!ParseContextFormat3(file, data, length, num_glyphs, num_lookups)) {
1432 return OTS_FAILURE_MSG("Failed to parse context format 3 subtable");
1434 } else {
1435 return OTS_FAILURE_MSG("Bad context subtable format %d", format);
1438 return true;
1441 bool ParseChainingContextSubtable(const ots::OpenTypeFile *file,
1442 const uint8_t *data, const size_t length,
1443 const uint16_t num_glyphs,
1444 const uint16_t num_lookups) {
1445 Buffer subtable(data, length);
1447 uint16_t format = 0;
1448 if (!subtable.ReadU16(&format)) {
1449 return OTS_FAILURE_MSG("Failed to read chaining context subtable format");
1452 if (format == 1) {
1453 if (!ParseChainContextFormat1(file, data, length, num_glyphs, num_lookups)) {
1454 return OTS_FAILURE_MSG("Failed to parse chaining context format 1 subtable");
1456 } else if (format == 2) {
1457 if (!ParseChainContextFormat2(file, data, length, num_glyphs, num_lookups)) {
1458 return OTS_FAILURE_MSG("Failed to parse chaining context format 2 subtable");
1460 } else if (format == 3) {
1461 if (!ParseChainContextFormat3(file, data, length, num_glyphs, num_lookups)) {
1462 return OTS_FAILURE_MSG("Failed to parse chaining context format 3 subtable");
1464 } else {
1465 return OTS_FAILURE_MSG("Bad chaining context subtable format %d", format);
1468 return true;
1471 bool ParseExtensionSubtable(const OpenTypeFile *file,
1472 const uint8_t *data, const size_t length,
1473 const LookupSubtableParser* parser) {
1474 Buffer subtable(data, length);
1476 uint16_t format = 0;
1477 uint16_t lookup_type = 0;
1478 uint32_t offset_extension = 0;
1479 if (!subtable.ReadU16(&format) ||
1480 !subtable.ReadU16(&lookup_type) ||
1481 !subtable.ReadU32(&offset_extension)) {
1482 return OTS_FAILURE_MSG("Failed to read extension table header");
1485 if (format != 1) {
1486 return OTS_FAILURE_MSG("Bad extension table format %d", format);
1488 // |lookup_type| should be other than |parser->extension_type|.
1489 if (lookup_type < 1 || lookup_type > parser->num_types ||
1490 lookup_type == parser->extension_type) {
1491 return OTS_FAILURE_MSG("Bad lookup type %d in extension table", lookup_type);
1494 const unsigned format_end = static_cast<unsigned>(8);
1495 if (offset_extension < format_end ||
1496 offset_extension >= length) {
1497 return OTS_FAILURE_MSG("Bad extension offset %d", offset_extension);
1500 // Parse the extension subtable of |lookup_type|.
1501 if (!parser->Parse(file, data + offset_extension, length - offset_extension,
1502 lookup_type)) {
1503 return OTS_FAILURE_MSG("Failed to parse lookup from extension lookup");
1506 return true;
1509 } // namespace ots
1511 #undef TABLE_NAME