| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "layout.h" | 5 #include "layout.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "gdef.h" | 10 #include "gdef.h" |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 struct LangSysRecord { | 39 struct LangSysRecord { |
| 40 uint32_t tag; | 40 uint32_t tag; |
| 41 uint16_t offset; | 41 uint16_t offset; |
| 42 }; | 42 }; |
| 43 | 43 |
| 44 struct FeatureRecord { | 44 struct FeatureRecord { |
| 45 uint32_t tag; | 45 uint32_t tag; |
| 46 uint16_t offset; | 46 uint16_t offset; |
| 47 }; | 47 }; |
| 48 | 48 |
| 49 bool ParseLangSysTable(const ots::OpenTypeFile *file, | 49 bool ParseLangSysTable(const ots::Font *font, |
| 50 ots::Buffer *subtable, const uint32_t tag, | 50 ots::Buffer *subtable, const uint32_t tag, |
| 51 const uint16_t num_features) { | 51 const uint16_t num_features) { |
| 52 uint16_t offset_lookup_order = 0; | 52 uint16_t offset_lookup_order = 0; |
| 53 uint16_t req_feature_index = 0; | 53 uint16_t req_feature_index = 0; |
| 54 uint16_t feature_count = 0; | 54 uint16_t feature_count = 0; |
| 55 if (!subtable->ReadU16(&offset_lookup_order) || | 55 if (!subtable->ReadU16(&offset_lookup_order) || |
| 56 !subtable->ReadU16(&req_feature_index) || | 56 !subtable->ReadU16(&req_feature_index) || |
| 57 !subtable->ReadU16(&feature_count)) { | 57 !subtable->ReadU16(&feature_count)) { |
| 58 return OTS_FAILURE_MSG("Failed to read langsys header for tag %4.4s", (char
*)&tag); | 58 return OTS_FAILURE_MSG("Failed to read langsys header for tag %c%c%c%c", OTS
_UNTAG(tag)); |
| 59 } | 59 } |
| 60 // |offset_lookup_order| is reserved and should be NULL. | 60 // |offset_lookup_order| is reserved and should be NULL. |
| 61 if (offset_lookup_order != 0) { | 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); | 62 return OTS_FAILURE_MSG("Bad lookup offset order %d for langsys tag %c%c%c%c"
, offset_lookup_order, OTS_UNTAG(tag)); |
| 63 } | 63 } |
| 64 if (req_feature_index != kNoRequiredFeatureIndexDefined && | 64 if (req_feature_index != kNoRequiredFeatureIndexDefined && |
| 65 req_feature_index >= num_features) { | 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); | 66 return OTS_FAILURE_MSG("Bad required features index %d for langsys tag %c%c%
c%c", req_feature_index, OTS_UNTAG(tag)); |
| 67 } | 67 } |
| 68 if (feature_count > num_features) { | 68 if (feature_count > num_features) { |
| 69 return OTS_FAILURE_MSG("Bad feature count %d for langsys tag %4.4s", feature
_count, (char *)&tag); | 69 return OTS_FAILURE_MSG("Bad feature count %d for langsys tag %c%c%c%c", feat
ure_count, OTS_UNTAG(tag)); |
| 70 } | 70 } |
| 71 | 71 |
| 72 for (unsigned i = 0; i < feature_count; ++i) { | 72 for (unsigned i = 0; i < feature_count; ++i) { |
| 73 uint16_t feature_index = 0; | 73 uint16_t feature_index = 0; |
| 74 if (!subtable->ReadU16(&feature_index)) { | 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); | 75 return OTS_FAILURE_MSG("Failed to read feature index %d for langsys tag %c
%c%c%c", i, OTS_UNTAG(tag)); |
| 76 } | 76 } |
| 77 if (feature_index >= num_features) { | 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); | 78 return OTS_FAILURE_MSG("Bad feature index %d for feature %d for langsys ta
g %c%c%c%c", feature_index, i, OTS_UNTAG(tag)); |
| 79 } | 79 } |
| 80 } | 80 } |
| 81 return true; | 81 return true; |
| 82 } | 82 } |
| 83 | 83 |
| 84 bool ParseScriptTable(const ots::OpenTypeFile *file, | 84 bool ParseScriptTable(const ots::Font *font, |
| 85 const uint8_t *data, const size_t length, | 85 const uint8_t *data, const size_t length, |
| 86 const uint32_t tag, const uint16_t num_features) { | 86 const uint32_t tag, const uint16_t num_features) { |
| 87 ots::Buffer subtable(data, length); | 87 ots::Buffer subtable(data, length); |
| 88 | 88 |
| 89 uint16_t offset_default_lang_sys = 0; | 89 uint16_t offset_default_lang_sys = 0; |
| 90 uint16_t lang_sys_count = 0; | 90 uint16_t lang_sys_count = 0; |
| 91 if (!subtable.ReadU16(&offset_default_lang_sys) || | 91 if (!subtable.ReadU16(&offset_default_lang_sys) || |
| 92 !subtable.ReadU16(&lang_sys_count)) { | 92 !subtable.ReadU16(&lang_sys_count)) { |
| 93 return OTS_FAILURE_MSG("Failed to read script header for script tag %4.4s",
(char *)&tag); | 93 return OTS_FAILURE_MSG("Failed to read script header for script tag %c%c%c%c
", OTS_UNTAG(tag)); |
| 94 } | 94 } |
| 95 | 95 |
| 96 // The spec requires a script table for 'DFLT' tag must contain non-NULL | 96 // The spec requires a script table for 'DFLT' tag must contain non-NULL |
| 97 // |offset_default_lang_sys| and |lang_sys_count| == 0 | 97 // |offset_default_lang_sys| and |lang_sys_count| == 0 |
| 98 if (tag == kScriptTableTagDflt && | 98 if (tag == kScriptTableTagDflt && |
| 99 (offset_default_lang_sys == 0 || lang_sys_count != 0)) { | 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); | 100 return OTS_FAILURE_MSG("DFLT table doesn't satisfy the spec. for script tag
%c%c%c%c", OTS_UNTAG(tag)); |
| 101 } | 101 } |
| 102 | 102 |
| 103 const unsigned lang_sys_record_end = | 103 const unsigned lang_sys_record_end = |
| 104 6 * static_cast<unsigned>(lang_sys_count) + 4; | 104 6 * static_cast<unsigned>(lang_sys_count) + 4; |
| 105 if (lang_sys_record_end > std::numeric_limits<uint16_t>::max()) { | 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); | 106 return OTS_FAILURE_MSG("Bad end of langsys record %d for script tag %c%c%c%c
", lang_sys_record_end, OTS_UNTAG(tag)); |
| 107 } | 107 } |
| 108 | 108 |
| 109 std::vector<LangSysRecord> lang_sys_records; | 109 std::vector<LangSysRecord> lang_sys_records; |
| 110 lang_sys_records.resize(lang_sys_count); | 110 lang_sys_records.resize(lang_sys_count); |
| 111 uint32_t last_tag = 0; | 111 uint32_t last_tag = 0; |
| 112 for (unsigned i = 0; i < lang_sys_count; ++i) { | 112 for (unsigned i = 0; i < lang_sys_count; ++i) { |
| 113 if (!subtable.ReadU32(&lang_sys_records[i].tag) || | 113 if (!subtable.ReadU32(&lang_sys_records[i].tag) || |
| 114 !subtable.ReadU16(&lang_sys_records[i].offset)) { | 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); | 115 return OTS_FAILURE_MSG("Failed to read langsys record header %d for script
tag %c%c%c%c", i, OTS_UNTAG(tag)); |
| 116 } | 116 } |
| 117 // The record array must store the records alphabetically by tag | 117 // The record array must store the records alphabetically by tag |
| 118 if (last_tag != 0 && last_tag > lang_sys_records[i].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); | 119 return OTS_FAILURE_MSG("Bad last tag %d for langsys record %d for script t
ag %c%c%c%c", last_tag, i, OTS_UNTAG(tag)); |
| 120 } | 120 } |
| 121 if (lang_sys_records[i].offset < lang_sys_record_end || | 121 if (lang_sys_records[i].offset < lang_sys_record_end || |
| 122 lang_sys_records[i].offset >= length) { | 122 lang_sys_records[i].offset >= length) { |
| 123 return OTS_FAILURE_MSG("bad offset to lang sys table: %x", | 123 return OTS_FAILURE_MSG("bad offset to lang sys table: %x", |
| 124 lang_sys_records[i].offset); | 124 lang_sys_records[i].offset); |
| 125 } | 125 } |
| 126 last_tag = lang_sys_records[i].tag; | 126 last_tag = lang_sys_records[i].tag; |
| 127 } | 127 } |
| 128 | 128 |
| 129 // Check lang sys tables | 129 // Check lang sys tables |
| 130 for (unsigned i = 0; i < lang_sys_count; ++i) { | 130 for (unsigned i = 0; i < lang_sys_count; ++i) { |
| 131 subtable.set_offset(lang_sys_records[i].offset); | 131 subtable.set_offset(lang_sys_records[i].offset); |
| 132 if (!ParseLangSysTable(file, &subtable, lang_sys_records[i].tag, num_feature
s)) { | 132 if (!ParseLangSysTable(font, &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); | 133 return OTS_FAILURE_MSG("Failed to parse langsys table %d (%c%c%c%c) for sc
ript tag %c%c%c%c", i, OTS_UNTAG(lang_sys_records[i].tag), OTS_UNTAG(tag)); |
| 134 } | 134 } |
| 135 } | 135 } |
| 136 | 136 |
| 137 return true; | 137 return true; |
| 138 } | 138 } |
| 139 | 139 |
| 140 bool ParseFeatureTable(const ots::OpenTypeFile *file, | 140 bool ParseFeatureTable(const ots::Font *font, |
| 141 const uint8_t *data, const size_t length, | 141 const uint8_t *data, const size_t length, |
| 142 const uint16_t num_lookups) { | 142 const uint16_t num_lookups) { |
| 143 ots::Buffer subtable(data, length); | 143 ots::Buffer subtable(data, length); |
| 144 | 144 |
| 145 uint16_t offset_feature_params = 0; | 145 uint16_t offset_feature_params = 0; |
| 146 uint16_t lookup_count = 0; | 146 uint16_t lookup_count = 0; |
| 147 if (!subtable.ReadU16(&offset_feature_params) || | 147 if (!subtable.ReadU16(&offset_feature_params) || |
| 148 !subtable.ReadU16(&lookup_count)) { | 148 !subtable.ReadU16(&lookup_count)) { |
| 149 return OTS_FAILURE_MSG("Failed to read feature table header"); | 149 return OTS_FAILURE_MSG("Failed to read feature table header"); |
| 150 } | 150 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 167 return OTS_FAILURE_MSG("Failed to read lookup index for lookup %d", i); | 167 return OTS_FAILURE_MSG("Failed to read lookup index for lookup %d", i); |
| 168 } | 168 } |
| 169 // lookup index starts with 0. | 169 // lookup index starts with 0. |
| 170 if (lookup_index >= num_lookups) { | 170 if (lookup_index >= num_lookups) { |
| 171 return OTS_FAILURE_MSG("Bad lookup index %d for lookup %d", lookup_index,
i); | 171 return OTS_FAILURE_MSG("Bad lookup index %d for lookup %d", lookup_index,
i); |
| 172 } | 172 } |
| 173 } | 173 } |
| 174 return true; | 174 return true; |
| 175 } | 175 } |
| 176 | 176 |
| 177 bool ParseLookupTable(ots::OpenTypeFile *file, const uint8_t *data, | 177 bool ParseLookupTable(ots::Font *font, const uint8_t *data, |
| 178 const size_t length, | 178 const size_t length, |
| 179 const ots::LookupSubtableParser* parser) { | 179 const ots::LookupSubtableParser* parser) { |
| 180 ots::Buffer subtable(data, length); | 180 ots::Buffer subtable(data, length); |
| 181 | 181 |
| 182 uint16_t lookup_type = 0; | 182 uint16_t lookup_type = 0; |
| 183 uint16_t lookup_flag = 0; | 183 uint16_t lookup_flag = 0; |
| 184 uint16_t subtable_count = 0; | 184 uint16_t subtable_count = 0; |
| 185 if (!subtable.ReadU16(&lookup_type) || | 185 if (!subtable.ReadU16(&lookup_type) || |
| 186 !subtable.ReadU16(&lookup_flag) || | 186 !subtable.ReadU16(&lookup_flag) || |
| 187 !subtable.ReadU16(&subtable_count)) { | 187 !subtable.ReadU16(&subtable_count)) { |
| 188 return OTS_FAILURE_MSG("Failed to read lookup table header"); | 188 return OTS_FAILURE_MSG("Failed to read lookup table header"); |
| 189 } | 189 } |
| 190 | 190 |
| 191 if (lookup_type == 0 || lookup_type > parser->num_types) { | 191 if (lookup_type == 0 || lookup_type > parser->num_types) { |
| 192 return OTS_FAILURE_MSG("Bad lookup type %d", lookup_type); | 192 return OTS_FAILURE_MSG("Bad lookup type %d", lookup_type); |
| 193 } | 193 } |
| 194 | 194 |
| 195 // Check lookup flags. | 195 // Check lookup flags. |
| 196 if ((lookup_flag & kGdefRequiredFlags) && | 196 if ((lookup_flag & kGdefRequiredFlags) && |
| 197 (!file->gdef || !file->gdef->has_glyph_class_def)) { | 197 (!font->gdef || !font->gdef->has_glyph_class_def)) { |
| 198 return OTS_FAILURE_MSG("Bad lookup flags %d", lookup_flag); | 198 return OTS_FAILURE_MSG("Bad lookup flags %d", lookup_flag); |
| 199 } | 199 } |
| 200 if ((lookup_flag & kMarkAttachmentTypeMask) && | 200 if ((lookup_flag & kMarkAttachmentTypeMask) && |
| 201 (!file->gdef || !file->gdef->has_mark_attachment_class_def)) { | 201 (!font->gdef || !font->gdef->has_mark_attachment_class_def)) { |
| 202 return OTS_FAILURE_MSG("lookup flag asks for mark attachment that is bad %d"
, lookup_flag); | 202 return OTS_FAILURE_MSG("lookup flag asks for mark attachment that is bad %d"
, lookup_flag); |
| 203 } | 203 } |
| 204 bool use_mark_filtering_set = false; | 204 bool use_mark_filtering_set = false; |
| 205 if (lookup_flag & kUseMarkFilteringSetBit) { | 205 if (lookup_flag & kUseMarkFilteringSetBit) { |
| 206 if (!file->gdef || !file->gdef->has_mark_glyph_sets_def) { | 206 if (!font->gdef || !font->gdef->has_mark_glyph_sets_def) { |
| 207 return OTS_FAILURE_MSG("lookup flag asks for mark filtering that is bad %d
", lookup_flag); | 207 return OTS_FAILURE_MSG("lookup flag asks for mark filtering that is bad %d
", lookup_flag); |
| 208 } | 208 } |
| 209 use_mark_filtering_set = true; | 209 use_mark_filtering_set = true; |
| 210 } | 210 } |
| 211 | 211 |
| 212 std::vector<uint16_t> subtables; | 212 std::vector<uint16_t> subtables; |
| 213 subtables.reserve(subtable_count); | 213 subtables.reserve(subtable_count); |
| 214 // If the |kUseMarkFilteringSetBit| of |lookup_flag| is set, | 214 // If the |kUseMarkFilteringSetBit| of |lookup_flag| is set, |
| 215 // extra 2 bytes will follow after subtable offset array. | 215 // extra 2 bytes will follow after subtable offset array. |
| 216 const unsigned lookup_table_end = 2 * static_cast<unsigned>(subtable_count) + | 216 const unsigned lookup_table_end = 2 * static_cast<unsigned>(subtable_count) + |
| (...skipping 14 matching lines...) Expand all Loading... |
| 231 } | 231 } |
| 232 if (subtables.size() != subtable_count) { | 232 if (subtables.size() != subtable_count) { |
| 233 return OTS_FAILURE_MSG("Bad subtable size %ld", subtables.size()); | 233 return OTS_FAILURE_MSG("Bad subtable size %ld", subtables.size()); |
| 234 } | 234 } |
| 235 | 235 |
| 236 if (use_mark_filtering_set) { | 236 if (use_mark_filtering_set) { |
| 237 uint16_t mark_filtering_set = 0; | 237 uint16_t mark_filtering_set = 0; |
| 238 if (!subtable.ReadU16(&mark_filtering_set)) { | 238 if (!subtable.ReadU16(&mark_filtering_set)) { |
| 239 return OTS_FAILURE_MSG("Failed to read mark filtering set"); | 239 return OTS_FAILURE_MSG("Failed to read mark filtering set"); |
| 240 } | 240 } |
| 241 if (file->gdef->num_mark_glyph_sets == 0 || | 241 if (font->gdef->num_mark_glyph_sets == 0 || |
| 242 mark_filtering_set >= file->gdef->num_mark_glyph_sets) { | 242 mark_filtering_set >= font->gdef->num_mark_glyph_sets) { |
| 243 return OTS_FAILURE_MSG("Bad mark filtering set %d", mark_filtering_set); | 243 return OTS_FAILURE_MSG("Bad mark filtering set %d", mark_filtering_set); |
| 244 } | 244 } |
| 245 } | 245 } |
| 246 | 246 |
| 247 // Parse lookup subtables for this lookup type. | 247 // Parse lookup subtables for this lookup type. |
| 248 for (unsigned i = 0; i < subtable_count; ++i) { | 248 for (unsigned i = 0; i < subtable_count; ++i) { |
| 249 if (!parser->Parse(file, data + subtables[i], length - subtables[i], | 249 if (!parser->Parse(font, data + subtables[i], length - subtables[i], |
| 250 lookup_type)) { | 250 lookup_type)) { |
| 251 return OTS_FAILURE_MSG("Failed to parse subtable %d", i); | 251 return OTS_FAILURE_MSG("Failed to parse subtable %d", i); |
| 252 } | 252 } |
| 253 } | 253 } |
| 254 return true; | 254 return true; |
| 255 } | 255 } |
| 256 | 256 |
| 257 bool ParseClassDefFormat1(const ots::OpenTypeFile *file, | 257 bool ParseClassDefFormat1(const ots::Font *font, |
| 258 const uint8_t *data, size_t length, | 258 const uint8_t *data, size_t length, |
| 259 const uint16_t num_glyphs, | 259 const uint16_t num_glyphs, |
| 260 const uint16_t num_classes) { | 260 const uint16_t num_classes) { |
| 261 ots::Buffer subtable(data, length); | 261 ots::Buffer subtable(data, length); |
| 262 | 262 |
| 263 // Skip format field. | 263 // Skip format field. |
| 264 if (!subtable.Skip(2)) { | 264 if (!subtable.Skip(2)) { |
| 265 return OTS_FAILURE_MSG("Failed to skip class definition header"); | 265 return OTS_FAILURE_MSG("Failed to skip class definition header"); |
| 266 } | 266 } |
| 267 | 267 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 286 return OTS_FAILURE_MSG("Failed to read class value for glyph %d in class d
efinition", i); | 286 return OTS_FAILURE_MSG("Failed to read class value for glyph %d in class d
efinition", i); |
| 287 } | 287 } |
| 288 if (class_value > num_classes) { | 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); | 289 return OTS_FAILURE_MSG("Bad class value %d for glyph %d in class definitio
n", class_value, i); |
| 290 } | 290 } |
| 291 } | 291 } |
| 292 | 292 |
| 293 return true; | 293 return true; |
| 294 } | 294 } |
| 295 | 295 |
| 296 bool ParseClassDefFormat2(const ots::OpenTypeFile *file, | 296 bool ParseClassDefFormat2(const ots::Font *font, |
| 297 const uint8_t *data, size_t length, | 297 const uint8_t *data, size_t length, |
| 298 const uint16_t num_glyphs, | 298 const uint16_t num_glyphs, |
| 299 const uint16_t num_classes) { | 299 const uint16_t num_classes) { |
| 300 ots::Buffer subtable(data, length); | 300 ots::Buffer subtable(data, length); |
| 301 | 301 |
| 302 // Skip format field. | 302 // Skip format field. |
| 303 if (!subtable.Skip(2)) { | 303 if (!subtable.Skip(2)) { |
| 304 return OTS_FAILURE_MSG("Failed to skip format of class defintion header"); | 304 return OTS_FAILURE_MSG("Failed to skip format of class defintion header"); |
| 305 } | 305 } |
| 306 | 306 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 327 } | 327 } |
| 328 if (class_value > num_classes) { | 328 if (class_value > num_classes) { |
| 329 return OTS_FAILURE_MSG("bad class value: %u", class_value); | 329 return OTS_FAILURE_MSG("bad class value: %u", class_value); |
| 330 } | 330 } |
| 331 last_end = end; | 331 last_end = end; |
| 332 } | 332 } |
| 333 | 333 |
| 334 return true; | 334 return true; |
| 335 } | 335 } |
| 336 | 336 |
| 337 bool ParseCoverageFormat1(const ots::OpenTypeFile *file, | 337 bool ParseCoverageFormat1(const ots::Font *font, |
| 338 const uint8_t *data, size_t length, | 338 const uint8_t *data, size_t length, |
| 339 const uint16_t num_glyphs, | 339 const uint16_t num_glyphs, |
| 340 const uint16_t expected_num_glyphs) { | 340 const uint16_t expected_num_glyphs) { |
| 341 ots::Buffer subtable(data, length); | 341 ots::Buffer subtable(data, length); |
| 342 | 342 |
| 343 // Skip format field. | 343 // Skip format field. |
| 344 if (!subtable.Skip(2)) { | 344 if (!subtable.Skip(2)) { |
| 345 return OTS_FAILURE_MSG("Failed to skip coverage format"); | 345 return OTS_FAILURE_MSG("Failed to skip coverage format"); |
| 346 } | 346 } |
| 347 | 347 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 362 } | 362 } |
| 363 } | 363 } |
| 364 | 364 |
| 365 if (expected_num_glyphs && expected_num_glyphs != glyph_count) { | 365 if (expected_num_glyphs && expected_num_glyphs != glyph_count) { |
| 366 return OTS_FAILURE_MSG("unexpected number of glyphs: %u", glyph_count); | 366 return OTS_FAILURE_MSG("unexpected number of glyphs: %u", glyph_count); |
| 367 } | 367 } |
| 368 | 368 |
| 369 return true; | 369 return true; |
| 370 } | 370 } |
| 371 | 371 |
| 372 bool ParseCoverageFormat2(const ots::OpenTypeFile *file, | 372 bool ParseCoverageFormat2(const ots::Font *font, |
| 373 const uint8_t *data, size_t length, | 373 const uint8_t *data, size_t length, |
| 374 const uint16_t num_glyphs, | 374 const uint16_t num_glyphs, |
| 375 const uint16_t expected_num_glyphs) { | 375 const uint16_t expected_num_glyphs) { |
| 376 ots::Buffer subtable(data, length); | 376 ots::Buffer subtable(data, length); |
| 377 | 377 |
| 378 // Skip format field. | 378 // Skip format field. |
| 379 if (!subtable.Skip(2)) { | 379 if (!subtable.Skip(2)) { |
| 380 return OTS_FAILURE_MSG("Failed to skip format of coverage type 2"); | 380 return OTS_FAILURE_MSG("Failed to skip format of coverage type 2"); |
| 381 } | 381 } |
| 382 | 382 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 416 if (expected_num_glyphs && | 416 if (expected_num_glyphs && |
| 417 expected_num_glyphs != last_start_coverage_index) { | 417 expected_num_glyphs != last_start_coverage_index) { |
| 418 return OTS_FAILURE_MSG("unexpected number of glyphs: %u", last_start_cover
age_index); | 418 return OTS_FAILURE_MSG("unexpected number of glyphs: %u", last_start_cover
age_index); |
| 419 } | 419 } |
| 420 | 420 |
| 421 return true; | 421 return true; |
| 422 } | 422 } |
| 423 | 423 |
| 424 // Parsers for Contextual subtables in GSUB/GPOS tables. | 424 // Parsers for Contextual subtables in GSUB/GPOS tables. |
| 425 | 425 |
| 426 bool ParseLookupRecord(const ots::OpenTypeFile *file, | 426 bool ParseLookupRecord(const ots::Font *font, |
| 427 ots::Buffer *subtable, const uint16_t num_glyphs, | 427 ots::Buffer *subtable, const uint16_t num_glyphs, |
| 428 const uint16_t num_lookups) { | 428 const uint16_t num_lookups) { |
| 429 uint16_t sequence_index = 0; | 429 uint16_t sequence_index = 0; |
| 430 uint16_t lookup_list_index = 0; | 430 uint16_t lookup_list_index = 0; |
| 431 if (!subtable->ReadU16(&sequence_index) || | 431 if (!subtable->ReadU16(&sequence_index) || |
| 432 !subtable->ReadU16(&lookup_list_index)) { | 432 !subtable->ReadU16(&lookup_list_index)) { |
| 433 return OTS_FAILURE_MSG("Failed to read header for lookup record"); | 433 return OTS_FAILURE_MSG("Failed to read header for lookup record"); |
| 434 } | 434 } |
| 435 if (sequence_index >= num_glyphs) { | 435 if (sequence_index >= num_glyphs) { |
| 436 return OTS_FAILURE_MSG("Bad sequence index %d in lookup record", sequence_in
dex); | 436 return OTS_FAILURE_MSG("Bad sequence index %d in lookup record", sequence_in
dex); |
| 437 } | 437 } |
| 438 if (lookup_list_index >= num_lookups) { | 438 if (lookup_list_index >= num_lookups) { |
| 439 return OTS_FAILURE_MSG("Bad lookup list index %d in lookup record", lookup_l
ist_index); | 439 return OTS_FAILURE_MSG("Bad lookup list index %d in lookup record", lookup_l
ist_index); |
| 440 } | 440 } |
| 441 return true; | 441 return true; |
| 442 } | 442 } |
| 443 | 443 |
| 444 bool ParseRuleSubtable(const ots::OpenTypeFile *file, | 444 bool ParseRuleSubtable(const ots::Font *font, |
| 445 const uint8_t *data, const size_t length, | 445 const uint8_t *data, const size_t length, |
| 446 const uint16_t num_glyphs, | 446 const uint16_t num_glyphs, |
| 447 const uint16_t num_lookups) { | 447 const uint16_t num_lookups) { |
| 448 ots::Buffer subtable(data, length); | 448 ots::Buffer subtable(data, length); |
| 449 | 449 |
| 450 uint16_t glyph_count = 0; | 450 uint16_t glyph_count = 0; |
| 451 uint16_t lookup_count = 0; | 451 uint16_t lookup_count = 0; |
| 452 if (!subtable.ReadU16(&glyph_count) || | 452 if (!subtable.ReadU16(&glyph_count) || |
| 453 !subtable.ReadU16(&lookup_count)) { | 453 !subtable.ReadU16(&lookup_count)) { |
| 454 return OTS_FAILURE_MSG("Failed to read rule subtable header"); | 454 return OTS_FAILURE_MSG("Failed to read rule subtable header"); |
| 455 } | 455 } |
| 456 | 456 |
| 457 if (glyph_count == 0 || glyph_count >= num_glyphs) { | 457 if (glyph_count == 0 || glyph_count >= num_glyphs) { |
| 458 return OTS_FAILURE_MSG("Bad glyph count %d in rule subtable", glyph_count); | 458 return OTS_FAILURE_MSG("Bad glyph count %d in rule subtable", glyph_count); |
| 459 } | 459 } |
| 460 for (unsigned i = 0; i < glyph_count - static_cast<unsigned>(1); ++i) { | 460 for (unsigned i = 0; i < glyph_count - static_cast<unsigned>(1); ++i) { |
| 461 uint16_t glyph_id = 0; | 461 uint16_t glyph_id = 0; |
| 462 if (!subtable.ReadU16(&glyph_id)) { | 462 if (!subtable.ReadU16(&glyph_id)) { |
| 463 return OTS_FAILURE_MSG("Failed to read glyph %d", i); | 463 return OTS_FAILURE_MSG("Failed to read glyph %d", i); |
| 464 } | 464 } |
| 465 if (glyph_id > num_glyphs) { | 465 if (glyph_id > num_glyphs) { |
| 466 return OTS_FAILURE_MSG("Bad glyph %d for entry %d", glyph_id, i); | 466 return OTS_FAILURE_MSG("Bad glyph %d for entry %d", glyph_id, i); |
| 467 } | 467 } |
| 468 } | 468 } |
| 469 | 469 |
| 470 for (unsigned i = 0; i < lookup_count; ++i) { | 470 for (unsigned i = 0; i < lookup_count; ++i) { |
| 471 if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) { | 471 if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) { |
| 472 return OTS_FAILURE_MSG("Failed to parse lookup record %d", i); | 472 return OTS_FAILURE_MSG("Failed to parse lookup record %d", i); |
| 473 } | 473 } |
| 474 } | 474 } |
| 475 return true; | 475 return true; |
| 476 } | 476 } |
| 477 | 477 |
| 478 bool ParseRuleSetTable(const ots::OpenTypeFile *file, | 478 bool ParseRuleSetTable(const ots::Font *font, |
| 479 const uint8_t *data, const size_t length, | 479 const uint8_t *data, const size_t length, |
| 480 const uint16_t num_glyphs, | 480 const uint16_t num_glyphs, |
| 481 const uint16_t num_lookups) { | 481 const uint16_t num_lookups) { |
| 482 ots::Buffer subtable(data, length); | 482 ots::Buffer subtable(data, length); |
| 483 | 483 |
| 484 uint16_t rule_count = 0; | 484 uint16_t rule_count = 0; |
| 485 if (!subtable.ReadU16(&rule_count)) { | 485 if (!subtable.ReadU16(&rule_count)) { |
| 486 return OTS_FAILURE_MSG("Failed to read rule count in rule set"); | 486 return OTS_FAILURE_MSG("Failed to read rule count in rule set"); |
| 487 } | 487 } |
| 488 const unsigned rule_end = 2 * static_cast<unsigned>(rule_count) + 2; | 488 const unsigned rule_end = 2 * static_cast<unsigned>(rule_count) + 2; |
| 489 if (rule_end > std::numeric_limits<uint16_t>::max()) { | 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); | 490 return OTS_FAILURE_MSG("Bad end of rule %d in rule set", rule_end); |
| 491 } | 491 } |
| 492 | 492 |
| 493 for (unsigned i = 0; i < rule_count; ++i) { | 493 for (unsigned i = 0; i < rule_count; ++i) { |
| 494 uint16_t offset_rule = 0; | 494 uint16_t offset_rule = 0; |
| 495 if (!subtable.ReadU16(&offset_rule)) { | 495 if (!subtable.ReadU16(&offset_rule)) { |
| 496 return OTS_FAILURE_MSG("Failed to read rule offset for rule set %d", i); | 496 return OTS_FAILURE_MSG("Failed to read rule offset for rule set %d", i); |
| 497 } | 497 } |
| 498 if (offset_rule < rule_end || offset_rule >= length) { | 498 if (offset_rule < rule_end || offset_rule >= length) { |
| 499 return OTS_FAILURE_MSG("Bad rule offset %d in set %d", offset_rule, i); | 499 return OTS_FAILURE_MSG("Bad rule offset %d in set %d", offset_rule, i); |
| 500 } | 500 } |
| 501 if (!ParseRuleSubtable(file, data + offset_rule, length - offset_rule, | 501 if (!ParseRuleSubtable(font, data + offset_rule, length - offset_rule, |
| 502 num_glyphs, num_lookups)) { | 502 num_glyphs, num_lookups)) { |
| 503 return OTS_FAILURE_MSG("Failed to parse rule set %d", i); | 503 return OTS_FAILURE_MSG("Failed to parse rule set %d", i); |
| 504 } | 504 } |
| 505 } | 505 } |
| 506 | 506 |
| 507 return true; | 507 return true; |
| 508 } | 508 } |
| 509 | 509 |
| 510 bool ParseContextFormat1(const ots::OpenTypeFile *file, | 510 bool ParseContextFormat1(const ots::Font *font, |
| 511 const uint8_t *data, const size_t length, | 511 const uint8_t *data, const size_t length, |
| 512 const uint16_t num_glyphs, | 512 const uint16_t num_glyphs, |
| 513 const uint16_t num_lookups) { | 513 const uint16_t num_lookups) { |
| 514 ots::Buffer subtable(data, length); | 514 ots::Buffer subtable(data, length); |
| 515 | 515 |
| 516 uint16_t offset_coverage = 0; | 516 uint16_t offset_coverage = 0; |
| 517 uint16_t rule_set_count = 0; | 517 uint16_t rule_set_count = 0; |
| 518 // Skip format field. | 518 // Skip format field. |
| 519 if (!subtable.Skip(2) || | 519 if (!subtable.Skip(2) || |
| 520 !subtable.ReadU16(&offset_coverage) || | 520 !subtable.ReadU16(&offset_coverage) || |
| 521 !subtable.ReadU16(&rule_set_count)) { | 521 !subtable.ReadU16(&rule_set_count)) { |
| 522 return OTS_FAILURE_MSG("Failed to read header of context format 1"); | 522 return OTS_FAILURE_MSG("Failed to read header of context format 1"); |
| 523 } | 523 } |
| 524 | 524 |
| 525 const unsigned rule_set_end = static_cast<unsigned>(6) + | 525 const unsigned rule_set_end = static_cast<unsigned>(6) + |
| 526 rule_set_count * 2; | 526 rule_set_count * 2; |
| 527 if (rule_set_end > std::numeric_limits<uint16_t>::max()) { | 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); | 528 return OTS_FAILURE_MSG("Bad end of rule set %d of context format 1", rule_se
t_end); |
| 529 } | 529 } |
| 530 if (offset_coverage < rule_set_end || offset_coverage >= length) { | 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); | 531 return OTS_FAILURE_MSG("Bad coverage offset %d in context format 1", offset_
coverage); |
| 532 } | 532 } |
| 533 if (!ots::ParseCoverageTable(file, data + offset_coverage, | 533 if (!ots::ParseCoverageTable(font, data + offset_coverage, |
| 534 length - offset_coverage, num_glyphs)) { | 534 length - offset_coverage, num_glyphs)) { |
| 535 return OTS_FAILURE_MSG("Failed to parse coverage table in context format 1")
; | 535 return OTS_FAILURE_MSG("Failed to parse coverage table in context format 1")
; |
| 536 } | 536 } |
| 537 | 537 |
| 538 for (unsigned i = 0; i < rule_set_count; ++i) { | 538 for (unsigned i = 0; i < rule_set_count; ++i) { |
| 539 uint16_t offset_rule = 0; | 539 uint16_t offset_rule = 0; |
| 540 if (!subtable.ReadU16(&offset_rule)) { | 540 if (!subtable.ReadU16(&offset_rule)) { |
| 541 return OTS_FAILURE_MSG("Failed to read rule offset %d in context format 1"
, i); | 541 return OTS_FAILURE_MSG("Failed to read rule offset %d in context format 1"
, i); |
| 542 } | 542 } |
| 543 if (offset_rule < rule_set_end || offset_rule >= length) { | 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); | 544 return OTS_FAILURE_MSG("Bad rule offset %d in rule %d in context format 1"
, offset_rule, i); |
| 545 } | 545 } |
| 546 if (!ParseRuleSetTable(file, data + offset_rule, length - offset_rule, | 546 if (!ParseRuleSetTable(font, data + offset_rule, length - offset_rule, |
| 547 num_glyphs, num_lookups)) { | 547 num_glyphs, num_lookups)) { |
| 548 return OTS_FAILURE_MSG("Failed to parse rule set %d in context format 1",
i); | 548 return OTS_FAILURE_MSG("Failed to parse rule set %d in context format 1",
i); |
| 549 } | 549 } |
| 550 } | 550 } |
| 551 | 551 |
| 552 return true; | 552 return true; |
| 553 } | 553 } |
| 554 | 554 |
| 555 bool ParseClassRuleTable(const ots::OpenTypeFile *file, | 555 bool ParseClassRuleTable(const ots::Font *font, |
| 556 const uint8_t *data, const size_t length, | 556 const uint8_t *data, const size_t length, |
| 557 const uint16_t num_glyphs, | 557 const uint16_t num_glyphs, |
| 558 const uint16_t num_lookups) { | 558 const uint16_t num_lookups) { |
| 559 ots::Buffer subtable(data, length); | 559 ots::Buffer subtable(data, length); |
| 560 | 560 |
| 561 uint16_t glyph_count = 0; | 561 uint16_t glyph_count = 0; |
| 562 uint16_t lookup_count = 0; | 562 uint16_t lookup_count = 0; |
| 563 if (!subtable.ReadU16(&glyph_count) || | 563 if (!subtable.ReadU16(&glyph_count) || |
| 564 !subtable.ReadU16(&lookup_count)) { | 564 !subtable.ReadU16(&lookup_count)) { |
| 565 return OTS_FAILURE_MSG("Failed to read header of class rule table"); | 565 return OTS_FAILURE_MSG("Failed to read header of class rule table"); |
| 566 } | 566 } |
| 567 | 567 |
| 568 if (glyph_count == 0 || glyph_count >= num_glyphs) { | 568 if (glyph_count == 0 || glyph_count >= num_glyphs) { |
| 569 return OTS_FAILURE_MSG("Bad glyph count %d in class rule table", glyph_count
); | 569 return OTS_FAILURE_MSG("Bad glyph count %d in class rule table", glyph_count
); |
| 570 } | 570 } |
| 571 | 571 |
| 572 // ClassRule table contains an array of classes. Each value of classes | 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. | 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); | 574 const unsigned num_classes = glyph_count - static_cast<unsigned>(1); |
| 575 if (!subtable.Skip(2 * num_classes)) { | 575 if (!subtable.Skip(2 * num_classes)) { |
| 576 return OTS_FAILURE_MSG("Failed to skip classes in class rule table"); | 576 return OTS_FAILURE_MSG("Failed to skip classes in class rule table"); |
| 577 } | 577 } |
| 578 | 578 |
| 579 for (unsigned i = 0; i < lookup_count; ++i) { | 579 for (unsigned i = 0; i < lookup_count; ++i) { |
| 580 if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) { | 580 if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) { |
| 581 return OTS_FAILURE_MSG("Failed to parse lookup record %d in class rule tab
le", i); | 581 return OTS_FAILURE_MSG("Failed to parse lookup record %d in class rule tab
le", i); |
| 582 } | 582 } |
| 583 } | 583 } |
| 584 return true; | 584 return true; |
| 585 } | 585 } |
| 586 | 586 |
| 587 bool ParseClassSetTable(const ots::OpenTypeFile *file, | 587 bool ParseClassSetTable(const ots::Font *font, |
| 588 const uint8_t *data, const size_t length, | 588 const uint8_t *data, const size_t length, |
| 589 const uint16_t num_glyphs, | 589 const uint16_t num_glyphs, |
| 590 const uint16_t num_lookups) { | 590 const uint16_t num_lookups) { |
| 591 ots::Buffer subtable(data, length); | 591 ots::Buffer subtable(data, length); |
| 592 | 592 |
| 593 uint16_t class_rule_count = 0; | 593 uint16_t class_rule_count = 0; |
| 594 if (!subtable.ReadU16(&class_rule_count)) { | 594 if (!subtable.ReadU16(&class_rule_count)) { |
| 595 return OTS_FAILURE_MSG("Failed to read class rule count in class set table")
; | 595 return OTS_FAILURE_MSG("Failed to read class rule count in class set table")
; |
| 596 } | 596 } |
| 597 const unsigned class_rule_end = | 597 const unsigned class_rule_end = |
| 598 2 * static_cast<unsigned>(class_rule_count) + 2; | 598 2 * static_cast<unsigned>(class_rule_count) + 2; |
| 599 if (class_rule_end > std::numeric_limits<uint16_t>::max()) { | 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); | 600 return OTS_FAILURE_MSG("bad class rule end %d in class set table", class_rul
e_end); |
| 601 } | 601 } |
| 602 for (unsigned i = 0; i < class_rule_count; ++i) { | 602 for (unsigned i = 0; i < class_rule_count; ++i) { |
| 603 uint16_t offset_class_rule = 0; | 603 uint16_t offset_class_rule = 0; |
| 604 if (!subtable.ReadU16(&offset_class_rule)) { | 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); | 605 return OTS_FAILURE_MSG("Failed to read class rule offset %d in class set t
able", i); |
| 606 } | 606 } |
| 607 if (offset_class_rule < class_rule_end || offset_class_rule >= length) { | 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); | 608 return OTS_FAILURE_MSG("Bad class rule offset %d in class %d", offset_clas
s_rule, i); |
| 609 } | 609 } |
| 610 if (!ParseClassRuleTable(file, data + offset_class_rule, | 610 if (!ParseClassRuleTable(font, data + offset_class_rule, |
| 611 length - offset_class_rule, num_glyphs, | 611 length - offset_class_rule, num_glyphs, |
| 612 num_lookups)) { | 612 num_lookups)) { |
| 613 return OTS_FAILURE_MSG("Failed to parse class rule table %d", i); | 613 return OTS_FAILURE_MSG("Failed to parse class rule table %d", i); |
| 614 } | 614 } |
| 615 } | 615 } |
| 616 | 616 |
| 617 return true; | 617 return true; |
| 618 } | 618 } |
| 619 | 619 |
| 620 bool ParseContextFormat2(const ots::OpenTypeFile *file, | 620 bool ParseContextFormat2(const ots::Font *font, |
| 621 const uint8_t *data, const size_t length, | 621 const uint8_t *data, const size_t length, |
| 622 const uint16_t num_glyphs, | 622 const uint16_t num_glyphs, |
| 623 const uint16_t num_lookups) { | 623 const uint16_t num_lookups) { |
| 624 ots::Buffer subtable(data, length); | 624 ots::Buffer subtable(data, length); |
| 625 | 625 |
| 626 uint16_t offset_coverage = 0; | 626 uint16_t offset_coverage = 0; |
| 627 uint16_t offset_class_def = 0; | 627 uint16_t offset_class_def = 0; |
| 628 uint16_t class_set_cnt = 0; | 628 uint16_t class_set_cnt = 0; |
| 629 // Skip format field. | 629 // Skip format field. |
| 630 if (!subtable.Skip(2) || | 630 if (!subtable.Skip(2) || |
| 631 !subtable.ReadU16(&offset_coverage) || | 631 !subtable.ReadU16(&offset_coverage) || |
| 632 !subtable.ReadU16(&offset_class_def) || | 632 !subtable.ReadU16(&offset_class_def) || |
| 633 !subtable.ReadU16(&class_set_cnt)) { | 633 !subtable.ReadU16(&class_set_cnt)) { |
| 634 return OTS_FAILURE_MSG("Failed to read header for context format 2"); | 634 return OTS_FAILURE_MSG("Failed to read header for context format 2"); |
| 635 } | 635 } |
| 636 | 636 |
| 637 const unsigned class_set_end = 2 * static_cast<unsigned>(class_set_cnt) + 8; | 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()) { | 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); | 639 return OTS_FAILURE_MSG("Bad end of class set %d for context format 2", class
_set_end); |
| 640 } | 640 } |
| 641 if (offset_coverage < class_set_end || offset_coverage >= length) { | 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); | 642 return OTS_FAILURE_MSG("Bad coverage offset %d in context format 2", offset_
coverage); |
| 643 } | 643 } |
| 644 if (!ots::ParseCoverageTable(file, data + offset_coverage, | 644 if (!ots::ParseCoverageTable(font, data + offset_coverage, |
| 645 length - offset_coverage, num_glyphs)) { | 645 length - offset_coverage, num_glyphs)) { |
| 646 return OTS_FAILURE_MSG("Failed to parse coverage table in context format 2")
; | 646 return OTS_FAILURE_MSG("Failed to parse coverage table in context format 2")
; |
| 647 } | 647 } |
| 648 | 648 |
| 649 if (offset_class_def < class_set_end || offset_class_def >= length) { | 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); | 650 return OTS_FAILURE_MSG("bad class definition offset %d in context format 2",
offset_class_def); |
| 651 } | 651 } |
| 652 if (!ots::ParseClassDefTable(file, data + offset_class_def, | 652 if (!ots::ParseClassDefTable(font, data + offset_class_def, |
| 653 length - offset_class_def, | 653 length - offset_class_def, |
| 654 num_glyphs, kMaxClassDefValue)) { | 654 num_glyphs, kMaxClassDefValue)) { |
| 655 return OTS_FAILURE_MSG("Failed to parse class definition table in context fo
rmat 2"); | 655 return OTS_FAILURE_MSG("Failed to parse class definition table in context fo
rmat 2"); |
| 656 } | 656 } |
| 657 | 657 |
| 658 for (unsigned i = 0; i < class_set_cnt; ++i) { | 658 for (unsigned i = 0; i < class_set_cnt; ++i) { |
| 659 uint16_t offset_class_rule = 0; | 659 uint16_t offset_class_rule = 0; |
| 660 if (!subtable.ReadU16(&offset_class_rule)) { | 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); | 661 return OTS_FAILURE_MSG("Failed to read class rule offset %d in context for
mat 2", i); |
| 662 } | 662 } |
| 663 if (offset_class_rule) { | 663 if (offset_class_rule) { |
| 664 if (offset_class_rule < class_set_end || offset_class_rule >= length) { | 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); | 665 return OTS_FAILURE_MSG("Bad class rule offset %d for rule %d in context
format 2", offset_class_rule, i); |
| 666 } | 666 } |
| 667 if (!ParseClassSetTable(file, data + offset_class_rule, | 667 if (!ParseClassSetTable(font, data + offset_class_rule, |
| 668 length - offset_class_rule, num_glyphs, | 668 length - offset_class_rule, num_glyphs, |
| 669 num_lookups)) { | 669 num_lookups)) { |
| 670 return OTS_FAILURE_MSG("Failed to parse class set %d in context format 2
", i); | 670 return OTS_FAILURE_MSG("Failed to parse class set %d in context format 2
", i); |
| 671 } | 671 } |
| 672 } | 672 } |
| 673 } | 673 } |
| 674 | 674 |
| 675 return true; | 675 return true; |
| 676 } | 676 } |
| 677 | 677 |
| 678 bool ParseContextFormat3(const ots::OpenTypeFile *file, | 678 bool ParseContextFormat3(const ots::Font *font, |
| 679 const uint8_t *data, const size_t length, | 679 const uint8_t *data, const size_t length, |
| 680 const uint16_t num_glyphs, | 680 const uint16_t num_glyphs, |
| 681 const uint16_t num_lookups) { | 681 const uint16_t num_lookups) { |
| 682 ots::Buffer subtable(data, length); | 682 ots::Buffer subtable(data, length); |
| 683 | 683 |
| 684 uint16_t glyph_count = 0; | 684 uint16_t glyph_count = 0; |
| 685 uint16_t lookup_count = 0; | 685 uint16_t lookup_count = 0; |
| 686 // Skip format field. | 686 // Skip format field. |
| 687 if (!subtable.Skip(2) || | 687 if (!subtable.Skip(2) || |
| 688 !subtable.ReadU16(&glyph_count) || | 688 !subtable.ReadU16(&glyph_count) || |
| (...skipping 10 matching lines...) Expand all Loading... |
| 699 return OTS_FAILURE_MSG("Bad end of lookup %d in context format 3", lookup_re
cord_end); | 699 return OTS_FAILURE_MSG("Bad end of lookup %d in context format 3", lookup_re
cord_end); |
| 700 } | 700 } |
| 701 for (unsigned i = 0; i < glyph_count; ++i) { | 701 for (unsigned i = 0; i < glyph_count; ++i) { |
| 702 uint16_t offset_coverage = 0; | 702 uint16_t offset_coverage = 0; |
| 703 if (!subtable.ReadU16(&offset_coverage)) { | 703 if (!subtable.ReadU16(&offset_coverage)) { |
| 704 return OTS_FAILURE_MSG("Failed to read coverage offset %d in conxtext form
at 3", i); | 704 return OTS_FAILURE_MSG("Failed to read coverage offset %d in conxtext form
at 3", i); |
| 705 } | 705 } |
| 706 if (offset_coverage < lookup_record_end || offset_coverage >= length) { | 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); | 707 return OTS_FAILURE_MSG("Bad coverage offset %d for glyph %d in context for
mat 3", offset_coverage, i); |
| 708 } | 708 } |
| 709 if (!ots::ParseCoverageTable(file, data + offset_coverage, | 709 if (!ots::ParseCoverageTable(font, data + offset_coverage, |
| 710 length - offset_coverage, num_glyphs)) { | 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); | 711 return OTS_FAILURE_MSG("Failed to parse coverage table for glyph %d in con
text format 3", i); |
| 712 } | 712 } |
| 713 } | 713 } |
| 714 | 714 |
| 715 for (unsigned i = 0; i < lookup_count; ++i) { | 715 for (unsigned i = 0; i < lookup_count; ++i) { |
| 716 if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) { | 716 if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) { |
| 717 return OTS_FAILURE_MSG("Failed to parse lookup record %d in context format
3", i); | 717 return OTS_FAILURE_MSG("Failed to parse lookup record %d in context format
3", i); |
| 718 } | 718 } |
| 719 } | 719 } |
| 720 | 720 |
| 721 return true; | 721 return true; |
| 722 } | 722 } |
| 723 | 723 |
| 724 // Parsers for Chaning Contextual subtables in GSUB/GPOS tables. | 724 // Parsers for Chaning Contextual subtables in GSUB/GPOS tables. |
| 725 | 725 |
| 726 bool ParseChainRuleSubtable(const ots::OpenTypeFile *file, | 726 bool ParseChainRuleSubtable(const ots::Font *font, |
| 727 const uint8_t *data, const size_t length, | 727 const uint8_t *data, const size_t length, |
| 728 const uint16_t num_glyphs, | 728 const uint16_t num_glyphs, |
| 729 const uint16_t num_lookups) { | 729 const uint16_t num_lookups) { |
| 730 ots::Buffer subtable(data, length); | 730 ots::Buffer subtable(data, length); |
| 731 | 731 |
| 732 uint16_t backtrack_count = 0; | 732 uint16_t backtrack_count = 0; |
| 733 if (!subtable.ReadU16(&backtrack_count)) { | 733 if (!subtable.ReadU16(&backtrack_count)) { |
| 734 return OTS_FAILURE_MSG("Failed to read backtrack count in chain rule subtabl
e"); | 734 return OTS_FAILURE_MSG("Failed to read backtrack count in chain rule subtabl
e"); |
| 735 } | 735 } |
| 736 if (backtrack_count >= num_glyphs) { | 736 if (backtrack_count >= num_glyphs) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 778 if (glyph_id > num_glyphs) { | 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); | 779 return OTS_FAILURE_MSG("Bad glyph id %d for lookadhead glyph %d in chain r
ule subtable", glyph_id, i); |
| 780 } | 780 } |
| 781 } | 781 } |
| 782 | 782 |
| 783 uint16_t lookup_count = 0; | 783 uint16_t lookup_count = 0; |
| 784 if (!subtable.ReadU16(&lookup_count)) { | 784 if (!subtable.ReadU16(&lookup_count)) { |
| 785 return OTS_FAILURE_MSG("Failed to read lookup count in chain rule subtable")
; | 785 return OTS_FAILURE_MSG("Failed to read lookup count in chain rule subtable")
; |
| 786 } | 786 } |
| 787 for (unsigned i = 0; i < lookup_count; ++i) { | 787 for (unsigned i = 0; i < lookup_count; ++i) { |
| 788 if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) { | 788 if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) { |
| 789 return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain rule sub
table", i); | 789 return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain rule sub
table", i); |
| 790 } | 790 } |
| 791 } | 791 } |
| 792 | 792 |
| 793 return true; | 793 return true; |
| 794 } | 794 } |
| 795 | 795 |
| 796 bool ParseChainRuleSetTable(const ots::OpenTypeFile *file, | 796 bool ParseChainRuleSetTable(const ots::Font *font, |
| 797 const uint8_t *data, const size_t length, | 797 const uint8_t *data, const size_t length, |
| 798 const uint16_t num_glyphs, | 798 const uint16_t num_glyphs, |
| 799 const uint16_t num_lookups) { | 799 const uint16_t num_lookups) { |
| 800 ots::Buffer subtable(data, length); | 800 ots::Buffer subtable(data, length); |
| 801 | 801 |
| 802 uint16_t chain_rule_count = 0; | 802 uint16_t chain_rule_count = 0; |
| 803 if (!subtable.ReadU16(&chain_rule_count)) { | 803 if (!subtable.ReadU16(&chain_rule_count)) { |
| 804 return OTS_FAILURE_MSG("Failed to read rule count in chain rule set"); | 804 return OTS_FAILURE_MSG("Failed to read rule count in chain rule set"); |
| 805 } | 805 } |
| 806 const unsigned chain_rule_end = | 806 const unsigned chain_rule_end = |
| 807 2 * static_cast<unsigned>(chain_rule_count) + 2; | 807 2 * static_cast<unsigned>(chain_rule_count) + 2; |
| 808 if (chain_rule_end > std::numeric_limits<uint16_t>::max()) { | 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); | 809 return OTS_FAILURE_MSG("Bad end of chain rule %d in chain rule set", chain_r
ule_end); |
| 810 } | 810 } |
| 811 for (unsigned i = 0; i < chain_rule_count; ++i) { | 811 for (unsigned i = 0; i < chain_rule_count; ++i) { |
| 812 uint16_t offset_chain_rule = 0; | 812 uint16_t offset_chain_rule = 0; |
| 813 if (!subtable.ReadU16(&offset_chain_rule)) { | 813 if (!subtable.ReadU16(&offset_chain_rule)) { |
| 814 return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain rule
set", i); | 814 return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain rule
set", i); |
| 815 } | 815 } |
| 816 if (offset_chain_rule < chain_rule_end || offset_chain_rule >= length) { | 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); | 817 return OTS_FAILURE_MSG("Bad chain rule offset %d for chain rule %d in chai
n rule set", offset_chain_rule, i); |
| 818 } | 818 } |
| 819 if (!ParseChainRuleSubtable(file, data + offset_chain_rule, | 819 if (!ParseChainRuleSubtable(font, data + offset_chain_rule, |
| 820 length - offset_chain_rule, | 820 length - offset_chain_rule, |
| 821 num_glyphs, num_lookups)) { | 821 num_glyphs, num_lookups)) { |
| 822 return OTS_FAILURE_MSG("Failed to parse chain rule %d in chain rule set",
i); | 822 return OTS_FAILURE_MSG("Failed to parse chain rule %d in chain rule set",
i); |
| 823 } | 823 } |
| 824 } | 824 } |
| 825 | 825 |
| 826 return true; | 826 return true; |
| 827 } | 827 } |
| 828 | 828 |
| 829 bool ParseChainContextFormat1(const ots::OpenTypeFile *file, | 829 bool ParseChainContextFormat1(const ots::Font *font, |
| 830 const uint8_t *data, const size_t length, | 830 const uint8_t *data, const size_t length, |
| 831 const uint16_t num_glyphs, | 831 const uint16_t num_glyphs, |
| 832 const uint16_t num_lookups) { | 832 const uint16_t num_lookups) { |
| 833 ots::Buffer subtable(data, length); | 833 ots::Buffer subtable(data, length); |
| 834 | 834 |
| 835 uint16_t offset_coverage = 0; | 835 uint16_t offset_coverage = 0; |
| 836 uint16_t chain_rule_set_count = 0; | 836 uint16_t chain_rule_set_count = 0; |
| 837 // Skip format field. | 837 // Skip format field. |
| 838 if (!subtable.Skip(2) || | 838 if (!subtable.Skip(2) || |
| 839 !subtable.ReadU16(&offset_coverage) || | 839 !subtable.ReadU16(&offset_coverage) || |
| 840 !subtable.ReadU16(&chain_rule_set_count)) { | 840 !subtable.ReadU16(&chain_rule_set_count)) { |
| 841 return OTS_FAILURE_MSG("Failed to read header of chain context format 1"); | 841 return OTS_FAILURE_MSG("Failed to read header of chain context format 1"); |
| 842 } | 842 } |
| 843 | 843 |
| 844 const unsigned chain_rule_set_end = | 844 const unsigned chain_rule_set_end = |
| 845 2 * static_cast<unsigned>(chain_rule_set_count) + 6; | 845 2 * static_cast<unsigned>(chain_rule_set_count) + 6; |
| 846 if (chain_rule_set_end > std::numeric_limits<uint16_t>::max()) { | 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); | 847 return OTS_FAILURE_MSG("Bad chain rule end %d in chain context format 1", ch
ain_rule_set_end); |
| 848 } | 848 } |
| 849 if (offset_coverage < chain_rule_set_end || offset_coverage >= length) { | 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); | 850 return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 1", c
hain_rule_set_end); |
| 851 } | 851 } |
| 852 if (!ots::ParseCoverageTable(file, data + offset_coverage, | 852 if (!ots::ParseCoverageTable(font, data + offset_coverage, |
| 853 length - offset_coverage, num_glyphs)) { | 853 length - offset_coverage, num_glyphs)) { |
| 854 return OTS_FAILURE_MSG("Failed to parse coverage table for chain context for
mat 1"); | 854 return OTS_FAILURE_MSG("Failed to parse coverage table for chain context for
mat 1"); |
| 855 } | 855 } |
| 856 | 856 |
| 857 for (unsigned i = 0; i < chain_rule_set_count; ++i) { | 857 for (unsigned i = 0; i < chain_rule_set_count; ++i) { |
| 858 uint16_t offset_chain_rule_set = 0; | 858 uint16_t offset_chain_rule_set = 0; |
| 859 if (!subtable.ReadU16(&offset_chain_rule_set)) { | 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); | 860 return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain conte
xt format 1", i); |
| 861 } | 861 } |
| 862 if (offset_chain_rule_set < chain_rule_set_end || | 862 if (offset_chain_rule_set < chain_rule_set_end || |
| 863 offset_chain_rule_set >= length) { | 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); | 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 } | 865 } |
| 866 if (!ParseChainRuleSetTable(file, data + offset_chain_rule_set, | 866 if (!ParseChainRuleSetTable(font, data + offset_chain_rule_set, |
| 867 length - offset_chain_rule_set, | 867 length - offset_chain_rule_set, |
| 868 num_glyphs, num_lookups)) { | 868 num_glyphs, num_lookups)) { |
| 869 return OTS_FAILURE_MSG("Failed to parse chain rule set %d in chain context
format 1", i); | 869 return OTS_FAILURE_MSG("Failed to parse chain rule set %d in chain context
format 1", i); |
| 870 } | 870 } |
| 871 } | 871 } |
| 872 | 872 |
| 873 return true; | 873 return true; |
| 874 } | 874 } |
| 875 | 875 |
| 876 bool ParseChainClassRuleSubtable(const ots::OpenTypeFile *file, | 876 bool ParseChainClassRuleSubtable(const ots::Font *font, |
| 877 const uint8_t *data, const size_t length, | 877 const uint8_t *data, const size_t length, |
| 878 const uint16_t num_glyphs, | 878 const uint16_t num_glyphs, |
| 879 const uint16_t num_lookups) { | 879 const uint16_t num_lookups) { |
| 880 ots::Buffer subtable(data, length); | 880 ots::Buffer subtable(data, length); |
| 881 | 881 |
| 882 // In this subtable, we don't check the value of classes for now since | 882 // In this subtable, we don't check the value of classes for now since |
| 883 // these could take arbitrary values. | 883 // these could take arbitrary values. |
| 884 | 884 |
| 885 uint16_t backtrack_count = 0; | 885 uint16_t backtrack_count = 0; |
| 886 if (!subtable.ReadU16(&backtrack_count)) { | 886 if (!subtable.ReadU16(&backtrack_count)) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 913 } | 913 } |
| 914 if (!subtable.Skip(2 * lookahead_count)) { | 914 if (!subtable.Skip(2 * lookahead_count)) { |
| 915 return OTS_FAILURE_MSG("Failed to skip lookahead offsets in chain class rule
subtable"); | 915 return OTS_FAILURE_MSG("Failed to skip lookahead offsets in chain class rule
subtable"); |
| 916 } | 916 } |
| 917 | 917 |
| 918 uint16_t lookup_count = 0; | 918 uint16_t lookup_count = 0; |
| 919 if (!subtable.ReadU16(&lookup_count)) { | 919 if (!subtable.ReadU16(&lookup_count)) { |
| 920 return OTS_FAILURE_MSG("Failed to read lookup count in chain class rule subt
able"); | 920 return OTS_FAILURE_MSG("Failed to read lookup count in chain class rule subt
able"); |
| 921 } | 921 } |
| 922 for (unsigned i = 0; i < lookup_count; ++i) { | 922 for (unsigned i = 0; i < lookup_count; ++i) { |
| 923 if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) { | 923 if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) { |
| 924 return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain class ru
le subtable", i); | 924 return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain class ru
le subtable", i); |
| 925 } | 925 } |
| 926 } | 926 } |
| 927 | 927 |
| 928 return true; | 928 return true; |
| 929 } | 929 } |
| 930 | 930 |
| 931 bool ParseChainClassSetTable(const ots::OpenTypeFile *file, | 931 bool ParseChainClassSetTable(const ots::Font *font, |
| 932 const uint8_t *data, const size_t length, | 932 const uint8_t *data, const size_t length, |
| 933 const uint16_t num_glyphs, | 933 const uint16_t num_glyphs, |
| 934 const uint16_t num_lookups) { | 934 const uint16_t num_lookups) { |
| 935 ots::Buffer subtable(data, length); | 935 ots::Buffer subtable(data, length); |
| 936 | 936 |
| 937 uint16_t chain_class_rule_count = 0; | 937 uint16_t chain_class_rule_count = 0; |
| 938 if (!subtable.ReadU16(&chain_class_rule_count)) { | 938 if (!subtable.ReadU16(&chain_class_rule_count)) { |
| 939 return OTS_FAILURE_MSG("Failed to read rule count in chain class set"); | 939 return OTS_FAILURE_MSG("Failed to read rule count in chain class set"); |
| 940 } | 940 } |
| 941 const unsigned chain_class_rule_end = | 941 const unsigned chain_class_rule_end = |
| 942 2 * static_cast<unsigned>(chain_class_rule_count) + 2; | 942 2 * static_cast<unsigned>(chain_class_rule_count) + 2; |
| 943 if (chain_class_rule_end > std::numeric_limits<uint16_t>::max()) { | 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); | 944 return OTS_FAILURE_MSG("Bad end of chain class set %d in chain class set", c
hain_class_rule_end); |
| 945 } | 945 } |
| 946 for (unsigned i = 0; i < chain_class_rule_count; ++i) { | 946 for (unsigned i = 0; i < chain_class_rule_count; ++i) { |
| 947 uint16_t offset_chain_class_rule = 0; | 947 uint16_t offset_chain_class_rule = 0; |
| 948 if (!subtable.ReadU16(&offset_chain_class_rule)) { | 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); | 949 return OTS_FAILURE_MSG("Failed to read chain class rule offset %d in chain
class set", i); |
| 950 } | 950 } |
| 951 if (offset_chain_class_rule < chain_class_rule_end || | 951 if (offset_chain_class_rule < chain_class_rule_end || |
| 952 offset_chain_class_rule >= length) { | 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); | 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 } | 954 } |
| 955 if (!ParseChainClassRuleSubtable(file, data + offset_chain_class_rule, | 955 if (!ParseChainClassRuleSubtable(font, data + offset_chain_class_rule, |
| 956 length - offset_chain_class_rule, | 956 length - offset_chain_class_rule, |
| 957 num_glyphs, num_lookups)) { | 957 num_glyphs, num_lookups)) { |
| 958 return OTS_FAILURE_MSG("Failed to parse chain class rule %d in chain class
set", i); | 958 return OTS_FAILURE_MSG("Failed to parse chain class rule %d in chain class
set", i); |
| 959 } | 959 } |
| 960 } | 960 } |
| 961 | 961 |
| 962 return true; | 962 return true; |
| 963 } | 963 } |
| 964 | 964 |
| 965 bool ParseChainContextFormat2(const ots::OpenTypeFile *file, | 965 bool ParseChainContextFormat2(const ots::Font *font, |
| 966 const uint8_t *data, const size_t length, | 966 const uint8_t *data, const size_t length, |
| 967 const uint16_t num_glyphs, | 967 const uint16_t num_glyphs, |
| 968 const uint16_t num_lookups) { | 968 const uint16_t num_lookups) { |
| 969 ots::Buffer subtable(data, length); | 969 ots::Buffer subtable(data, length); |
| 970 | 970 |
| 971 uint16_t offset_coverage = 0; | 971 uint16_t offset_coverage = 0; |
| 972 uint16_t offset_backtrack_class_def = 0; | 972 uint16_t offset_backtrack_class_def = 0; |
| 973 uint16_t offset_input_class_def = 0; | 973 uint16_t offset_input_class_def = 0; |
| 974 uint16_t offset_lookahead_class_def = 0; | 974 uint16_t offset_lookahead_class_def = 0; |
| 975 uint16_t chain_class_set_count = 0; | 975 uint16_t chain_class_set_count = 0; |
| 976 // Skip format field. | 976 // Skip format field. |
| 977 if (!subtable.Skip(2) || | 977 if (!subtable.Skip(2) || |
| 978 !subtable.ReadU16(&offset_coverage) || | 978 !subtable.ReadU16(&offset_coverage) || |
| 979 !subtable.ReadU16(&offset_backtrack_class_def) || | 979 !subtable.ReadU16(&offset_backtrack_class_def) || |
| 980 !subtable.ReadU16(&offset_input_class_def) || | 980 !subtable.ReadU16(&offset_input_class_def) || |
| 981 !subtable.ReadU16(&offset_lookahead_class_def) || | 981 !subtable.ReadU16(&offset_lookahead_class_def) || |
| 982 !subtable.ReadU16(&chain_class_set_count)) { | 982 !subtable.ReadU16(&chain_class_set_count)) { |
| 983 return OTS_FAILURE_MSG("Failed to read header of chain context format 2"); | 983 return OTS_FAILURE_MSG("Failed to read header of chain context format 2"); |
| 984 } | 984 } |
| 985 | 985 |
| 986 const unsigned chain_class_set_end = | 986 const unsigned chain_class_set_end = |
| 987 2 * static_cast<unsigned>(chain_class_set_count) + 12; | 987 2 * static_cast<unsigned>(chain_class_set_count) + 12; |
| 988 if (chain_class_set_end > std::numeric_limits<uint16_t>::max()) { | 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); | 989 return OTS_FAILURE_MSG("Bad chain class set end %d in chain context format 2
", chain_class_set_end); |
| 990 } | 990 } |
| 991 if (offset_coverage < chain_class_set_end || offset_coverage >= length) { | 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); | 992 return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 2", o
ffset_coverage); |
| 993 } | 993 } |
| 994 if (!ots::ParseCoverageTable(file, data + offset_coverage, | 994 if (!ots::ParseCoverageTable(font, data + offset_coverage, |
| 995 length - offset_coverage, num_glyphs)) { | 995 length - offset_coverage, num_glyphs)) { |
| 996 return OTS_FAILURE_MSG("Failed to parse coverage table in chain context form
at 2"); | 996 return OTS_FAILURE_MSG("Failed to parse coverage table in chain context form
at 2"); |
| 997 } | 997 } |
| 998 | 998 |
| 999 // Classes for backtrack/lookahead sequences might not be defined. | 999 // Classes for backtrack/lookahead sequences might not be defined. |
| 1000 if (offset_backtrack_class_def) { | 1000 if (offset_backtrack_class_def) { |
| 1001 if (offset_backtrack_class_def < chain_class_set_end || | 1001 if (offset_backtrack_class_def < chain_class_set_end || |
| 1002 offset_backtrack_class_def >= length) { | 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); | 1003 return OTS_FAILURE_MSG("Bad backtrack class offset %d in chain context for
mat 2", offset_backtrack_class_def); |
| 1004 } | 1004 } |
| 1005 if (!ots::ParseClassDefTable(file, data + offset_backtrack_class_def, | 1005 if (!ots::ParseClassDefTable(font, data + offset_backtrack_class_def, |
| 1006 length - offset_backtrack_class_def, | 1006 length - offset_backtrack_class_def, |
| 1007 num_glyphs, kMaxClassDefValue)) { | 1007 num_glyphs, kMaxClassDefValue)) { |
| 1008 return OTS_FAILURE_MSG("Failed to parse backtrack class defn table in chai
n context format 2"); | 1008 return OTS_FAILURE_MSG("Failed to parse backtrack class defn table in chai
n context format 2"); |
| 1009 } | 1009 } |
| 1010 } | 1010 } |
| 1011 | 1011 |
| 1012 if (offset_input_class_def < chain_class_set_end || | 1012 if (offset_input_class_def < chain_class_set_end || |
| 1013 offset_input_class_def >= length) { | 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); | 1014 return OTS_FAILURE_MSG("Bad input class defn offset %d in chain context form
at 2", offset_input_class_def); |
| 1015 } | 1015 } |
| 1016 if (!ots::ParseClassDefTable(file, data + offset_input_class_def, | 1016 if (!ots::ParseClassDefTable(font, data + offset_input_class_def, |
| 1017 length - offset_input_class_def, | 1017 length - offset_input_class_def, |
| 1018 num_glyphs, kMaxClassDefValue)) { | 1018 num_glyphs, kMaxClassDefValue)) { |
| 1019 return OTS_FAILURE_MSG("Failed to parse input class defn in chain context fo
rmat 2"); | 1019 return OTS_FAILURE_MSG("Failed to parse input class defn in chain context fo
rmat 2"); |
| 1020 } | 1020 } |
| 1021 | 1021 |
| 1022 if (offset_lookahead_class_def) { | 1022 if (offset_lookahead_class_def) { |
| 1023 if (offset_lookahead_class_def < chain_class_set_end || | 1023 if (offset_lookahead_class_def < chain_class_set_end || |
| 1024 offset_lookahead_class_def >= length) { | 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); | 1025 return OTS_FAILURE_MSG("Bad lookahead class defn offset %d in chain contex
t format 2", offset_lookahead_class_def); |
| 1026 } | 1026 } |
| 1027 if (!ots::ParseClassDefTable(file, data + offset_lookahead_class_def, | 1027 if (!ots::ParseClassDefTable(font, data + offset_lookahead_class_def, |
| 1028 length - offset_lookahead_class_def, | 1028 length - offset_lookahead_class_def, |
| 1029 num_glyphs, kMaxClassDefValue)) { | 1029 num_glyphs, kMaxClassDefValue)) { |
| 1030 return OTS_FAILURE_MSG("Failed to parse lookahead class defn in chain cont
ext format 2"); | 1030 return OTS_FAILURE_MSG("Failed to parse lookahead class defn in chain cont
ext format 2"); |
| 1031 } | 1031 } |
| 1032 } | 1032 } |
| 1033 | 1033 |
| 1034 for (unsigned i = 0; i < chain_class_set_count; ++i) { | 1034 for (unsigned i = 0; i < chain_class_set_count; ++i) { |
| 1035 uint16_t offset_chain_class_set = 0; | 1035 uint16_t offset_chain_class_set = 0; |
| 1036 if (!subtable.ReadU16(&offset_chain_class_set)) { | 1036 if (!subtable.ReadU16(&offset_chain_class_set)) { |
| 1037 return OTS_FAILURE_MSG("Failed to read chain class set offset %d", i); | 1037 return OTS_FAILURE_MSG("Failed to read chain class set offset %d", i); |
| 1038 } | 1038 } |
| 1039 // |offset_chain_class_set| could be NULL. | 1039 // |offset_chain_class_set| could be NULL. |
| 1040 if (offset_chain_class_set) { | 1040 if (offset_chain_class_set) { |
| 1041 if (offset_chain_class_set < chain_class_set_end || | 1041 if (offset_chain_class_set < chain_class_set_end || |
| 1042 offset_chain_class_set >= length) { | 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); | 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 } | 1044 } |
| 1045 if (!ParseChainClassSetTable(file, data + offset_chain_class_set, | 1045 if (!ParseChainClassSetTable(font, data + offset_chain_class_set, |
| 1046 length - offset_chain_class_set, | 1046 length - offset_chain_class_set, |
| 1047 num_glyphs, num_lookups)) { | 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); | 1048 return OTS_FAILURE_MSG("Failed to parse chain class set table %d in chai
n context format 2", i); |
| 1049 } | 1049 } |
| 1050 } | 1050 } |
| 1051 } | 1051 } |
| 1052 | 1052 |
| 1053 return true; | 1053 return true; |
| 1054 } | 1054 } |
| 1055 | 1055 |
| 1056 bool ParseChainContextFormat3(const ots::OpenTypeFile *file, | 1056 bool ParseChainContextFormat3(const ots::Font *font, |
| 1057 const uint8_t *data, const size_t length, | 1057 const uint8_t *data, const size_t length, |
| 1058 const uint16_t num_glyphs, | 1058 const uint16_t num_glyphs, |
| 1059 const uint16_t num_lookups) { | 1059 const uint16_t num_lookups) { |
| 1060 ots::Buffer subtable(data, length); | 1060 ots::Buffer subtable(data, length); |
| 1061 | 1061 |
| 1062 uint16_t backtrack_count = 0; | 1062 uint16_t backtrack_count = 0; |
| 1063 // Skip format field. | 1063 // Skip format field. |
| 1064 if (!subtable.Skip(2) || | 1064 if (!subtable.Skip(2) || |
| 1065 !subtable.ReadU16(&backtrack_count)) { | 1065 !subtable.ReadU16(&backtrack_count)) { |
| 1066 return OTS_FAILURE_MSG("Failed to read backtrack count in chain context form
at 3"); | 1066 return OTS_FAILURE_MSG("Failed to read backtrack count in chain context form
at 3"); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1120 } | 1120 } |
| 1121 if (offsets_lookahead.size() != lookahead_count) { | 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()); | 1122 return OTS_FAILURE_MSG("Bad lookahead offsets size %ld in chain context form
at 3", offsets_lookahead.size()); |
| 1123 } | 1123 } |
| 1124 | 1124 |
| 1125 uint16_t lookup_count = 0; | 1125 uint16_t lookup_count = 0; |
| 1126 if (!subtable.ReadU16(&lookup_count)) { | 1126 if (!subtable.ReadU16(&lookup_count)) { |
| 1127 return OTS_FAILURE_MSG("Failed to read lookup count in chain context format
3"); | 1127 return OTS_FAILURE_MSG("Failed to read lookup count in chain context format
3"); |
| 1128 } | 1128 } |
| 1129 for (unsigned i = 0; i < lookup_count; ++i) { | 1129 for (unsigned i = 0; i < lookup_count; ++i) { |
| 1130 if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) { | 1130 if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) { |
| 1131 return OTS_FAILURE_MSG("Failed to parse lookup %d in chain context format
3", i); | 1131 return OTS_FAILURE_MSG("Failed to parse lookup %d in chain context format
3", i); |
| 1132 } | 1132 } |
| 1133 } | 1133 } |
| 1134 | 1134 |
| 1135 const unsigned lookup_record_end = | 1135 const unsigned lookup_record_end = |
| 1136 2 * (static_cast<unsigned>(backtrack_count) + | 1136 2 * (static_cast<unsigned>(backtrack_count) + |
| 1137 static_cast<unsigned>(input_count) + | 1137 static_cast<unsigned>(input_count) + |
| 1138 static_cast<unsigned>(lookahead_count)) + | 1138 static_cast<unsigned>(lookahead_count)) + |
| 1139 4 * static_cast<unsigned>(lookup_count) + 10; | 1139 4 * static_cast<unsigned>(lookup_count) + 10; |
| 1140 if (lookup_record_end > std::numeric_limits<uint16_t>::max()) { | 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); | 1141 return OTS_FAILURE_MSG("Bad end of lookup record %d in chain context format
3", lookup_record_end); |
| 1142 } | 1142 } |
| 1143 for (unsigned i = 0; i < backtrack_count; ++i) { | 1143 for (unsigned i = 0; i < backtrack_count; ++i) { |
| 1144 if (offsets_backtrack[i] < lookup_record_end || | 1144 if (offsets_backtrack[i] < lookup_record_end || |
| 1145 offsets_backtrack[i] >= length) { | 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); | 1146 return OTS_FAILURE_MSG("Bad backtrack offset of %d for backtrack %d in cha
in context format 3", offsets_backtrack[i], i); |
| 1147 } | 1147 } |
| 1148 if (!ots::ParseCoverageTable(file, data + offsets_backtrack[i], | 1148 if (!ots::ParseCoverageTable(font, data + offsets_backtrack[i], |
| 1149 length - offsets_backtrack[i], num_glyphs)) { | 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); | 1150 return OTS_FAILURE_MSG("Failed to parse backtrack coverage %d in chain con
text format 3", i); |
| 1151 } | 1151 } |
| 1152 } | 1152 } |
| 1153 for (unsigned i = 0; i < input_count; ++i) { | 1153 for (unsigned i = 0; i < input_count; ++i) { |
| 1154 if (offsets_input[i] < lookup_record_end || offsets_input[i] >= length) { | 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); | 1155 return OTS_FAILURE_MSG("Bad input offset %d for input %d in chain context
format 3", offsets_input[i], i); |
| 1156 } | 1156 } |
| 1157 if (!ots::ParseCoverageTable(file, data + offsets_input[i], | 1157 if (!ots::ParseCoverageTable(font, data + offsets_input[i], |
| 1158 length - offsets_input[i], num_glyphs)) { | 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); | 1159 return OTS_FAILURE_MSG("Failed to parse input coverage table %d in chain c
ontext format 3", i); |
| 1160 } | 1160 } |
| 1161 } | 1161 } |
| 1162 for (unsigned i = 0; i < lookahead_count; ++i) { | 1162 for (unsigned i = 0; i < lookahead_count; ++i) { |
| 1163 if (offsets_lookahead[i] < lookup_record_end || | 1163 if (offsets_lookahead[i] < lookup_record_end || |
| 1164 offsets_lookahead[i] >= length) { | 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); | 1165 return OTS_FAILURE_MSG("Bad lookadhead offset %d for lookahead %d in chain
context format 3", offsets_lookahead[i], i); |
| 1166 } | 1166 } |
| 1167 if (!ots::ParseCoverageTable(file, data + offsets_lookahead[i], | 1167 if (!ots::ParseCoverageTable(font, data + offsets_lookahead[i], |
| 1168 length - offsets_lookahead[i], num_glyphs)) { | 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); | 1169 return OTS_FAILURE_MSG("Failed to parse lookahead coverage table %d in cha
in context format 3", i); |
| 1170 } | 1170 } |
| 1171 } | 1171 } |
| 1172 | 1172 |
| 1173 return true; | 1173 return true; |
| 1174 } | 1174 } |
| 1175 | 1175 |
| 1176 } // namespace | 1176 } // namespace |
| 1177 | 1177 |
| 1178 namespace ots { | 1178 namespace ots { |
| 1179 | 1179 |
| 1180 bool LookupSubtableParser::Parse(const OpenTypeFile *file, const uint8_t *data, | 1180 bool LookupSubtableParser::Parse(const Font *font, const uint8_t *data, |
| 1181 const size_t length, | 1181 const size_t length, |
| 1182 const uint16_t lookup_type) const { | 1182 const uint16_t lookup_type) const { |
| 1183 for (unsigned i = 0; i < num_types; ++i) { | 1183 for (unsigned i = 0; i < num_types; ++i) { |
| 1184 if (parsers[i].type == lookup_type && parsers[i].parse) { | 1184 if (parsers[i].type == lookup_type && parsers[i].parse) { |
| 1185 if (!parsers[i].parse(file, data, length)) { | 1185 if (!parsers[i].parse(font, data, length)) { |
| 1186 return OTS_FAILURE_MSG("Failed to parse lookup subtable %d", i); | 1186 return OTS_FAILURE_MSG("Failed to parse lookup subtable %d", i); |
| 1187 } | 1187 } |
| 1188 return true; | 1188 return true; |
| 1189 } | 1189 } |
| 1190 } | 1190 } |
| 1191 return OTS_FAILURE_MSG("No lookup subtables to parse"); | 1191 return OTS_FAILURE_MSG("No lookup subtables to parse"); |
| 1192 } | 1192 } |
| 1193 | 1193 |
| 1194 // Parsing ScriptListTable requires number of features so we need to | 1194 // Parsing ScriptListTable requires number of features so we need to |
| 1195 // parse FeatureListTable before calling this function. | 1195 // parse FeatureListTable before calling this function. |
| 1196 bool ParseScriptListTable(const ots::OpenTypeFile *file, | 1196 bool ParseScriptListTable(const ots::Font *font, |
| 1197 const uint8_t *data, const size_t length, | 1197 const uint8_t *data, const size_t length, |
| 1198 const uint16_t num_features) { | 1198 const uint16_t num_features) { |
| 1199 Buffer subtable(data, length); | 1199 Buffer subtable(data, length); |
| 1200 | 1200 |
| 1201 uint16_t script_count = 0; | 1201 uint16_t script_count = 0; |
| 1202 if (!subtable.ReadU16(&script_count)) { | 1202 if (!subtable.ReadU16(&script_count)) { |
| 1203 return OTS_FAILURE_MSG("Failed to read script count in script list table"); | 1203 return OTS_FAILURE_MSG("Failed to read script count in script list table"); |
| 1204 } | 1204 } |
| 1205 | 1205 |
| 1206 const unsigned script_record_end = | 1206 const unsigned script_record_end = |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1219 } | 1219 } |
| 1220 // Script tags should be arranged alphabetically by tag | 1220 // Script tags should be arranged alphabetically by tag |
| 1221 if (last_tag != 0 && last_tag > record.tag) { | 1221 if (last_tag != 0 && last_tag > record.tag) { |
| 1222 // Several fonts don't arrange tags alphabetically. | 1222 // Several fonts don't arrange tags alphabetically. |
| 1223 // It seems that the order of tags might not be a security issue | 1223 // It seems that the order of tags might not be a security issue |
| 1224 // so we just warn it. | 1224 // so we just warn it. |
| 1225 OTS_WARNING("tags aren't arranged alphabetically."); | 1225 OTS_WARNING("tags aren't arranged alphabetically."); |
| 1226 } | 1226 } |
| 1227 last_tag = record.tag; | 1227 last_tag = record.tag; |
| 1228 if (record.offset < script_record_end || record.offset >= length) { | 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); | 1229 return OTS_FAILURE_MSG("Bad record offset %d for script %c%c%c%c entry %d
in script list table", record.offset, OTS_UNTAG(record.tag), i); |
| 1230 } | 1230 } |
| 1231 script_list.push_back(record); | 1231 script_list.push_back(record); |
| 1232 } | 1232 } |
| 1233 if (script_list.size() != script_count) { | 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()); | 1234 return OTS_FAILURE_MSG("Bad script list size %ld in script list table", scri
pt_list.size()); |
| 1235 } | 1235 } |
| 1236 | 1236 |
| 1237 // Check script records. | 1237 // Check script records. |
| 1238 for (unsigned i = 0; i < script_count; ++i) { | 1238 for (unsigned i = 0; i < script_count; ++i) { |
| 1239 if (!ParseScriptTable(file, data + script_list[i].offset, | 1239 if (!ParseScriptTable(font, data + script_list[i].offset, |
| 1240 length - script_list[i].offset, | 1240 length - script_list[i].offset, |
| 1241 script_list[i].tag, num_features)) { | 1241 script_list[i].tag, num_features)) { |
| 1242 return OTS_FAILURE_MSG("Failed to parse script table %d", i); | 1242 return OTS_FAILURE_MSG("Failed to parse script table %d", i); |
| 1243 } | 1243 } |
| 1244 } | 1244 } |
| 1245 | 1245 |
| 1246 return true; | 1246 return true; |
| 1247 } | 1247 } |
| 1248 | 1248 |
| 1249 // Parsing FeatureListTable requires number of lookups so we need to parse | 1249 // Parsing FeatureListTable requires number of lookups so we need to parse |
| 1250 // LookupListTable before calling this function. | 1250 // LookupListTable before calling this function. |
| 1251 bool ParseFeatureListTable(const ots::OpenTypeFile *file, | 1251 bool ParseFeatureListTable(const ots::Font *font, |
| 1252 const uint8_t *data, const size_t length, | 1252 const uint8_t *data, const size_t length, |
| 1253 const uint16_t num_lookups, | 1253 const uint16_t num_lookups, |
| 1254 uint16_t* num_features) { | 1254 uint16_t* num_features) { |
| 1255 Buffer subtable(data, length); | 1255 Buffer subtable(data, length); |
| 1256 | 1256 |
| 1257 uint16_t feature_count = 0; | 1257 uint16_t feature_count = 0; |
| 1258 if (!subtable.ReadU16(&feature_count)) { | 1258 if (!subtable.ReadU16(&feature_count)) { |
| 1259 return OTS_FAILURE_MSG("Failed to read feature count"); | 1259 return OTS_FAILURE_MSG("Failed to read feature count"); |
| 1260 } | 1260 } |
| 1261 | 1261 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1275 // Feature record array should be arranged alphabetically by tag | 1275 // Feature record array should be arranged alphabetically by tag |
| 1276 if (last_tag != 0 && last_tag > feature_records[i].tag) { | 1276 if (last_tag != 0 && last_tag > feature_records[i].tag) { |
| 1277 // Several fonts don't arrange tags alphabetically. | 1277 // Several fonts don't arrange tags alphabetically. |
| 1278 // It seems that the order of tags might not be a security issue | 1278 // It seems that the order of tags might not be a security issue |
| 1279 // so we just warn it. | 1279 // so we just warn it. |
| 1280 OTS_WARNING("tags aren't arranged alphabetically."); | 1280 OTS_WARNING("tags aren't arranged alphabetically."); |
| 1281 } | 1281 } |
| 1282 last_tag = feature_records[i].tag; | 1282 last_tag = feature_records[i].tag; |
| 1283 if (feature_records[i].offset < feature_record_end || | 1283 if (feature_records[i].offset < feature_record_end || |
| 1284 feature_records[i].offset >= length) { | 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); | 1285 return OTS_FAILURE_MSG("Bad feature offset %d for feature %d %c%c%c%c", fe
ature_records[i].offset, i, OTS_UNTAG(feature_records[i].tag)); |
| 1286 } | 1286 } |
| 1287 } | 1287 } |
| 1288 | 1288 |
| 1289 for (unsigned i = 0; i < feature_count; ++i) { | 1289 for (unsigned i = 0; i < feature_count; ++i) { |
| 1290 if (!ParseFeatureTable(file, data + feature_records[i].offset, | 1290 if (!ParseFeatureTable(font, data + feature_records[i].offset, |
| 1291 length - feature_records[i].offset, num_lookups)) { | 1291 length - feature_records[i].offset, num_lookups)) { |
| 1292 return OTS_FAILURE_MSG("Failed to parse feature table %d", i); | 1292 return OTS_FAILURE_MSG("Failed to parse feature table %d", i); |
| 1293 } | 1293 } |
| 1294 } | 1294 } |
| 1295 *num_features = feature_count; | 1295 *num_features = feature_count; |
| 1296 return true; | 1296 return true; |
| 1297 } | 1297 } |
| 1298 | 1298 |
| 1299 // For parsing GPOS/GSUB tables, this function should be called at first to | 1299 // For parsing GPOS/GSUB tables, this function should be called at first to |
| 1300 // obtain the number of lookups because parsing FeatureTableList requires | 1300 // obtain the number of lookups because parsing FeatureTableList requires |
| 1301 // the number. | 1301 // the number. |
| 1302 bool ParseLookupListTable(OpenTypeFile *file, const uint8_t *data, | 1302 bool ParseLookupListTable(Font *font, const uint8_t *data, |
| 1303 const size_t length, | 1303 const size_t length, |
| 1304 const LookupSubtableParser* parser, | 1304 const LookupSubtableParser* parser, |
| 1305 uint16_t *num_lookups) { | 1305 uint16_t *num_lookups) { |
| 1306 Buffer subtable(data, length); | 1306 Buffer subtable(data, length); |
| 1307 | 1307 |
| 1308 if (!subtable.ReadU16(num_lookups)) { | 1308 if (!subtable.ReadU16(num_lookups)) { |
| 1309 return OTS_FAILURE_MSG("Failed to read number of lookups"); | 1309 return OTS_FAILURE_MSG("Failed to read number of lookups"); |
| 1310 } | 1310 } |
| 1311 | 1311 |
| 1312 std::vector<uint16_t> lookups; | 1312 std::vector<uint16_t> lookups; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1324 if (offset < lookup_end || offset >= length) { | 1324 if (offset < lookup_end || offset >= length) { |
| 1325 return OTS_FAILURE_MSG("Bad lookup offset %d for lookup %d", offset, i); | 1325 return OTS_FAILURE_MSG("Bad lookup offset %d for lookup %d", offset, i); |
| 1326 } | 1326 } |
| 1327 lookups.push_back(offset); | 1327 lookups.push_back(offset); |
| 1328 } | 1328 } |
| 1329 if (lookups.size() != *num_lookups) { | 1329 if (lookups.size() != *num_lookups) { |
| 1330 return OTS_FAILURE_MSG("Bad lookup offsets list size %ld", lookups.size()); | 1330 return OTS_FAILURE_MSG("Bad lookup offsets list size %ld", lookups.size()); |
| 1331 } | 1331 } |
| 1332 | 1332 |
| 1333 for (unsigned i = 0; i < *num_lookups; ++i) { | 1333 for (unsigned i = 0; i < *num_lookups; ++i) { |
| 1334 if (!ParseLookupTable(file, data + lookups[i], length - lookups[i], | 1334 if (!ParseLookupTable(font, data + lookups[i], length - lookups[i], |
| 1335 parser)) { | 1335 parser)) { |
| 1336 return OTS_FAILURE_MSG("Failed to parse lookup %d", i); | 1336 return OTS_FAILURE_MSG("Failed to parse lookup %d", i); |
| 1337 } | 1337 } |
| 1338 } | 1338 } |
| 1339 | 1339 |
| 1340 return true; | 1340 return true; |
| 1341 } | 1341 } |
| 1342 | 1342 |
| 1343 bool ParseClassDefTable(const ots::OpenTypeFile *file, | 1343 bool ParseClassDefTable(const ots::Font *font, |
| 1344 const uint8_t *data, size_t length, | 1344 const uint8_t *data, size_t length, |
| 1345 const uint16_t num_glyphs, | 1345 const uint16_t num_glyphs, |
| 1346 const uint16_t num_classes) { | 1346 const uint16_t num_classes) { |
| 1347 Buffer subtable(data, length); | 1347 Buffer subtable(data, length); |
| 1348 | 1348 |
| 1349 uint16_t format = 0; | 1349 uint16_t format = 0; |
| 1350 if (!subtable.ReadU16(&format)) { | 1350 if (!subtable.ReadU16(&format)) { |
| 1351 return OTS_FAILURE_MSG("Failed to read class defn format"); | 1351 return OTS_FAILURE_MSG("Failed to read class defn format"); |
| 1352 } | 1352 } |
| 1353 if (format == 1) { | 1353 if (format == 1) { |
| 1354 return ParseClassDefFormat1(file, data, length, num_glyphs, num_classes); | 1354 return ParseClassDefFormat1(font, data, length, num_glyphs, num_classes); |
| 1355 } else if (format == 2) { | 1355 } else if (format == 2) { |
| 1356 return ParseClassDefFormat2(file, data, length, num_glyphs, num_classes); | 1356 return ParseClassDefFormat2(font, data, length, num_glyphs, num_classes); |
| 1357 } | 1357 } |
| 1358 | 1358 |
| 1359 return OTS_FAILURE_MSG("Bad class defn format %d", format); | 1359 return OTS_FAILURE_MSG("Bad class defn format %d", format); |
| 1360 } | 1360 } |
| 1361 | 1361 |
| 1362 bool ParseCoverageTable(const ots::OpenTypeFile *file, | 1362 bool ParseCoverageTable(const ots::Font *font, |
| 1363 const uint8_t *data, size_t length, | 1363 const uint8_t *data, size_t length, |
| 1364 const uint16_t num_glyphs, | 1364 const uint16_t num_glyphs, |
| 1365 const uint16_t expected_num_glyphs) { | 1365 const uint16_t expected_num_glyphs) { |
| 1366 Buffer subtable(data, length); | 1366 Buffer subtable(data, length); |
| 1367 | 1367 |
| 1368 uint16_t format = 0; | 1368 uint16_t format = 0; |
| 1369 if (!subtable.ReadU16(&format)) { | 1369 if (!subtable.ReadU16(&format)) { |
| 1370 return OTS_FAILURE_MSG("Failed to read coverage table format"); | 1370 return OTS_FAILURE_MSG("Failed to read coverage table format"); |
| 1371 } | 1371 } |
| 1372 if (format == 1) { | 1372 if (format == 1) { |
| 1373 return ParseCoverageFormat1(file, data, length, num_glyphs, expected_num_gly
phs); | 1373 return ParseCoverageFormat1(font, data, length, num_glyphs, expected_num_gly
phs); |
| 1374 } else if (format == 2) { | 1374 } else if (format == 2) { |
| 1375 return ParseCoverageFormat2(file, data, length, num_glyphs, expected_num_gly
phs); | 1375 return ParseCoverageFormat2(font, data, length, num_glyphs, expected_num_gly
phs); |
| 1376 } | 1376 } |
| 1377 | 1377 |
| 1378 return OTS_FAILURE_MSG("Bad coverage table format %d", format); | 1378 return OTS_FAILURE_MSG("Bad coverage table format %d", format); |
| 1379 } | 1379 } |
| 1380 | 1380 |
| 1381 bool ParseDeviceTable(const ots::OpenTypeFile *file, | 1381 bool ParseDeviceTable(const ots::Font *font, |
| 1382 const uint8_t *data, size_t length) { | 1382 const uint8_t *data, size_t length) { |
| 1383 Buffer subtable(data, length); | 1383 Buffer subtable(data, length); |
| 1384 | 1384 |
| 1385 uint16_t start_size = 0; | 1385 uint16_t start_size = 0; |
| 1386 uint16_t end_size = 0; | 1386 uint16_t end_size = 0; |
| 1387 uint16_t delta_format = 0; | 1387 uint16_t delta_format = 0; |
| 1388 if (!subtable.ReadU16(&start_size) || | 1388 if (!subtable.ReadU16(&start_size) || |
| 1389 !subtable.ReadU16(&end_size) || | 1389 !subtable.ReadU16(&end_size) || |
| 1390 !subtable.ReadU16(&delta_format)) { | 1390 !subtable.ReadU16(&delta_format)) { |
| 1391 return OTS_FAILURE_MSG("Failed to read device table header"); | 1391 return OTS_FAILURE_MSG("Failed to read device table header"); |
| 1392 } | 1392 } |
| 1393 if (start_size > end_size) { | 1393 if (start_size > end_size) { |
| 1394 return OTS_FAILURE_MSG("bad size range: %u > %u", start_size, end_size); | 1394 return OTS_FAILURE_MSG("bad size range: %u > %u", start_size, end_size); |
| 1395 } | 1395 } |
| 1396 if (delta_format == 0 || delta_format > kMaxDeltaFormatType) { | 1396 if (delta_format == 0 || delta_format > kMaxDeltaFormatType) { |
| 1397 return OTS_FAILURE_MSG("bad delta format: %u", delta_format); | 1397 return OTS_FAILURE_MSG("bad delta format: %u", delta_format); |
| 1398 } | 1398 } |
| 1399 // The number of delta values per uint16. The device table should contain | 1399 // The number of delta values per uint16. The device table should contain |
| 1400 // at least |num_units| * 2 bytes compressed data. | 1400 // at least |num_units| * 2 bytes compressed data. |
| 1401 const unsigned num_units = (end_size - start_size) / | 1401 const unsigned num_units = (end_size - start_size) / |
| 1402 (1 << (4 - delta_format)) + 1; | 1402 (1 << (4 - delta_format)) + 1; |
| 1403 // Just skip |num_units| * 2 bytes since the compressed data could take | 1403 // Just skip |num_units| * 2 bytes since the compressed data could take |
| 1404 // arbitrary values. | 1404 // arbitrary values. |
| 1405 if (!subtable.Skip(num_units * 2)) { | 1405 if (!subtable.Skip(num_units * 2)) { |
| 1406 return OTS_FAILURE_MSG("Failed to skip data in device table"); | 1406 return OTS_FAILURE_MSG("Failed to skip data in device table"); |
| 1407 } | 1407 } |
| 1408 return true; | 1408 return true; |
| 1409 } | 1409 } |
| 1410 | 1410 |
| 1411 bool ParseContextSubtable(const ots::OpenTypeFile *file, | 1411 bool ParseContextSubtable(const ots::Font *font, |
| 1412 const uint8_t *data, const size_t length, | 1412 const uint8_t *data, const size_t length, |
| 1413 const uint16_t num_glyphs, | 1413 const uint16_t num_glyphs, |
| 1414 const uint16_t num_lookups) { | 1414 const uint16_t num_lookups) { |
| 1415 Buffer subtable(data, length); | 1415 Buffer subtable(data, length); |
| 1416 | 1416 |
| 1417 uint16_t format = 0; | 1417 uint16_t format = 0; |
| 1418 if (!subtable.ReadU16(&format)) { | 1418 if (!subtable.ReadU16(&format)) { |
| 1419 return OTS_FAILURE_MSG("Failed to read context subtable format"); | 1419 return OTS_FAILURE_MSG("Failed to read context subtable format"); |
| 1420 } | 1420 } |
| 1421 | 1421 |
| 1422 if (format == 1) { | 1422 if (format == 1) { |
| 1423 if (!ParseContextFormat1(file, data, length, num_glyphs, num_lookups)) { | 1423 if (!ParseContextFormat1(font, data, length, num_glyphs, num_lookups)) { |
| 1424 return OTS_FAILURE_MSG("Failed to parse context format 1 subtable"); | 1424 return OTS_FAILURE_MSG("Failed to parse context format 1 subtable"); |
| 1425 } | 1425 } |
| 1426 } else if (format == 2) { | 1426 } else if (format == 2) { |
| 1427 if (!ParseContextFormat2(file, data, length, num_glyphs, num_lookups)) { | 1427 if (!ParseContextFormat2(font, data, length, num_glyphs, num_lookups)) { |
| 1428 return OTS_FAILURE_MSG("Failed to parse context format 2 subtable"); | 1428 return OTS_FAILURE_MSG("Failed to parse context format 2 subtable"); |
| 1429 } | 1429 } |
| 1430 } else if (format == 3) { | 1430 } else if (format == 3) { |
| 1431 if (!ParseContextFormat3(file, data, length, num_glyphs, num_lookups)) { | 1431 if (!ParseContextFormat3(font, data, length, num_glyphs, num_lookups)) { |
| 1432 return OTS_FAILURE_MSG("Failed to parse context format 3 subtable"); | 1432 return OTS_FAILURE_MSG("Failed to parse context format 3 subtable"); |
| 1433 } | 1433 } |
| 1434 } else { | 1434 } else { |
| 1435 return OTS_FAILURE_MSG("Bad context subtable format %d", format); | 1435 return OTS_FAILURE_MSG("Bad context subtable format %d", format); |
| 1436 } | 1436 } |
| 1437 | 1437 |
| 1438 return true; | 1438 return true; |
| 1439 } | 1439 } |
| 1440 | 1440 |
| 1441 bool ParseChainingContextSubtable(const ots::OpenTypeFile *file, | 1441 bool ParseChainingContextSubtable(const ots::Font *font, |
| 1442 const uint8_t *data, const size_t length, | 1442 const uint8_t *data, const size_t length, |
| 1443 const uint16_t num_glyphs, | 1443 const uint16_t num_glyphs, |
| 1444 const uint16_t num_lookups) { | 1444 const uint16_t num_lookups) { |
| 1445 Buffer subtable(data, length); | 1445 Buffer subtable(data, length); |
| 1446 | 1446 |
| 1447 uint16_t format = 0; | 1447 uint16_t format = 0; |
| 1448 if (!subtable.ReadU16(&format)) { | 1448 if (!subtable.ReadU16(&format)) { |
| 1449 return OTS_FAILURE_MSG("Failed to read chaining context subtable format"); | 1449 return OTS_FAILURE_MSG("Failed to read chaining context subtable format"); |
| 1450 } | 1450 } |
| 1451 | 1451 |
| 1452 if (format == 1) { | 1452 if (format == 1) { |
| 1453 if (!ParseChainContextFormat1(file, data, length, num_glyphs, num_lookups))
{ | 1453 if (!ParseChainContextFormat1(font, data, length, num_glyphs, num_lookups))
{ |
| 1454 return OTS_FAILURE_MSG("Failed to parse chaining context format 1 subtable
"); | 1454 return OTS_FAILURE_MSG("Failed to parse chaining context format 1 subtable
"); |
| 1455 } | 1455 } |
| 1456 } else if (format == 2) { | 1456 } else if (format == 2) { |
| 1457 if (!ParseChainContextFormat2(file, data, length, num_glyphs, num_lookups))
{ | 1457 if (!ParseChainContextFormat2(font, data, length, num_glyphs, num_lookups))
{ |
| 1458 return OTS_FAILURE_MSG("Failed to parse chaining context format 2 subtable
"); | 1458 return OTS_FAILURE_MSG("Failed to parse chaining context format 2 subtable
"); |
| 1459 } | 1459 } |
| 1460 } else if (format == 3) { | 1460 } else if (format == 3) { |
| 1461 if (!ParseChainContextFormat3(file, data, length, num_glyphs, num_lookups))
{ | 1461 if (!ParseChainContextFormat3(font, data, length, num_glyphs, num_lookups))
{ |
| 1462 return OTS_FAILURE_MSG("Failed to parse chaining context format 3 subtable
"); | 1462 return OTS_FAILURE_MSG("Failed to parse chaining context format 3 subtable
"); |
| 1463 } | 1463 } |
| 1464 } else { | 1464 } else { |
| 1465 return OTS_FAILURE_MSG("Bad chaining context subtable format %d", format); | 1465 return OTS_FAILURE_MSG("Bad chaining context subtable format %d", format); |
| 1466 } | 1466 } |
| 1467 | 1467 |
| 1468 return true; | 1468 return true; |
| 1469 } | 1469 } |
| 1470 | 1470 |
| 1471 bool ParseExtensionSubtable(const OpenTypeFile *file, | 1471 bool ParseExtensionSubtable(const Font *font, |
| 1472 const uint8_t *data, const size_t length, | 1472 const uint8_t *data, const size_t length, |
| 1473 const LookupSubtableParser* parser) { | 1473 const LookupSubtableParser* parser) { |
| 1474 Buffer subtable(data, length); | 1474 Buffer subtable(data, length); |
| 1475 | 1475 |
| 1476 uint16_t format = 0; | 1476 uint16_t format = 0; |
| 1477 uint16_t lookup_type = 0; | 1477 uint16_t lookup_type = 0; |
| 1478 uint32_t offset_extension = 0; | 1478 uint32_t offset_extension = 0; |
| 1479 if (!subtable.ReadU16(&format) || | 1479 if (!subtable.ReadU16(&format) || |
| 1480 !subtable.ReadU16(&lookup_type) || | 1480 !subtable.ReadU16(&lookup_type) || |
| 1481 !subtable.ReadU32(&offset_extension)) { | 1481 !subtable.ReadU32(&offset_extension)) { |
| 1482 return OTS_FAILURE_MSG("Failed to read extension table header"); | 1482 return OTS_FAILURE_MSG("Failed to read extension table header"); |
| 1483 } | 1483 } |
| 1484 | 1484 |
| 1485 if (format != 1) { | 1485 if (format != 1) { |
| 1486 return OTS_FAILURE_MSG("Bad extension table format %d", format); | 1486 return OTS_FAILURE_MSG("Bad extension table format %d", format); |
| 1487 } | 1487 } |
| 1488 // |lookup_type| should be other than |parser->extension_type|. | 1488 // |lookup_type| should be other than |parser->extension_type|. |
| 1489 if (lookup_type < 1 || lookup_type > parser->num_types || | 1489 if (lookup_type < 1 || lookup_type > parser->num_types || |
| 1490 lookup_type == parser->extension_type) { | 1490 lookup_type == parser->extension_type) { |
| 1491 return OTS_FAILURE_MSG("Bad lookup type %d in extension table", lookup_type)
; | 1491 return OTS_FAILURE_MSG("Bad lookup type %d in extension table", lookup_type)
; |
| 1492 } | 1492 } |
| 1493 | 1493 |
| 1494 const unsigned format_end = static_cast<unsigned>(8); | 1494 const unsigned format_end = static_cast<unsigned>(8); |
| 1495 if (offset_extension < format_end || | 1495 if (offset_extension < format_end || |
| 1496 offset_extension >= length) { | 1496 offset_extension >= length) { |
| 1497 return OTS_FAILURE_MSG("Bad extension offset %d", offset_extension); | 1497 return OTS_FAILURE_MSG("Bad extension offset %d", offset_extension); |
| 1498 } | 1498 } |
| 1499 | 1499 |
| 1500 // Parse the extension subtable of |lookup_type|. | 1500 // Parse the extension subtable of |lookup_type|. |
| 1501 if (!parser->Parse(file, data + offset_extension, length - offset_extension, | 1501 if (!parser->Parse(font, data + offset_extension, length - offset_extension, |
| 1502 lookup_type)) { | 1502 lookup_type)) { |
| 1503 return OTS_FAILURE_MSG("Failed to parse lookup from extension lookup"); | 1503 return OTS_FAILURE_MSG("Failed to parse lookup from extension lookup"); |
| 1504 } | 1504 } |
| 1505 | 1505 |
| 1506 return true; | 1506 return true; |
| 1507 } | 1507 } |
| 1508 | 1508 |
| 1509 } // namespace ots | 1509 } // namespace ots |
| 1510 | 1510 |
| 1511 #undef TABLE_NAME | 1511 #undef TABLE_NAME |
| OLD | NEW |