Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2011-2017 The OTS Authors. All rights reserved. |
2 | | // Use of this source code is governed by a BSD-style license that can be |
3 | | // found in the LICENSE file. |
4 | | |
5 | | #include "gdef.h" |
6 | | |
7 | | #include <limits> |
8 | | #include <vector> |
9 | | |
10 | | #include "gpos.h" |
11 | | #include "gsub.h" |
12 | | #include "layout.h" |
13 | | #include "maxp.h" |
14 | | #include "variations.h" |
15 | | |
16 | | // GDEF - The Glyph Definition Table |
17 | | // http://www.microsoft.com/typography/otspec/gdef.htm |
18 | | |
19 | | namespace { |
20 | | |
21 | | // The maximum class value in the glyph class definision table. |
22 | | const uint16_t kMaxGlyphClassDefValue = 4; |
23 | | // The maximum format number of caret value tables. |
24 | | const uint16_t kMaxCaretValueFormat = 3; |
25 | | |
26 | | } // namespace |
27 | | |
28 | | namespace ots { |
29 | | |
30 | 312 | bool OpenTypeGDEF::ParseAttachListTable(const uint8_t *data, size_t length) { |
31 | 312 | ots::Buffer subtable(data, length); |
32 | | |
33 | 312 | uint16_t offset_coverage = 0; |
34 | 312 | uint16_t glyph_count = 0; |
35 | 312 | if (!subtable.ReadU16(&offset_coverage) || |
36 | 312 | !subtable.ReadU16(&glyph_count)) { |
37 | 4 | return Error("Failed to read gdef header"); |
38 | 4 | } |
39 | 308 | const unsigned attach_points_end = |
40 | 308 | 2 * static_cast<unsigned>(glyph_count) + 4; |
41 | 308 | if (attach_points_end > std::numeric_limits<uint16_t>::max()) { |
42 | 3 | return Error("Bad glyph count in gdef"); |
43 | 3 | } |
44 | 305 | if (offset_coverage == 0 || offset_coverage >= length || |
45 | 305 | offset_coverage < attach_points_end) { |
46 | 61 | return Error("Bad coverage offset %d", offset_coverage); |
47 | 61 | } |
48 | 244 | if (glyph_count > this->m_num_glyphs) { |
49 | 4 | return Error("Bad glyph count %u", glyph_count); |
50 | 4 | } |
51 | | |
52 | 240 | std::vector<uint16_t> attach_points; |
53 | 240 | attach_points.resize(glyph_count); |
54 | 805 | for (unsigned i = 0; i < glyph_count; ++i) { |
55 | 582 | if (!subtable.ReadU16(&attach_points[i])) { |
56 | 0 | return Error("Can't read attachment point %d", i); |
57 | 0 | } |
58 | 582 | if (attach_points[i] >= length || |
59 | 582 | attach_points[i] < attach_points_end) { |
60 | 17 | return Error("Bad attachment point %d of %d", i, attach_points[i]); |
61 | 17 | } |
62 | 582 | } |
63 | | |
64 | | // Parse coverage table |
65 | 223 | if (!ots::ParseCoverageTable(GetFont(), data + offset_coverage, |
66 | 223 | length - offset_coverage, this->m_num_glyphs)) { |
67 | 36 | return Error("Bad coverage table"); |
68 | 36 | } |
69 | | |
70 | | // Parse attach point table |
71 | 594 | for (unsigned i = 0; i < attach_points.size(); ++i) { |
72 | 444 | subtable.set_offset(attach_points[i]); |
73 | 444 | uint16_t point_count = 0; |
74 | 444 | if (!subtable.ReadU16(&point_count)) { |
75 | 1 | return Error("Can't read point count %d", i); |
76 | 1 | } |
77 | 443 | if (point_count == 0) { |
78 | 1 | return Error("zero point count %d", i); |
79 | 1 | } |
80 | 442 | uint16_t last_point_index = 0; |
81 | 442 | uint16_t point_index = 0; |
82 | 1.23k | for (unsigned j = 0; j < point_count; ++j) { |
83 | 824 | if (!subtable.ReadU16(&point_index)) { |
84 | 18 | return Error("Can't read point index %d in point %d", j, i); |
85 | 18 | } |
86 | | // Contour point indices are in increasing numerical order |
87 | 806 | if (last_point_index != 0 && last_point_index >= point_index) { |
88 | 17 | return Error("bad contour indices: %u >= %u", |
89 | 17 | last_point_index, point_index); |
90 | 17 | } |
91 | 789 | last_point_index = point_index; |
92 | 789 | } |
93 | 442 | } |
94 | 150 | return true; |
95 | 187 | } |
96 | | |
97 | 411 | bool OpenTypeGDEF::ParseLigCaretListTable(const uint8_t *data, size_t length) { |
98 | 411 | ots::Buffer subtable(data, length); |
99 | 411 | uint16_t offset_coverage = 0; |
100 | 411 | uint16_t lig_glyph_count = 0; |
101 | 411 | if (!subtable.ReadU16(&offset_coverage) || |
102 | 411 | !subtable.ReadU16(&lig_glyph_count)) { |
103 | 24 | return Error("Can't read caret structure"); |
104 | 24 | } |
105 | 387 | const unsigned lig_glyphs_end = |
106 | 387 | 2 * static_cast<unsigned>(lig_glyph_count) + 4; |
107 | 387 | if (lig_glyphs_end > std::numeric_limits<uint16_t>::max()) { |
108 | 5 | return Error("Bad caret structure"); |
109 | 5 | } |
110 | 382 | if (offset_coverage == 0 || offset_coverage >= length || |
111 | 382 | offset_coverage < lig_glyphs_end) { |
112 | 98 | return Error("Bad caret coverate offset %d", offset_coverage); |
113 | 98 | } |
114 | 284 | if (lig_glyph_count > this->m_num_glyphs) { |
115 | 0 | return Error("bad ligature glyph count: %u", lig_glyph_count); |
116 | 0 | } |
117 | | |
118 | 284 | std::vector<uint16_t> lig_glyphs; |
119 | 284 | lig_glyphs.resize(lig_glyph_count); |
120 | 700 | for (unsigned i = 0; i < lig_glyph_count; ++i) { |
121 | 443 | if (!subtable.ReadU16(&lig_glyphs[i])) { |
122 | 0 | return Error("Can't read ligature glyph location %d", i); |
123 | 0 | } |
124 | 443 | if (lig_glyphs[i] >= length || lig_glyphs[i] < lig_glyphs_end) { |
125 | 27 | return Error("Bad ligature glyph location %d in glyph %d", lig_glyphs[i], i); |
126 | 27 | } |
127 | 443 | } |
128 | | |
129 | | // Parse coverage table |
130 | 257 | if (!ots::ParseCoverageTable(GetFont(), data + offset_coverage, |
131 | 257 | length - offset_coverage, this->m_num_glyphs)) { |
132 | 20 | return Error("Can't parse caret coverage table"); |
133 | 20 | } |
134 | | |
135 | | // Parse ligature glyph table |
136 | 427 | for (unsigned i = 0; i < lig_glyphs.size(); ++i) { |
137 | 302 | subtable.set_offset(lig_glyphs[i]); |
138 | 302 | uint16_t caret_count = 0; |
139 | 302 | if (!subtable.ReadU16(&caret_count)) { |
140 | 0 | return Error("Can't read caret count for glyph %d", i); |
141 | 0 | } |
142 | 302 | if (caret_count == 0) { |
143 | 15 | return Error("bad caret value count: %u", caret_count); |
144 | 15 | } |
145 | | |
146 | 287 | std::vector<uint16_t> caret_value_offsets; |
147 | 287 | caret_value_offsets.resize(caret_count); |
148 | 287 | unsigned caret_value_offsets_end = 2 * static_cast<unsigned>(caret_count) + 2; |
149 | 837 | for (unsigned j = 0; j < caret_count; ++j) { |
150 | 592 | if (!subtable.ReadU16(&caret_value_offsets[j])) { |
151 | 1 | return Error("Can't read caret offset %d for glyph %d", j, i); |
152 | 1 | } |
153 | 591 | if (caret_value_offsets[j] >= length || caret_value_offsets[j] < caret_value_offsets_end) { |
154 | 41 | return Error("Bad caret offset %d for caret %d glyph %d", caret_value_offsets[j], j, i); |
155 | 41 | } |
156 | 591 | } |
157 | | |
158 | | // Parse caret values table |
159 | 524 | for (unsigned j = 0; j < caret_count; ++j) { |
160 | 334 | subtable.set_offset(lig_glyphs[i] + caret_value_offsets[j]); |
161 | 334 | uint16_t caret_format = 0; |
162 | 334 | if (!subtable.ReadU16(&caret_format)) { |
163 | 16 | return Error("Can't read caret values table %d in glyph %d", j, i); |
164 | 16 | } |
165 | 318 | if (caret_format == 0 || caret_format > kMaxCaretValueFormat) { |
166 | 26 | return Error("bad caret value format: %u", caret_format); |
167 | 26 | } |
168 | | // CaretValueFormats contain a 2-byte field which could be |
169 | | // arbitrary value. |
170 | 292 | if (!subtable.Skip(2)) { |
171 | 0 | return Error("Bad caret value table structure %d in glyph %d", j, i); |
172 | 0 | } |
173 | 292 | if (caret_format == 3) { |
174 | 119 | uint16_t offset_device = 0; |
175 | 119 | if (!subtable.ReadU16(&offset_device)) { |
176 | 0 | return Error("Can't read device offset for caret value %d " |
177 | 0 | "in glyph %d", j, i); |
178 | 0 | } |
179 | 119 | size_t absolute_offset = lig_glyphs[i] + caret_value_offsets[j] |
180 | 119 | + offset_device; |
181 | 119 | if (offset_device == 0 || absolute_offset >= length) { |
182 | 1 | return Error("Bad device offset for caret value %d in glyph %d: %d", |
183 | 1 | j, i, offset_device); |
184 | 1 | } |
185 | 118 | if (!ots::ParseDeviceTable(GetFont(), data + absolute_offset, |
186 | 118 | length - absolute_offset)) { |
187 | 12 | return Error("Bad device table for caret value %d in glyph %d", |
188 | 12 | j, i, offset_device); |
189 | 12 | } |
190 | 118 | } |
191 | 292 | } |
192 | 245 | } |
193 | 125 | return true; |
194 | 237 | } |
195 | | |
196 | 402 | bool OpenTypeGDEF::ParseMarkGlyphSetsDefTable(const uint8_t *data, size_t length) { |
197 | 402 | ots::Buffer subtable(data, length); |
198 | 402 | uint16_t format = 0; |
199 | 402 | uint16_t mark_set_count = 0; |
200 | 402 | if (!subtable.ReadU16(&format) || |
201 | 402 | !subtable.ReadU16(&mark_set_count)) { |
202 | 2 | return Error("Can' read mark glyph table structure"); |
203 | 2 | } |
204 | 400 | if (format != 1) { |
205 | 32 | return Error("bad mark glyph set table format: %u", format); |
206 | 32 | } |
207 | | |
208 | 368 | const unsigned mark_sets_end = 2 * static_cast<unsigned>(mark_set_count) + 4; |
209 | 368 | if (mark_sets_end > std::numeric_limits<uint16_t>::max()) { |
210 | 18 | return Error("Bad mark_set %d", mark_sets_end); |
211 | 18 | } |
212 | 1.73k | for (unsigned i = 0; i < mark_set_count; ++i) { |
213 | 1.45k | uint32_t offset_coverage = 0; |
214 | 1.45k | if (!subtable.ReadU32(&offset_coverage)) { |
215 | 5 | return Error("Can't read covrage location for mark set %d", i); |
216 | 5 | } |
217 | 1.45k | if (offset_coverage >= length || |
218 | 1.45k | offset_coverage < mark_sets_end) { |
219 | 59 | return Error("Bad coverage location %d for mark set %d", offset_coverage, i); |
220 | 59 | } |
221 | 1.39k | if (!ots::ParseCoverageTable(GetFont(), data + offset_coverage, |
222 | 1.39k | length - offset_coverage, this->m_num_glyphs)) { |
223 | 7 | return Error("Failed to parse coverage table for mark set %d", i); |
224 | 7 | } |
225 | 1.39k | } |
226 | 279 | this->num_mark_glyph_sets = mark_set_count; |
227 | 279 | return true; |
228 | 350 | } |
229 | | |
230 | 2.35k | bool OpenTypeGDEF::Parse(const uint8_t *data, size_t length) { |
231 | 2.35k | OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>( |
232 | 2.35k | GetFont()->GetTypedTable(OTS_TAG_MAXP)); |
233 | | |
234 | | // Grab the number of glyphs in the font from the maxp table to check |
235 | | // GlyphIDs in GDEF table. |
236 | 2.35k | if (!maxp) { |
237 | 0 | return Error("No maxp table in font, needed by GDEF"); |
238 | 0 | } |
239 | 2.35k | this->m_num_glyphs = maxp->num_glyphs; |
240 | | |
241 | 2.35k | Buffer table(data, length); |
242 | | |
243 | 2.35k | uint16_t version_major = 0, version_minor = 0; |
244 | 2.35k | if (!table.ReadU16(&version_major) || |
245 | 2.35k | !table.ReadU16(&version_minor)) { |
246 | 2 | return Error("Incomplete table"); |
247 | 2 | } |
248 | 2.35k | if (version_major != 1 || version_minor == 1) { // there is no v1.1 |
249 | 38 | return Error("Bad version"); |
250 | 38 | } |
251 | | |
252 | 2.31k | uint16_t offset_glyph_class_def = 0; |
253 | 2.31k | uint16_t offset_attach_list = 0; |
254 | 2.31k | uint16_t offset_lig_caret_list = 0; |
255 | 2.31k | uint16_t offset_mark_attach_class_def = 0; |
256 | 2.31k | if (!table.ReadU16(&offset_glyph_class_def) || |
257 | 2.31k | !table.ReadU16(&offset_attach_list) || |
258 | 2.31k | !table.ReadU16(&offset_lig_caret_list) || |
259 | 2.31k | !table.ReadU16(&offset_mark_attach_class_def)) { |
260 | 4 | return Error("Incomplete table"); |
261 | 4 | } |
262 | 2.31k | uint16_t offset_mark_glyph_sets_def = 0; |
263 | 2.31k | if (version_minor >= 2) { |
264 | 1.16k | if (!table.ReadU16(&offset_mark_glyph_sets_def)) { |
265 | 1 | return Error("Incomplete table"); |
266 | 1 | } |
267 | 1.16k | } |
268 | 2.31k | uint32_t item_var_store_offset = 0; |
269 | 2.31k | if (version_minor >= 3) { |
270 | 1.01k | if (!table.ReadU32(&item_var_store_offset)) { |
271 | 19 | return Error("Incomplete table"); |
272 | 19 | } |
273 | 1.01k | } |
274 | | |
275 | 2.29k | unsigned gdef_header_end = 4 + 4 * 2; |
276 | 2.29k | if (version_minor >= 2) |
277 | 1.14k | gdef_header_end += 2; |
278 | 2.29k | if (version_minor >= 3) |
279 | 997 | gdef_header_end += 4; |
280 | | |
281 | | // Parse subtables |
282 | 2.29k | if (offset_glyph_class_def) { |
283 | 1.21k | if (offset_glyph_class_def >= length || |
284 | 1.21k | offset_glyph_class_def < gdef_header_end) { |
285 | 18 | return Error("Invalid offset to glyph classes"); |
286 | 18 | } |
287 | 1.19k | if (!ots::ParseClassDefTable(GetFont(), data + offset_glyph_class_def, |
288 | 1.19k | length - offset_glyph_class_def, |
289 | 1.19k | this->m_num_glyphs, kMaxGlyphClassDefValue)) { |
290 | 97 | return Error("Invalid glyph classes"); |
291 | 97 | } |
292 | 1.19k | } |
293 | | |
294 | 2.17k | if (offset_attach_list) { |
295 | 336 | if (offset_attach_list >= length || |
296 | 336 | offset_attach_list < gdef_header_end) { |
297 | 24 | return Error("Invalid offset to attachment list"); |
298 | 24 | } |
299 | 312 | if (!ParseAttachListTable(data + offset_attach_list, |
300 | 312 | length - offset_attach_list)) { |
301 | 162 | return Error("Invalid attachment list"); |
302 | 162 | } |
303 | 312 | } |
304 | | |
305 | 1.99k | if (offset_lig_caret_list) { |
306 | 429 | if (offset_lig_caret_list >= length || |
307 | 429 | offset_lig_caret_list < gdef_header_end) { |
308 | 18 | return Error("Invalid offset to ligature caret list"); |
309 | 18 | } |
310 | 411 | if (!ParseLigCaretListTable(data + offset_lig_caret_list, |
311 | 411 | length - offset_lig_caret_list)) { |
312 | 286 | return Error("Invalid ligature caret list"); |
313 | 286 | } |
314 | 411 | } |
315 | | |
316 | 1.68k | if (offset_mark_attach_class_def) { |
317 | 545 | if (offset_mark_attach_class_def >= length || |
318 | 545 | offset_mark_attach_class_def < gdef_header_end) { |
319 | 40 | return Error("Invalid offset to mark attachment list"); |
320 | 40 | } |
321 | 505 | if (!ots::ParseClassDefTable(GetFont(), |
322 | 505 | data + offset_mark_attach_class_def, |
323 | 505 | length - offset_mark_attach_class_def, |
324 | 505 | this->m_num_glyphs, kMaxClassDefValue)) { |
325 | 24 | return Error("Invalid mark attachment list"); |
326 | 24 | } |
327 | 505 | } |
328 | | |
329 | 1.62k | if (offset_mark_glyph_sets_def) { |
330 | 414 | if (offset_mark_glyph_sets_def >= length || |
331 | 414 | offset_mark_glyph_sets_def < gdef_header_end) { |
332 | 12 | return Error("invalid offset to mark glyph sets"); |
333 | 12 | } |
334 | 402 | if (!ParseMarkGlyphSetsDefTable(data + offset_mark_glyph_sets_def, |
335 | 402 | length - offset_mark_glyph_sets_def)) { |
336 | 123 | return Error("Invalid mark glyph sets"); |
337 | 123 | } |
338 | 402 | } |
339 | | |
340 | 1.48k | if (item_var_store_offset) { |
341 | 232 | if (item_var_store_offset >= length || |
342 | 232 | item_var_store_offset < gdef_header_end) { |
343 | 60 | return Error("invalid offset to item variation store"); |
344 | 60 | } |
345 | 172 | if (!ParseItemVariationStore(GetFont(), data + item_var_store_offset, |
346 | 172 | length - item_var_store_offset)) { |
347 | 102 | return Error("Invalid item variation store"); |
348 | 102 | } |
349 | 172 | } |
350 | | |
351 | 1.32k | this->m_data = data; |
352 | 1.32k | this->m_length = length; |
353 | 1.32k | return true; |
354 | 1.48k | } |
355 | | |
356 | 541 | bool OpenTypeGDEF::Serialize(OTSStream *out) { |
357 | 541 | if (!out->Write(this->m_data, this->m_length)) { |
358 | 0 | return Error("Failed to write table"); |
359 | 0 | } |
360 | | |
361 | 541 | return true; |
362 | 541 | } |
363 | | |
364 | | } // namespace ots |