blob: 0482a27b854d33e2bd3f0a771a331c5a94b129ab [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;
bashi@chromium.orgdf5b76f2011-03-22 19:02:34 +000023// The lookup flags which require GDEF table.
24const uint16_t kGdefRequiredFlags = 0x0002 | 0x0004 | 0x0008;
bashi@google.com78a8baa2011-02-07 06:21:25 +000025// The mask for MarkAttachmentType.
26const uint16_t kMarkAttachmentTypeMask = 0xFF00;
27// The maximum type number of format for device tables.
28const uint16_t kMaxDeltaFormatType = 3;
bashi@chromium.orgced71122011-02-17 10:23:47 +000029// The maximum number of class value.
30const uint16_t kMaxClassDefValue = 0xFFFF;
bashi@google.com78a8baa2011-02-07 06:21:25 +000031
32struct ScriptRecord {
33 uint32_t tag;
34 uint16_t offset;
35};
36
37struct LangSysRecord {
38 uint32_t tag;
39 uint16_t offset;
40};
41
42struct FeatureRecord {
43 uint32_t tag;
44 uint16_t offset;
45};
46
47bool ParseLangSysTable(ots::Buffer *subtable, const uint32_t tag,
48 const uint16_t num_features) {
49 uint16_t offset_lookup_order = 0;
50 uint16_t req_feature_index = 0;
51 uint16_t feature_count = 0;
52 if (!subtable->ReadU16(&offset_lookup_order) ||
53 !subtable->ReadU16(&req_feature_index) ||
54 !subtable->ReadU16(&feature_count)) {
55 return OTS_FAILURE();
56 }
57 // |offset_lookup_order| is reserved and should be NULL.
58 if (offset_lookup_order != 0) {
59 return OTS_FAILURE();
60 }
61 if (req_feature_index != kNoRequiredFeatureIndexDefined &&
62 req_feature_index >= num_features) {
63 return OTS_FAILURE();
64 }
65 if (feature_count > num_features) {
66 return OTS_FAILURE();
67 }
68
69 for (unsigned i = 0; i < feature_count; ++i) {
70 uint16_t feature_index = 0;
71 if (!subtable->ReadU16(&feature_index)) {
72 return OTS_FAILURE();
73 }
74 if (feature_index >= num_features) {
75 return OTS_FAILURE();
76 }
77 }
78 return true;
79}
80
81bool ParseScriptTable(const uint8_t *data, const size_t length,
82 const uint32_t tag, const uint16_t num_features) {
83 ots::Buffer subtable(data, length);
84
85 uint16_t offset_default_lang_sys = 0;
86 uint16_t lang_sys_count = 0;
87 if (!subtable.ReadU16(&offset_default_lang_sys) ||
88 !subtable.ReadU16(&lang_sys_count)) {
89 return OTS_FAILURE();
90 }
91
92 // The spec requires a script table for 'DFLT' tag must contain non-NULL
93 // |offset_default_lang_sys| and |lang_sys_count| == 0
94 if (tag == kScriptTableTagDflt &&
95 (offset_default_lang_sys == 0 || lang_sys_count != 0)) {
96 OTS_WARNING("DFLT table doesn't satisfy the spec.");
97 return OTS_FAILURE();
98 }
99
bashi@chromium.org26afae82011-08-25 05:38:57 +0000100 const unsigned lang_sys_record_end =
101 6 * static_cast<unsigned>(lang_sys_count) + 4;
bashi@google.com78a8baa2011-02-07 06:21:25 +0000102 if (lang_sys_record_end > std::numeric_limits<uint16_t>::max()) {
103 return OTS_FAILURE();
104 }
105
106 std::vector<LangSysRecord> lang_sys_records;
107 lang_sys_records.resize(lang_sys_count);
108 uint32_t last_tag = 0;
109 for (unsigned i = 0; i < lang_sys_count; ++i) {
110 if (!subtable.ReadU32(&lang_sys_records[i].tag) ||
111 !subtable.ReadU16(&lang_sys_records[i].offset)) {
112 return OTS_FAILURE();
113 }
114 // The record array must store the records alphabetically by tag
115 if (last_tag != 0 && last_tag > lang_sys_records[i].tag) {
116 return OTS_FAILURE();
117 }
118 if (lang_sys_records[i].offset < lang_sys_record_end ||
119 lang_sys_records[i].offset >= length) {
bashi@chromium.orga5748662011-03-18 17:48:29 +0000120 OTS_WARNING("bad offset to lang sys table: %x",
121 lang_sys_records[i].offset);
bashi@google.com78a8baa2011-02-07 06:21:25 +0000122 return OTS_FAILURE();
123 }
124 last_tag = lang_sys_records[i].tag;
125 }
126
127 // Check lang sys tables
128 for (unsigned i = 0; i < lang_sys_count; ++i) {
129 subtable.set_offset(lang_sys_records[i].offset);
130 if (!ParseLangSysTable(&subtable, lang_sys_records[i].tag, num_features)) {
131 return OTS_FAILURE();
132 }
133 }
134
135 return true;
136}
137
138bool ParseFeatureTable(const uint8_t *data, const size_t length,
139 const uint16_t num_lookups) {
140 ots::Buffer subtable(data, length);
141
142 uint16_t offset_feature_params = 0;
143 uint16_t lookup_count = 0;
144 if (!subtable.ReadU16(&offset_feature_params) ||
145 !subtable.ReadU16(&lookup_count)) {
146 return OTS_FAILURE();
147 }
148
bashi@chromium.org26afae82011-08-25 05:38:57 +0000149 const unsigned feature_table_end =
bashi@chromium.org58b44a42011-11-30 01:59:49 +0000150 2 * static_cast<unsigned>(lookup_count) + 4;
bashi@google.com78a8baa2011-02-07 06:21:25 +0000151 if (feature_table_end > std::numeric_limits<uint16_t>::max()) {
152 return OTS_FAILURE();
153 }
154 // |offset_feature_params| is generally set to NULL.
155 if (offset_feature_params != 0 &&
156 (offset_feature_params < feature_table_end ||
157 offset_feature_params >= length)) {
158 return OTS_FAILURE();
159 }
160
161 for (unsigned i = 0; i < lookup_count; ++i) {
162 uint16_t lookup_index = 0;
163 if (!subtable.ReadU16(&lookup_index)) {
164 return OTS_FAILURE();
165 }
166 // lookup index starts with 0.
167 if (lookup_index >= num_lookups) {
168 return OTS_FAILURE();
169 }
170 }
171 return true;
172}
173
bashi@google.com78a8baa2011-02-07 06:21:25 +0000174bool ParseLookupTable(ots::OpenTypeFile *file, const uint8_t *data,
bashi@chromium.orgced71122011-02-17 10:23:47 +0000175 const size_t length,
176 const ots::LookupSubtableParser* parser) {
bashi@google.com78a8baa2011-02-07 06:21:25 +0000177 ots::Buffer subtable(data, length);
178
179 uint16_t lookup_type = 0;
180 uint16_t lookup_flag = 0;
181 uint16_t subtable_count = 0;
182 if (!subtable.ReadU16(&lookup_type) ||
183 !subtable.ReadU16(&lookup_flag) ||
184 !subtable.ReadU16(&subtable_count)) {
185 return OTS_FAILURE();
186 }
187
bashi@chromium.orgced71122011-02-17 10:23:47 +0000188 if (lookup_type == 0 || lookup_type > parser->num_types) {
bashi@google.com78a8baa2011-02-07 06:21:25 +0000189 return OTS_FAILURE();
190 }
191
192 // Check lookup flags.
bashi@chromium.orgdf5b76f2011-03-22 19:02:34 +0000193 if ((lookup_flag & kGdefRequiredFlags) &&
194 (!file->gdef || !file->gdef->has_glyph_class_def)) {
195 return OTS_FAILURE();
196 }
bashi@google.com78a8baa2011-02-07 06:21:25 +0000197 if ((lookup_flag & kMarkAttachmentTypeMask) &&
198 (!file->gdef || !file->gdef->has_mark_attachment_class_def)) {
199 return OTS_FAILURE();
200 }
201 bool use_mark_filtering_set = false;
202 if (lookup_flag & kUseMarkFilteringSetBit) {
203 if (!file->gdef || !file->gdef->has_mark_glyph_sets_def) {
204 return OTS_FAILURE();
205 }
206 use_mark_filtering_set = true;
207 }
208
209 std::vector<uint16_t> subtables;
210 subtables.reserve(subtable_count);
211 // If the |kUseMarkFilteringSetBit| of |lookup_flag| is set,
212 // extra 2 bytes will follow after subtable offset array.
bashi@chromium.org26afae82011-08-25 05:38:57 +0000213 const unsigned lookup_table_end = 2 * static_cast<unsigned>(subtable_count) +
214 (use_mark_filtering_set ? 8 : 6);
bashi@google.com78a8baa2011-02-07 06:21:25 +0000215 if (lookup_table_end > std::numeric_limits<uint16_t>::max()) {
216 return OTS_FAILURE();
217 }
218 for (unsigned i = 0; i < subtable_count; ++i) {
bashi@chromium.orge2b566a2011-02-23 00:22:24 +0000219 uint16_t offset_subtable = 0;
220 if (!subtable.ReadU16(&offset_subtable)) {
bashi@google.com78a8baa2011-02-07 06:21:25 +0000221 return OTS_FAILURE();
222 }
bashi@chromium.orge2b566a2011-02-23 00:22:24 +0000223 if (offset_subtable < lookup_table_end ||
224 offset_subtable >= length) {
bashi@google.com78a8baa2011-02-07 06:21:25 +0000225 return OTS_FAILURE();
226 }
bashi@chromium.orge2b566a2011-02-23 00:22:24 +0000227 subtables.push_back(offset_subtable);
bashi@google.com78a8baa2011-02-07 06:21:25 +0000228 }
bashi@chromium.org6b410202011-02-23 04:12:49 +0000229 if (subtables.size() != subtable_count) {
230 return OTS_FAILURE();
231 }
bashi@google.com78a8baa2011-02-07 06:21:25 +0000232
233 if (use_mark_filtering_set) {
234 uint16_t mark_filtering_set = 0;
235 if (!subtable.ReadU16(&mark_filtering_set)) {
236 return OTS_FAILURE();
237 }
238 if (file->gdef->num_mark_glyph_sets == 0 ||
239 mark_filtering_set >= file->gdef->num_mark_glyph_sets) {
240 return OTS_FAILURE();
241 }
242 }
243
244 // Parse lookup subtables for this lookup type.
245 for (unsigned i = 0; i < subtable_count; ++i) {
bashi@chromium.orgced71122011-02-17 10:23:47 +0000246 if (!parser->Parse(file, data + subtables[i], length - subtables[i],
247 lookup_type)) {
bashi@google.com78a8baa2011-02-07 06:21:25 +0000248 return OTS_FAILURE();
249 }
250 }
251 return true;
252}
253
bashi@google.com00b790a2011-01-27 06:35:42 +0000254bool ParseClassDefFormat1(const uint8_t *data, size_t length,
255 const uint16_t num_glyphs,
256 const uint16_t num_classes) {
257 ots::Buffer subtable(data, length);
258
259 // Skip format field.
260 if (!subtable.Skip(2)) {
261 return OTS_FAILURE();
262 }
263
264 uint16_t start_glyph = 0;
265 if (!subtable.ReadU16(&start_glyph)) {
266 return OTS_FAILURE();
267 }
268 if (start_glyph > num_glyphs) {
269 OTS_WARNING("bad start glyph ID: %u", start_glyph);
270 return OTS_FAILURE();
271 }
272
273 uint16_t glyph_count = 0;
274 if (!subtable.ReadU16(&glyph_count)) {
275 return OTS_FAILURE();
276 }
277 if (glyph_count > num_glyphs) {
278 OTS_WARNING("bad glyph count: %u", glyph_count);
279 return OTS_FAILURE();
280 }
281 for (unsigned i = 0; i < glyph_count; ++i) {
282 uint16_t class_value = 0;
283 if (!subtable.ReadU16(&class_value)) {
284 return OTS_FAILURE();
285 }
bashi@chromium.orgced71122011-02-17 10:23:47 +0000286 if (class_value > num_classes) {
bashi@google.com00b790a2011-01-27 06:35:42 +0000287 OTS_WARNING("bad class value: %u", class_value);
288 return OTS_FAILURE();
289 }
290 }
291
292 return true;
293}
294
295bool ParseClassDefFormat2(const uint8_t *data, size_t length,
296 const uint16_t num_glyphs,
297 const uint16_t num_classes) {
298 ots::Buffer subtable(data, length);
299
300 // Skip format field.
301 if (!subtable.Skip(2)) {
302 return OTS_FAILURE();
303 }
304
305 uint16_t range_count = 0;
306 if (!subtable.ReadU16(&range_count)) {
307 return OTS_FAILURE();
308 }
309 if (range_count > num_glyphs) {
310 OTS_WARNING("bad range count: %u", range_count);
311 return OTS_FAILURE();
312 }
313
314 uint16_t last_end = 0;
315 for (unsigned i = 0; i < range_count; ++i) {
316 uint16_t start = 0;
317 uint16_t end = 0;
318 uint16_t class_value = 0;
319 if (!subtable.ReadU16(&start) ||
320 !subtable.ReadU16(&end) ||
321 !subtable.ReadU16(&class_value)) {
322 return OTS_FAILURE();
323 }
324 if (start > end || (last_end && start <= last_end)) {
325 OTS_WARNING("glyph range is overlapping.");
326 return OTS_FAILURE();
327 }
bashi@chromium.orgced71122011-02-17 10:23:47 +0000328 if (class_value > num_classes) {
bashi@google.com00b790a2011-01-27 06:35:42 +0000329 OTS_WARNING("bad class value: %u", class_value);
330 return OTS_FAILURE();
331 }
bashi@google.com78a8baa2011-02-07 06:21:25 +0000332 last_end = end;
bashi@google.com00b790a2011-01-27 06:35:42 +0000333 }
334
335 return true;
336}
337
338bool ParseCoverageFormat1(const uint8_t *data, size_t length,
339 const uint16_t num_glyphs) {
340 ots::Buffer subtable(data, length);
341
342 // Skip format field.
343 if (!subtable.Skip(2)) {
344 return OTS_FAILURE();
345 }
346
347 uint16_t glyph_count = 0;
348 if (!subtable.ReadU16(&glyph_count)) {
349 return OTS_FAILURE();
350 }
351 if (glyph_count > num_glyphs) {
352 OTS_WARNING("bad glyph count: %u", glyph_count);
353 return OTS_FAILURE();
354 }
355 for (unsigned i = 0; i < glyph_count; ++i) {
356 uint16_t glyph = 0;
357 if (!subtable.ReadU16(&glyph)) {
358 return OTS_FAILURE();
359 }
360 if (glyph > num_glyphs) {
361 OTS_WARNING("bad glyph ID: %u", glyph);
362 return OTS_FAILURE();
363 }
364 }
365
366 return true;
367}
368
369bool ParseCoverageFormat2(const uint8_t *data, size_t length,
370 const uint16_t num_glyphs) {
371 ots::Buffer subtable(data, length);
372
373 // Skip format field.
374 if (!subtable.Skip(2)) {
375 return OTS_FAILURE();
376 }
377
378 uint16_t range_count = 0;
379 if (!subtable.ReadU16(&range_count)) {
380 return OTS_FAILURE();
381 }
bashi@google.com78a8baa2011-02-07 06:21:25 +0000382 if (range_count > num_glyphs) {
bashi@google.com00b790a2011-01-27 06:35:42 +0000383 OTS_WARNING("bad range count: %u", range_count);
384 return OTS_FAILURE();
385 }
386 uint16_t last_end = 0;
bashi@google.com78a8baa2011-02-07 06:21:25 +0000387 uint16_t last_start_coverage_index = 0;
bashi@google.com00b790a2011-01-27 06:35:42 +0000388 for (unsigned i = 0; i < range_count; ++i) {
389 uint16_t start = 0;
390 uint16_t end = 0;
391 uint16_t start_coverage_index = 0;
392 if (!subtable.ReadU16(&start) ||
393 !subtable.ReadU16(&end) ||
394 !subtable.ReadU16(&start_coverage_index)) {
395 return OTS_FAILURE();
396 }
397 if (start > end || (last_end && start <= last_end)) {
398 OTS_WARNING("glyph range is overlapping.");
399 return OTS_FAILURE();
400 }
bashi@google.com78a8baa2011-02-07 06:21:25 +0000401 if (start_coverage_index != last_start_coverage_index) {
402 OTS_WARNING("bad start coverage index.");
403 return OTS_FAILURE();
404 }
405 last_end = end;
406 last_start_coverage_index += end - start + 1;
bashi@google.com00b790a2011-01-27 06:35:42 +0000407 }
408
409 return true;
410}
411
bashi@chromium.orgced71122011-02-17 10:23:47 +0000412// Parsers for Contextual subtables in GSUB/GPOS tables.
413
414bool ParseLookupRecord(ots::Buffer *subtable, const uint16_t num_glyphs,
415 const uint16_t num_lookups) {
416 uint16_t sequence_index = 0;
417 uint16_t lookup_list_index = 0;
418 if (!subtable->ReadU16(&sequence_index) ||
419 !subtable->ReadU16(&lookup_list_index)) {
420 return OTS_FAILURE();
421 }
422 if (sequence_index >= num_glyphs) {
423 return OTS_FAILURE();
424 }
425 if (lookup_list_index >= num_lookups) {
426 return OTS_FAILURE();
427 }
428 return true;
429}
430
431bool ParseRuleSubtable(const uint8_t *data, const size_t length,
432 const uint16_t num_glyphs,
433 const uint16_t num_lookups) {
434 ots::Buffer subtable(data, length);
435
436 uint16_t glyph_count = 0;
437 uint16_t lookup_count = 0;
438 if (!subtable.ReadU16(&glyph_count) ||
439 !subtable.ReadU16(&lookup_count)) {
440 return OTS_FAILURE();
441 }
442
443 if (glyph_count == 0 || glyph_count >= num_glyphs) {
444 return OTS_FAILURE();
445 }
446 for (unsigned i = 0; i < glyph_count - static_cast<unsigned>(1); ++i) {
447 uint16_t glyph_id = 0;
448 if (!subtable.ReadU16(&glyph_id)) {
449 return OTS_FAILURE();
450 }
451 if (glyph_id > num_glyphs) {
452 return OTS_FAILURE();
453 }
454 }
455
456 for (unsigned i = 0; i < lookup_count; ++i) {
457 if (!ParseLookupRecord(&subtable, num_glyphs, num_lookups)) {
458 return OTS_FAILURE();
459 }
460 }
461 return true;
462}
463
464bool ParseRuleSetTable(const uint8_t *data, const size_t length,
465 const uint16_t num_glyphs,
466 const uint16_t num_lookups) {
467 ots::Buffer subtable(data, length);
468
469 uint16_t rule_count = 0;
470 if (!subtable.ReadU16(&rule_count)) {
471 return OTS_FAILURE();
472 }
bashi@chromium.org26afae82011-08-25 05:38:57 +0000473 const unsigned rule_end = 2 * static_cast<unsigned>(rule_count) + 2;
bashi@chromium.orgced71122011-02-17 10:23:47 +0000474 if (rule_end > std::numeric_limits<uint16_t>::max()) {
475 return OTS_FAILURE();
476 }
477
478 for (unsigned i = 0; i < rule_count; ++i) {
479 uint16_t offset_rule = 0;
480 if (!subtable.ReadU16(&offset_rule)) {
481 return OTS_FAILURE();
482 }
483 if (offset_rule < rule_end || offset_rule >= length) {
484 return OTS_FAILURE();
485 }
486 if (!ParseRuleSubtable(data + offset_rule, length - offset_rule,
487 num_glyphs, num_lookups)) {
488 return OTS_FAILURE();
489 }
490 }
491
492 return true;
493}
494
495bool ParseContextFormat1(const uint8_t *data, const size_t length,
496 const uint16_t num_glyphs,
497 const uint16_t num_lookups) {
498 ots::Buffer subtable(data, length);
499
500 uint16_t offset_coverage = 0;
501 uint16_t rule_set_count = 0;
502 // Skip format field.
503 if (!subtable.Skip(2) ||
504 !subtable.ReadU16(&offset_coverage) ||
505 !subtable.ReadU16(&rule_set_count)) {
506 return OTS_FAILURE();
507 }
508
509 const unsigned rule_set_end = static_cast<unsigned>(6) +
510 rule_set_count * 2;
511 if (rule_set_end > std::numeric_limits<uint16_t>::max()) {
512 return OTS_FAILURE();
513 }
514 if (offset_coverage < rule_set_end || offset_coverage >= length) {
515 return OTS_FAILURE();
516 }
517 if (!ots::ParseCoverageTable(data + offset_coverage,
518 length - offset_coverage, num_glyphs)) {
519 return OTS_FAILURE();
520 }
521
522 for (unsigned i = 0; i < rule_set_count; ++i) {
523 uint16_t offset_rule = 0;
524 if (!subtable.ReadU16(&offset_rule)) {
525 return OTS_FAILURE();
526 }
527 if (offset_rule < rule_set_end || offset_rule >= length) {
528 return OTS_FAILURE();
529 }
530 if (!ParseRuleSetTable(data + offset_rule, length - offset_rule,
531 num_glyphs, num_lookups)) {
532 return OTS_FAILURE();
533 }
534 }
535
536 return true;
537}
538
539bool ParseClassRuleTable(const uint8_t *data, const size_t length,
540 const uint16_t num_glyphs,
541 const uint16_t num_lookups) {
542 ots::Buffer subtable(data, length);
543
544 uint16_t glyph_count = 0;
545 uint16_t lookup_count = 0;
546 if (!subtable.ReadU16(&glyph_count) ||
547 !subtable.ReadU16(&lookup_count)) {
548 return OTS_FAILURE();
549 }
550
551 if (glyph_count == 0 || glyph_count >= num_glyphs) {
552 return OTS_FAILURE();
553 }
554
555 // ClassRule table contains an array of classes. Each value of classes
556 // could take arbitrary values including zero so we don't check these value.
557 const unsigned num_classes = glyph_count - static_cast<unsigned>(1);
558 if (!subtable.Skip(2 * num_classes)) {
559 return OTS_FAILURE();
560 }
561
562 for (unsigned i = 0; i < lookup_count; ++i) {
563 if (!ParseLookupRecord(&subtable, num_glyphs, num_lookups)) {
564 return OTS_FAILURE();
565 }
566 }
567 return true;
568}
569
570bool ParseClassSetTable(const uint8_t *data, const size_t length,
571 const uint16_t num_glyphs,
572 const uint16_t num_lookups) {
573 ots::Buffer subtable(data, length);
574
575 uint16_t class_rule_count = 0;
576 if (!subtable.ReadU16(&class_rule_count)) {
577 return OTS_FAILURE();
578 }
bashi@chromium.org26afae82011-08-25 05:38:57 +0000579 const unsigned class_rule_end =
580 2 * static_cast<unsigned>(class_rule_count) + 2;
bashi@chromium.orgced71122011-02-17 10:23:47 +0000581 if (class_rule_end > std::numeric_limits<uint16_t>::max()) {
582 return OTS_FAILURE();
583 }
584 for (unsigned i = 0; i < class_rule_count; ++i) {
585 uint16_t offset_class_rule = 0;
586 if (!subtable.ReadU16(&offset_class_rule)) {
587 return OTS_FAILURE();
588 }
589 if (offset_class_rule < class_rule_end || offset_class_rule >= length) {
590 return OTS_FAILURE();
591 }
592 if (!ParseClassRuleTable(data + offset_class_rule,
593 length - offset_class_rule, num_glyphs,
594 num_lookups)) {
595 return OTS_FAILURE();
596 }
597 }
598
599 return true;
600}
601
602bool ParseContextFormat2(const uint8_t *data, const size_t length,
603 const uint16_t num_glyphs,
604 const uint16_t num_lookups) {
605 ots::Buffer subtable(data, length);
606
607 uint16_t offset_coverage = 0;
608 uint16_t offset_class_def = 0;
609 uint16_t class_set_cnt = 0;
610 // Skip format field.
611 if (!subtable.Skip(2) ||
612 !subtable.ReadU16(&offset_coverage) ||
613 !subtable.ReadU16(&offset_class_def) ||
614 !subtable.ReadU16(&class_set_cnt)) {
615 return OTS_FAILURE();
616 }
617
bashi@chromium.org26afae82011-08-25 05:38:57 +0000618 const unsigned class_set_end = 2 * static_cast<unsigned>(class_set_cnt) + 8;
bashi@chromium.orgced71122011-02-17 10:23:47 +0000619 if (class_set_end > std::numeric_limits<uint16_t>::max()) {
620 return OTS_FAILURE();
621 }
622 if (offset_coverage < class_set_end || offset_coverage >= length) {
623 return OTS_FAILURE();
624 }
625 if (!ots::ParseCoverageTable(data + offset_coverage,
626 length - offset_coverage, num_glyphs)) {
627 return OTS_FAILURE();
628 }
629
630 if (offset_class_def < class_set_end || offset_class_def >= length) {
631 return OTS_FAILURE();
632 }
633 if (!ots::ParseClassDefTable(data + offset_class_def,
634 length - offset_class_def,
635 num_glyphs, kMaxClassDefValue)) {
636 return OTS_FAILURE();
637 }
638
639 for (unsigned i = 0; i < class_set_cnt; ++i) {
640 uint16_t offset_class_rule = 0;
641 if (!subtable.ReadU16(&offset_class_rule)) {
642 return OTS_FAILURE();
643 }
644 if (offset_class_rule) {
645 if (offset_class_rule < class_set_end || offset_class_rule >= length) {
646 return OTS_FAILURE();
647 }
648 if (!ParseClassSetTable(data + offset_class_rule,
649 length - offset_class_rule, num_glyphs,
650 num_lookups)) {
651 return OTS_FAILURE();
652 }
653 }
654 }
655
656 return true;
657}
658
659bool ParseContextFormat3(const uint8_t *data, const size_t length,
660 const uint16_t num_glyphs,
661 const uint16_t num_lookups) {
662 ots::Buffer subtable(data, length);
663
664 uint16_t glyph_count = 0;
665 uint16_t lookup_count = 0;
666 // Skip format field.
667 if (!subtable.Skip(2) ||
668 !subtable.ReadU16(&glyph_count) ||
669 !subtable.ReadU16(&lookup_count)) {
670 return OTS_FAILURE();
671 }
672
673 if (glyph_count >= num_glyphs) {
674 return OTS_FAILURE();
675 }
bashi@chromium.org26afae82011-08-25 05:38:57 +0000676 const unsigned lookup_record_end = 2 * static_cast<unsigned>(glyph_count) +
677 4 * static_cast<unsigned>(lookup_count) + 6;
bashi@chromium.orgced71122011-02-17 10:23:47 +0000678 if (lookup_record_end > std::numeric_limits<uint16_t>::max()) {
679 return OTS_FAILURE();
680 }
681 for (unsigned i = 0; i < glyph_count; ++i) {
682 uint16_t offset_coverage = 0;
683 if (!subtable.ReadU16(&offset_coverage)) {
684 return OTS_FAILURE();
685 }
686 if (offset_coverage < lookup_record_end || offset_coverage >= length) {
687 return OTS_FAILURE();
688 }
689 if (!ots::ParseCoverageTable(data + offset_coverage,
690 length - offset_coverage, num_glyphs)) {
691 return OTS_FAILURE();
692 }
693 }
694
695 for (unsigned i = 0; i < lookup_count; ++i) {
696 if (!ParseLookupRecord(&subtable, num_glyphs, num_lookups)) {
697 return OTS_FAILURE();
698 }
699 }
700
701 return true;
702}
703
704// Parsers for Chaning Contextual subtables in GSUB/GPOS tables.
705
706bool ParseChainRuleSubtable(const uint8_t *data, const size_t length,
707 const uint16_t num_glyphs,
708 const uint16_t num_lookups) {
709 ots::Buffer subtable(data, length);
710
711 uint16_t backtrack_count = 0;
712 if (!subtable.ReadU16(&backtrack_count)) {
713 return OTS_FAILURE();
714 }
715 if (backtrack_count >= num_glyphs) {
716 return OTS_FAILURE();
717 }
718 for (unsigned i = 0; i < backtrack_count; ++i) {
719 uint16_t glyph_id = 0;
720 if (!subtable.ReadU16(&glyph_id)) {
721 return OTS_FAILURE();
722 }
723 if (glyph_id > num_glyphs) {
724 return OTS_FAILURE();
725 }
726 }
727
728 uint16_t input_count = 0;
729 if (!subtable.ReadU16(&input_count)) {
730 return OTS_FAILURE();
731 }
732 if (input_count == 0 || input_count >= num_glyphs) {
733 return OTS_FAILURE();
734 }
735 for (unsigned i = 0; i < input_count - static_cast<unsigned>(1); ++i) {
736 uint16_t glyph_id = 0;
737 if (!subtable.ReadU16(&glyph_id)) {
738 return OTS_FAILURE();
739 }
740 if (glyph_id > num_glyphs) {
741 return OTS_FAILURE();
742 }
743 }
744
745 uint16_t lookahead_count = 0;
746 if (!subtable.ReadU16(&lookahead_count)) {
747 return OTS_FAILURE();
748 }
749 if (lookahead_count >= num_glyphs) {
750 return OTS_FAILURE();
751 }
752 for (unsigned i = 0; i < lookahead_count; ++i) {
753 uint16_t glyph_id = 0;
754 if (!subtable.ReadU16(&glyph_id)) {
755 return OTS_FAILURE();
756 }
757 if (glyph_id > num_glyphs) {
758 return OTS_FAILURE();
759 }
760 }
761
762 uint16_t lookup_count = 0;
763 if (!subtable.ReadU16(&lookup_count)) {
764 return OTS_FAILURE();
765 }
766 for (unsigned i = 0; i < lookup_count; ++i) {
767 if (!ParseLookupRecord(&subtable, num_glyphs, num_lookups)) {
768 return OTS_FAILURE();
769 }
770 }
771
772 return true;
773}
774
775bool ParseChainRuleSetTable(const uint8_t *data, const size_t length,
776 const uint16_t num_glyphs,
777 const uint16_t num_lookups) {
778 ots::Buffer subtable(data, length);
779
780 uint16_t chain_rule_count = 0;
781 if (!subtable.ReadU16(&chain_rule_count)) {
782 return OTS_FAILURE();
783 }
bashi@chromium.org26afae82011-08-25 05:38:57 +0000784 const unsigned chain_rule_end =
785 2 * static_cast<unsigned>(chain_rule_count) + 2;
bashi@chromium.orgced71122011-02-17 10:23:47 +0000786 if (chain_rule_end > std::numeric_limits<uint16_t>::max()) {
787 return OTS_FAILURE();
788 }
789 for (unsigned i = 0; i < chain_rule_count; ++i) {
790 uint16_t offset_chain_rule = 0;
791 if (!subtable.ReadU16(&offset_chain_rule)) {
792 return OTS_FAILURE();
793 }
794 if (offset_chain_rule < chain_rule_end || offset_chain_rule >= length) {
795 return OTS_FAILURE();
796 }
797 if (!ParseChainRuleSubtable(data + offset_chain_rule,
798 length - offset_chain_rule,
799 num_glyphs, num_lookups)) {
800 return OTS_FAILURE();
801 }
802 }
803
804 return true;
805}
806
807bool ParseChainContextFormat1(const uint8_t *data, const size_t length,
808 const uint16_t num_glyphs,
809 const uint16_t num_lookups) {
810 ots::Buffer subtable(data, length);
811
812 uint16_t offset_coverage = 0;
813 uint16_t chain_rule_set_count = 0;
814 // Skip format field.
815 if (!subtable.Skip(2) ||
816 !subtable.ReadU16(&offset_coverage) ||
817 !subtable.ReadU16(&chain_rule_set_count)) {
818 return OTS_FAILURE();
819 }
820
bashi@chromium.org26afae82011-08-25 05:38:57 +0000821 const unsigned chain_rule_set_end =
822 2 * static_cast<unsigned>(chain_rule_set_count) + 6;
bashi@chromium.orgced71122011-02-17 10:23:47 +0000823 if (chain_rule_set_end > std::numeric_limits<uint16_t>::max()) {
824 return OTS_FAILURE();
825 }
826 if (offset_coverage < chain_rule_set_end || offset_coverage >= length) {
827 return OTS_FAILURE();
828 }
829 if (!ots::ParseCoverageTable(data + offset_coverage,
830 length - offset_coverage, num_glyphs)) {
831 return OTS_FAILURE();
832 }
833
834 for (unsigned i = 0; i < chain_rule_set_count; ++i) {
835 uint16_t offset_chain_rule_set = 0;
836 if (!subtable.ReadU16(&offset_chain_rule_set)) {
837 return OTS_FAILURE();
838 }
839 if (offset_chain_rule_set < chain_rule_set_end ||
840 offset_chain_rule_set >= length) {
841 return OTS_FAILURE();
842 }
843 if (!ParseChainRuleSetTable(data + offset_chain_rule_set,
844 length - offset_chain_rule_set,
845 num_glyphs, num_lookups)) {
846 return OTS_FAILURE();
847 }
848 }
849
850 return true;
851}
852
853bool ParseChainClassRuleSubtable(const uint8_t *data, const size_t length,
854 const uint16_t num_glyphs,
855 const uint16_t num_lookups) {
856 ots::Buffer subtable(data, length);
857
858 // In this subtable, we don't check the value of classes for now since
859 // these could take arbitrary values.
860
861 uint16_t backtrack_count = 0;
862 if (!subtable.ReadU16(&backtrack_count)) {
863 return OTS_FAILURE();
864 }
865 if (backtrack_count >= num_glyphs) {
866 return OTS_FAILURE();
867 }
868 if (!subtable.Skip(2 * backtrack_count)) {
869 return OTS_FAILURE();
870 }
871
872 uint16_t input_count = 0;
873 if (!subtable.ReadU16(&input_count)) {
874 return OTS_FAILURE();
875 }
876 if (input_count == 0 || input_count >= num_glyphs) {
877 return OTS_FAILURE();
878 }
879 if (!subtable.Skip(2 * (input_count - 1))) {
880 return OTS_FAILURE();
881 }
882
883 uint16_t lookahead_count = 0;
884 if (!subtable.ReadU16(&lookahead_count)) {
885 return OTS_FAILURE();
886 }
887 if (lookahead_count >= num_glyphs) {
888 return OTS_FAILURE();
889 }
890 if (!subtable.Skip(2 * lookahead_count)) {
891 return OTS_FAILURE();
892 }
893
894 uint16_t lookup_count = 0;
895 if (!subtable.ReadU16(&lookup_count)) {
896 return OTS_FAILURE();
897 }
898 for (unsigned i = 0; i < lookup_count; ++i) {
899 if (!ParseLookupRecord(&subtable, num_glyphs, num_lookups)) {
900 return OTS_FAILURE();
901 }
902 }
903
904 return true;
905}
906
907bool ParseChainClassSetTable(const uint8_t *data, const size_t length,
908 const uint16_t num_glyphs,
909 const uint16_t num_lookups) {
910 ots::Buffer subtable(data, length);
911
912 uint16_t chain_class_rule_count = 0;
913 if (!subtable.ReadU16(&chain_class_rule_count)) {
914 return OTS_FAILURE();
915 }
bashi@chromium.org26afae82011-08-25 05:38:57 +0000916 const unsigned chain_class_rule_end =
917 2 * static_cast<unsigned>(chain_class_rule_count) + 2;
bashi@chromium.orgced71122011-02-17 10:23:47 +0000918 if (chain_class_rule_end > std::numeric_limits<uint16_t>::max()) {
919 return OTS_FAILURE();
920 }
921 for (unsigned i = 0; i < chain_class_rule_count; ++i) {
922 uint16_t offset_chain_class_rule = 0;
923 if (!subtable.ReadU16(&offset_chain_class_rule)) {
924 return OTS_FAILURE();
925 }
926 if (offset_chain_class_rule < chain_class_rule_end ||
927 offset_chain_class_rule >= length) {
928 return OTS_FAILURE();
929 }
930 if (!ParseChainClassRuleSubtable(data + offset_chain_class_rule,
931 length - offset_chain_class_rule,
932 num_glyphs, num_lookups)) {
933 return OTS_FAILURE();
934 }
935 }
936
937 return true;
938}
939
940bool ParseChainContextFormat2(const uint8_t *data, const size_t length,
941 const uint16_t num_glyphs,
942 const uint16_t num_lookups) {
943 ots::Buffer subtable(data, length);
944
945 uint16_t offset_coverage = 0;
946 uint16_t offset_backtrack_class_def = 0;
947 uint16_t offset_input_class_def = 0;
948 uint16_t offset_lookahead_class_def = 0;
949 uint16_t chain_class_set_count = 0;
950 // Skip format field.
951 if (!subtable.Skip(2) ||
952 !subtable.ReadU16(&offset_coverage) ||
953 !subtable.ReadU16(&offset_backtrack_class_def) ||
954 !subtable.ReadU16(&offset_input_class_def) ||
955 !subtable.ReadU16(&offset_lookahead_class_def) ||
956 !subtable.ReadU16(&chain_class_set_count)) {
957 return OTS_FAILURE();
958 }
959
bashi@chromium.org26afae82011-08-25 05:38:57 +0000960 const unsigned chain_class_set_end =
961 2 * static_cast<unsigned>(chain_class_set_count) + 12;
bashi@chromium.orgced71122011-02-17 10:23:47 +0000962 if (chain_class_set_end > std::numeric_limits<uint16_t>::max()) {
963 return OTS_FAILURE();
964 }
965 if (offset_coverage < chain_class_set_end || offset_coverage >= length) {
966 return OTS_FAILURE();
967 }
968 if (!ots::ParseCoverageTable(data + offset_coverage,
969 length - offset_coverage, num_glyphs)) {
970 return OTS_FAILURE();
971 }
972
973 // Classes for backtrack/lookahead sequences might not be defined.
974 if (offset_backtrack_class_def) {
975 if (offset_backtrack_class_def < chain_class_set_end ||
976 offset_backtrack_class_def >= length) {
977 return OTS_FAILURE();
978 }
979 if (!ots::ParseClassDefTable(data + offset_backtrack_class_def,
980 length - offset_backtrack_class_def,
981 num_glyphs, kMaxClassDefValue)) {
982 return OTS_FAILURE();
983 }
984 }
985
986 if (offset_input_class_def < chain_class_set_end ||
987 offset_input_class_def >= length) {
988 return OTS_FAILURE();
989 }
990 if (!ots::ParseClassDefTable(data + offset_input_class_def,
991 length - offset_input_class_def,
992 num_glyphs, kMaxClassDefValue)) {
993 return OTS_FAILURE();
994 }
995
996 if (offset_lookahead_class_def) {
997 if (offset_lookahead_class_def < chain_class_set_end ||
998 offset_lookahead_class_def >= length) {
999 return OTS_FAILURE();
1000 }
1001 if (!ots::ParseClassDefTable(data + offset_lookahead_class_def,
1002 length - offset_lookahead_class_def,
1003 num_glyphs, kMaxClassDefValue)) {
1004 return OTS_FAILURE();
1005 }
1006 }
1007
1008 for (unsigned i = 0; i < chain_class_set_count; ++i) {
1009 uint16_t offset_chain_class_set = 0;
1010 if (!subtable.ReadU16(&offset_chain_class_set)) {
1011 return OTS_FAILURE();
1012 }
1013 // |offset_chain_class_set| could be NULL.
1014 if (offset_chain_class_set) {
1015 if (offset_chain_class_set < chain_class_set_end ||
1016 offset_chain_class_set >= length) {
1017 return OTS_FAILURE();
1018 }
1019 if (!ParseChainClassSetTable(data + offset_chain_class_set,
1020 length - offset_chain_class_set,
1021 num_glyphs, num_lookups)) {
1022 return OTS_FAILURE();
1023 }
1024 }
1025 }
1026
1027 return true;
1028}
1029
1030bool ParseChainContextFormat3(const uint8_t *data, const size_t length,
1031 const uint16_t num_glyphs,
1032 const uint16_t num_lookups) {
1033 ots::Buffer subtable(data, length);
1034
1035 uint16_t backtrack_count = 0;
1036 // Skip format field.
1037 if (!subtable.Skip(2) ||
1038 !subtable.ReadU16(&backtrack_count)) {
1039 return OTS_FAILURE();
1040 }
1041
1042 if (backtrack_count >= num_glyphs) {
1043 return OTS_FAILURE();
1044 }
1045 std::vector<uint16_t> offsets_backtrack;
1046 offsets_backtrack.reserve(backtrack_count);
1047 for (unsigned i = 0; i < backtrack_count; ++i) {
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001048 uint16_t offset = 0;
1049 if (!subtable.ReadU16(&offset)) {
bashi@chromium.orgced71122011-02-17 10:23:47 +00001050 return OTS_FAILURE();
1051 }
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001052 offsets_backtrack.push_back(offset);
bashi@chromium.orgced71122011-02-17 10:23:47 +00001053 }
bashi@chromium.org6b410202011-02-23 04:12:49 +00001054 if (offsets_backtrack.size() != backtrack_count) {
1055 return OTS_FAILURE();
1056 }
bashi@chromium.orgced71122011-02-17 10:23:47 +00001057
1058 uint16_t input_count = 0;
1059 if (!subtable.ReadU16(&input_count)) {
1060 return OTS_FAILURE();
1061 }
1062 if (input_count >= num_glyphs) {
1063 return OTS_FAILURE();
1064 }
1065 std::vector<uint16_t> offsets_input;
1066 offsets_input.reserve(input_count);
1067 for (unsigned i = 0; i < input_count; ++i) {
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001068 uint16_t offset = 0;
1069 if (!subtable.ReadU16(&offset)) {
bashi@chromium.orgced71122011-02-17 10:23:47 +00001070 return OTS_FAILURE();
1071 }
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001072 offsets_input.push_back(offset);
bashi@chromium.orgced71122011-02-17 10:23:47 +00001073 }
bashi@chromium.org6b410202011-02-23 04:12:49 +00001074 if (offsets_input.size() != input_count) {
1075 return OTS_FAILURE();
1076 }
bashi@chromium.orgced71122011-02-17 10:23:47 +00001077
1078 uint16_t lookahead_count = 0;
1079 if (!subtable.ReadU16(&lookahead_count)) {
1080 return OTS_FAILURE();
1081 }
1082 if (lookahead_count >= num_glyphs) {
1083 return OTS_FAILURE();
1084 }
1085 std::vector<uint16_t> offsets_lookahead;
1086 offsets_lookahead.reserve(lookahead_count);
1087 for (unsigned i = 0; i < lookahead_count; ++i) {
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001088 uint16_t offset = 0;
1089 if (!subtable.ReadU16(&offset)) {
bashi@chromium.orgced71122011-02-17 10:23:47 +00001090 return OTS_FAILURE();
1091 }
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001092 offsets_lookahead.push_back(offset);
bashi@chromium.orgced71122011-02-17 10:23:47 +00001093 }
bashi@chromium.org6b410202011-02-23 04:12:49 +00001094 if (offsets_lookahead.size() != lookahead_count) {
1095 return OTS_FAILURE();
1096 }
bashi@chromium.orgced71122011-02-17 10:23:47 +00001097
1098 uint16_t lookup_count = 0;
1099 if (!subtable.ReadU16(&lookup_count)) {
1100 return OTS_FAILURE();
1101 }
1102 for (unsigned i = 0; i < lookup_count; ++i) {
1103 if (!ParseLookupRecord(&subtable, num_glyphs, num_lookups)) {
1104 return OTS_FAILURE();
1105 }
1106 }
1107
bashi@chromium.org26afae82011-08-25 05:38:57 +00001108 const unsigned lookup_record_end =
1109 2 * (static_cast<unsigned>(backtrack_count) +
1110 static_cast<unsigned>(input_count) +
1111 static_cast<unsigned>(lookahead_count)) +
1112 4 * static_cast<unsigned>(lookup_count) + 10;
bashi@chromium.orgced71122011-02-17 10:23:47 +00001113 if (lookup_record_end > std::numeric_limits<uint16_t>::max()) {
1114 return OTS_FAILURE();
1115 }
1116 for (unsigned i = 0; i < backtrack_count; ++i) {
1117 if (offsets_backtrack[i] < lookup_record_end ||
1118 offsets_backtrack[i] >= length) {
1119 return OTS_FAILURE();
1120 }
1121 if (!ots::ParseCoverageTable(data + offsets_backtrack[i],
1122 length - offsets_backtrack[i], num_glyphs)) {
1123 return OTS_FAILURE();
1124 }
1125 }
1126 for (unsigned i = 0; i < input_count; ++i) {
1127 if (offsets_input[i] < lookup_record_end || offsets_input[i] >= length) {
1128 return OTS_FAILURE();
1129 }
1130 if (!ots::ParseCoverageTable(data + offsets_input[i],
1131 length - offsets_input[i], num_glyphs)) {
1132 return OTS_FAILURE();
1133 }
1134 }
1135 for (unsigned i = 0; i < lookahead_count; ++i) {
1136 if (offsets_lookahead[i] < lookup_record_end ||
1137 offsets_lookahead[i] >= length) {
1138 return OTS_FAILURE();
1139 }
1140 if (!ots::ParseCoverageTable(data + offsets_lookahead[i],
1141 length - offsets_lookahead[i], num_glyphs)) {
1142 return OTS_FAILURE();
1143 }
1144 }
1145
1146 return true;
1147}
1148
bashi@google.com00b790a2011-01-27 06:35:42 +00001149} // namespace
1150
1151namespace ots {
1152
bashi@chromium.orgced71122011-02-17 10:23:47 +00001153bool LookupSubtableParser::Parse(const OpenTypeFile *file, const uint8_t *data,
1154 const size_t length,
1155 const uint16_t lookup_type) const {
1156 for (unsigned i = 0; i < num_types; ++i) {
1157 if (parsers[i].type == lookup_type && parsers[i].parse) {
1158 if (!parsers[i].parse(file, data, length)) {
1159 return OTS_FAILURE();
1160 }
1161 return true;
1162 }
1163 }
1164 return OTS_FAILURE();
1165}
1166
bashi@google.com78a8baa2011-02-07 06:21:25 +00001167// Parsing ScriptListTable requires number of features so we need to
1168// parse FeatureListTable before calling this function.
1169bool ParseScriptListTable(const uint8_t *data, const size_t length,
1170 const uint16_t num_features) {
1171 Buffer subtable(data, length);
1172
1173 uint16_t script_count = 0;
1174 if (!subtable.ReadU16(&script_count)) {
1175 return OTS_FAILURE();
1176 }
1177
bashi@chromium.org26afae82011-08-25 05:38:57 +00001178 const unsigned script_record_end =
1179 6 * static_cast<unsigned>(script_count) + 2;
bashi@google.com78a8baa2011-02-07 06:21:25 +00001180 if (script_record_end > std::numeric_limits<uint16_t>::max()) {
1181 return OTS_FAILURE();
1182 }
1183 std::vector<ScriptRecord> script_list;
1184 script_list.reserve(script_count);
1185 uint32_t last_tag = 0;
1186 for (unsigned i = 0; i < script_count; ++i) {
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001187 ScriptRecord record;
1188 if (!subtable.ReadU32(&record.tag) ||
1189 !subtable.ReadU16(&record.offset)) {
bashi@google.com78a8baa2011-02-07 06:21:25 +00001190 return OTS_FAILURE();
1191 }
1192 // Script tags should be arranged alphabetically by tag
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001193 if (last_tag != 0 && last_tag > record.tag) {
bashi@chromium.orga5748662011-03-18 17:48:29 +00001194 // Several fonts don't arrange tags alphabetically.
1195 // It seems that the order of tags might not be a security issue
1196 // so we just warn it.
1197 OTS_WARNING("tags aren't arranged alphabetically.");
bashi@google.com78a8baa2011-02-07 06:21:25 +00001198 }
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001199 last_tag = record.tag;
1200 if (record.offset < script_record_end || record.offset >= length) {
bashi@google.com78a8baa2011-02-07 06:21:25 +00001201 return OTS_FAILURE();
1202 }
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001203 script_list.push_back(record);
bashi@google.com78a8baa2011-02-07 06:21:25 +00001204 }
bashi@chromium.org6b410202011-02-23 04:12:49 +00001205 if (script_list.size() != script_count) {
1206 return OTS_FAILURE();
1207 }
bashi@google.com78a8baa2011-02-07 06:21:25 +00001208
1209 // Check script records.
1210 for (unsigned i = 0; i < script_count; ++i) {
1211 if (!ParseScriptTable(data + script_list[i].offset,
1212 length - script_list[i].offset,
1213 script_list[i].tag, num_features)) {
1214 return OTS_FAILURE();
1215 }
1216 }
1217
1218 return true;
1219}
1220
1221// Parsing FeatureListTable requires number of lookups so we need to parse
1222// LookupListTable before calling this function.
1223bool ParseFeatureListTable(const uint8_t *data, const size_t length,
1224 const uint16_t num_lookups,
1225 uint16_t* num_features) {
1226 Buffer subtable(data, length);
1227
1228 uint16_t feature_count = 0;
1229 if (!subtable.ReadU16(&feature_count)) {
1230 return OTS_FAILURE();
1231 }
1232
1233 std::vector<FeatureRecord> feature_records;
1234 feature_records.resize(feature_count);
bashi@chromium.org26afae82011-08-25 05:38:57 +00001235 const unsigned feature_record_end =
1236 6 * static_cast<unsigned>(feature_count) + 2;
bashi@google.com78a8baa2011-02-07 06:21:25 +00001237 if (feature_record_end > std::numeric_limits<uint16_t>::max()) {
1238 return OTS_FAILURE();
1239 }
1240 uint32_t last_tag = 0;
1241 for (unsigned i = 0; i < feature_count; ++i) {
1242 if (!subtable.ReadU32(&feature_records[i].tag) ||
1243 !subtable.ReadU16(&feature_records[i].offset)) {
1244 return OTS_FAILURE();
1245 }
1246 // Feature record array should be arranged alphabetically by tag
1247 if (last_tag != 0 && last_tag > feature_records[i].tag) {
bashi@chromium.orga5748662011-03-18 17:48:29 +00001248 // Several fonts don't arrange tags alphabetically.
1249 // It seems that the order of tags might not be a security issue
1250 // so we just warn it.
1251 OTS_WARNING("tags aren't arranged alphabetically.");
bashi@google.com78a8baa2011-02-07 06:21:25 +00001252 }
1253 last_tag = feature_records[i].tag;
1254 if (feature_records[i].offset < feature_record_end ||
1255 feature_records[i].offset >= length) {
1256 return OTS_FAILURE();
1257 }
1258 }
1259
1260 for (unsigned i = 0; i < feature_count; ++i) {
1261 if (!ParseFeatureTable(data + feature_records[i].offset,
1262 length - feature_records[i].offset, num_lookups)) {
1263 return OTS_FAILURE();
1264 }
1265 }
1266 *num_features = feature_count;
1267 return true;
1268}
1269
1270// For parsing GPOS/GSUB tables, this function should be called at first to
1271// obtain the number of lookups because parsing FeatureTableList requires
1272// the number.
1273bool ParseLookupListTable(OpenTypeFile *file, const uint8_t *data,
bashi@chromium.orgced71122011-02-17 10:23:47 +00001274 const size_t length,
1275 const LookupSubtableParser* parser,
bashi@google.com78a8baa2011-02-07 06:21:25 +00001276 uint16_t *num_lookups) {
1277 Buffer subtable(data, length);
1278
1279 if (!subtable.ReadU16(num_lookups)) {
1280 return OTS_FAILURE();
1281 }
1282
1283 std::vector<uint16_t> lookups;
1284 lookups.reserve(*num_lookups);
bashi@chromium.org26afae82011-08-25 05:38:57 +00001285 const unsigned lookup_end =
1286 2 * static_cast<unsigned>(*num_lookups) + 2;
bashi@google.com78a8baa2011-02-07 06:21:25 +00001287 if (lookup_end > std::numeric_limits<uint16_t>::max()) {
1288 return OTS_FAILURE();
1289 }
1290 for (unsigned i = 0; i < *num_lookups; ++i) {
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001291 uint16_t offset = 0;
1292 if (!subtable.ReadU16(&offset)) {
bashi@google.com78a8baa2011-02-07 06:21:25 +00001293 return OTS_FAILURE();
1294 }
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001295 if (offset < lookup_end || offset >= length) {
bashi@google.com78a8baa2011-02-07 06:21:25 +00001296 return OTS_FAILURE();
1297 }
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001298 lookups.push_back(offset);
bashi@google.com78a8baa2011-02-07 06:21:25 +00001299 }
bashi@chromium.org6b410202011-02-23 04:12:49 +00001300 if (lookups.size() != *num_lookups) {
1301 return OTS_FAILURE();
1302 }
bashi@google.com78a8baa2011-02-07 06:21:25 +00001303
1304 for (unsigned i = 0; i < *num_lookups; ++i) {
1305 if (!ParseLookupTable(file, data + lookups[i], length - lookups[i],
bashi@chromium.orgced71122011-02-17 10:23:47 +00001306 parser)) {
bashi@google.com78a8baa2011-02-07 06:21:25 +00001307 return OTS_FAILURE();
1308 }
1309 }
1310
1311 return true;
1312}
1313
bashi@google.com00b790a2011-01-27 06:35:42 +00001314bool ParseClassDefTable(const uint8_t *data, size_t length,
1315 const uint16_t num_glyphs,
1316 const uint16_t num_classes) {
1317 Buffer subtable(data, length);
1318
1319 uint16_t format = 0;
1320 if (!subtable.ReadU16(&format)) {
1321 return OTS_FAILURE();
1322 }
1323 if (format == 1) {
1324 return ParseClassDefFormat1(data, length, num_glyphs, num_classes);
1325 } else if (format == 2) {
1326 return ParseClassDefFormat2(data, length, num_glyphs, num_classes);
1327 }
1328
1329 return OTS_FAILURE();
1330}
1331
1332bool ParseCoverageTable(const uint8_t *data, size_t length,
1333 const uint16_t num_glyphs) {
1334 Buffer subtable(data, length);
1335
1336 uint16_t format = 0;
1337 if (!subtable.ReadU16(&format)) {
1338 return OTS_FAILURE();
1339 }
1340 if (format == 1) {
1341 return ParseCoverageFormat1(data, length, num_glyphs);
1342 } else if (format == 2) {
1343 return ParseCoverageFormat2(data, length, num_glyphs);
1344 }
1345
1346 return OTS_FAILURE();
1347}
1348
bashi@google.com78a8baa2011-02-07 06:21:25 +00001349bool ParseDeviceTable(const uint8_t *data, size_t length) {
1350 Buffer subtable(data, length);
1351
1352 uint16_t start_size = 0;
1353 uint16_t end_size = 0;
1354 uint16_t delta_format = 0;
1355 if (!subtable.ReadU16(&start_size) ||
1356 !subtable.ReadU16(&end_size) ||
1357 !subtable.ReadU16(&delta_format)) {
1358 return OTS_FAILURE();
1359 }
1360 if (start_size > end_size) {
1361 OTS_WARNING("bad size range: %u > %u", start_size, end_size);
1362 return OTS_FAILURE();
1363 }
1364 if (delta_format == 0 || delta_format > kMaxDeltaFormatType) {
1365 OTS_WARNING("bad delta format: %u", delta_format);
1366 return OTS_FAILURE();
1367 }
1368 // The number of delta values per uint16. The device table should contain
1369 // at least |num_units| * 2 bytes compressed data.
1370 const unsigned num_units = (end_size - start_size) /
1371 (1 << (4 - delta_format)) + 1;
1372 // Just skip |num_units| * 2 bytes since the compressed data could take
1373 // arbitrary values.
1374 if (!subtable.Skip(num_units * 2)) {
1375 return OTS_FAILURE();
1376 }
1377 return true;
1378}
1379
bashi@chromium.orgced71122011-02-17 10:23:47 +00001380bool ParseContextSubtable(const uint8_t *data, const size_t length,
1381 const uint16_t num_glyphs,
1382 const uint16_t num_lookups) {
1383 Buffer subtable(data, length);
1384
1385 uint16_t format = 0;
1386 if (!subtable.ReadU16(&format)) {
1387 return OTS_FAILURE();
1388 }
1389
1390 if (format == 1) {
1391 if (!ParseContextFormat1(data, length, num_glyphs, num_lookups)) {
1392 return OTS_FAILURE();
1393 }
1394 } else if (format == 2) {
1395 if (!ParseContextFormat2(data, length, num_glyphs, num_lookups)) {
1396 return OTS_FAILURE();
1397 }
1398 } else if (format == 3) {
1399 if (!ParseContextFormat3(data, length, num_glyphs, num_lookups)) {
1400 return OTS_FAILURE();
1401 }
1402 } else {
1403 return OTS_FAILURE();
1404 }
1405
1406 return true;
1407}
1408
1409bool ParseChainingContextSubtable(const uint8_t *data, const size_t length,
1410 const uint16_t num_glyphs,
1411 const uint16_t num_lookups) {
1412 Buffer subtable(data, length);
1413
1414 uint16_t format = 0;
1415 if (!subtable.ReadU16(&format)) {
1416 return OTS_FAILURE();
1417 }
1418
1419 if (format == 1) {
1420 if (!ParseChainContextFormat1(data, length, num_glyphs, num_lookups)) {
1421 return OTS_FAILURE();
1422 }
1423 } else if (format == 2) {
1424 if (!ParseChainContextFormat2(data, length, num_glyphs, num_lookups)) {
1425 return OTS_FAILURE();
1426 }
1427 } else if (format == 3) {
1428 if (!ParseChainContextFormat3(data, length, num_glyphs, num_lookups)) {
1429 return OTS_FAILURE();
1430 }
1431 } else {
1432 return OTS_FAILURE();
1433 }
1434
1435 return true;
1436}
1437
1438bool ParseExtensionSubtable(const OpenTypeFile *file,
1439 const uint8_t *data, const size_t length,
1440 const LookupSubtableParser* parser) {
1441 Buffer subtable(data, length);
1442
1443 uint16_t format = 0;
1444 uint16_t lookup_type = 0;
1445 uint32_t offset_extension = 0;
1446 if (!subtable.ReadU16(&format) ||
1447 !subtable.ReadU16(&lookup_type) ||
1448 !subtable.ReadU32(&offset_extension)) {
1449 return OTS_FAILURE();
1450 }
1451
1452 if (format != 1) {
1453 return OTS_FAILURE();
1454 }
1455 // |lookup_type| should be other than |parser->extension_type|.
1456 if (lookup_type < 1 || lookup_type > parser->num_types ||
1457 lookup_type == parser->extension_type) {
1458 return OTS_FAILURE();
1459 }
1460
1461 const unsigned format_end = static_cast<unsigned>(8);
1462 if (offset_extension < format_end ||
1463 offset_extension >= length) {
1464 return OTS_FAILURE();
1465 }
1466
1467 // Parse the extension subtable of |lookup_type|.
1468 if (!parser->Parse(file, data + offset_extension, length - offset_extension,
1469 lookup_type)) {
1470 return OTS_FAILURE();
1471 }
1472
1473 return true;
1474}
1475
bashi@google.com00b790a2011-01-27 06:35:42 +00001476} // namespace ots
1477