OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 "cmap.h" | 5 #include "cmap.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <set> | 8 #include <set> |
9 #include <utility> | 9 #include <utility> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "maxp.h" | 12 #include "maxp.h" |
13 #include "os2.h" | 13 #include "os2.h" |
14 | 14 |
15 // cmap - Character To Glyph Index Mapping Table | 15 // cmap - Character To Glyph Index Mapping Table |
16 // http://www.microsoft.com/opentype/otspec/cmap.htm | 16 // http://www.microsoft.com/typography/otspec/cmap.htm |
| 17 |
| 18 #define TABLE_NAME "cmap" |
17 | 19 |
18 namespace { | 20 namespace { |
19 | 21 |
20 struct CMAPSubtableHeader { | 22 struct CMAPSubtableHeader { |
21 uint16_t platform; | 23 uint16_t platform; |
22 uint16_t encoding; | 24 uint16_t encoding; |
23 uint32_t offset; | 25 uint32_t offset; |
24 uint16_t format; | 26 uint16_t format; |
25 uint32_t length; | 27 uint32_t length; |
| 28 uint32_t language; |
26 }; | 29 }; |
27 | 30 |
28 struct Subtable314Range { | 31 struct Subtable314Range { |
29 uint16_t start_range; | 32 uint16_t start_range; |
30 uint16_t end_range; | 33 uint16_t end_range; |
31 int16_t id_delta; | 34 int16_t id_delta; |
32 uint16_t id_range_offset; | 35 uint16_t id_range_offset; |
33 uint32_t id_range_offset_offset; | 36 uint32_t id_range_offset_offset; |
34 }; | 37 }; |
35 | 38 |
(...skipping 24 matching lines...) Expand all Loading... |
60 // Parses Format 4 tables | 63 // Parses Format 4 tables |
61 bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding, | 64 bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding, |
62 const uint8_t *data, size_t length, uint16_t num_glyphs) { | 65 const uint8_t *data, size_t length, uint16_t num_glyphs) { |
63 ots::Buffer subtable(data, length); | 66 ots::Buffer subtable(data, length); |
64 | 67 |
65 // 0.3.4, 3.0.4 or 3.1.4 subtables are complex and, rather than expanding the | 68 // 0.3.4, 3.0.4 or 3.1.4 subtables are complex and, rather than expanding the |
66 // whole thing and recompacting it, we validate it and include it verbatim | 69 // whole thing and recompacting it, we validate it and include it verbatim |
67 // in the output. | 70 // in the output. |
68 | 71 |
69 if (!file->os2) { | 72 if (!file->os2) { |
70 return OTS_FAILURE(); | 73 return OTS_FAILURE_MSG("Required OS/2 table missing"); |
71 } | 74 } |
72 | 75 |
73 if (!subtable.Skip(4)) { | 76 if (!subtable.Skip(4)) { |
74 return OTS_FAILURE(); | 77 return OTS_FAILURE_MSG("Can't read 4 bytes at start of cmap format 4 subtabl
e"); |
75 } | 78 } |
76 uint16_t language = 0; | 79 uint16_t language = 0; |
77 if (!subtable.ReadU16(&language)) { | 80 if (!subtable.ReadU16(&language)) { |
78 return OTS_FAILURE(); | 81 return OTS_FAILURE_MSG("Can't read language"); |
79 } | 82 } |
80 if (language) { | 83 if (language) { |
81 // Platform ID 3 (windows) subtables should have language '0'. | 84 // Platform ID 3 (windows) subtables should have language '0'. |
82 return OTS_FAILURE(); | 85 return OTS_FAILURE_MSG("Languages should be 0 (%d)", language); |
83 } | 86 } |
84 | 87 |
85 uint16_t segcountx2, search_range, entry_selector, range_shift; | 88 uint16_t segcountx2, search_range, entry_selector, range_shift; |
86 segcountx2 = search_range = entry_selector = range_shift = 0; | 89 segcountx2 = search_range = entry_selector = range_shift = 0; |
87 if (!subtable.ReadU16(&segcountx2) || | 90 if (!subtable.ReadU16(&segcountx2) || |
88 !subtable.ReadU16(&search_range) || | 91 !subtable.ReadU16(&search_range) || |
89 !subtable.ReadU16(&entry_selector) || | 92 !subtable.ReadU16(&entry_selector) || |
90 !subtable.ReadU16(&range_shift)) { | 93 !subtable.ReadU16(&range_shift)) { |
91 return OTS_FAILURE(); | 94 return OTS_FAILURE_MSG("Failed to read subcmap structure"); |
92 } | 95 } |
93 | 96 |
94 if (segcountx2 & 1 || search_range & 1) { | 97 if (segcountx2 & 1 || search_range & 1) { |
95 return OTS_FAILURE(); | 98 return OTS_FAILURE_MSG("Bad subcmap structure"); |
96 } | 99 } |
97 const uint16_t segcount = segcountx2 >> 1; | 100 const uint16_t segcount = segcountx2 >> 1; |
98 // There must be at least one segment according the spec. | 101 // There must be at least one segment according the spec. |
99 if (segcount < 1) { | 102 if (segcount < 1) { |
100 return OTS_FAILURE(); | 103 return OTS_FAILURE_MSG("Segcount < 1 (%d)", segcount); |
101 } | 104 } |
102 | 105 |
103 // log2segcount is the maximal x s.t. 2^x < segcount | 106 // log2segcount is the maximal x s.t. 2^x < segcount |
104 unsigned log2segcount = 0; | 107 unsigned log2segcount = 0; |
105 while (1u << (log2segcount + 1) <= segcount) { | 108 while (1u << (log2segcount + 1) <= segcount) { |
106 log2segcount++; | 109 log2segcount++; |
107 } | 110 } |
108 | 111 |
109 const uint16_t expected_search_range = 2 * 1u << log2segcount; | 112 const uint16_t expected_search_range = 2 * 1u << log2segcount; |
110 if (expected_search_range != search_range) { | 113 if (expected_search_range != search_range) { |
111 return OTS_FAILURE(); | 114 return OTS_FAILURE_MSG("expected search range != search range (%d != %d)", e
xpected_search_range, search_range); |
112 } | 115 } |
113 | 116 |
114 if (entry_selector != log2segcount) { | 117 if (entry_selector != log2segcount) { |
115 return OTS_FAILURE(); | 118 return OTS_FAILURE_MSG("entry selector != log2(segement count) (%d != %d)",
entry_selector, log2segcount); |
116 } | 119 } |
117 | 120 |
118 const uint16_t expected_range_shift = segcountx2 - search_range; | 121 const uint16_t expected_range_shift = segcountx2 - search_range; |
119 if (range_shift != expected_range_shift) { | 122 if (range_shift != expected_range_shift) { |
120 return OTS_FAILURE(); | 123 return OTS_FAILURE_MSG("unexpected range shift (%d != %d)", range_shift, exp
ected_range_shift); |
121 } | 124 } |
122 | 125 |
123 std::vector<Subtable314Range> ranges(segcount); | 126 std::vector<Subtable314Range> ranges(segcount); |
124 | 127 |
125 for (unsigned i = 0; i < segcount; ++i) { | 128 for (unsigned i = 0; i < segcount; ++i) { |
126 if (!subtable.ReadU16(&ranges[i].end_range)) { | 129 if (!subtable.ReadU16(&ranges[i].end_range)) { |
127 return OTS_FAILURE(); | 130 return OTS_FAILURE_MSG("Failed to read segment %d", i); |
128 } | 131 } |
129 } | 132 } |
130 | 133 |
131 uint16_t padding; | 134 uint16_t padding; |
132 if (!subtable.ReadU16(&padding)) { | 135 if (!subtable.ReadU16(&padding)) { |
133 return OTS_FAILURE(); | 136 return OTS_FAILURE_MSG("Failed to read cmap subtable segment padding"); |
134 } | 137 } |
135 if (padding) { | 138 if (padding) { |
136 return OTS_FAILURE(); | 139 return OTS_FAILURE_MSG("Non zero cmap subtable segment padding (%d)", paddin
g); |
137 } | 140 } |
138 | 141 |
139 for (unsigned i = 0; i < segcount; ++i) { | 142 for (unsigned i = 0; i < segcount; ++i) { |
140 if (!subtable.ReadU16(&ranges[i].start_range)) { | 143 if (!subtable.ReadU16(&ranges[i].start_range)) { |
141 return OTS_FAILURE(); | 144 return OTS_FAILURE_MSG("Failed to read segment start range %d", i); |
142 } | 145 } |
143 } | 146 } |
144 for (unsigned i = 0; i < segcount; ++i) { | 147 for (unsigned i = 0; i < segcount; ++i) { |
145 if (!subtable.ReadS16(&ranges[i].id_delta)) { | 148 if (!subtable.ReadS16(&ranges[i].id_delta)) { |
146 return OTS_FAILURE(); | 149 return OTS_FAILURE_MSG("Failed to read segment delta %d", i); |
147 } | 150 } |
148 } | 151 } |
149 for (unsigned i = 0; i < segcount; ++i) { | 152 for (unsigned i = 0; i < segcount; ++i) { |
150 ranges[i].id_range_offset_offset = subtable.offset(); | 153 ranges[i].id_range_offset_offset = subtable.offset(); |
151 if (!subtable.ReadU16(&ranges[i].id_range_offset)) { | 154 if (!subtable.ReadU16(&ranges[i].id_range_offset)) { |
152 return OTS_FAILURE(); | 155 return OTS_FAILURE_MSG("Failed to read segment range offset %d", i); |
153 } | 156 } |
154 | 157 |
155 if (ranges[i].id_range_offset & 1) { | 158 if (ranges[i].id_range_offset & 1) { |
156 // Some font generators seem to put 65535 on id_range_offset | 159 // Some font generators seem to put 65535 on id_range_offset |
157 // for 0xFFFF-0xFFFF range. | 160 // for 0xFFFF-0xFFFF range. |
158 // (e.g., many fonts in http://www.princexml.com/fonts/) | 161 // (e.g., many fonts in http://www.princexml.com/fonts/) |
159 if (i == segcount - 1u) { | 162 if (i == segcount - 1u) { |
160 OTS_WARNING("bad id_range_offset"); | 163 OTS_WARNING("bad id_range_offset"); |
161 ranges[i].id_range_offset = 0; | 164 ranges[i].id_range_offset = 0; |
162 // The id_range_offset value in the transcoded font will not change | 165 // The id_range_offset value in the transcoded font will not change |
163 // since this table is not actually "transcoded" yet. | 166 // since this table is not actually "transcoded" yet. |
164 } else { | 167 } else { |
165 return OTS_FAILURE(); | 168 return OTS_FAILURE_MSG("Bad segment offset (%d)", ranges[i].id_range_off
set); |
166 } | 169 } |
167 } | 170 } |
168 } | 171 } |
169 | 172 |
170 // ranges must be ascending order, based on the end_code. Ranges may not | 173 // ranges must be ascending order, based on the end_code. Ranges may not |
171 // overlap. | 174 // overlap. |
172 for (unsigned i = 1; i < segcount; ++i) { | 175 for (unsigned i = 1; i < segcount; ++i) { |
173 if ((i == segcount - 1u) && | 176 if ((i == segcount - 1u) && |
174 (ranges[i - 1].start_range == 0xffff) && | 177 (ranges[i - 1].start_range == 0xffff) && |
175 (ranges[i - 1].end_range == 0xffff) && | 178 (ranges[i - 1].end_range == 0xffff) && |
176 (ranges[i].start_range == 0xffff) && | 179 (ranges[i].start_range == 0xffff) && |
177 (ranges[i].end_range == 0xffff)) { | 180 (ranges[i].end_range == 0xffff)) { |
178 // Some fonts (e.g., Germania.ttf) have multiple 0xffff terminators. | 181 // Some fonts (e.g., Germania.ttf) have multiple 0xffff terminators. |
179 // We'll accept them as an exception. | 182 // We'll accept them as an exception. |
180 OTS_WARNING("multiple 0xffff terminators found"); | 183 OTS_WARNING("multiple 0xffff terminators found"); |
181 continue; | 184 continue; |
182 } | 185 } |
183 | 186 |
184 // Note: some Linux fonts (e.g., LucidaSansOblique.ttf, bsmi00lp.ttf) have | 187 // Note: some Linux fonts (e.g., LucidaSansOblique.ttf, bsmi00lp.ttf) have |
185 // unsorted table... | 188 // unsorted table... |
186 if (ranges[i].end_range <= ranges[i - 1].end_range) { | 189 if (ranges[i].end_range <= ranges[i - 1].end_range) { |
187 return OTS_FAILURE(); | 190 return OTS_FAILURE_MSG("Out of order end range (%d <= %d)", ranges[i].end_
range, ranges[i-1].end_range); |
188 } | 191 } |
189 if (ranges[i].start_range <= ranges[i - 1].end_range) { | 192 if (ranges[i].start_range <= ranges[i - 1].end_range) { |
190 return OTS_FAILURE(); | 193 return OTS_FAILURE_MSG("out of order start range (%d <= %d)", ranges[i].st
art_range, ranges[i-1].end_range); |
191 } | 194 } |
192 | 195 |
193 // On many fonts, the value of {first, last}_char_index are incorrect. | 196 // On many fonts, the value of {first, last}_char_index are incorrect. |
194 // Fix them. | 197 // Fix them. |
195 if (file->os2->first_char_index != 0xFFFF && | 198 if (file->os2->first_char_index != 0xFFFF && |
196 ranges[i].start_range != 0xFFFF && | 199 ranges[i].start_range != 0xFFFF && |
197 file->os2->first_char_index > ranges[i].start_range) { | 200 file->os2->first_char_index > ranges[i].start_range) { |
198 file->os2->first_char_index = ranges[i].start_range; | 201 file->os2->first_char_index = ranges[i].start_range; |
199 } | 202 } |
200 if (file->os2->last_char_index != 0xFFFF && | 203 if (file->os2->last_char_index != 0xFFFF && |
201 ranges[i].end_range != 0xFFFF && | 204 ranges[i].end_range != 0xFFFF && |
202 file->os2->last_char_index < ranges[i].end_range) { | 205 file->os2->last_char_index < ranges[i].end_range) { |
203 file->os2->last_char_index = ranges[i].end_range; | 206 file->os2->last_char_index = ranges[i].end_range; |
204 } | 207 } |
205 } | 208 } |
206 | 209 |
207 // The last range must end at 0xffff | 210 // The last range must end at 0xffff |
208 if (ranges[segcount - 1].end_range != 0xffff) { | 211 if (ranges[segcount - 1].start_range != 0xffff || ranges[segcount - 1].end_ran
ge != 0xffff) { |
209 return OTS_FAILURE(); | 212 return OTS_FAILURE_MSG("Final segment start and end must be 0xFFFF (0x%04X-0
x%04X)", |
| 213 ranges[segcount - 1].start_range, ranges[segcount - 1
].end_range); |
210 } | 214 } |
211 | 215 |
212 // A format 4 CMAP subtable is complex. To be safe we simulate a lookup of | 216 // A format 4 CMAP subtable is complex. To be safe we simulate a lookup of |
213 // each code-point defined in the table and make sure that they are all valid | 217 // each code-point defined in the table and make sure that they are all valid |
214 // glyphs and that we don't access anything out-of-bounds. | 218 // glyphs and that we don't access anything out-of-bounds. |
215 for (unsigned i = 0; i < segcount; ++i) { | 219 for (unsigned i = 0; i < segcount; ++i) { |
216 for (unsigned cp = ranges[i].start_range; cp <= ranges[i].end_range; ++cp) { | 220 for (unsigned cp = ranges[i].start_range; cp <= ranges[i].end_range; ++cp) { |
217 const uint16_t code_point = static_cast<uint16_t>(cp); | 221 const uint16_t code_point = static_cast<uint16_t>(cp); |
218 if (ranges[i].id_range_offset == 0) { | 222 if (ranges[i].id_range_offset == 0) { |
219 // this is explictly allowed to overflow in the spec | 223 // this is explictly allowed to overflow in the spec |
220 const uint16_t glyph = code_point + ranges[i].id_delta; | 224 const uint16_t glyph = code_point + ranges[i].id_delta; |
221 if (glyph >= num_glyphs) { | 225 if (glyph >= num_glyphs) { |
222 return OTS_FAILURE(); | 226 return OTS_FAILURE_MSG("Range glyph reference too high (%d > %d)", gly
ph, num_glyphs - 1); |
223 } | 227 } |
224 } else { | 228 } else { |
225 const uint16_t range_delta = code_point - ranges[i].start_range; | 229 const uint16_t range_delta = code_point - ranges[i].start_range; |
226 // this might seem odd, but it's true. The offset is relative to the | 230 // this might seem odd, but it's true. The offset is relative to the |
227 // location of the offset value itself. | 231 // location of the offset value itself. |
228 const uint32_t glyph_id_offset = ranges[i].id_range_offset_offset + | 232 const uint32_t glyph_id_offset = ranges[i].id_range_offset_offset + |
229 ranges[i].id_range_offset + | 233 ranges[i].id_range_offset + |
230 range_delta * 2; | 234 range_delta * 2; |
231 // We need to be able to access a 16-bit value from this offset | 235 // We need to be able to access a 16-bit value from this offset |
232 if (glyph_id_offset + 1 >= length) { | 236 if (glyph_id_offset + 1 >= length) { |
233 return OTS_FAILURE(); | 237 return OTS_FAILURE_MSG("bad glyph id offset (%d > %ld)", glyph_id_offs
et, length); |
234 } | 238 } |
235 uint16_t glyph; | 239 uint16_t glyph; |
236 std::memcpy(&glyph, data + glyph_id_offset, 2); | 240 std::memcpy(&glyph, data + glyph_id_offset, 2); |
237 glyph = ntohs(glyph); | 241 glyph = ntohs(glyph); |
238 if (glyph >= num_glyphs) { | 242 if (glyph >= num_glyphs) { |
239 return OTS_FAILURE(); | 243 return OTS_FAILURE_MSG("Range glyph reference too high (%d > %d)", gly
ph, num_glyphs - 1); |
240 } | 244 } |
241 } | 245 } |
242 } | 246 } |
243 } | 247 } |
244 | 248 |
245 // We accept the table. | 249 // We accept the table. |
246 // TODO(yusukes): transcode the subtable. | 250 // TODO(yusukes): transcode the subtable. |
247 if (platform == 3 && encoding == 0) { | 251 if (platform == 3 && encoding == 0) { |
248 file->cmap->subtable_3_0_4_data = data; | 252 file->cmap->subtable_3_0_4_data = data; |
249 file->cmap->subtable_3_0_4_length = length; | 253 file->cmap->subtable_3_0_4_length = length; |
250 } else if (platform == 3 && encoding == 1) { | 254 } else if (platform == 3 && encoding == 1) { |
251 file->cmap->subtable_3_1_4_data = data; | 255 file->cmap->subtable_3_1_4_data = data; |
252 file->cmap->subtable_3_1_4_length = length; | 256 file->cmap->subtable_3_1_4_length = length; |
253 } else if (platform == 0 && encoding == 3) { | 257 } else if (platform == 0 && encoding == 3) { |
254 file->cmap->subtable_0_3_4_data = data; | 258 file->cmap->subtable_0_3_4_data = data; |
255 file->cmap->subtable_0_3_4_length = length; | 259 file->cmap->subtable_0_3_4_length = length; |
256 } else { | 260 } else { |
257 return OTS_FAILURE(); | 261 return OTS_FAILURE_MSG("Unknown cmap subtable type (platform=%d, encoding=%d
)", platform, encoding); |
258 } | 262 } |
259 | 263 |
260 return true; | 264 return true; |
261 } | 265 } |
262 | 266 |
263 bool Parse31012(ots::OpenTypeFile *file, | 267 bool Parse31012(ots::OpenTypeFile *file, |
264 const uint8_t *data, size_t length, uint16_t num_glyphs) { | 268 const uint8_t *data, size_t length, uint16_t num_glyphs) { |
265 ots::Buffer subtable(data, length); | 269 ots::Buffer subtable(data, length); |
266 | 270 |
267 // Format 12 tables are simple. We parse these and fully serialise them | 271 // Format 12 tables are simple. We parse these and fully serialise them |
268 // later. | 272 // later. |
269 | 273 |
270 if (!subtable.Skip(8)) { | 274 if (!subtable.Skip(8)) { |
271 return OTS_FAILURE(); | 275 return OTS_FAILURE_MSG("failed to skip the first 8 bytes of format 12 subtab
le"); |
272 } | 276 } |
273 uint32_t language = 0; | 277 uint32_t language = 0; |
274 if (!subtable.ReadU32(&language)) { | 278 if (!subtable.ReadU32(&language)) { |
275 return OTS_FAILURE(); | 279 return OTS_FAILURE_MSG("can't read format 12 subtable language"); |
276 } | 280 } |
277 if (language) { | 281 if (language) { |
278 return OTS_FAILURE(); | 282 return OTS_FAILURE_MSG("format 12 subtable language should be zero (%d)", la
nguage); |
279 } | 283 } |
280 | 284 |
281 uint32_t num_groups = 0; | 285 uint32_t num_groups = 0; |
282 if (!subtable.ReadU32(&num_groups)) { | 286 if (!subtable.ReadU32(&num_groups)) { |
283 return OTS_FAILURE(); | 287 return OTS_FAILURE_MSG("can't read number of format 12 subtable groups"); |
284 } | 288 } |
285 if (num_groups == 0 || num_groups > kMaxCMAPGroups) { | 289 if (num_groups == 0 || num_groups > kMaxCMAPGroups) { |
286 return OTS_FAILURE(); | 290 return OTS_FAILURE_MSG("bad format 12 subtable group count %d", num_groups); |
287 } | 291 } |
288 | 292 |
289 std::vector<ots::OpenTypeCMAPSubtableRange> &groups | 293 std::vector<ots::OpenTypeCMAPSubtableRange> &groups |
290 = file->cmap->subtable_3_10_12; | 294 = file->cmap->subtable_3_10_12; |
291 groups.resize(num_groups); | 295 groups.resize(num_groups); |
292 | 296 |
293 for (unsigned i = 0; i < num_groups; ++i) { | 297 for (unsigned i = 0; i < num_groups; ++i) { |
294 if (!subtable.ReadU32(&groups[i].start_range) || | 298 if (!subtable.ReadU32(&groups[i].start_range) || |
295 !subtable.ReadU32(&groups[i].end_range) || | 299 !subtable.ReadU32(&groups[i].end_range) || |
296 !subtable.ReadU32(&groups[i].start_glyph_id)) { | 300 !subtable.ReadU32(&groups[i].start_glyph_id)) { |
297 return OTS_FAILURE(); | 301 return OTS_FAILURE_MSG("can't read format 12 subtable group"); |
298 } | 302 } |
299 | 303 |
300 if (groups[i].start_range > kUnicodeUpperLimit || | 304 if (groups[i].start_range > kUnicodeUpperLimit || |
301 groups[i].end_range > kUnicodeUpperLimit || | 305 groups[i].end_range > kUnicodeUpperLimit || |
302 groups[i].start_glyph_id > 0xFFFF) { | 306 groups[i].start_glyph_id > 0xFFFF) { |
303 return OTS_FAILURE(); | 307 return OTS_FAILURE_MSG("bad format 12 subtable group (startCharCode=0x%4X,
endCharCode=0x%4X, startGlyphID=%d)", |
| 308 groups[i].start_range, groups[i].end_range, groups[
i].start_glyph_id); |
304 } | 309 } |
305 | 310 |
306 // [0xD800, 0xDFFF] are surrogate code points. | 311 // [0xD800, 0xDFFF] are surrogate code points. |
307 if (groups[i].start_range >= 0xD800 && | 312 if (groups[i].start_range >= 0xD800 && |
308 groups[i].start_range <= 0xDFFF) { | 313 groups[i].start_range <= 0xDFFF) { |
309 return OTS_FAILURE(); | 314 return OTS_FAILURE_MSG("format 12 subtable out of range group startCharCod
e (0x%4X)", groups[i].start_range); |
310 } | 315 } |
311 if (groups[i].end_range >= 0xD800 && | 316 if (groups[i].end_range >= 0xD800 && |
312 groups[i].end_range <= 0xDFFF) { | 317 groups[i].end_range <= 0xDFFF) { |
313 return OTS_FAILURE(); | 318 return OTS_FAILURE_MSG("format 12 subtable out of range group endCharCode
(0x%4X)", groups[i].end_range); |
314 } | 319 } |
315 if (groups[i].start_range < 0xD800 && | 320 if (groups[i].start_range < 0xD800 && |
316 groups[i].end_range > 0xDFFF) { | 321 groups[i].end_range > 0xDFFF) { |
317 return OTS_FAILURE(); | 322 return OTS_FAILURE_MSG("bad format 12 subtable group startCharCode (0x%4X)
or endCharCode (0x%4X)", |
| 323 groups[i].start_range, groups[i].end_range); |
318 } | 324 } |
319 | 325 |
320 // We assert that the glyph value is within range. Because of the range | 326 // We assert that the glyph value is within range. Because of the range |
321 // limits, above, we don't need to worry about overflow. | 327 // limits, above, we don't need to worry about overflow. |
322 if (groups[i].end_range < groups[i].start_range) { | 328 if (groups[i].end_range < groups[i].start_range) { |
323 return OTS_FAILURE(); | 329 return OTS_FAILURE_MSG("format 12 subtable group endCharCode before startC
harCode (0x%4X < 0x%4X)", |
| 330 groups[i].end_range, groups[i].start_range); |
324 } | 331 } |
325 if ((groups[i].end_range - groups[i].start_range) + | 332 if ((groups[i].end_range - groups[i].start_range) + |
326 groups[i].start_glyph_id > num_glyphs) { | 333 groups[i].start_glyph_id > num_glyphs) { |
327 return OTS_FAILURE(); | 334 return OTS_FAILURE_MSG("bad format 12 subtable group startGlyphID (%d)", g
roups[i].start_glyph_id); |
328 } | 335 } |
329 } | 336 } |
330 | 337 |
331 // the groups must be sorted by start code and may not overlap | 338 // the groups must be sorted by start code and may not overlap |
332 for (unsigned i = 1; i < num_groups; ++i) { | 339 for (unsigned i = 1; i < num_groups; ++i) { |
333 if (groups[i].start_range <= groups[i - 1].start_range) { | 340 if (groups[i].start_range <= groups[i - 1].start_range) { |
334 return OTS_FAILURE(); | 341 return OTS_FAILURE_MSG("out of order format 12 subtable group (startCharCo
de=0x%4X <= startCharCode=0x%4X of previous group)", |
| 342 groups[i].start_range, groups[i-1].start_range); |
335 } | 343 } |
336 if (groups[i].start_range <= groups[i - 1].end_range) { | 344 if (groups[i].start_range <= groups[i - 1].end_range) { |
337 return OTS_FAILURE(); | 345 return OTS_FAILURE_MSG("overlapping format 12 subtable groups (startCharCo
de=0x%4X <= endCharCode=0x%4X of previous group)", |
| 346 groups[i].start_range, groups[i-1].end_range); |
338 } | 347 } |
339 } | 348 } |
340 | 349 |
341 return true; | 350 return true; |
342 } | 351 } |
343 | 352 |
344 bool Parse31013(ots::OpenTypeFile *file, | 353 bool Parse31013(ots::OpenTypeFile *file, |
345 const uint8_t *data, size_t length, uint16_t num_glyphs) { | 354 const uint8_t *data, size_t length, uint16_t num_glyphs) { |
346 ots::Buffer subtable(data, length); | 355 ots::Buffer subtable(data, length); |
347 | 356 |
348 // Format 13 tables are simple. We parse these and fully serialise them | 357 // Format 13 tables are simple. We parse these and fully serialise them |
349 // later. | 358 // later. |
350 | 359 |
351 if (!subtable.Skip(8)) { | 360 if (!subtable.Skip(8)) { |
352 return OTS_FAILURE(); | 361 return OTS_FAILURE_MSG("Bad cmap subtable length"); |
353 } | 362 } |
354 uint32_t language = 0; | 363 uint32_t language = 0; |
355 if (!subtable.ReadU32(&language)) { | 364 if (!subtable.ReadU32(&language)) { |
356 return OTS_FAILURE(); | 365 return OTS_FAILURE_MSG("Can't read cmap subtable language"); |
357 } | 366 } |
358 if (language) { | 367 if (language) { |
359 return OTS_FAILURE(); | 368 return OTS_FAILURE_MSG("Cmap subtable language should be zero but is %d", la
nguage); |
360 } | 369 } |
361 | 370 |
362 uint32_t num_groups = 0; | 371 uint32_t num_groups = 0; |
363 if (!subtable.ReadU32(&num_groups)) { | 372 if (!subtable.ReadU32(&num_groups)) { |
364 return OTS_FAILURE(); | 373 return OTS_FAILURE_MSG("Can't read number of groups in a cmap subtable"); |
365 } | 374 } |
366 | 375 |
367 // We limit the number of groups in the same way as in 3.10.12 tables. See | 376 // We limit the number of groups in the same way as in 3.10.12 tables. See |
368 // the comment there in | 377 // the comment there in |
369 if (num_groups == 0 || num_groups > kMaxCMAPGroups) { | 378 if (num_groups == 0 || num_groups > kMaxCMAPGroups) { |
370 return OTS_FAILURE(); | 379 return OTS_FAILURE_MSG("Bad number of groups (%d) in a cmap subtable", num_g
roups); |
371 } | 380 } |
372 | 381 |
373 std::vector<ots::OpenTypeCMAPSubtableRange> &groups | 382 std::vector<ots::OpenTypeCMAPSubtableRange> &groups |
374 = file->cmap->subtable_3_10_13; | 383 = file->cmap->subtable_3_10_13; |
375 groups.resize(num_groups); | 384 groups.resize(num_groups); |
376 | 385 |
377 for (unsigned i = 0; i < num_groups; ++i) { | 386 for (unsigned i = 0; i < num_groups; ++i) { |
378 if (!subtable.ReadU32(&groups[i].start_range) || | 387 if (!subtable.ReadU32(&groups[i].start_range) || |
379 !subtable.ReadU32(&groups[i].end_range) || | 388 !subtable.ReadU32(&groups[i].end_range) || |
380 !subtable.ReadU32(&groups[i].start_glyph_id)) { | 389 !subtable.ReadU32(&groups[i].start_glyph_id)) { |
381 return OTS_FAILURE(); | 390 return OTS_FAILURE_MSG("Can't read subrange structure in a cmap subtable")
; |
382 } | 391 } |
383 | 392 |
384 // We conservatively limit all of the values to protect some parsers from | 393 // We conservatively limit all of the values to protect some parsers from |
385 // overflows | 394 // overflows |
386 if (groups[i].start_range > kUnicodeUpperLimit || | 395 if (groups[i].start_range > kUnicodeUpperLimit || |
387 groups[i].end_range > kUnicodeUpperLimit || | 396 groups[i].end_range > kUnicodeUpperLimit || |
388 groups[i].start_glyph_id > 0xFFFF) { | 397 groups[i].start_glyph_id > 0xFFFF) { |
389 return OTS_FAILURE(); | 398 return OTS_FAILURE_MSG("Bad subrange with start_range=%d, end_range=%d, st
art_glyph_id=%d", groups[i].start_range, groups[i].end_range, groups[i].start_gl
yph_id); |
390 } | 399 } |
391 | 400 |
392 if (groups[i].start_glyph_id >= num_glyphs) { | 401 if (groups[i].start_glyph_id >= num_glyphs) { |
393 return OTS_FAILURE(); | 402 return OTS_FAILURE_MSG("Subrange starting glyph id too high (%d > %d)", gr
oups[i].start_glyph_id, num_glyphs); |
394 } | 403 } |
395 } | 404 } |
396 | 405 |
397 // the groups must be sorted by start code and may not overlap | 406 // the groups must be sorted by start code and may not overlap |
398 for (unsigned i = 1; i < num_groups; ++i) { | 407 for (unsigned i = 1; i < num_groups; ++i) { |
399 if (groups[i].start_range <= groups[i - 1].start_range) { | 408 if (groups[i].start_range <= groups[i - 1].start_range) { |
400 return OTS_FAILURE(); | 409 return OTS_FAILURE_MSG("Overlapping subrange starts (%d >= %d)", groups[i]
. start_range, groups[i-1].start_range); |
401 } | 410 } |
402 if (groups[i].start_range <= groups[i - 1].end_range) { | 411 if (groups[i].start_range <= groups[i - 1].end_range) { |
403 return OTS_FAILURE(); | 412 return OTS_FAILURE_MSG("Overlapping subranges (%d <= %d)", groups[i].start
_range, groups[i-1].end_range); |
404 } | 413 } |
405 } | 414 } |
406 | 415 |
407 return true; | 416 return true; |
408 } | 417 } |
409 | 418 |
410 bool Parse0514(ots::OpenTypeFile *file, | 419 bool Parse0514(ots::OpenTypeFile *file, |
411 const uint8_t *data, size_t length, uint16_t num_glyphs) { | 420 const uint8_t *data, size_t length, uint16_t num_glyphs) { |
412 // Unicode Variation Selector table | 421 // Unicode Variation Selector table |
413 ots::Buffer subtable(data, length); | 422 ots::Buffer subtable(data, length); |
414 | 423 |
415 // Format 14 tables are simple. We parse these and fully serialise them | 424 // Format 14 tables are simple. We parse these and fully serialise them |
416 // later. | 425 // later. |
417 | 426 |
418 // Skip format (USHORT) and length (ULONG) | 427 // Skip format (USHORT) and length (ULONG) |
419 if (!subtable.Skip(6)) { | 428 if (!subtable.Skip(6)) { |
420 return OTS_FAILURE(); | 429 return OTS_FAILURE_MSG("Can't read start of cmap subtable"); |
421 } | 430 } |
422 | 431 |
423 uint32_t num_records = 0; | 432 uint32_t num_records = 0; |
424 if (!subtable.ReadU32(&num_records)) { | 433 if (!subtable.ReadU32(&num_records)) { |
425 return OTS_FAILURE(); | 434 return OTS_FAILURE_MSG("Can't read number of records in cmap subtable"); |
426 } | 435 } |
427 if (num_records == 0 || num_records > kMaxCMAPSelectorRecords) { | 436 if (num_records == 0 || num_records > kMaxCMAPSelectorRecords) { |
428 return OTS_FAILURE(); | 437 return OTS_FAILURE_MSG("Bad number of records (%d) in cmap subtable", num_re
cords); |
429 } | 438 } |
430 | 439 |
431 std::vector<ots::OpenTypeCMAPSubtableVSRecord>& records | 440 std::vector<ots::OpenTypeCMAPSubtableVSRecord>& records |
432 = file->cmap->subtable_0_5_14; | 441 = file->cmap->subtable_0_5_14; |
433 records.resize(num_records); | 442 records.resize(num_records); |
434 | 443 |
435 for (unsigned i = 0; i < num_records; ++i) { | 444 for (unsigned i = 0; i < num_records; ++i) { |
436 if (!subtable.ReadU24(&records[i].var_selector) || | 445 if (!subtable.ReadU24(&records[i].var_selector) || |
437 !subtable.ReadU32(&records[i].default_offset) || | 446 !subtable.ReadU32(&records[i].default_offset) || |
438 !subtable.ReadU32(&records[i].non_default_offset)) { | 447 !subtable.ReadU32(&records[i].non_default_offset)) { |
439 return OTS_FAILURE(); | 448 return OTS_FAILURE_MSG("Can't read record structure of record %d in cmap s
ubtale", i); |
440 } | 449 } |
441 // Checks the value of variation selector | 450 // Checks the value of variation selector |
442 if (!((records[i].var_selector >= kMongolianVSStart && | 451 if (!((records[i].var_selector >= kMongolianVSStart && |
443 records[i].var_selector <= kMongolianVSEnd) || | 452 records[i].var_selector <= kMongolianVSEnd) || |
444 (records[i].var_selector >= kVSStart && | 453 (records[i].var_selector >= kVSStart && |
445 records[i].var_selector <= kVSEnd) || | 454 records[i].var_selector <= kVSEnd) || |
446 (records[i].var_selector >= kIVSStart && | 455 (records[i].var_selector >= kIVSStart && |
447 records[i].var_selector <= kIVSEnd))) { | 456 records[i].var_selector <= kIVSEnd))) { |
448 return OTS_FAILURE(); | 457 return OTS_FAILURE_MSG("Bad record variation selector (%04X) in record %i"
, records[i].var_selector, i); |
449 } | 458 } |
450 if (i > 0 && | 459 if (i > 0 && |
451 records[i-1].var_selector >= records[i].var_selector) { | 460 records[i-1].var_selector >= records[i].var_selector) { |
452 return OTS_FAILURE(); | 461 return OTS_FAILURE_MSG("Out of order variation selector (%04X >= %04X) in
record %d", records[i-1].var_selector, records[i].var_selector, i); |
453 } | 462 } |
454 | 463 |
455 // Checks offsets | 464 // Checks offsets |
456 if (!records[i].default_offset && !records[i].non_default_offset) { | 465 if (!records[i].default_offset && !records[i].non_default_offset) { |
457 return OTS_FAILURE(); | 466 return OTS_FAILURE_MSG("No default aoffset in variation selector record %d
", i); |
458 } | 467 } |
459 if (records[i].default_offset && | 468 if (records[i].default_offset && |
460 records[i].default_offset >= length) { | 469 records[i].default_offset >= length) { |
461 return OTS_FAILURE(); | 470 return OTS_FAILURE_MSG("Default offset too high (%d >= %ld) in record %d",
records[i].default_offset, length, i); |
462 } | 471 } |
463 if (records[i].non_default_offset && | 472 if (records[i].non_default_offset && |
464 records[i].non_default_offset >= length) { | 473 records[i].non_default_offset >= length) { |
465 return OTS_FAILURE(); | 474 return OTS_FAILURE_MSG("Non default offset too high (%d >= %ld) in record
%d", records[i].non_default_offset, length, i); |
466 } | 475 } |
467 } | 476 } |
468 | 477 |
469 for (unsigned i = 0; i < num_records; ++i) { | 478 for (unsigned i = 0; i < num_records; ++i) { |
470 // Checks default UVS table | 479 // Checks default UVS table |
471 if (records[i].default_offset) { | 480 if (records[i].default_offset) { |
472 subtable.set_offset(records[i].default_offset); | 481 subtable.set_offset(records[i].default_offset); |
473 uint32_t num_ranges = 0; | 482 uint32_t num_ranges = 0; |
474 if (!subtable.ReadU32(&num_ranges)) { | 483 if (!subtable.ReadU32(&num_ranges)) { |
475 return OTS_FAILURE(); | 484 return OTS_FAILURE_MSG("Can't read number of ranges in record %d", i); |
476 } | 485 } |
477 if (!num_ranges || num_ranges > kMaxCMAPGroups) { | 486 if (!num_ranges || num_ranges > kMaxCMAPGroups) { |
478 return OTS_FAILURE(); | 487 return OTS_FAILURE_MSG("number of ranges too high (%d > %d) in record %d
", num_ranges, kMaxCMAPGroups, i); |
479 } | 488 } |
480 | 489 |
481 uint32_t last_unicode_value = 0; | 490 uint32_t last_unicode_value = 0; |
482 std::vector<ots::OpenTypeCMAPSubtableVSRange>& ranges | 491 std::vector<ots::OpenTypeCMAPSubtableVSRange>& ranges |
483 = records[i].ranges; | 492 = records[i].ranges; |
484 ranges.resize(num_ranges); | 493 ranges.resize(num_ranges); |
485 | 494 |
486 for (unsigned j = 0; j < num_ranges; ++j) { | 495 for (unsigned j = 0; j < num_ranges; ++j) { |
487 if (!subtable.ReadU24(&ranges[j].unicode_value) || | 496 if (!subtable.ReadU24(&ranges[j].unicode_value) || |
488 !subtable.ReadU8(&ranges[j].additional_count)) { | 497 !subtable.ReadU8(&ranges[j].additional_count)) { |
489 return OTS_FAILURE(); | 498 return OTS_FAILURE_MSG("Can't read range info in variation selector re
cord %d", i); |
490 } | 499 } |
491 const uint32_t check_value = | 500 const uint32_t check_value = |
492 ranges[j].unicode_value + ranges[j].additional_count; | 501 ranges[j].unicode_value + ranges[j].additional_count; |
493 if (ranges[j].unicode_value == 0 || | 502 if (ranges[j].unicode_value == 0 || |
494 ranges[j].unicode_value > kUnicodeUpperLimit || | 503 ranges[j].unicode_value > kUnicodeUpperLimit || |
495 check_value > kUVSUpperLimit || | 504 check_value > kUVSUpperLimit || |
496 (last_unicode_value && | 505 (last_unicode_value && |
497 ranges[j].unicode_value <= last_unicode_value)) { | 506 ranges[j].unicode_value <= last_unicode_value)) { |
498 return OTS_FAILURE(); | 507 return OTS_FAILURE_MSG("Bad Unicode value *%04X) in variation selector
range %d record %d", ranges[j].unicode_value, j, i); |
499 } | 508 } |
500 last_unicode_value = check_value; | 509 last_unicode_value = check_value; |
501 } | 510 } |
502 } | 511 } |
503 | 512 |
504 // Checks non default UVS table | 513 // Checks non default UVS table |
505 if (records[i].non_default_offset) { | 514 if (records[i].non_default_offset) { |
506 subtable.set_offset(records[i].non_default_offset); | 515 subtable.set_offset(records[i].non_default_offset); |
507 uint32_t num_mappings = 0; | 516 uint32_t num_mappings = 0; |
508 if (!subtable.ReadU32(&num_mappings)) { | 517 if (!subtable.ReadU32(&num_mappings)) { |
509 return OTS_FAILURE(); | 518 return OTS_FAILURE_MSG("Can't read number of mappings in variation selec
tor record %d", i); |
510 } | 519 } |
511 if (!num_mappings || num_mappings > kMaxCMAPGroups) { | 520 if (!num_mappings || num_mappings > kMaxCMAPGroups) { |
512 return OTS_FAILURE(); | 521 return OTS_FAILURE_MSG("Number of mappings too high (%d) in variation se
lector record %d", num_mappings, i); |
513 } | 522 } |
514 | 523 |
515 uint32_t last_unicode_value = 0; | 524 uint32_t last_unicode_value = 0; |
516 std::vector<ots::OpenTypeCMAPSubtableVSMapping>& mappings | 525 std::vector<ots::OpenTypeCMAPSubtableVSMapping>& mappings |
517 = records[i].mappings; | 526 = records[i].mappings; |
518 mappings.resize(num_mappings); | 527 mappings.resize(num_mappings); |
519 | 528 |
520 for (unsigned j = 0; j < num_mappings; ++j) { | 529 for (unsigned j = 0; j < num_mappings; ++j) { |
521 if (!subtable.ReadU24(&mappings[j].unicode_value) || | 530 if (!subtable.ReadU24(&mappings[j].unicode_value) || |
522 !subtable.ReadU16(&mappings[j].glyph_id)) { | 531 !subtable.ReadU16(&mappings[j].glyph_id)) { |
523 return OTS_FAILURE(); | 532 return OTS_FAILURE_MSG("Can't read mapping %d in variation selector re
cord %d", j, i); |
524 } | 533 } |
525 if (mappings[j].glyph_id == 0 || | 534 if (mappings[j].glyph_id == 0 || |
526 mappings[j].unicode_value == 0 || | 535 mappings[j].unicode_value == 0 || |
527 mappings[j].unicode_value > kUnicodeUpperLimit || | 536 mappings[j].unicode_value > kUnicodeUpperLimit || |
528 (last_unicode_value && | 537 (last_unicode_value && |
529 mappings[j].unicode_value <= last_unicode_value)) { | 538 mappings[j].unicode_value <= last_unicode_value)) { |
530 return OTS_FAILURE(); | 539 return OTS_FAILURE_MSG("Bad mapping (%04X -> %d) in mapping %d of vari
ation selector %d", mappings[j].unicode_value, mappings[j].glyph_id, j, i); |
531 } | 540 } |
532 last_unicode_value = mappings[j].unicode_value; | 541 last_unicode_value = mappings[j].unicode_value; |
533 } | 542 } |
534 } | 543 } |
535 } | 544 } |
536 | 545 |
537 if (subtable.offset() != length) { | 546 if (subtable.offset() != length) { |
538 return OTS_FAILURE(); | 547 return OTS_FAILURE_MSG("Bad subtable offset (%ld != %ld)", subtable.offset()
, length); |
539 } | 548 } |
540 file->cmap->subtable_0_5_14_length = subtable.offset(); | 549 file->cmap->subtable_0_5_14_length = subtable.offset(); |
541 return true; | 550 return true; |
542 } | 551 } |
543 | 552 |
544 bool Parse100(ots::OpenTypeFile *file, const uint8_t *data, size_t length) { | 553 bool Parse100(ots::OpenTypeFile *file, const uint8_t *data, size_t length) { |
545 // Mac Roman table | 554 // Mac Roman table |
546 ots::Buffer subtable(data, length); | 555 ots::Buffer subtable(data, length); |
547 | 556 |
548 if (!subtable.Skip(4)) { | 557 if (!subtable.Skip(4)) { |
549 return OTS_FAILURE(); | 558 return OTS_FAILURE_MSG("Bad cmap subtable"); |
550 } | 559 } |
551 uint16_t language = 0; | 560 uint16_t language = 0; |
552 if (!subtable.ReadU16(&language)) { | 561 if (!subtable.ReadU16(&language)) { |
553 return OTS_FAILURE(); | 562 return OTS_FAILURE_MSG("Can't read language in cmap subtable"); |
554 } | 563 } |
555 if (language) { | 564 if (language) { |
556 // simsun.ttf has non-zero language id. | 565 // simsun.ttf has non-zero language id. |
557 OTS_WARNING("language id should be zero: %u", language); | 566 OTS_WARNING("language id should be zero: %u", language); |
558 } | 567 } |
559 | 568 |
560 file->cmap->subtable_1_0_0.reserve(kFormat0ArraySize); | 569 file->cmap->subtable_1_0_0.reserve(kFormat0ArraySize); |
561 for (size_t i = 0; i < kFormat0ArraySize; ++i) { | 570 for (size_t i = 0; i < kFormat0ArraySize; ++i) { |
562 uint8_t glyph_id = 0; | 571 uint8_t glyph_id = 0; |
563 if (!subtable.ReadU8(&glyph_id)) { | 572 if (!subtable.ReadU8(&glyph_id)) { |
564 return OTS_FAILURE(); | 573 return OTS_FAILURE_MSG("Can't read glyph id at array[%ld] in cmap subtable
", i); |
565 } | 574 } |
566 file->cmap->subtable_1_0_0.push_back(glyph_id); | 575 file->cmap->subtable_1_0_0.push_back(glyph_id); |
567 } | 576 } |
568 | 577 |
569 return true; | 578 return true; |
570 } | 579 } |
571 | 580 |
572 } // namespace | 581 } // namespace |
573 | 582 |
574 namespace ots { | 583 namespace ots { |
575 | 584 |
576 bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { | 585 bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { |
577 Buffer table(data, length); | 586 Buffer table(data, length); |
578 file->cmap = new OpenTypeCMAP; | 587 file->cmap = new OpenTypeCMAP; |
579 | 588 |
580 uint16_t version = 0; | 589 uint16_t version = 0; |
581 uint16_t num_tables = 0; | 590 uint16_t num_tables = 0; |
582 if (!table.ReadU16(&version) || | 591 if (!table.ReadU16(&version) || |
583 !table.ReadU16(&num_tables)) { | 592 !table.ReadU16(&num_tables)) { |
584 return OTS_FAILURE(); | 593 return OTS_FAILURE_MSG("Can't read structure of cmap"); |
585 } | 594 } |
586 | 595 |
587 if (version != 0) { | 596 if (version != 0) { |
588 return OTS_FAILURE(); | 597 return OTS_FAILURE_MSG("Non zero cmap version (%d)", version); |
589 } | 598 } |
590 if (!num_tables) { | 599 if (!num_tables) { |
591 return OTS_FAILURE(); | 600 return OTS_FAILURE_MSG("No subtables in cmap!"); |
592 } | 601 } |
593 | 602 |
594 std::vector<CMAPSubtableHeader> subtable_headers; | 603 std::vector<CMAPSubtableHeader> subtable_headers; |
595 | 604 |
596 // read the subtable headers | 605 // read the subtable headers |
597 subtable_headers.reserve(num_tables); | 606 subtable_headers.reserve(num_tables); |
598 for (unsigned i = 0; i < num_tables; ++i) { | 607 for (unsigned i = 0; i < num_tables; ++i) { |
599 CMAPSubtableHeader subt; | 608 CMAPSubtableHeader subt; |
600 | 609 |
601 if (!table.ReadU16(&subt.platform) || | 610 if (!table.ReadU16(&subt.platform) || |
602 !table.ReadU16(&subt.encoding) || | 611 !table.ReadU16(&subt.encoding) || |
603 !table.ReadU32(&subt.offset)) { | 612 !table.ReadU32(&subt.offset)) { |
604 return OTS_FAILURE(); | 613 return OTS_FAILURE_MSG("Can't read subtable information cmap subtable %d",
i); |
605 } | 614 } |
606 | 615 |
607 subtable_headers.push_back(subt); | 616 subtable_headers.push_back(subt); |
608 } | 617 } |
609 | 618 |
610 const size_t data_offset = table.offset(); | 619 const size_t data_offset = table.offset(); |
611 | 620 |
612 // make sure that all the offsets are valid. | 621 // make sure that all the offsets are valid. |
613 uint32_t last_id = 0; | |
614 for (unsigned i = 0; i < num_tables; ++i) { | 622 for (unsigned i = 0; i < num_tables; ++i) { |
615 if (subtable_headers[i].offset > 1024 * 1024 * 1024) { | 623 if (subtable_headers[i].offset > 1024 * 1024 * 1024) { |
616 return OTS_FAILURE(); | 624 return OTS_FAILURE_MSG("Bad subtable offset in cmap subtable %d", i); |
617 } | 625 } |
618 if (subtable_headers[i].offset < data_offset || | 626 if (subtable_headers[i].offset < data_offset || |
619 subtable_headers[i].offset >= length) { | 627 subtable_headers[i].offset >= length) { |
620 return OTS_FAILURE(); | 628 return OTS_FAILURE_MSG("Bad subtable offset (%d) in cmap subtable %d", sub
table_headers[i].offset, i); |
621 } | 629 } |
622 | |
623 // check if the table is sorted first by platform ID, then by encoding ID. | |
624 uint32_t current_id | |
625 = (subtable_headers[i].platform << 16) + subtable_headers[i].encoding; | |
626 if ((i != 0) && (last_id >= current_id)) { | |
627 return OTS_FAILURE(); | |
628 } | |
629 last_id = current_id; | |
630 } | 630 } |
631 | 631 |
632 // the format of the table is the first couple of bytes in the table. The | 632 // the format of the table is the first couple of bytes in the table. The |
633 // length of the table is stored in a format-specific way. | 633 // length of the table is stored in a format-specific way. |
634 for (unsigned i = 0; i < num_tables; ++i) { | 634 for (unsigned i = 0; i < num_tables; ++i) { |
635 table.set_offset(subtable_headers[i].offset); | 635 table.set_offset(subtable_headers[i].offset); |
636 if (!table.ReadU16(&subtable_headers[i].format)) { | 636 if (!table.ReadU16(&subtable_headers[i].format)) { |
637 return OTS_FAILURE(); | 637 return OTS_FAILURE_MSG("Can't read cmap subtable header format %d", i); |
638 } | 638 } |
639 | 639 |
640 uint16_t len = 0; | 640 uint16_t len = 0; |
| 641 uint16_t lang = 0; |
641 switch (subtable_headers[i].format) { | 642 switch (subtable_headers[i].format) { |
642 case 0: | 643 case 0: |
643 case 4: | 644 case 4: |
644 if (!table.ReadU16(&len)) { | 645 if (!table.ReadU16(&len)) { |
645 return OTS_FAILURE(); | 646 return OTS_FAILURE_MSG("Can't read cmap subtable %d length", i); |
| 647 } |
| 648 if (!table.ReadU16(&lang)) { |
| 649 return OTS_FAILURE_MSG("Can't read cmap subtable %d language", i); |
646 } | 650 } |
647 subtable_headers[i].length = len; | 651 subtable_headers[i].length = len; |
| 652 subtable_headers[i].language = lang; |
648 break; | 653 break; |
649 case 12: | 654 case 12: |
650 case 13: | 655 case 13: |
651 if (!table.Skip(2)) { | 656 if (!table.Skip(2)) { |
652 return OTS_FAILURE(); | 657 return OTS_FAILURE_MSG("Bad cmap subtable %d structure", i); |
653 } | 658 } |
654 if (!table.ReadU32(&subtable_headers[i].length)) { | 659 if (!table.ReadU32(&subtable_headers[i].length)) { |
655 return OTS_FAILURE(); | 660 return OTS_FAILURE_MSG("Can read cmap subtable %d length", i); |
| 661 } |
| 662 if (!table.ReadU32(&subtable_headers[i].language)) { |
| 663 return OTS_FAILURE_MSG("Can't read cmap subtable %d language", i); |
656 } | 664 } |
657 break; | 665 break; |
658 case 14: | 666 case 14: |
659 if (!table.ReadU32(&subtable_headers[i].length)) { | 667 if (!table.ReadU32(&subtable_headers[i].length)) { |
660 return OTS_FAILURE(); | 668 return OTS_FAILURE_MSG("Can't read cmap subtable %d length", i); |
661 } | 669 } |
| 670 subtable_headers[i].language = 0; |
662 break; | 671 break; |
663 default: | 672 default: |
664 subtable_headers[i].length = 0; | 673 subtable_headers[i].length = 0; |
| 674 subtable_headers[i].language = 0; |
665 break; | 675 break; |
666 } | 676 } |
667 } | 677 } |
668 | 678 |
| 679 // check if the table is sorted first by platform ID, then by encoding ID. |
| 680 uint32_t last_id = 0; |
| 681 for (unsigned i = 0; i < num_tables; ++i) { |
| 682 uint32_t current_id |
| 683 = (subtable_headers[i].platform << 24) |
| 684 + (subtable_headers[i].encoding << 16) |
| 685 + subtable_headers[i].language; |
| 686 if ((i != 0) && (last_id >= current_id)) { |
| 687 return OTS_FAILURE_MSG("subtable %d with platform ID %d, encoding ID %d, l
anguage ID %d " |
| 688 "following subtable with platform ID %d, encoding I
D %d, language ID %d", |
| 689 i, |
| 690 (uint8_t)(current_id >> 24), (uint8_t)(current_id >
> 16), (uint8_t)(current_id), |
| 691 (uint8_t)(last_id >> 24), (uint8_t)(last_id >> 16),
(uint8_t)(last_id)); |
| 692 } |
| 693 last_id = current_id; |
| 694 } |
| 695 |
669 // Now, verify that all the lengths are sane | 696 // Now, verify that all the lengths are sane |
670 for (unsigned i = 0; i < num_tables; ++i) { | 697 for (unsigned i = 0; i < num_tables; ++i) { |
671 if (!subtable_headers[i].length) continue; | 698 if (!subtable_headers[i].length) continue; |
672 if (subtable_headers[i].length > 1024 * 1024 * 1024) { | 699 if (subtable_headers[i].length > 1024 * 1024 * 1024) { |
673 return OTS_FAILURE(); | 700 return OTS_FAILURE_MSG("Bad cmap subtable %d length", i); |
674 } | 701 } |
675 // We know that both the offset and length are < 1GB, so the following | 702 // We know that both the offset and length are < 1GB, so the following |
676 // addition doesn't overflow | 703 // addition doesn't overflow |
677 const uint32_t end_byte | 704 const uint32_t end_byte |
678 = subtable_headers[i].offset + subtable_headers[i].length; | 705 = subtable_headers[i].offset + subtable_headers[i].length; |
679 if (end_byte > length) { | 706 if (end_byte > length) { |
680 return OTS_FAILURE(); | 707 return OTS_FAILURE_MSG("Over long cmap subtable %d @ %d for %d", i, subtab
le_headers[i].offset, subtable_headers[i].length); |
681 } | 708 } |
682 } | 709 } |
683 | 710 |
684 // check that the cmap subtables are not overlapping. | 711 // check that the cmap subtables are not overlapping. |
685 std::set<std::pair<uint32_t, uint32_t> > uniq_checker; | 712 std::set<std::pair<uint32_t, uint32_t> > uniq_checker; |
686 std::vector<std::pair<uint32_t, uint8_t> > overlap_checker; | 713 std::vector<std::pair<uint32_t, uint8_t> > overlap_checker; |
687 for (unsigned i = 0; i < num_tables; ++i) { | 714 for (unsigned i = 0; i < num_tables; ++i) { |
688 const uint32_t end_byte | 715 const uint32_t end_byte |
689 = subtable_headers[i].offset + subtable_headers[i].length; | 716 = subtable_headers[i].offset + subtable_headers[i].length; |
690 | 717 |
691 if (!uniq_checker.insert(std::make_pair(subtable_headers[i].offset, | 718 if (!uniq_checker.insert(std::make_pair(subtable_headers[i].offset, |
692 end_byte)).second) { | 719 end_byte)).second) { |
693 // Sometimes Unicode table and MS table share exactly the same data. | 720 // Sometimes Unicode table and MS table share exactly the same data. |
694 // We'll allow this. | 721 // We'll allow this. |
695 continue; | 722 continue; |
696 } | 723 } |
697 overlap_checker.push_back( | 724 overlap_checker.push_back( |
698 std::make_pair(subtable_headers[i].offset, | 725 std::make_pair(subtable_headers[i].offset, |
699 static_cast<uint8_t>(1) /* start */)); | 726 static_cast<uint8_t>(1) /* start */)); |
700 overlap_checker.push_back( | 727 overlap_checker.push_back( |
701 std::make_pair(end_byte, static_cast<uint8_t>(0) /* end */)); | 728 std::make_pair(end_byte, static_cast<uint8_t>(0) /* end */)); |
702 } | 729 } |
703 std::sort(overlap_checker.begin(), overlap_checker.end()); | 730 std::sort(overlap_checker.begin(), overlap_checker.end()); |
704 int overlap_count = 0; | 731 int overlap_count = 0; |
705 for (unsigned i = 0; i < overlap_checker.size(); ++i) { | 732 for (unsigned i = 0; i < overlap_checker.size(); ++i) { |
706 overlap_count += (overlap_checker[i].second ? 1 : -1); | 733 overlap_count += (overlap_checker[i].second ? 1 : -1); |
707 if (overlap_count > 1) { | 734 if (overlap_count > 1) { |
708 return OTS_FAILURE(); | 735 return OTS_FAILURE_MSG("Excessive overlap count %d", overlap_count); |
709 } | 736 } |
710 } | 737 } |
711 | 738 |
712 // we grab the number of glyphs in the file from the maxp table to make sure | 739 // we grab the number of glyphs in the file from the maxp table to make sure |
713 // that the character map isn't referencing anything beyound this range. | 740 // that the character map isn't referencing anything beyound this range. |
714 if (!file->maxp) { | 741 if (!file->maxp) { |
715 return OTS_FAILURE(); | 742 return OTS_FAILURE_MSG("No maxp table in font! Needed by cmap."); |
716 } | 743 } |
717 const uint16_t num_glyphs = file->maxp->num_glyphs; | 744 const uint16_t num_glyphs = file->maxp->num_glyphs; |
718 | 745 |
719 // We only support a subset of the possible character map tables. Microsoft | 746 // We only support a subset of the possible character map tables. Microsoft |
720 // 'strongly recommends' that everyone supports the Unicode BMP table with | 747 // 'strongly recommends' that everyone supports the Unicode BMP table with |
721 // the UCS-4 table for non-BMP glyphs. We'll pass the following subtables: | 748 // the UCS-4 table for non-BMP glyphs. We'll pass the following subtables: |
722 // Platform ID Encoding ID Format | 749 // Platform ID Encoding ID Format |
723 // 0 0 4 (Unicode Default) | 750 // 0 0 4 (Unicode Default) |
| 751 // 0 1 4 (Unicode 1.1) |
724 // 0 3 4 (Unicode BMP) | 752 // 0 3 4 (Unicode BMP) |
725 // 0 3 12 (Unicode UCS-4) | 753 // 0 3 12 (Unicode UCS-4) |
726 // 0 5 14 (Unicode Variation Sequences) | 754 // 0 5 14 (Unicode Variation Sequences) |
727 // 1 0 0 (Mac Roman) | 755 // 1 0 0 (Mac Roman) |
728 // 3 0 4 (MS Symbol) | 756 // 3 0 4 (MS Symbol) |
729 // 3 1 4 (MS Unicode BMP) | 757 // 3 1 4 (MS Unicode BMP) |
730 // 3 10 12 (MS Unicode UCS-4) | 758 // 3 10 12 (MS Unicode UCS-4) |
731 // 3 10 13 (MS UCS-4 Fallback mapping) | 759 // 3 10 13 (MS UCS-4 Fallback mapping) |
732 // | 760 // |
733 // Note: | 761 // Note: |
734 // * 0-0-4 table is (usually) written as a 3-1-4 table. If 3-1-4 table | 762 // * 0-0-4 and 0-1-4 tables are (usually) written as a 3-1-4 table. If 3-1-4
table |
735 // also exists, the 0-0-4 table is ignored. | 763 // also exists, the 0-0-4 or 0-1-4 tables are ignored. |
736 // * Unlike 0-0-4 table, 0-3-4 table is written as a 0-3-4 table. | 764 // * Unlike 0-0-4 table, 0-3-4 table is written as a 0-3-4 table. |
737 // Some fonts which include 0-5-14 table seems to be required 0-3-4 | 765 // Some fonts which include 0-5-14 table seems to be required 0-3-4 |
738 // table. The 0-3-4 table will be wriiten even if 3-1-4 table also exists. | 766 // table. The 0-3-4 table will be wriiten even if 3-1-4 table also exists. |
739 // * 0-3-12 table is written as a 3-10-12 table. If 3-10-12 table also | 767 // * 0-3-12 table is written as a 3-10-12 table. If 3-10-12 table also |
740 // exists, the 0-3-12 table is ignored. | 768 // exists, the 0-3-12 table is ignored. |
741 // | 769 // |
742 | 770 |
743 for (unsigned i = 0; i < num_tables; ++i) { | 771 for (unsigned i = 0; i < num_tables; ++i) { |
744 if (subtable_headers[i].platform == 0) { | 772 if (subtable_headers[i].platform == 0) { |
745 // Unicode platform | 773 // Unicode platform |
746 | 774 |
747 if ((subtable_headers[i].encoding == 0) && | 775 if ((subtable_headers[i].encoding == 0 || subtable_headers[i].encoding ==
1) && |
748 (subtable_headers[i].format == 4)) { | 776 (subtable_headers[i].format == 4)) { |
749 // parse and output the 0-0-4 table as 3-1-4 table. Sometimes the 0-0-4 | 777 // parse and output the 0-0-4 and 0-1-4 tables as 3-1-4 table. Sometimes
the 0-0-4 |
750 // table actually points to MS symbol data and thus should be parsed as | 778 // table actually points to MS symbol data and thus should be parsed as |
751 // 3-0-4 table (e.g., marqueem.ttf and quixotic.ttf). This error will be | 779 // 3-0-4 table (e.g., marqueem.ttf and quixotic.ttf). This error will be |
752 // recovered in ots_cmap_serialise(). | 780 // recovered in ots_cmap_serialise(). |
753 if (!ParseFormat4(file, 3, 1, data + subtable_headers[i].offset, | 781 if (!ParseFormat4(file, 3, 1, data + subtable_headers[i].offset, |
754 subtable_headers[i].length, num_glyphs)) { | 782 subtable_headers[i].length, num_glyphs)) { |
755 return OTS_FAILURE(); | 783 return OTS_FAILURE_MSG("Failed to parse format 4 cmap subtable %d", i)
; |
756 } | 784 } |
757 } else if ((subtable_headers[i].encoding == 3) && | 785 } else if ((subtable_headers[i].encoding == 3) && |
758 (subtable_headers[i].format == 4)) { | 786 (subtable_headers[i].format == 4)) { |
759 // parse and output the 0-3-4 table as 0-3-4 table. | 787 // parse and output the 0-3-4 table as 0-3-4 table. |
760 if (!ParseFormat4(file, 0, 3, data + subtable_headers[i].offset, | 788 if (!ParseFormat4(file, 0, 3, data + subtable_headers[i].offset, |
761 subtable_headers[i].length, num_glyphs)) { | 789 subtable_headers[i].length, num_glyphs)) { |
762 return OTS_FAILURE(); | 790 return OTS_FAILURE_MSG("Failed to parse format 4 cmap subtable %d", i)
; |
763 } | 791 } |
764 } else if ((subtable_headers[i].encoding == 3) && | 792 } else if ((subtable_headers[i].encoding == 3) && |
765 (subtable_headers[i].format == 12)) { | 793 (subtable_headers[i].format == 12)) { |
766 // parse and output the 0-3-12 table as 3-10-12 table. | 794 // parse and output the 0-3-12 table as 3-10-12 table. |
767 if (!Parse31012(file, data + subtable_headers[i].offset, | 795 if (!Parse31012(file, data + subtable_headers[i].offset, |
768 subtable_headers[i].length, num_glyphs)) { | 796 subtable_headers[i].length, num_glyphs)) { |
769 return OTS_FAILURE(); | 797 return OTS_FAILURE_MSG("Failed to parse format 12 cmap subtable %d", i
); |
770 } | 798 } |
771 } else if ((subtable_headers[i].encoding == 5) && | 799 } else if ((subtable_headers[i].encoding == 5) && |
772 (subtable_headers[i].format == 14)) { | 800 (subtable_headers[i].format == 14)) { |
773 if (!Parse0514(file, data + subtable_headers[i].offset, | 801 if (!Parse0514(file, data + subtable_headers[i].offset, |
774 subtable_headers[i].length, num_glyphs)) { | 802 subtable_headers[i].length, num_glyphs)) { |
775 return OTS_FAILURE(); | 803 return OTS_FAILURE_MSG("Failed to parse format 14 cmap subtable %d", i
); |
776 } | 804 } |
777 } | 805 } |
778 } else if (subtable_headers[i].platform == 1) { | 806 } else if (subtable_headers[i].platform == 1) { |
779 // Mac platform | 807 // Mac platform |
780 | 808 |
781 if ((subtable_headers[i].encoding == 0) && | 809 if ((subtable_headers[i].encoding == 0) && |
782 (subtable_headers[i].format == 0)) { | 810 (subtable_headers[i].format == 0)) { |
783 // parse and output the 1-0-0 table. | 811 // parse and output the 1-0-0 table. |
784 if (!Parse100(file, data + subtable_headers[i].offset, | 812 if (!Parse100(file, data + subtable_headers[i].offset, |
785 subtable_headers[i].length)) { | 813 subtable_headers[i].length)) { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
841 const uint16_t num_subtables = static_cast<uint16_t>(have_034) + | 869 const uint16_t num_subtables = static_cast<uint16_t>(have_034) + |
842 static_cast<uint16_t>(have_0514) + | 870 static_cast<uint16_t>(have_0514) + |
843 static_cast<uint16_t>(have_100) + | 871 static_cast<uint16_t>(have_100) + |
844 static_cast<uint16_t>(have_304) + | 872 static_cast<uint16_t>(have_304) + |
845 static_cast<uint16_t>(have_314) + | 873 static_cast<uint16_t>(have_314) + |
846 static_cast<uint16_t>(have_31012) + | 874 static_cast<uint16_t>(have_31012) + |
847 static_cast<uint16_t>(have_31013); | 875 static_cast<uint16_t>(have_31013); |
848 const off_t table_start = out->Tell(); | 876 const off_t table_start = out->Tell(); |
849 | 877 |
850 // Some fonts don't have 3-0-4 MS Symbol nor 3-1-4 Unicode BMP tables | 878 // Some fonts don't have 3-0-4 MS Symbol nor 3-1-4 Unicode BMP tables |
851 // (e.g., old fonts for Mac). We don't support them except for color bitmap | 879 // (e.g., old fonts for Mac). We don't support them. |
852 // fonts. | 880 if (!have_304 && !have_314 && !have_034 && !have_31012 && !have_31013) { |
853 if (!have_304 && !have_314 && !have_034) { | |
854 if (!(file->cbdt && file->cblc)) { | 881 if (!(file->cbdt && file->cblc)) { |
855 return OTS_FAILURE(); | 882 » return OTS_FAILURE_MSG("no supported subtables were found"); |
856 } | 883 » } |
857 } | 884 } |
858 | 885 |
859 if (!out->WriteU16(0) || | 886 if (!out->WriteU16(0) || |
860 !out->WriteU16(num_subtables)) { | 887 !out->WriteU16(num_subtables)) { |
861 return OTS_FAILURE(); | 888 return OTS_FAILURE(); |
862 } | 889 } |
863 | 890 |
864 const off_t record_offset = out->Tell(); | 891 const off_t record_offset = out->Tell(); |
865 if (!out->Pad(num_subtables * 8)) { | 892 if (!out->Pad(num_subtables * 8)) { |
866 return OTS_FAILURE(); | 893 return OTS_FAILURE(); |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1070 out->RestoreChecksum(saved_checksum); | 1097 out->RestoreChecksum(saved_checksum); |
1071 | 1098 |
1072 return true; | 1099 return true; |
1073 } | 1100 } |
1074 | 1101 |
1075 void ots_cmap_free(OpenTypeFile *file) { | 1102 void ots_cmap_free(OpenTypeFile *file) { |
1076 delete file->cmap; | 1103 delete file->cmap; |
1077 } | 1104 } |
1078 | 1105 |
1079 } // namespace ots | 1106 } // namespace ots |
| 1107 |
| 1108 #undef TABLE_NAME |
OLD | NEW |