blob: 99d04b30291b9506d8ef8ddaf5fd08f5644d2bb4 [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 }
agl@chromium.org006c3452012-06-26 14:47:24 +0000397
398 // Some of the Adobe Pro fonts have ranges that overlap by one element: the
399 // start of one range is equal to the end of the previous range. Therefore
400 // the < in the following condition should be <= were it not for this.
401 // See crbug.com/134135.
402 if (start > end || (last_end && start < last_end)) {
bashi@google.com00b790a2011-01-27 06:35:42 +0000403 OTS_WARNING("glyph range is overlapping.");
404 return OTS_FAILURE();
405 }
bashi@google.com78a8baa2011-02-07 06:21:25 +0000406 if (start_coverage_index != last_start_coverage_index) {
407 OTS_WARNING("bad start coverage index.");
408 return OTS_FAILURE();
409 }
410 last_end = end;
411 last_start_coverage_index += end - start + 1;
bashi@google.com00b790a2011-01-27 06:35:42 +0000412 }
413
414 return true;
415}
416
bashi@chromium.orgced71122011-02-17 10:23:47 +0000417// Parsers for Contextual subtables in GSUB/GPOS tables.
418
419bool ParseLookupRecord(ots::Buffer *subtable, const uint16_t num_glyphs,
420 const uint16_t num_lookups) {
421 uint16_t sequence_index = 0;
422 uint16_t lookup_list_index = 0;
423 if (!subtable->ReadU16(&sequence_index) ||
424 !subtable->ReadU16(&lookup_list_index)) {
425 return OTS_FAILURE();
426 }
427 if (sequence_index >= num_glyphs) {
428 return OTS_FAILURE();
429 }
430 if (lookup_list_index >= num_lookups) {
431 return OTS_FAILURE();
432 }
433 return true;
434}
435
436bool ParseRuleSubtable(const uint8_t *data, const size_t length,
437 const uint16_t num_glyphs,
438 const uint16_t num_lookups) {
439 ots::Buffer subtable(data, length);
440
441 uint16_t glyph_count = 0;
442 uint16_t lookup_count = 0;
443 if (!subtable.ReadU16(&glyph_count) ||
444 !subtable.ReadU16(&lookup_count)) {
445 return OTS_FAILURE();
446 }
447
448 if (glyph_count == 0 || glyph_count >= num_glyphs) {
449 return OTS_FAILURE();
450 }
451 for (unsigned i = 0; i < glyph_count - static_cast<unsigned>(1); ++i) {
452 uint16_t glyph_id = 0;
453 if (!subtable.ReadU16(&glyph_id)) {
454 return OTS_FAILURE();
455 }
456 if (glyph_id > num_glyphs) {
457 return OTS_FAILURE();
458 }
459 }
460
461 for (unsigned i = 0; i < lookup_count; ++i) {
462 if (!ParseLookupRecord(&subtable, num_glyphs, num_lookups)) {
463 return OTS_FAILURE();
464 }
465 }
466 return true;
467}
468
469bool ParseRuleSetTable(const uint8_t *data, const size_t length,
470 const uint16_t num_glyphs,
471 const uint16_t num_lookups) {
472 ots::Buffer subtable(data, length);
473
474 uint16_t rule_count = 0;
475 if (!subtable.ReadU16(&rule_count)) {
476 return OTS_FAILURE();
477 }
bashi@chromium.org26afae82011-08-25 05:38:57 +0000478 const unsigned rule_end = 2 * static_cast<unsigned>(rule_count) + 2;
bashi@chromium.orgced71122011-02-17 10:23:47 +0000479 if (rule_end > std::numeric_limits<uint16_t>::max()) {
480 return OTS_FAILURE();
481 }
482
483 for (unsigned i = 0; i < rule_count; ++i) {
484 uint16_t offset_rule = 0;
485 if (!subtable.ReadU16(&offset_rule)) {
486 return OTS_FAILURE();
487 }
488 if (offset_rule < rule_end || offset_rule >= length) {
489 return OTS_FAILURE();
490 }
491 if (!ParseRuleSubtable(data + offset_rule, length - offset_rule,
492 num_glyphs, num_lookups)) {
493 return OTS_FAILURE();
494 }
495 }
496
497 return true;
498}
499
500bool ParseContextFormat1(const uint8_t *data, const size_t length,
501 const uint16_t num_glyphs,
502 const uint16_t num_lookups) {
503 ots::Buffer subtable(data, length);
504
505 uint16_t offset_coverage = 0;
506 uint16_t rule_set_count = 0;
507 // Skip format field.
508 if (!subtable.Skip(2) ||
509 !subtable.ReadU16(&offset_coverage) ||
510 !subtable.ReadU16(&rule_set_count)) {
511 return OTS_FAILURE();
512 }
513
514 const unsigned rule_set_end = static_cast<unsigned>(6) +
515 rule_set_count * 2;
516 if (rule_set_end > std::numeric_limits<uint16_t>::max()) {
517 return OTS_FAILURE();
518 }
519 if (offset_coverage < rule_set_end || offset_coverage >= length) {
520 return OTS_FAILURE();
521 }
522 if (!ots::ParseCoverageTable(data + offset_coverage,
523 length - offset_coverage, num_glyphs)) {
524 return OTS_FAILURE();
525 }
526
527 for (unsigned i = 0; i < rule_set_count; ++i) {
528 uint16_t offset_rule = 0;
529 if (!subtable.ReadU16(&offset_rule)) {
530 return OTS_FAILURE();
531 }
532 if (offset_rule < rule_set_end || offset_rule >= length) {
533 return OTS_FAILURE();
534 }
535 if (!ParseRuleSetTable(data + offset_rule, length - offset_rule,
536 num_glyphs, num_lookups)) {
537 return OTS_FAILURE();
538 }
539 }
540
541 return true;
542}
543
544bool ParseClassRuleTable(const uint8_t *data, const size_t length,
545 const uint16_t num_glyphs,
546 const uint16_t num_lookups) {
547 ots::Buffer subtable(data, length);
548
549 uint16_t glyph_count = 0;
550 uint16_t lookup_count = 0;
551 if (!subtable.ReadU16(&glyph_count) ||
552 !subtable.ReadU16(&lookup_count)) {
553 return OTS_FAILURE();
554 }
555
556 if (glyph_count == 0 || glyph_count >= num_glyphs) {
557 return OTS_FAILURE();
558 }
559
560 // ClassRule table contains an array of classes. Each value of classes
561 // could take arbitrary values including zero so we don't check these value.
562 const unsigned num_classes = glyph_count - static_cast<unsigned>(1);
563 if (!subtable.Skip(2 * num_classes)) {
564 return OTS_FAILURE();
565 }
566
567 for (unsigned i = 0; i < lookup_count; ++i) {
568 if (!ParseLookupRecord(&subtable, num_glyphs, num_lookups)) {
569 return OTS_FAILURE();
570 }
571 }
572 return true;
573}
574
575bool ParseClassSetTable(const uint8_t *data, const size_t length,
576 const uint16_t num_glyphs,
577 const uint16_t num_lookups) {
578 ots::Buffer subtable(data, length);
579
580 uint16_t class_rule_count = 0;
581 if (!subtable.ReadU16(&class_rule_count)) {
582 return OTS_FAILURE();
583 }
bashi@chromium.org26afae82011-08-25 05:38:57 +0000584 const unsigned class_rule_end =
585 2 * static_cast<unsigned>(class_rule_count) + 2;
bashi@chromium.orgced71122011-02-17 10:23:47 +0000586 if (class_rule_end > std::numeric_limits<uint16_t>::max()) {
587 return OTS_FAILURE();
588 }
589 for (unsigned i = 0; i < class_rule_count; ++i) {
590 uint16_t offset_class_rule = 0;
591 if (!subtable.ReadU16(&offset_class_rule)) {
592 return OTS_FAILURE();
593 }
594 if (offset_class_rule < class_rule_end || offset_class_rule >= length) {
595 return OTS_FAILURE();
596 }
597 if (!ParseClassRuleTable(data + offset_class_rule,
598 length - offset_class_rule, num_glyphs,
599 num_lookups)) {
600 return OTS_FAILURE();
601 }
602 }
603
604 return true;
605}
606
607bool ParseContextFormat2(const uint8_t *data, const size_t length,
608 const uint16_t num_glyphs,
609 const uint16_t num_lookups) {
610 ots::Buffer subtable(data, length);
611
612 uint16_t offset_coverage = 0;
613 uint16_t offset_class_def = 0;
614 uint16_t class_set_cnt = 0;
615 // Skip format field.
616 if (!subtable.Skip(2) ||
617 !subtable.ReadU16(&offset_coverage) ||
618 !subtable.ReadU16(&offset_class_def) ||
619 !subtable.ReadU16(&class_set_cnt)) {
620 return OTS_FAILURE();
621 }
622
bashi@chromium.org26afae82011-08-25 05:38:57 +0000623 const unsigned class_set_end = 2 * static_cast<unsigned>(class_set_cnt) + 8;
bashi@chromium.orgced71122011-02-17 10:23:47 +0000624 if (class_set_end > std::numeric_limits<uint16_t>::max()) {
625 return OTS_FAILURE();
626 }
627 if (offset_coverage < class_set_end || offset_coverage >= length) {
628 return OTS_FAILURE();
629 }
630 if (!ots::ParseCoverageTable(data + offset_coverage,
631 length - offset_coverage, num_glyphs)) {
632 return OTS_FAILURE();
633 }
634
635 if (offset_class_def < class_set_end || offset_class_def >= length) {
636 return OTS_FAILURE();
637 }
638 if (!ots::ParseClassDefTable(data + offset_class_def,
639 length - offset_class_def,
640 num_glyphs, kMaxClassDefValue)) {
641 return OTS_FAILURE();
642 }
643
644 for (unsigned i = 0; i < class_set_cnt; ++i) {
645 uint16_t offset_class_rule = 0;
646 if (!subtable.ReadU16(&offset_class_rule)) {
647 return OTS_FAILURE();
648 }
649 if (offset_class_rule) {
650 if (offset_class_rule < class_set_end || offset_class_rule >= length) {
651 return OTS_FAILURE();
652 }
653 if (!ParseClassSetTable(data + offset_class_rule,
654 length - offset_class_rule, num_glyphs,
655 num_lookups)) {
656 return OTS_FAILURE();
657 }
658 }
659 }
660
661 return true;
662}
663
664bool ParseContextFormat3(const uint8_t *data, const size_t length,
665 const uint16_t num_glyphs,
666 const uint16_t num_lookups) {
667 ots::Buffer subtable(data, length);
668
669 uint16_t glyph_count = 0;
670 uint16_t lookup_count = 0;
671 // Skip format field.
672 if (!subtable.Skip(2) ||
673 !subtable.ReadU16(&glyph_count) ||
674 !subtable.ReadU16(&lookup_count)) {
675 return OTS_FAILURE();
676 }
677
678 if (glyph_count >= num_glyphs) {
679 return OTS_FAILURE();
680 }
bashi@chromium.org26afae82011-08-25 05:38:57 +0000681 const unsigned lookup_record_end = 2 * static_cast<unsigned>(glyph_count) +
682 4 * static_cast<unsigned>(lookup_count) + 6;
bashi@chromium.orgced71122011-02-17 10:23:47 +0000683 if (lookup_record_end > std::numeric_limits<uint16_t>::max()) {
684 return OTS_FAILURE();
685 }
686 for (unsigned i = 0; i < glyph_count; ++i) {
687 uint16_t offset_coverage = 0;
688 if (!subtable.ReadU16(&offset_coverage)) {
689 return OTS_FAILURE();
690 }
691 if (offset_coverage < lookup_record_end || offset_coverage >= length) {
692 return OTS_FAILURE();
693 }
694 if (!ots::ParseCoverageTable(data + offset_coverage,
695 length - offset_coverage, num_glyphs)) {
696 return OTS_FAILURE();
697 }
698 }
699
700 for (unsigned i = 0; i < lookup_count; ++i) {
701 if (!ParseLookupRecord(&subtable, num_glyphs, num_lookups)) {
702 return OTS_FAILURE();
703 }
704 }
705
706 return true;
707}
708
709// Parsers for Chaning Contextual subtables in GSUB/GPOS tables.
710
711bool ParseChainRuleSubtable(const uint8_t *data, const size_t length,
712 const uint16_t num_glyphs,
713 const uint16_t num_lookups) {
714 ots::Buffer subtable(data, length);
715
716 uint16_t backtrack_count = 0;
717 if (!subtable.ReadU16(&backtrack_count)) {
718 return OTS_FAILURE();
719 }
720 if (backtrack_count >= num_glyphs) {
721 return OTS_FAILURE();
722 }
723 for (unsigned i = 0; i < backtrack_count; ++i) {
724 uint16_t glyph_id = 0;
725 if (!subtable.ReadU16(&glyph_id)) {
726 return OTS_FAILURE();
727 }
728 if (glyph_id > num_glyphs) {
729 return OTS_FAILURE();
730 }
731 }
732
733 uint16_t input_count = 0;
734 if (!subtable.ReadU16(&input_count)) {
735 return OTS_FAILURE();
736 }
737 if (input_count == 0 || input_count >= num_glyphs) {
738 return OTS_FAILURE();
739 }
740 for (unsigned i = 0; i < input_count - static_cast<unsigned>(1); ++i) {
741 uint16_t glyph_id = 0;
742 if (!subtable.ReadU16(&glyph_id)) {
743 return OTS_FAILURE();
744 }
745 if (glyph_id > num_glyphs) {
746 return OTS_FAILURE();
747 }
748 }
749
750 uint16_t lookahead_count = 0;
751 if (!subtable.ReadU16(&lookahead_count)) {
752 return OTS_FAILURE();
753 }
754 if (lookahead_count >= num_glyphs) {
755 return OTS_FAILURE();
756 }
757 for (unsigned i = 0; i < lookahead_count; ++i) {
758 uint16_t glyph_id = 0;
759 if (!subtable.ReadU16(&glyph_id)) {
760 return OTS_FAILURE();
761 }
762 if (glyph_id > num_glyphs) {
763 return OTS_FAILURE();
764 }
765 }
766
767 uint16_t lookup_count = 0;
768 if (!subtable.ReadU16(&lookup_count)) {
769 return OTS_FAILURE();
770 }
771 for (unsigned i = 0; i < lookup_count; ++i) {
772 if (!ParseLookupRecord(&subtable, num_glyphs, num_lookups)) {
773 return OTS_FAILURE();
774 }
775 }
776
777 return true;
778}
779
780bool ParseChainRuleSetTable(const uint8_t *data, const size_t length,
781 const uint16_t num_glyphs,
782 const uint16_t num_lookups) {
783 ots::Buffer subtable(data, length);
784
785 uint16_t chain_rule_count = 0;
786 if (!subtable.ReadU16(&chain_rule_count)) {
787 return OTS_FAILURE();
788 }
bashi@chromium.org26afae82011-08-25 05:38:57 +0000789 const unsigned chain_rule_end =
790 2 * static_cast<unsigned>(chain_rule_count) + 2;
bashi@chromium.orgced71122011-02-17 10:23:47 +0000791 if (chain_rule_end > std::numeric_limits<uint16_t>::max()) {
792 return OTS_FAILURE();
793 }
794 for (unsigned i = 0; i < chain_rule_count; ++i) {
795 uint16_t offset_chain_rule = 0;
796 if (!subtable.ReadU16(&offset_chain_rule)) {
797 return OTS_FAILURE();
798 }
799 if (offset_chain_rule < chain_rule_end || offset_chain_rule >= length) {
800 return OTS_FAILURE();
801 }
802 if (!ParseChainRuleSubtable(data + offset_chain_rule,
803 length - offset_chain_rule,
804 num_glyphs, num_lookups)) {
805 return OTS_FAILURE();
806 }
807 }
808
809 return true;
810}
811
812bool ParseChainContextFormat1(const uint8_t *data, const size_t length,
813 const uint16_t num_glyphs,
814 const uint16_t num_lookups) {
815 ots::Buffer subtable(data, length);
816
817 uint16_t offset_coverage = 0;
818 uint16_t chain_rule_set_count = 0;
819 // Skip format field.
820 if (!subtable.Skip(2) ||
821 !subtable.ReadU16(&offset_coverage) ||
822 !subtable.ReadU16(&chain_rule_set_count)) {
823 return OTS_FAILURE();
824 }
825
bashi@chromium.org26afae82011-08-25 05:38:57 +0000826 const unsigned chain_rule_set_end =
827 2 * static_cast<unsigned>(chain_rule_set_count) + 6;
bashi@chromium.orgced71122011-02-17 10:23:47 +0000828 if (chain_rule_set_end > std::numeric_limits<uint16_t>::max()) {
829 return OTS_FAILURE();
830 }
831 if (offset_coverage < chain_rule_set_end || offset_coverage >= length) {
832 return OTS_FAILURE();
833 }
834 if (!ots::ParseCoverageTable(data + offset_coverage,
835 length - offset_coverage, num_glyphs)) {
836 return OTS_FAILURE();
837 }
838
839 for (unsigned i = 0; i < chain_rule_set_count; ++i) {
840 uint16_t offset_chain_rule_set = 0;
841 if (!subtable.ReadU16(&offset_chain_rule_set)) {
842 return OTS_FAILURE();
843 }
844 if (offset_chain_rule_set < chain_rule_set_end ||
845 offset_chain_rule_set >= length) {
846 return OTS_FAILURE();
847 }
848 if (!ParseChainRuleSetTable(data + offset_chain_rule_set,
849 length - offset_chain_rule_set,
850 num_glyphs, num_lookups)) {
851 return OTS_FAILURE();
852 }
853 }
854
855 return true;
856}
857
858bool ParseChainClassRuleSubtable(const uint8_t *data, const size_t length,
859 const uint16_t num_glyphs,
860 const uint16_t num_lookups) {
861 ots::Buffer subtable(data, length);
862
863 // In this subtable, we don't check the value of classes for now since
864 // these could take arbitrary values.
865
866 uint16_t backtrack_count = 0;
867 if (!subtable.ReadU16(&backtrack_count)) {
868 return OTS_FAILURE();
869 }
870 if (backtrack_count >= num_glyphs) {
871 return OTS_FAILURE();
872 }
873 if (!subtable.Skip(2 * backtrack_count)) {
874 return OTS_FAILURE();
875 }
876
877 uint16_t input_count = 0;
878 if (!subtable.ReadU16(&input_count)) {
879 return OTS_FAILURE();
880 }
881 if (input_count == 0 || input_count >= num_glyphs) {
882 return OTS_FAILURE();
883 }
884 if (!subtable.Skip(2 * (input_count - 1))) {
885 return OTS_FAILURE();
886 }
887
888 uint16_t lookahead_count = 0;
889 if (!subtable.ReadU16(&lookahead_count)) {
890 return OTS_FAILURE();
891 }
892 if (lookahead_count >= num_glyphs) {
893 return OTS_FAILURE();
894 }
895 if (!subtable.Skip(2 * lookahead_count)) {
896 return OTS_FAILURE();
897 }
898
899 uint16_t lookup_count = 0;
900 if (!subtable.ReadU16(&lookup_count)) {
901 return OTS_FAILURE();
902 }
903 for (unsigned i = 0; i < lookup_count; ++i) {
904 if (!ParseLookupRecord(&subtable, num_glyphs, num_lookups)) {
905 return OTS_FAILURE();
906 }
907 }
908
909 return true;
910}
911
912bool ParseChainClassSetTable(const uint8_t *data, const size_t length,
913 const uint16_t num_glyphs,
914 const uint16_t num_lookups) {
915 ots::Buffer subtable(data, length);
916
917 uint16_t chain_class_rule_count = 0;
918 if (!subtable.ReadU16(&chain_class_rule_count)) {
919 return OTS_FAILURE();
920 }
bashi@chromium.org26afae82011-08-25 05:38:57 +0000921 const unsigned chain_class_rule_end =
922 2 * static_cast<unsigned>(chain_class_rule_count) + 2;
bashi@chromium.orgced71122011-02-17 10:23:47 +0000923 if (chain_class_rule_end > std::numeric_limits<uint16_t>::max()) {
924 return OTS_FAILURE();
925 }
926 for (unsigned i = 0; i < chain_class_rule_count; ++i) {
927 uint16_t offset_chain_class_rule = 0;
928 if (!subtable.ReadU16(&offset_chain_class_rule)) {
929 return OTS_FAILURE();
930 }
931 if (offset_chain_class_rule < chain_class_rule_end ||
932 offset_chain_class_rule >= length) {
933 return OTS_FAILURE();
934 }
935 if (!ParseChainClassRuleSubtable(data + offset_chain_class_rule,
936 length - offset_chain_class_rule,
937 num_glyphs, num_lookups)) {
938 return OTS_FAILURE();
939 }
940 }
941
942 return true;
943}
944
945bool ParseChainContextFormat2(const uint8_t *data, const size_t length,
946 const uint16_t num_glyphs,
947 const uint16_t num_lookups) {
948 ots::Buffer subtable(data, length);
949
950 uint16_t offset_coverage = 0;
951 uint16_t offset_backtrack_class_def = 0;
952 uint16_t offset_input_class_def = 0;
953 uint16_t offset_lookahead_class_def = 0;
954 uint16_t chain_class_set_count = 0;
955 // Skip format field.
956 if (!subtable.Skip(2) ||
957 !subtable.ReadU16(&offset_coverage) ||
958 !subtable.ReadU16(&offset_backtrack_class_def) ||
959 !subtable.ReadU16(&offset_input_class_def) ||
960 !subtable.ReadU16(&offset_lookahead_class_def) ||
961 !subtable.ReadU16(&chain_class_set_count)) {
962 return OTS_FAILURE();
963 }
964
bashi@chromium.org26afae82011-08-25 05:38:57 +0000965 const unsigned chain_class_set_end =
966 2 * static_cast<unsigned>(chain_class_set_count) + 12;
bashi@chromium.orgced71122011-02-17 10:23:47 +0000967 if (chain_class_set_end > std::numeric_limits<uint16_t>::max()) {
968 return OTS_FAILURE();
969 }
970 if (offset_coverage < chain_class_set_end || offset_coverage >= length) {
971 return OTS_FAILURE();
972 }
973 if (!ots::ParseCoverageTable(data + offset_coverage,
974 length - offset_coverage, num_glyphs)) {
975 return OTS_FAILURE();
976 }
977
978 // Classes for backtrack/lookahead sequences might not be defined.
979 if (offset_backtrack_class_def) {
980 if (offset_backtrack_class_def < chain_class_set_end ||
981 offset_backtrack_class_def >= length) {
982 return OTS_FAILURE();
983 }
984 if (!ots::ParseClassDefTable(data + offset_backtrack_class_def,
985 length - offset_backtrack_class_def,
986 num_glyphs, kMaxClassDefValue)) {
987 return OTS_FAILURE();
988 }
989 }
990
991 if (offset_input_class_def < chain_class_set_end ||
992 offset_input_class_def >= length) {
993 return OTS_FAILURE();
994 }
995 if (!ots::ParseClassDefTable(data + offset_input_class_def,
996 length - offset_input_class_def,
997 num_glyphs, kMaxClassDefValue)) {
998 return OTS_FAILURE();
999 }
1000
1001 if (offset_lookahead_class_def) {
1002 if (offset_lookahead_class_def < chain_class_set_end ||
1003 offset_lookahead_class_def >= length) {
1004 return OTS_FAILURE();
1005 }
1006 if (!ots::ParseClassDefTable(data + offset_lookahead_class_def,
1007 length - offset_lookahead_class_def,
1008 num_glyphs, kMaxClassDefValue)) {
1009 return OTS_FAILURE();
1010 }
1011 }
1012
1013 for (unsigned i = 0; i < chain_class_set_count; ++i) {
1014 uint16_t offset_chain_class_set = 0;
1015 if (!subtable.ReadU16(&offset_chain_class_set)) {
1016 return OTS_FAILURE();
1017 }
1018 // |offset_chain_class_set| could be NULL.
1019 if (offset_chain_class_set) {
1020 if (offset_chain_class_set < chain_class_set_end ||
1021 offset_chain_class_set >= length) {
1022 return OTS_FAILURE();
1023 }
1024 if (!ParseChainClassSetTable(data + offset_chain_class_set,
1025 length - offset_chain_class_set,
1026 num_glyphs, num_lookups)) {
1027 return OTS_FAILURE();
1028 }
1029 }
1030 }
1031
1032 return true;
1033}
1034
1035bool ParseChainContextFormat3(const uint8_t *data, const size_t length,
1036 const uint16_t num_glyphs,
1037 const uint16_t num_lookups) {
1038 ots::Buffer subtable(data, length);
1039
1040 uint16_t backtrack_count = 0;
1041 // Skip format field.
1042 if (!subtable.Skip(2) ||
1043 !subtable.ReadU16(&backtrack_count)) {
1044 return OTS_FAILURE();
1045 }
1046
1047 if (backtrack_count >= num_glyphs) {
1048 return OTS_FAILURE();
1049 }
1050 std::vector<uint16_t> offsets_backtrack;
1051 offsets_backtrack.reserve(backtrack_count);
1052 for (unsigned i = 0; i < backtrack_count; ++i) {
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001053 uint16_t offset = 0;
1054 if (!subtable.ReadU16(&offset)) {
bashi@chromium.orgced71122011-02-17 10:23:47 +00001055 return OTS_FAILURE();
1056 }
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001057 offsets_backtrack.push_back(offset);
bashi@chromium.orgced71122011-02-17 10:23:47 +00001058 }
bashi@chromium.org6b410202011-02-23 04:12:49 +00001059 if (offsets_backtrack.size() != backtrack_count) {
1060 return OTS_FAILURE();
1061 }
bashi@chromium.orgced71122011-02-17 10:23:47 +00001062
1063 uint16_t input_count = 0;
1064 if (!subtable.ReadU16(&input_count)) {
1065 return OTS_FAILURE();
1066 }
1067 if (input_count >= num_glyphs) {
1068 return OTS_FAILURE();
1069 }
1070 std::vector<uint16_t> offsets_input;
1071 offsets_input.reserve(input_count);
1072 for (unsigned i = 0; i < input_count; ++i) {
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001073 uint16_t offset = 0;
1074 if (!subtable.ReadU16(&offset)) {
bashi@chromium.orgced71122011-02-17 10:23:47 +00001075 return OTS_FAILURE();
1076 }
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001077 offsets_input.push_back(offset);
bashi@chromium.orgced71122011-02-17 10:23:47 +00001078 }
bashi@chromium.org6b410202011-02-23 04:12:49 +00001079 if (offsets_input.size() != input_count) {
1080 return OTS_FAILURE();
1081 }
bashi@chromium.orgced71122011-02-17 10:23:47 +00001082
1083 uint16_t lookahead_count = 0;
1084 if (!subtable.ReadU16(&lookahead_count)) {
1085 return OTS_FAILURE();
1086 }
1087 if (lookahead_count >= num_glyphs) {
1088 return OTS_FAILURE();
1089 }
1090 std::vector<uint16_t> offsets_lookahead;
1091 offsets_lookahead.reserve(lookahead_count);
1092 for (unsigned i = 0; i < lookahead_count; ++i) {
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001093 uint16_t offset = 0;
1094 if (!subtable.ReadU16(&offset)) {
bashi@chromium.orgced71122011-02-17 10:23:47 +00001095 return OTS_FAILURE();
1096 }
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001097 offsets_lookahead.push_back(offset);
bashi@chromium.orgced71122011-02-17 10:23:47 +00001098 }
bashi@chromium.org6b410202011-02-23 04:12:49 +00001099 if (offsets_lookahead.size() != lookahead_count) {
1100 return OTS_FAILURE();
1101 }
bashi@chromium.orgced71122011-02-17 10:23:47 +00001102
1103 uint16_t lookup_count = 0;
1104 if (!subtable.ReadU16(&lookup_count)) {
1105 return OTS_FAILURE();
1106 }
1107 for (unsigned i = 0; i < lookup_count; ++i) {
1108 if (!ParseLookupRecord(&subtable, num_glyphs, num_lookups)) {
1109 return OTS_FAILURE();
1110 }
1111 }
1112
bashi@chromium.org26afae82011-08-25 05:38:57 +00001113 const unsigned lookup_record_end =
1114 2 * (static_cast<unsigned>(backtrack_count) +
1115 static_cast<unsigned>(input_count) +
1116 static_cast<unsigned>(lookahead_count)) +
1117 4 * static_cast<unsigned>(lookup_count) + 10;
bashi@chromium.orgced71122011-02-17 10:23:47 +00001118 if (lookup_record_end > std::numeric_limits<uint16_t>::max()) {
1119 return OTS_FAILURE();
1120 }
1121 for (unsigned i = 0; i < backtrack_count; ++i) {
1122 if (offsets_backtrack[i] < lookup_record_end ||
1123 offsets_backtrack[i] >= length) {
1124 return OTS_FAILURE();
1125 }
1126 if (!ots::ParseCoverageTable(data + offsets_backtrack[i],
1127 length - offsets_backtrack[i], num_glyphs)) {
1128 return OTS_FAILURE();
1129 }
1130 }
1131 for (unsigned i = 0; i < input_count; ++i) {
1132 if (offsets_input[i] < lookup_record_end || offsets_input[i] >= length) {
1133 return OTS_FAILURE();
1134 }
1135 if (!ots::ParseCoverageTable(data + offsets_input[i],
1136 length - offsets_input[i], num_glyphs)) {
1137 return OTS_FAILURE();
1138 }
1139 }
1140 for (unsigned i = 0; i < lookahead_count; ++i) {
1141 if (offsets_lookahead[i] < lookup_record_end ||
1142 offsets_lookahead[i] >= length) {
1143 return OTS_FAILURE();
1144 }
1145 if (!ots::ParseCoverageTable(data + offsets_lookahead[i],
1146 length - offsets_lookahead[i], num_glyphs)) {
1147 return OTS_FAILURE();
1148 }
1149 }
1150
1151 return true;
1152}
1153
bashi@google.com00b790a2011-01-27 06:35:42 +00001154} // namespace
1155
1156namespace ots {
1157
bashi@chromium.orgced71122011-02-17 10:23:47 +00001158bool LookupSubtableParser::Parse(const OpenTypeFile *file, const uint8_t *data,
1159 const size_t length,
1160 const uint16_t lookup_type) const {
1161 for (unsigned i = 0; i < num_types; ++i) {
1162 if (parsers[i].type == lookup_type && parsers[i].parse) {
1163 if (!parsers[i].parse(file, data, length)) {
1164 return OTS_FAILURE();
1165 }
1166 return true;
1167 }
1168 }
1169 return OTS_FAILURE();
1170}
1171
bashi@google.com78a8baa2011-02-07 06:21:25 +00001172// Parsing ScriptListTable requires number of features so we need to
1173// parse FeatureListTable before calling this function.
1174bool ParseScriptListTable(const uint8_t *data, const size_t length,
1175 const uint16_t num_features) {
1176 Buffer subtable(data, length);
1177
1178 uint16_t script_count = 0;
1179 if (!subtable.ReadU16(&script_count)) {
1180 return OTS_FAILURE();
1181 }
1182
bashi@chromium.org26afae82011-08-25 05:38:57 +00001183 const unsigned script_record_end =
1184 6 * static_cast<unsigned>(script_count) + 2;
bashi@google.com78a8baa2011-02-07 06:21:25 +00001185 if (script_record_end > std::numeric_limits<uint16_t>::max()) {
1186 return OTS_FAILURE();
1187 }
1188 std::vector<ScriptRecord> script_list;
1189 script_list.reserve(script_count);
1190 uint32_t last_tag = 0;
1191 for (unsigned i = 0; i < script_count; ++i) {
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001192 ScriptRecord record;
1193 if (!subtable.ReadU32(&record.tag) ||
1194 !subtable.ReadU16(&record.offset)) {
bashi@google.com78a8baa2011-02-07 06:21:25 +00001195 return OTS_FAILURE();
1196 }
1197 // Script tags should be arranged alphabetically by tag
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001198 if (last_tag != 0 && last_tag > record.tag) {
bashi@chromium.orga5748662011-03-18 17:48:29 +00001199 // Several fonts don't arrange tags alphabetically.
1200 // It seems that the order of tags might not be a security issue
1201 // so we just warn it.
1202 OTS_WARNING("tags aren't arranged alphabetically.");
bashi@google.com78a8baa2011-02-07 06:21:25 +00001203 }
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001204 last_tag = record.tag;
1205 if (record.offset < script_record_end || record.offset >= length) {
bashi@google.com78a8baa2011-02-07 06:21:25 +00001206 return OTS_FAILURE();
1207 }
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001208 script_list.push_back(record);
bashi@google.com78a8baa2011-02-07 06:21:25 +00001209 }
bashi@chromium.org6b410202011-02-23 04:12:49 +00001210 if (script_list.size() != script_count) {
1211 return OTS_FAILURE();
1212 }
bashi@google.com78a8baa2011-02-07 06:21:25 +00001213
1214 // Check script records.
1215 for (unsigned i = 0; i < script_count; ++i) {
1216 if (!ParseScriptTable(data + script_list[i].offset,
1217 length - script_list[i].offset,
1218 script_list[i].tag, num_features)) {
1219 return OTS_FAILURE();
1220 }
1221 }
1222
1223 return true;
1224}
1225
1226// Parsing FeatureListTable requires number of lookups so we need to parse
1227// LookupListTable before calling this function.
1228bool ParseFeatureListTable(const uint8_t *data, const size_t length,
1229 const uint16_t num_lookups,
1230 uint16_t* num_features) {
1231 Buffer subtable(data, length);
1232
1233 uint16_t feature_count = 0;
1234 if (!subtable.ReadU16(&feature_count)) {
1235 return OTS_FAILURE();
1236 }
1237
1238 std::vector<FeatureRecord> feature_records;
1239 feature_records.resize(feature_count);
bashi@chromium.org26afae82011-08-25 05:38:57 +00001240 const unsigned feature_record_end =
1241 6 * static_cast<unsigned>(feature_count) + 2;
bashi@google.com78a8baa2011-02-07 06:21:25 +00001242 if (feature_record_end > std::numeric_limits<uint16_t>::max()) {
1243 return OTS_FAILURE();
1244 }
1245 uint32_t last_tag = 0;
1246 for (unsigned i = 0; i < feature_count; ++i) {
1247 if (!subtable.ReadU32(&feature_records[i].tag) ||
1248 !subtable.ReadU16(&feature_records[i].offset)) {
1249 return OTS_FAILURE();
1250 }
1251 // Feature record array should be arranged alphabetically by tag
1252 if (last_tag != 0 && last_tag > feature_records[i].tag) {
bashi@chromium.orga5748662011-03-18 17:48:29 +00001253 // Several fonts don't arrange tags alphabetically.
1254 // It seems that the order of tags might not be a security issue
1255 // so we just warn it.
1256 OTS_WARNING("tags aren't arranged alphabetically.");
bashi@google.com78a8baa2011-02-07 06:21:25 +00001257 }
1258 last_tag = feature_records[i].tag;
1259 if (feature_records[i].offset < feature_record_end ||
1260 feature_records[i].offset >= length) {
1261 return OTS_FAILURE();
1262 }
1263 }
1264
1265 for (unsigned i = 0; i < feature_count; ++i) {
1266 if (!ParseFeatureTable(data + feature_records[i].offset,
1267 length - feature_records[i].offset, num_lookups)) {
1268 return OTS_FAILURE();
1269 }
1270 }
1271 *num_features = feature_count;
1272 return true;
1273}
1274
1275// For parsing GPOS/GSUB tables, this function should be called at first to
1276// obtain the number of lookups because parsing FeatureTableList requires
1277// the number.
1278bool ParseLookupListTable(OpenTypeFile *file, const uint8_t *data,
bashi@chromium.orgced71122011-02-17 10:23:47 +00001279 const size_t length,
1280 const LookupSubtableParser* parser,
bashi@google.com78a8baa2011-02-07 06:21:25 +00001281 uint16_t *num_lookups) {
1282 Buffer subtable(data, length);
1283
1284 if (!subtable.ReadU16(num_lookups)) {
1285 return OTS_FAILURE();
1286 }
1287
1288 std::vector<uint16_t> lookups;
1289 lookups.reserve(*num_lookups);
bashi@chromium.org26afae82011-08-25 05:38:57 +00001290 const unsigned lookup_end =
1291 2 * static_cast<unsigned>(*num_lookups) + 2;
bashi@google.com78a8baa2011-02-07 06:21:25 +00001292 if (lookup_end > std::numeric_limits<uint16_t>::max()) {
1293 return OTS_FAILURE();
1294 }
1295 for (unsigned i = 0; i < *num_lookups; ++i) {
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001296 uint16_t offset = 0;
1297 if (!subtable.ReadU16(&offset)) {
bashi@google.com78a8baa2011-02-07 06:21:25 +00001298 return OTS_FAILURE();
1299 }
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001300 if (offset < lookup_end || offset >= length) {
bashi@google.com78a8baa2011-02-07 06:21:25 +00001301 return OTS_FAILURE();
1302 }
bashi@chromium.orge2b566a2011-02-23 00:22:24 +00001303 lookups.push_back(offset);
bashi@google.com78a8baa2011-02-07 06:21:25 +00001304 }
bashi@chromium.org6b410202011-02-23 04:12:49 +00001305 if (lookups.size() != *num_lookups) {
1306 return OTS_FAILURE();
1307 }
bashi@google.com78a8baa2011-02-07 06:21:25 +00001308
1309 for (unsigned i = 0; i < *num_lookups; ++i) {
1310 if (!ParseLookupTable(file, data + lookups[i], length - lookups[i],
bashi@chromium.orgced71122011-02-17 10:23:47 +00001311 parser)) {
bashi@google.com78a8baa2011-02-07 06:21:25 +00001312 return OTS_FAILURE();
1313 }
1314 }
1315
1316 return true;
1317}
1318
bashi@google.com00b790a2011-01-27 06:35:42 +00001319bool ParseClassDefTable(const uint8_t *data, size_t length,
1320 const uint16_t num_glyphs,
1321 const uint16_t num_classes) {
1322 Buffer subtable(data, length);
1323
1324 uint16_t format = 0;
1325 if (!subtable.ReadU16(&format)) {
1326 return OTS_FAILURE();
1327 }
1328 if (format == 1) {
1329 return ParseClassDefFormat1(data, length, num_glyphs, num_classes);
1330 } else if (format == 2) {
1331 return ParseClassDefFormat2(data, length, num_glyphs, num_classes);
1332 }
1333
1334 return OTS_FAILURE();
1335}
1336
1337bool ParseCoverageTable(const uint8_t *data, size_t length,
1338 const uint16_t num_glyphs) {
1339 Buffer subtable(data, length);
1340
1341 uint16_t format = 0;
1342 if (!subtable.ReadU16(&format)) {
1343 return OTS_FAILURE();
1344 }
1345 if (format == 1) {
1346 return ParseCoverageFormat1(data, length, num_glyphs);
1347 } else if (format == 2) {
1348 return ParseCoverageFormat2(data, length, num_glyphs);
1349 }
1350
1351 return OTS_FAILURE();
1352}
1353
bashi@google.com78a8baa2011-02-07 06:21:25 +00001354bool ParseDeviceTable(const uint8_t *data, size_t length) {
1355 Buffer subtable(data, length);
1356
1357 uint16_t start_size = 0;
1358 uint16_t end_size = 0;
1359 uint16_t delta_format = 0;
1360 if (!subtable.ReadU16(&start_size) ||
1361 !subtable.ReadU16(&end_size) ||
1362 !subtable.ReadU16(&delta_format)) {
1363 return OTS_FAILURE();
1364 }
1365 if (start_size > end_size) {
1366 OTS_WARNING("bad size range: %u > %u", start_size, end_size);
1367 return OTS_FAILURE();
1368 }
1369 if (delta_format == 0 || delta_format > kMaxDeltaFormatType) {
1370 OTS_WARNING("bad delta format: %u", delta_format);
1371 return OTS_FAILURE();
1372 }
1373 // The number of delta values per uint16. The device table should contain
1374 // at least |num_units| * 2 bytes compressed data.
1375 const unsigned num_units = (end_size - start_size) /
1376 (1 << (4 - delta_format)) + 1;
1377 // Just skip |num_units| * 2 bytes since the compressed data could take
1378 // arbitrary values.
1379 if (!subtable.Skip(num_units * 2)) {
1380 return OTS_FAILURE();
1381 }
1382 return true;
1383}
1384
bashi@chromium.orgced71122011-02-17 10:23:47 +00001385bool ParseContextSubtable(const uint8_t *data, const size_t length,
1386 const uint16_t num_glyphs,
1387 const uint16_t num_lookups) {
1388 Buffer subtable(data, length);
1389
1390 uint16_t format = 0;
1391 if (!subtable.ReadU16(&format)) {
1392 return OTS_FAILURE();
1393 }
1394
1395 if (format == 1) {
1396 if (!ParseContextFormat1(data, length, num_glyphs, num_lookups)) {
1397 return OTS_FAILURE();
1398 }
1399 } else if (format == 2) {
1400 if (!ParseContextFormat2(data, length, num_glyphs, num_lookups)) {
1401 return OTS_FAILURE();
1402 }
1403 } else if (format == 3) {
1404 if (!ParseContextFormat3(data, length, num_glyphs, num_lookups)) {
1405 return OTS_FAILURE();
1406 }
1407 } else {
1408 return OTS_FAILURE();
1409 }
1410
1411 return true;
1412}
1413
1414bool ParseChainingContextSubtable(const uint8_t *data, const size_t length,
1415 const uint16_t num_glyphs,
1416 const uint16_t num_lookups) {
1417 Buffer subtable(data, length);
1418
1419 uint16_t format = 0;
1420 if (!subtable.ReadU16(&format)) {
1421 return OTS_FAILURE();
1422 }
1423
1424 if (format == 1) {
1425 if (!ParseChainContextFormat1(data, length, num_glyphs, num_lookups)) {
1426 return OTS_FAILURE();
1427 }
1428 } else if (format == 2) {
1429 if (!ParseChainContextFormat2(data, length, num_glyphs, num_lookups)) {
1430 return OTS_FAILURE();
1431 }
1432 } else if (format == 3) {
1433 if (!ParseChainContextFormat3(data, length, num_glyphs, num_lookups)) {
1434 return OTS_FAILURE();
1435 }
1436 } else {
1437 return OTS_FAILURE();
1438 }
1439
1440 return true;
1441}
1442
1443bool ParseExtensionSubtable(const OpenTypeFile *file,
1444 const uint8_t *data, const size_t length,
1445 const LookupSubtableParser* parser) {
1446 Buffer subtable(data, length);
1447
1448 uint16_t format = 0;
1449 uint16_t lookup_type = 0;
1450 uint32_t offset_extension = 0;
1451 if (!subtable.ReadU16(&format) ||
1452 !subtable.ReadU16(&lookup_type) ||
1453 !subtable.ReadU32(&offset_extension)) {
1454 return OTS_FAILURE();
1455 }
1456
1457 if (format != 1) {
1458 return OTS_FAILURE();
1459 }
1460 // |lookup_type| should be other than |parser->extension_type|.
1461 if (lookup_type < 1 || lookup_type > parser->num_types ||
1462 lookup_type == parser->extension_type) {
1463 return OTS_FAILURE();
1464 }
1465
1466 const unsigned format_end = static_cast<unsigned>(8);
1467 if (offset_extension < format_end ||
1468 offset_extension >= length) {
1469 return OTS_FAILURE();
1470 }
1471
1472 // Parse the extension subtable of |lookup_type|.
1473 if (!parser->Parse(file, data + offset_extension, length - offset_extension,
1474 lookup_type)) {
1475 return OTS_FAILURE();
1476 }
1477
1478 return true;
1479}
1480
bashi@google.com00b790a2011-01-27 06:35:42 +00001481} // namespace ots
1482