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