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