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.
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
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;
39 struct LangSysRecord
{
44 struct FeatureRecord
{
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
);
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
);
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
);
177 bool ParseLookupTable(ots::OpenTypeFile
*file
, const uint8_t *data
,
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
],
251 return OTS_FAILURE_MSG("Failed to parse subtable %d", i
);
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
);
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
) {
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
);
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
) {
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
);
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
) {
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.");
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
);
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
);
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
);
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
);
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) +
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
);
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
);
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
,
613 return OTS_FAILURE_MSG("Failed to parse class rule table %d", i
);
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
,
670 return OTS_FAILURE_MSG("Failed to parse class set %d in context format 2", i
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
;
1299 // For parsing GPOS/GSUB tables, this function should be called at first to
1300 // obtain the number of lookups because parsing FeatureTableList requires
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
],
1336 return OTS_FAILURE_MSG("Failed to parse lookup %d", i
);
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");
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");
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");
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");
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");
1435 return OTS_FAILURE_MSG("Bad context subtable format %d", format
);
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");
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");
1465 return OTS_FAILURE_MSG("Bad chaining context subtable format %d", format
);
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");
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
,
1503 return OTS_FAILURE_MSG("Failed to parse lookup from extension lookup");