Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(48)

Side by Side Diff: third_party/ots/src/layout.cc

Issue 775893002: Updating OTS repo from https://github.com/khaledhosny/ots.git (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Updating with 4800 warning fix Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/ots/src/layout.h ('k') | third_party/ots/src/loca.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "layout.h"
6
7 #include <limits>
8 #include <vector>
9
10 #include "gdef.h"
11
12 // OpenType Layout Common Table Formats
13 // http://www.microsoft.com/typography/otspec/chapter2.htm
14
15 #define TABLE_NAME "Layout" // XXX: use individual table names
16
17 namespace {
18
19 // The 'DFLT' tag of script table.
20 const uint32_t kScriptTableTagDflt = 0x44464c54;
21 // The value which represents there is no required feature index.
22 const uint16_t kNoRequiredFeatureIndexDefined = 0xFFFF;
23 // The lookup flag bit which indicates existence of MarkFilteringSet.
24 const uint16_t kUseMarkFilteringSetBit = 0x0010;
25 // The lookup flags which require GDEF table.
26 const uint16_t kGdefRequiredFlags = 0x0002 | 0x0004 | 0x0008;
27 // The mask for MarkAttachmentType.
28 const uint16_t kMarkAttachmentTypeMask = 0xFF00;
29 // The maximum type number of format for device tables.
30 const uint16_t kMaxDeltaFormatType = 3;
31 // The maximum number of class value.
32 const uint16_t kMaxClassDefValue = 0xFFFF;
33
34 struct ScriptRecord {
35 uint32_t tag;
36 uint16_t offset;
37 };
38
39 struct LangSysRecord {
40 uint32_t tag;
41 uint16_t offset;
42 };
43
44 struct FeatureRecord {
45 uint32_t tag;
46 uint16_t offset;
47 };
48
49 bool ParseLangSysTable(const ots::OpenTypeFile *file,
50 ots::Buffer *subtable, const uint32_t tag,
51 const uint16_t num_features) {
52 uint16_t offset_lookup_order = 0;
53 uint16_t req_feature_index = 0;
54 uint16_t feature_count = 0;
55 if (!subtable->ReadU16(&offset_lookup_order) ||
56 !subtable->ReadU16(&req_feature_index) ||
57 !subtable->ReadU16(&feature_count)) {
58 return OTS_FAILURE_MSG("Failed to read langsys header for tag %4.4s", (char *)&tag);
59 }
60 // |offset_lookup_order| is reserved and should be NULL.
61 if (offset_lookup_order != 0) {
62 return OTS_FAILURE_MSG("Bad lookup offset order %d for langsys tag %4.4s", o ffset_lookup_order, (char *)&tag);
63 }
64 if (req_feature_index != kNoRequiredFeatureIndexDefined &&
65 req_feature_index >= num_features) {
66 return OTS_FAILURE_MSG("Bad required features index %d for langsys tag %4.4s ", req_feature_index, (char *)&tag);
67 }
68 if (feature_count > num_features) {
69 return OTS_FAILURE_MSG("Bad feature count %d for langsys tag %4.4s", feature _count, (char *)&tag);
70 }
71
72 for (unsigned i = 0; i < feature_count; ++i) {
73 uint16_t feature_index = 0;
74 if (!subtable->ReadU16(&feature_index)) {
75 return OTS_FAILURE_MSG("Failed to read feature index %d for langsys tag %4 .4s", i, (char *)&tag);
76 }
77 if (feature_index >= num_features) {
78 return OTS_FAILURE_MSG("Bad feature index %d for feature %d for langsys ta g %4.4s", feature_index, i, (char *)&tag);
79 }
80 }
81 return true;
82 }
83
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);
88
89 uint16_t offset_default_lang_sys = 0;
90 uint16_t lang_sys_count = 0;
91 if (!subtable.ReadU16(&offset_default_lang_sys) ||
92 !subtable.ReadU16(&lang_sys_count)) {
93 return OTS_FAILURE_MSG("Failed to read script header for script tag %4.4s", (char *)&tag);
94 }
95
96 // The spec requires a script table for 'DFLT' tag must contain non-NULL
97 // |offset_default_lang_sys| and |lang_sys_count| == 0
98 if (tag == kScriptTableTagDflt &&
99 (offset_default_lang_sys == 0 || lang_sys_count != 0)) {
100 return OTS_FAILURE_MSG("DFLT table doesn't satisfy the spec. for script tag %4.4s", (char *)&tag);
101 }
102
103 const unsigned lang_sys_record_end =
104 6 * static_cast<unsigned>(lang_sys_count) + 4;
105 if (lang_sys_record_end > std::numeric_limits<uint16_t>::max()) {
106 return OTS_FAILURE_MSG("Bad end of langsys record %d for script tag %4.4s", lang_sys_record_end, (char *)&tag);
107 }
108
109 std::vector<LangSysRecord> lang_sys_records;
110 lang_sys_records.resize(lang_sys_count);
111 uint32_t last_tag = 0;
112 for (unsigned i = 0; i < lang_sys_count; ++i) {
113 if (!subtable.ReadU32(&lang_sys_records[i].tag) ||
114 !subtable.ReadU16(&lang_sys_records[i].offset)) {
115 return OTS_FAILURE_MSG("Failed to read langsys record header %d for script tag %4.4s", i, (char *)&tag);
116 }
117 // The record array must store the records alphabetically by tag
118 if (last_tag != 0 && last_tag > lang_sys_records[i].tag) {
119 return OTS_FAILURE_MSG("Bad last tag %d for langsys record %d for script t ag %4.4s", last_tag, i, (char *)&tag);
120 }
121 if (lang_sys_records[i].offset < lang_sys_record_end ||
122 lang_sys_records[i].offset >= length) {
123 return OTS_FAILURE_MSG("bad offset to lang sys table: %x",
124 lang_sys_records[i].offset);
125 }
126 last_tag = lang_sys_records[i].tag;
127 }
128
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_feature s)) {
133 return OTS_FAILURE_MSG("Failed to parse langsys table %d (%4.4s) for scrip t tag %4.4s", i, (char *)&lang_sys_records[i].tag, (char *)&tag);
134 }
135 }
136
137 return true;
138 }
139
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);
144
145 uint16_t offset_feature_params = 0;
146 uint16_t lookup_count = 0;
147 if (!subtable.ReadU16(&offset_feature_params) ||
148 !subtable.ReadU16(&lookup_count)) {
149 return OTS_FAILURE_MSG("Failed to read feature table header");
150 }
151
152 const unsigned feature_table_end =
153 2 * static_cast<unsigned>(lookup_count) + 4;
154 if (feature_table_end > std::numeric_limits<uint16_t>::max()) {
155 return OTS_FAILURE_MSG("Bad end of feature table %d", feature_table_end);
156 }
157 // |offset_feature_params| is generally set to NULL.
158 if (offset_feature_params != 0 &&
159 (offset_feature_params < feature_table_end ||
160 offset_feature_params >= length)) {
161 return OTS_FAILURE_MSG("Bad feature params offset %d", offset_feature_params );
162 }
163
164 for (unsigned i = 0; i < lookup_count; ++i) {
165 uint16_t lookup_index = 0;
166 if (!subtable.ReadU16(&lookup_index)) {
167 return OTS_FAILURE_MSG("Failed to read lookup index for lookup %d", i);
168 }
169 // lookup index starts with 0.
170 if (lookup_index >= num_lookups) {
171 return OTS_FAILURE_MSG("Bad lookup index %d for lookup %d", lookup_index, i);
172 }
173 }
174 return true;
175 }
176
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);
181
182 uint16_t lookup_type = 0;
183 uint16_t lookup_flag = 0;
184 uint16_t subtable_count = 0;
185 if (!subtable.ReadU16(&lookup_type) ||
186 !subtable.ReadU16(&lookup_flag) ||
187 !subtable.ReadU16(&subtable_count)) {
188 return OTS_FAILURE_MSG("Failed to read lookup table header");
189 }
190
191 if (lookup_type == 0 || lookup_type > parser->num_types) {
192 return OTS_FAILURE_MSG("Bad lookup type %d", lookup_type);
193 }
194
195 // Check lookup flags.
196 if ((lookup_flag & kGdefRequiredFlags) &&
197 (!file->gdef || !file->gdef->has_glyph_class_def)) {
198 return OTS_FAILURE_MSG("Bad lookup flags %d", lookup_flag);
199 }
200 if ((lookup_flag & kMarkAttachmentTypeMask) &&
201 (!file->gdef || !file->gdef->has_mark_attachment_class_def)) {
202 return OTS_FAILURE_MSG("lookup flag asks for mark attachment that is bad %d" , lookup_flag);
203 }
204 bool use_mark_filtering_set = false;
205 if (lookup_flag & kUseMarkFilteringSetBit) {
206 if (!file->gdef || !file->gdef->has_mark_glyph_sets_def) {
207 return OTS_FAILURE_MSG("lookup flag asks for mark filtering that is bad %d ", lookup_flag);
208 }
209 use_mark_filtering_set = true;
210 }
211
212 std::vector<uint16_t> subtables;
213 subtables.reserve(subtable_count);
214 // If the |kUseMarkFilteringSetBit| of |lookup_flag| is set,
215 // extra 2 bytes will follow after subtable offset array.
216 const unsigned lookup_table_end = 2 * static_cast<unsigned>(subtable_count) +
217 (use_mark_filtering_set ? 8 : 6);
218 if (lookup_table_end > std::numeric_limits<uint16_t>::max()) {
219 return OTS_FAILURE_MSG("Bad end of lookup %d", lookup_table_end);
220 }
221 for (unsigned i = 0; i < subtable_count; ++i) {
222 uint16_t offset_subtable = 0;
223 if (!subtable.ReadU16(&offset_subtable)) {
224 return OTS_FAILURE_MSG("Failed to read subtable offset %d", i);
225 }
226 if (offset_subtable < lookup_table_end ||
227 offset_subtable >= length) {
228 return OTS_FAILURE_MSG("Bad subtable offset %d for subtable %d", offset_su btable, i);
229 }
230 subtables.push_back(offset_subtable);
231 }
232 if (subtables.size() != subtable_count) {
233 return OTS_FAILURE_MSG("Bad subtable size %ld", subtables.size());
234 }
235
236 if (use_mark_filtering_set) {
237 uint16_t mark_filtering_set = 0;
238 if (!subtable.ReadU16(&mark_filtering_set)) {
239 return OTS_FAILURE_MSG("Failed to read mark filtering set");
240 }
241 if (file->gdef->num_mark_glyph_sets == 0 ||
242 mark_filtering_set >= file->gdef->num_mark_glyph_sets) {
243 return OTS_FAILURE_MSG("Bad mark filtering set %d", mark_filtering_set);
244 }
245 }
246
247 // Parse lookup subtables for this lookup type.
248 for (unsigned i = 0; i < subtable_count; ++i) {
249 if (!parser->Parse(file, data + subtables[i], length - subtables[i],
250 lookup_type)) {
251 return OTS_FAILURE_MSG("Failed to parse subtable %d", i);
252 }
253 }
254 return true;
255 }
256
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);
262
263 // Skip format field.
264 if (!subtable.Skip(2)) {
265 return OTS_FAILURE_MSG("Failed to skip class definition header");
266 }
267
268 uint16_t start_glyph = 0;
269 if (!subtable.ReadU16(&start_glyph)) {
270 return OTS_FAILURE_MSG("Failed to read starting glyph of class definition");
271 }
272 if (start_glyph > num_glyphs) {
273 return OTS_FAILURE_MSG("Bad starting glyph %d in class definition", start_gl yph);
274 }
275
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");
279 }
280 if (glyph_count > num_glyphs) {
281 return OTS_FAILURE_MSG("bad glyph count: %u", glyph_count);
282 }
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 d efinition", i);
287 }
288 if (class_value > num_classes) {
289 return OTS_FAILURE_MSG("Bad class value %d for glyph %d in class definitio n", class_value, i);
290 }
291 }
292
293 return true;
294 }
295
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);
301
302 // Skip format field.
303 if (!subtable.Skip(2)) {
304 return OTS_FAILURE_MSG("Failed to skip format of class defintion header");
305 }
306
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");
310 }
311 if (range_count > num_glyphs) {
312 return OTS_FAILURE_MSG("bad range count: %u", range_count);
313 }
314
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);
324 }
325 if (start > end || (last_end && start <= last_end)) {
326 return OTS_FAILURE_MSG("glyph range is overlapping.in range %d", i);
327 }
328 if (class_value > num_classes) {
329 return OTS_FAILURE_MSG("bad class value: %u", class_value);
330 }
331 last_end = end;
332 }
333
334 return true;
335 }
336
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);
342
343 // Skip format field.
344 if (!subtable.Skip(2)) {
345 return OTS_FAILURE_MSG("Failed to skip coverage format");
346 }
347
348 uint16_t glyph_count = 0;
349 if (!subtable.ReadU16(&glyph_count)) {
350 return OTS_FAILURE_MSG("Failed to read glyph count in coverage");
351 }
352 if (glyph_count > num_glyphs) {
353 return OTS_FAILURE_MSG("bad glyph count: %u", glyph_count);
354 }
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);
359 }
360 if (glyph > num_glyphs) {
361 return OTS_FAILURE_MSG("bad glyph ID: %u", glyph);
362 }
363 }
364
365 if (expected_num_glyphs && expected_num_glyphs != glyph_count) {
366 return OTS_FAILURE_MSG("unexpected number of glyphs: %u", glyph_count);
367 }
368
369 return true;
370 }
371
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);
377
378 // Skip format field.
379 if (!subtable.Skip(2)) {
380 return OTS_FAILURE_MSG("Failed to skip format of coverage type 2");
381 }
382
383 uint16_t range_count = 0;
384 if (!subtable.ReadU16(&range_count)) {
385 return OTS_FAILURE_MSG("Failed to read range count in coverage");
386 }
387 if (range_count > num_glyphs) {
388 return OTS_FAILURE_MSG("bad range count: %u", range_count);
389 }
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);
400 }
401
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.");
408 }
409 if (start_coverage_index != last_start_coverage_index) {
410 return OTS_FAILURE_MSG("bad start coverage index.");
411 }
412 last_end = end;
413 last_start_coverage_index += end - start + 1;
414 }
415
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_cover age_index);
419 }
420
421 return true;
422 }
423
424 // Parsers for Contextual subtables in GSUB/GPOS tables.
425
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");
434 }
435 if (sequence_index >= num_glyphs) {
436 return OTS_FAILURE_MSG("Bad sequence index %d in lookup record", sequence_in dex);
437 }
438 if (lookup_list_index >= num_lookups) {
439 return OTS_FAILURE_MSG("Bad lookup list index %d in lookup record", lookup_l ist_index);
440 }
441 return true;
442 }
443
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);
449
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");
455 }
456
457 if (glyph_count == 0 || glyph_count >= num_glyphs) {
458 return OTS_FAILURE_MSG("Bad glyph count %d in rule subtable", glyph_count);
459 }
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);
464 }
465 if (glyph_id > num_glyphs) {
466 return OTS_FAILURE_MSG("Bad glyph %d for entry %d", glyph_id, i);
467 }
468 }
469
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);
473 }
474 }
475 return true;
476 }
477
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);
483
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");
487 }
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);
491 }
492
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);
497 }
498 if (offset_rule < rule_end || offset_rule >= length) {
499 return OTS_FAILURE_MSG("Bad rule offset %d in set %d", offset_rule, i);
500 }
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);
504 }
505 }
506
507 return true;
508 }
509
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);
515
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");
523 }
524
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_se t_end);
529 }
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);
532 }
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") ;
536 }
537
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);
542 }
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);
545 }
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);
549 }
550 }
551
552 return true;
553 }
554
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);
560
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");
566 }
567
568 if (glyph_count == 0 || glyph_count >= num_glyphs) {
569 return OTS_FAILURE_MSG("Bad glyph count %d in class rule table", glyph_count );
570 }
571
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");
577 }
578
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 tab le", i);
582 }
583 }
584 return true;
585 }
586
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);
592
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") ;
596 }
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_rul e_end);
601 }
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 t able", i);
606 }
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_clas s_rule, i);
609 }
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);
614 }
615 }
616
617 return true;
618 }
619
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);
625
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");
635 }
636
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);
640 }
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);
643 }
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") ;
647 }
648
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);
651 }
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 fo rmat 2");
656 }
657
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 for mat 2", i);
662 }
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);
666 }
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);
671 }
672 }
673 }
674
675 return true;
676 }
677
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);
683
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");
691 }
692
693 if (glyph_count >= num_glyphs) {
694 return OTS_FAILURE_MSG("Bad glyph count %d in context format 3", glyph_count );
695 }
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_re cord_end);
700 }
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 form at 3", i);
705 }
706 if (offset_coverage < lookup_record_end || offset_coverage >= length) {
707 return OTS_FAILURE_MSG("Bad coverage offset %d for glyph %d in context for mat 3", offset_coverage, i);
708 }
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 con text format 3", i);
712 }
713 }
714
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);
718 }
719 }
720
721 return true;
722 }
723
724 // Parsers for Chaning Contextual subtables in GSUB/GPOS tables.
725
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);
731
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 subtabl e");
735 }
736 if (backtrack_count >= num_glyphs) {
737 return OTS_FAILURE_MSG("Bad backtrack count %d in chain rule subtable", back track_count);
738 }
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 su btable", i);
743 }
744 if (glyph_id > num_glyphs) {
745 return OTS_FAILURE_MSG("Bad glyph id %d for bactrack glyph %d in chain rul e subtable", glyph_id, i);
746 }
747 }
748
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");
752 }
753 if (input_count == 0 || input_count >= num_glyphs) {
754 return OTS_FAILURE_MSG("Bad input count %d in chain rule subtable", input_co unt);
755 }
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 subtab le", i);
760 }
761 if (glyph_id > num_glyphs) {
762 return OTS_FAILURE_MSG("Bad glyph id %d for input glyph %d in chain rule s ubtable", glyph_id, i);
763 }
764 }
765
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 subtabl e");
769 }
770 if (lookahead_count >= num_glyphs) {
771 return OTS_FAILURE_MSG("Bad lookahead count %d in chain rule subtable", look ahead_count);
772 }
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 su btable", i);
777 }
778 if (glyph_id > num_glyphs) {
779 return OTS_FAILURE_MSG("Bad glyph id %d for lookadhead glyph %d in chain r ule subtable", glyph_id, i);
780 }
781 }
782
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") ;
786 }
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 sub table", i);
790 }
791 }
792
793 return true;
794 }
795
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);
801
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");
805 }
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_r ule_end);
810 }
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);
815 }
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 chai n rule set", offset_chain_rule, i);
818 }
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);
823 }
824 }
825
826 return true;
827 }
828
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);
834
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");
842 }
843
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", ch ain_rule_set_end);
848 }
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", c hain_rule_set_end);
851 }
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 for mat 1");
855 }
856
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 conte xt format 1", i);
861 }
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);
865 }
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);
870 }
871 }
872
873 return true;
874 }
875
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);
881
882 // In this subtable, we don't check the value of classes for now since
883 // these could take arbitrary values.
884
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 s ubtable");
888 }
889 if (backtrack_count >= num_glyphs) {
890 return OTS_FAILURE_MSG("Bad backtrack count %d in chain class rule subtable" , backtrack_count);
891 }
892 if (!subtable.Skip(2 * backtrack_count)) {
893 return OTS_FAILURE_MSG("Failed to skip backtrack offsets in chain class rule subtable");
894 }
895
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 subta ble");
899 }
900 if (input_count == 0 || input_count >= num_glyphs) {
901 return OTS_FAILURE_MSG("Bad input count %d in chain class rule subtable", in put_count);
902 }
903 if (!subtable.Skip(2 * (input_count - 1))) {
904 return OTS_FAILURE_MSG("Failed to skip input offsets in chain class rule sub table");
905 }
906
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 s ubtable");
910 }
911 if (lookahead_count >= num_glyphs) {
912 return OTS_FAILURE_MSG("Bad lookahead count %d in chain class rule subtable" , lookahead_count);
913 }
914 if (!subtable.Skip(2 * lookahead_count)) {
915 return OTS_FAILURE_MSG("Failed to skip lookahead offsets in chain class rule subtable");
916 }
917
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 subt able");
921 }
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 ru le subtable", i);
925 }
926 }
927
928 return true;
929 }
930
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);
936
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");
940 }
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", c hain_class_rule_end);
945 }
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);
950 }
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);
954 }
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);
959 }
960 }
961
962 return true;
963 }
964
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);
970
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");
984 }
985
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);
990 }
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", o ffset_coverage);
993 }
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 form at 2");
997 }
998
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 for mat 2", offset_backtrack_class_def);
1004 }
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 chai n context format 2");
1009 }
1010 }
1011
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 form at 2", offset_input_class_def);
1015 }
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 fo rmat 2");
1020 }
1021
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 contex t format 2", offset_lookahead_class_def);
1026 }
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 cont ext format 2");
1031 }
1032 }
1033
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);
1038 }
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 i n chain context format 2", offset_chain_class_set, i);
1044 }
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 chai n context format 2", i);
1049 }
1050 }
1051 }
1052
1053 return true;
1054 }
1055
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);
1061
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 form at 3");
1067 }
1068
1069 if (backtrack_count >= num_glyphs) {
1070 return OTS_FAILURE_MSG("Bad backtrack count %d in chain context format 3", b acktrack_count);
1071 }
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 contex t format 3", i);
1078 }
1079 offsets_backtrack.push_back(offset);
1080 }
1081 if (offsets_backtrack.size() != backtrack_count) {
1082 return OTS_FAILURE_MSG("Bad backtrack offsets size %ld in chain context form at 3", offsets_backtrack.size());
1083 }
1084
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 ");
1088 }
1089 if (input_count >= num_glyphs) {
1090 return OTS_FAILURE_MSG("Bad input count %d in chain context format 3", input _count);
1091 }
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 fo rmat 3", i);
1098 }
1099 offsets_input.push_back(offset);
1100 }
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());
1103 }
1104
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 form at 3");
1108 }
1109 if (lookahead_count >= num_glyphs) {
1110 return OTS_FAILURE_MSG("Bad lookahead count %d in chain context format 3", l ookahead_count);
1111 }
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 contex t format 3", i);
1118 }
1119 offsets_lookahead.push_back(offset);
1120 }
1121 if (offsets_lookahead.size() != lookahead_count) {
1122 return OTS_FAILURE_MSG("Bad lookahead offsets size %ld in chain context form at 3", offsets_lookahead.size());
1123 }
1124
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");
1128 }
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);
1132 }
1133 }
1134
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);
1142 }
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 cha in context format 3", offsets_backtrack[i], i);
1147 }
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 con text format 3", i);
1151 }
1152 }
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);
1156 }
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 c ontext format 3", i);
1160 }
1161 }
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);
1166 }
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 cha in context format 3", i);
1170 }
1171 }
1172
1173 return true;
1174 }
1175
1176 } // namespace
1177
1178 namespace ots {
1179
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);
1187 }
1188 return true;
1189 }
1190 }
1191 return OTS_FAILURE_MSG("No lookup subtables to parse");
1192 }
1193
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);
1200
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");
1204 }
1205
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", s cript_record_end);
1210 }
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 tab le", i);
1219 }
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.");
1226 }
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);
1230 }
1231 script_list.push_back(record);
1232 }
1233 if (script_list.size() != script_count) {
1234 return OTS_FAILURE_MSG("Bad script list size %ld in script list table", scri pt_list.size());
1235 }
1236
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);
1243 }
1244 }
1245
1246 return true;
1247 }
1248
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);
1256
1257 uint16_t feature_count = 0;
1258 if (!subtable.ReadU16(&feature_count)) {
1259 return OTS_FAILURE_MSG("Failed to read feature count");
1260 }
1261
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);
1268 }
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);
1274 }
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.");
1281 }
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", featu re_records[i].offset, i, (char *)&feature_records[i].tag);
1286 }
1287 }
1288
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);
1293 }
1294 }
1295 *num_features = feature_count;
1296 return true;
1297 }
1298
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);
1307
1308 if (!subtable.ReadU16(num_lookups)) {
1309 return OTS_FAILURE_MSG("Failed to read number of lookups");
1310 }
1311
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);
1318 }
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);
1323 }
1324 if (offset < lookup_end || offset >= length) {
1325 return OTS_FAILURE_MSG("Bad lookup offset %d for lookup %d", offset, i);
1326 }
1327 lookups.push_back(offset);
1328 }
1329 if (lookups.size() != *num_lookups) {
1330 return OTS_FAILURE_MSG("Bad lookup offsets list size %ld", lookups.size());
1331 }
1332
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);
1337 }
1338 }
1339
1340 return true;
1341 }
1342
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);
1348
1349 uint16_t format = 0;
1350 if (!subtable.ReadU16(&format)) {
1351 return OTS_FAILURE_MSG("Failed to read class defn format");
1352 }
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);
1357 }
1358
1359 return OTS_FAILURE_MSG("Bad class defn format %d", format);
1360 }
1361
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);
1367
1368 uint16_t format = 0;
1369 if (!subtable.ReadU16(&format)) {
1370 return OTS_FAILURE_MSG("Failed to read coverage table format");
1371 }
1372 if (format == 1) {
1373 return ParseCoverageFormat1(file, data, length, num_glyphs, expected_num_gly phs);
1374 } else if (format == 2) {
1375 return ParseCoverageFormat2(file, data, length, num_glyphs, expected_num_gly phs);
1376 }
1377
1378 return OTS_FAILURE_MSG("Bad coverage table format %d", format);
1379 }
1380
1381 bool ParseDeviceTable(const ots::OpenTypeFile *file,
1382 const uint8_t *data, size_t length) {
1383 Buffer subtable(data, length);
1384
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");
1392 }
1393 if (start_size > end_size) {
1394 return OTS_FAILURE_MSG("bad size range: %u > %u", start_size, end_size);
1395 }
1396 if (delta_format == 0 || delta_format > kMaxDeltaFormatType) {
1397 return OTS_FAILURE_MSG("bad delta format: %u", delta_format);
1398 }
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");
1407 }
1408 return true;
1409 }
1410
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);
1416
1417 uint16_t format = 0;
1418 if (!subtable.ReadU16(&format)) {
1419 return OTS_FAILURE_MSG("Failed to read context subtable format");
1420 }
1421
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");
1425 }
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");
1429 }
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");
1433 }
1434 } else {
1435 return OTS_FAILURE_MSG("Bad context subtable format %d", format);
1436 }
1437
1438 return true;
1439 }
1440
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);
1446
1447 uint16_t format = 0;
1448 if (!subtable.ReadU16(&format)) {
1449 return OTS_FAILURE_MSG("Failed to read chaining context subtable format");
1450 }
1451
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 ");
1455 }
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 ");
1459 }
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 ");
1463 }
1464 } else {
1465 return OTS_FAILURE_MSG("Bad chaining context subtable format %d", format);
1466 }
1467
1468 return true;
1469 }
1470
1471 bool ParseExtensionSubtable(const OpenTypeFile *file,
1472 const uint8_t *data, const size_t length,
1473 const LookupSubtableParser* parser) {
1474 Buffer subtable(data, length);
1475
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");
1483 }
1484
1485 if (format != 1) {
1486 return OTS_FAILURE_MSG("Bad extension table format %d", format);
1487 }
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) ;
1492 }
1493
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);
1498 }
1499
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");
1504 }
1505
1506 return true;
1507 }
1508
1509 } // namespace ots
1510
1511 #undef TABLE_NAME
OLDNEW
« no previous file with comments | « third_party/ots/src/layout.h ('k') | third_party/ots/src/loca.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698