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 "name.h" | 5 #include "name.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cstring> | 8 #include <cstring> |
9 | 9 |
10 #include "cff.h" | 10 #include "cff.h" |
11 | 11 |
12 // name - Naming Table | 12 // name - Naming Table |
13 // http://www.microsoft.com/opentype/otspec/name.htm | 13 // http://www.microsoft.com/typography/otspec/name.htm |
| 14 |
| 15 #define TABLE_NAME "name" |
14 | 16 |
15 namespace { | 17 namespace { |
16 | 18 |
17 bool ValidInPsName(char c) { | 19 bool ValidInPsName(char c) { |
18 return (c > 0x20 && c < 0x7f && !std::strchr("[](){}<>/%", c)); | 20 return (c > 0x20 && c < 0x7f && !std::strchr("[](){}<>/%", c)); |
19 } | 21 } |
20 | 22 |
21 bool CheckPsNameAscii(const std::string& name) { | 23 bool CheckPsNameAscii(const std::string& name) { |
22 for (unsigned i = 0; i < name.size(); ++i) { | 24 for (unsigned i = 0; i < name.size(); ++i) { |
23 if (!ValidInPsName(name[i])) { | 25 if (!ValidInPsName(name[i])) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 namespace ots { | 59 namespace ots { |
58 | 60 |
59 bool ots_name_parse(OpenTypeFile* file, const uint8_t* data, size_t length) { | 61 bool ots_name_parse(OpenTypeFile* file, const uint8_t* data, size_t length) { |
60 Buffer table(data, length); | 62 Buffer table(data, length); |
61 | 63 |
62 OpenTypeNAME* name = new OpenTypeNAME; | 64 OpenTypeNAME* name = new OpenTypeNAME; |
63 file->name = name; | 65 file->name = name; |
64 | 66 |
65 uint16_t format = 0; | 67 uint16_t format = 0; |
66 if (!table.ReadU16(&format) || format > 1) { | 68 if (!table.ReadU16(&format) || format > 1) { |
67 return OTS_FAILURE(); | 69 return OTS_FAILURE_MSG("Failed to read name table format or bad format %d",
format); |
68 } | 70 } |
69 | 71 |
70 uint16_t count = 0; | 72 uint16_t count = 0; |
71 if (!table.ReadU16(&count)) { | 73 if (!table.ReadU16(&count)) { |
72 return OTS_FAILURE(); | 74 return OTS_FAILURE_MSG("Failed to read name count"); |
73 } | 75 } |
74 | 76 |
75 uint16_t string_offset = 0; | 77 uint16_t string_offset = 0; |
76 if (!table.ReadU16(&string_offset) || string_offset > length) { | 78 if (!table.ReadU16(&string_offset) || string_offset > length) { |
77 return OTS_FAILURE(); | 79 return OTS_FAILURE_MSG("Failed to read strings offset"); |
78 } | 80 } |
79 const char* string_base = reinterpret_cast<const char*>(data) + | 81 const char* string_base = reinterpret_cast<const char*>(data) + |
80 string_offset; | 82 string_offset; |
81 | 83 |
82 NameRecord prev_record; | 84 NameRecord prev_record; |
83 bool sort_required = false; | 85 bool sort_required = false; |
84 | 86 |
85 // Read all the names, discarding any with invalid IDs, | 87 // Read all the names, discarding any with invalid IDs, |
86 // and any where the offset/length would be outside the table. | 88 // and any where the offset/length would be outside the table. |
87 // A stricter alternative would be to reject the font if there | 89 // A stricter alternative would be to reject the font if there |
88 // are invalid name records, but it's not clear that is necessary. | 90 // are invalid name records, but it's not clear that is necessary. |
89 for (unsigned i = 0; i < count; ++i) { | 91 for (unsigned i = 0; i < count; ++i) { |
90 NameRecord rec; | 92 NameRecord rec; |
91 uint16_t name_length, name_offset; | 93 uint16_t name_length, name_offset = 0; |
92 if (!table.ReadU16(&rec.platform_id) || | 94 if (!table.ReadU16(&rec.platform_id) || |
93 !table.ReadU16(&rec.encoding_id) || | 95 !table.ReadU16(&rec.encoding_id) || |
94 !table.ReadU16(&rec.language_id) || | 96 !table.ReadU16(&rec.language_id) || |
95 !table.ReadU16(&rec.name_id) || | 97 !table.ReadU16(&rec.name_id) || |
96 !table.ReadU16(&name_length) || | 98 !table.ReadU16(&name_length) || |
97 !table.ReadU16(&name_offset)) { | 99 !table.ReadU16(&name_offset)) { |
98 return OTS_FAILURE(); | 100 return OTS_FAILURE_MSG("Failed to read name entry %d", i); |
99 } | 101 } |
100 // check platform & encoding, discard names with unknown values | 102 // check platform & encoding, discard names with unknown values |
101 switch (rec.platform_id) { | 103 switch (rec.platform_id) { |
102 case 0: // Unicode | 104 case 0: // Unicode |
103 if (rec.encoding_id > 6) { | 105 if (rec.encoding_id > 6) { |
104 continue; | 106 continue; |
105 } | 107 } |
106 break; | 108 break; |
107 case 1: // Macintosh | 109 case 1: // Macintosh |
108 if (rec.encoding_id > 32) { | 110 if (rec.encoding_id > 32) { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 } | 161 } |
160 | 162 |
161 name->names.push_back(rec); | 163 name->names.push_back(rec); |
162 prev_record = rec; | 164 prev_record = rec; |
163 } | 165 } |
164 | 166 |
165 if (format == 1) { | 167 if (format == 1) { |
166 // extended name table format with language tags | 168 // extended name table format with language tags |
167 uint16_t lang_tag_count; | 169 uint16_t lang_tag_count; |
168 if (!table.ReadU16(&lang_tag_count)) { | 170 if (!table.ReadU16(&lang_tag_count)) { |
169 return OTS_FAILURE(); | 171 return OTS_FAILURE_MSG("Failed to read language tag count"); |
170 } | 172 } |
171 for (unsigned i = 0; i < lang_tag_count; ++i) { | 173 for (unsigned i = 0; i < lang_tag_count; ++i) { |
172 uint16_t tag_length = 0; | 174 uint16_t tag_length = 0; |
173 uint16_t tag_offset = 0; | 175 uint16_t tag_offset = 0; |
174 if (!table.ReadU16(&tag_length) || !table.ReadU16(&tag_offset)) { | 176 if (!table.ReadU16(&tag_length) || !table.ReadU16(&tag_offset)) { |
175 return OTS_FAILURE(); | 177 return OTS_FAILURE_MSG("Faile to read tag length or offset"); |
176 } | 178 } |
177 const unsigned tag_end = static_cast<unsigned>(string_offset) + | 179 const unsigned tag_end = static_cast<unsigned>(string_offset) + |
178 tag_offset + tag_length; | 180 tag_offset + tag_length; |
179 if (tag_end > length) { | 181 if (tag_end > length) { |
180 return OTS_FAILURE(); | 182 return OTS_FAILURE_MSG("bad end of tag %d > %ld for name entry %d", tag_
end, length, i); |
181 } | 183 } |
182 std::string tag(string_base + tag_offset, tag_length); | 184 std::string tag(string_base + tag_offset, tag_length); |
183 name->lang_tags.push_back(tag); | 185 name->lang_tags.push_back(tag); |
184 } | 186 } |
185 } | 187 } |
186 | 188 |
187 if (table.offset() > string_offset) { | 189 if (table.offset() > string_offset) { |
188 // the string storage apparently overlapped the name/tag records; | 190 // the string storage apparently overlapped the name/tag records; |
189 // consider this font to be badly broken | 191 // consider this font to be badly broken |
190 return OTS_FAILURE(); | 192 return OTS_FAILURE_MSG("Bad table offset %ld > %d", table.offset(), string_o
ffset); |
191 } | 193 } |
192 | 194 |
193 // check existence of required name strings (synthesize if necessary) | 195 // check existence of required name strings (synthesize if necessary) |
194 // [0 - copyright - skip] | 196 // [0 - copyright - skip] |
195 // 1 - family | 197 // 1 - family |
196 // 2 - subfamily | 198 // 2 - subfamily |
197 // [3 - unique ID - skip] | 199 // [3 - unique ID - skip] |
198 // 4 - full name | 200 // 4 - full name |
199 // 5 - version | 201 // 5 - version |
200 // 6 - postscript name | 202 // 6 - postscript name |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
273 uint16_t lang_tag_count = static_cast<uint16_t>(name->lang_tags.size()); | 275 uint16_t lang_tag_count = static_cast<uint16_t>(name->lang_tags.size()); |
274 uint16_t format = 0; | 276 uint16_t format = 0; |
275 size_t string_offset = 6 + name_count * 12; | 277 size_t string_offset = 6 + name_count * 12; |
276 | 278 |
277 if (name->lang_tags.size() > 0) { | 279 if (name->lang_tags.size() > 0) { |
278 // lang tags require a format-1 name table | 280 // lang tags require a format-1 name table |
279 format = 1; | 281 format = 1; |
280 string_offset += 2 + lang_tag_count * 4; | 282 string_offset += 2 + lang_tag_count * 4; |
281 } | 283 } |
282 if (string_offset > 0xffff) { | 284 if (string_offset > 0xffff) { |
283 return OTS_FAILURE(); | 285 return OTS_FAILURE_MSG("Bad string offset %ld", string_offset); |
284 } | 286 } |
285 if (!out->WriteU16(format) || | 287 if (!out->WriteU16(format) || |
286 !out->WriteU16(name_count) || | 288 !out->WriteU16(name_count) || |
287 !out->WriteU16(static_cast<uint16_t>(string_offset))) { | 289 !out->WriteU16(static_cast<uint16_t>(string_offset))) { |
288 return OTS_FAILURE(); | 290 return OTS_FAILURE_MSG("Failed to write name header"); |
289 } | 291 } |
290 | 292 |
291 std::string string_data; | 293 std::string string_data; |
292 for (std::vector<NameRecord>::const_iterator name_iter = name->names.begin(); | 294 for (std::vector<NameRecord>::const_iterator name_iter = name->names.begin(); |
293 name_iter != name->names.end(); name_iter++) { | 295 name_iter != name->names.end(); name_iter++) { |
294 const NameRecord& rec = *name_iter; | 296 const NameRecord& rec = *name_iter; |
295 if (string_data.size() + rec.text.size() > | 297 if (string_data.size() + rec.text.size() > |
296 std::numeric_limits<uint16_t>::max() || | 298 std::numeric_limits<uint16_t>::max() || |
297 !out->WriteU16(rec.platform_id) || | 299 !out->WriteU16(rec.platform_id) || |
298 !out->WriteU16(rec.encoding_id) || | 300 !out->WriteU16(rec.encoding_id) || |
299 !out->WriteU16(rec.language_id) || | 301 !out->WriteU16(rec.language_id) || |
300 !out->WriteU16(rec.name_id) || | 302 !out->WriteU16(rec.name_id) || |
301 !out->WriteU16(static_cast<uint16_t>(rec.text.size())) || | 303 !out->WriteU16(static_cast<uint16_t>(rec.text.size())) || |
302 !out->WriteU16(static_cast<uint16_t>(string_data.size())) ) { | 304 !out->WriteU16(static_cast<uint16_t>(string_data.size())) ) { |
303 return OTS_FAILURE(); | 305 return OTS_FAILURE_MSG("Faile to write name entry"); |
304 } | 306 } |
305 string_data.append(rec.text); | 307 string_data.append(rec.text); |
306 } | 308 } |
307 | 309 |
308 if (format == 1) { | 310 if (format == 1) { |
309 if (!out->WriteU16(lang_tag_count)) { | 311 if (!out->WriteU16(lang_tag_count)) { |
310 return OTS_FAILURE(); | 312 return OTS_FAILURE_MSG("Faile to write language tag count"); |
311 } | 313 } |
312 for (std::vector<std::string>::const_iterator tag_iter = | 314 for (std::vector<std::string>::const_iterator tag_iter = |
313 name->lang_tags.begin(); | 315 name->lang_tags.begin(); |
314 tag_iter != name->lang_tags.end(); tag_iter++) { | 316 tag_iter != name->lang_tags.end(); tag_iter++) { |
315 if (string_data.size() + tag_iter->size() > | 317 if (string_data.size() + tag_iter->size() > |
316 std::numeric_limits<uint16_t>::max() || | 318 std::numeric_limits<uint16_t>::max() || |
317 !out->WriteU16(static_cast<uint16_t>(tag_iter->size())) || | 319 !out->WriteU16(static_cast<uint16_t>(tag_iter->size())) || |
318 !out->WriteU16(static_cast<uint16_t>(string_data.size()))) { | 320 !out->WriteU16(static_cast<uint16_t>(string_data.size()))) { |
319 return OTS_FAILURE(); | 321 return OTS_FAILURE_MSG("Failed to write string"); |
320 } | 322 } |
321 string_data.append(*tag_iter); | 323 string_data.append(*tag_iter); |
322 } | 324 } |
323 } | 325 } |
324 | 326 |
325 if (!out->Write(string_data.data(), string_data.size())) { | 327 if (!out->Write(string_data.data(), string_data.size())) { |
326 return OTS_FAILURE(); | 328 return OTS_FAILURE_MSG("Faile to write string data"); |
327 } | 329 } |
328 | 330 |
329 return true; | 331 return true; |
330 } | 332 } |
331 | 333 |
332 void ots_name_free(OpenTypeFile* file) { | 334 void ots_name_free(OpenTypeFile* file) { |
333 delete file->name; | 335 delete file->name; |
334 } | 336 } |
335 | 337 |
336 } // namespace | 338 } // namespace |
| 339 |
| 340 #undef TABLE_NAME |
OLD | NEW |