Line data Source code
1 : // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "name.h"
6 :
7 : #include <algorithm>
8 : #include <cstring>
9 :
10 : // name - Naming Table
11 : // http://www.microsoft.com/typography/otspec/name.htm
12 :
13 : #define TABLE_NAME "name"
14 :
15 : namespace {
16 :
17 0 : bool ValidInPsName(char c) {
18 0 : return (c > 0x20 && c < 0x7f && !std::strchr("[](){}<>/%", c));
19 : }
20 :
21 0 : bool CheckPsNameAscii(const std::string& name) {
22 0 : for (unsigned i = 0; i < name.size(); ++i) {
23 0 : if (!ValidInPsName(name[i])) {
24 0 : return false;
25 : }
26 : }
27 0 : return true;
28 : }
29 :
30 0 : bool CheckPsNameUtf16Be(const std::string& name) {
31 0 : if ((name.size() & 1) != 0)
32 0 : return false;
33 :
34 0 : for (unsigned i = 0; i < name.size(); i += 2) {
35 0 : if (name[i] != 0) {
36 0 : return false;
37 : }
38 0 : if (!ValidInPsName(name[i+1])) {
39 0 : return false;
40 : }
41 : }
42 0 : return true;
43 : }
44 :
45 0 : void AssignToUtf16BeFromAscii(std::string* target,
46 : const std::string& source) {
47 0 : target->resize(source.size() * 2);
48 0 : for (unsigned i = 0, j = 0; i < source.size(); i++) {
49 0 : (*target)[j++] = '\0';
50 0 : (*target)[j++] = source[i];
51 : }
52 0 : }
53 :
54 : } // namespace
55 :
56 :
57 : namespace ots {
58 :
59 0 : bool ots_name_parse(Font *font, const uint8_t* data, size_t length) {
60 0 : Buffer table(data, length);
61 :
62 0 : OpenTypeNAME* name = new OpenTypeNAME;
63 0 : font->name = name;
64 :
65 0 : uint16_t format = 0;
66 0 : if (!table.ReadU16(&format) || format > 1) {
67 0 : return OTS_FAILURE_MSG("Failed to read name table format or bad format %d", format);
68 : }
69 :
70 0 : uint16_t count = 0;
71 0 : if (!table.ReadU16(&count)) {
72 0 : return OTS_FAILURE_MSG("Failed to read name count");
73 : }
74 :
75 0 : uint16_t string_offset = 0;
76 0 : if (!table.ReadU16(&string_offset) || string_offset > length) {
77 0 : return OTS_FAILURE_MSG("Failed to read strings offset");
78 : }
79 0 : const char* string_base = reinterpret_cast<const char*>(data) +
80 0 : string_offset;
81 :
82 0 : bool sort_required = false;
83 :
84 : // Read all the names, discarding any with invalid IDs,
85 : // and any where the offset/length would be outside the table.
86 : // A stricter alternative would be to reject the font if there
87 : // are invalid name records, but it's not clear that is necessary.
88 0 : for (unsigned i = 0; i < count; ++i) {
89 0 : NameRecord rec;
90 0 : uint16_t name_length, name_offset = 0;
91 0 : if (!table.ReadU16(&rec.platform_id) ||
92 0 : !table.ReadU16(&rec.encoding_id) ||
93 0 : !table.ReadU16(&rec.language_id) ||
94 0 : !table.ReadU16(&rec.name_id) ||
95 0 : !table.ReadU16(&name_length) ||
96 0 : !table.ReadU16(&name_offset)) {
97 0 : return OTS_FAILURE_MSG("Failed to read name entry %d", i);
98 : }
99 : // check platform & encoding, discard names with unknown values
100 0 : switch (rec.platform_id) {
101 : case 0: // Unicode
102 0 : if (rec.encoding_id > 6) {
103 0 : continue;
104 : }
105 0 : break;
106 : case 1: // Macintosh
107 0 : if (rec.encoding_id > 32) {
108 0 : continue;
109 : }
110 0 : break;
111 : case 2: // ISO
112 0 : if (rec.encoding_id > 2) {
113 0 : continue;
114 : }
115 0 : break;
116 : case 3: // Windows: IDs 7 to 9 are "reserved"
117 0 : if (rec.encoding_id > 6 && rec.encoding_id != 10) {
118 0 : continue;
119 : }
120 0 : break;
121 : case 4: // Custom (OTF Windows NT compatibility)
122 0 : if (rec.encoding_id > 255) {
123 0 : continue;
124 : }
125 0 : break;
126 : default: // unknown platform
127 0 : continue;
128 : }
129 :
130 0 : const unsigned name_end = static_cast<unsigned>(string_offset) +
131 0 : name_offset + name_length;
132 0 : if (name_end > length) {
133 0 : continue;
134 : }
135 0 : rec.text.resize(name_length);
136 0 : rec.text.assign(string_base + name_offset, name_length);
137 :
138 0 : if (rec.name_id == 6) {
139 : // PostScript name: check that it is valid, if not then discard it
140 0 : if (rec.platform_id == 1) {
141 0 : if (!CheckPsNameAscii(rec.text)) {
142 0 : continue;
143 : }
144 0 : } else if (rec.platform_id == 0 || rec.platform_id == 3) {
145 0 : if (!CheckPsNameUtf16Be(rec.text)) {
146 0 : continue;
147 : }
148 : }
149 : }
150 :
151 0 : if (!name->names.empty() && !(name->names.back() < rec)) {
152 0 : OTS_WARNING("name records are not sorted.");
153 0 : sort_required = true;
154 : }
155 :
156 0 : name->names.push_back(rec);
157 : }
158 :
159 0 : if (format == 1) {
160 : // extended name table format with language tags
161 : uint16_t lang_tag_count;
162 0 : if (!table.ReadU16(&lang_tag_count)) {
163 0 : return OTS_FAILURE_MSG("Failed to read language tag count");
164 : }
165 0 : for (unsigned i = 0; i < lang_tag_count; ++i) {
166 0 : uint16_t tag_length = 0;
167 0 : uint16_t tag_offset = 0;
168 0 : if (!table.ReadU16(&tag_length) || !table.ReadU16(&tag_offset)) {
169 0 : return OTS_FAILURE_MSG("Faile to read tag length or offset");
170 : }
171 0 : const unsigned tag_end = static_cast<unsigned>(string_offset) +
172 0 : tag_offset + tag_length;
173 0 : if (tag_end > length) {
174 0 : return OTS_FAILURE_MSG("bad end of tag %d > %ld for name entry %d", tag_end, length, i);
175 : }
176 0 : std::string tag(string_base + tag_offset, tag_length);
177 0 : name->lang_tags.push_back(tag);
178 : }
179 : }
180 :
181 0 : if (table.offset() > string_offset) {
182 : // the string storage apparently overlapped the name/tag records;
183 : // consider this font to be badly broken
184 0 : return OTS_FAILURE_MSG("Bad table offset %ld > %d", table.offset(), string_offset);
185 : }
186 :
187 : // check existence of required name strings (synthesize if necessary)
188 : // [0 - copyright - skip]
189 : // 1 - family
190 : // 2 - subfamily
191 : // [3 - unique ID - skip]
192 : // 4 - full name
193 : // 5 - version
194 : // 6 - postscript name
195 : static const uint16_t kStdNameCount = 7;
196 : static const char* kStdNames[kStdNameCount] = {
197 : NULL,
198 : "OTS derived font",
199 : "Unspecified",
200 : NULL,
201 : "OTS derived font",
202 : "1.000",
203 : "OTS-derived-font"
204 : };
205 :
206 : // scan the names to check whether the required "standard" ones are present;
207 : // if not, we'll add our fixed versions here
208 0 : bool mac_name[kStdNameCount] = { 0 };
209 0 : bool win_name[kStdNameCount] = { 0 };
210 0 : for (std::vector<NameRecord>::iterator name_iter = name->names.begin();
211 0 : name_iter != name->names.end(); ++name_iter) {
212 0 : const uint16_t id = name_iter->name_id;
213 0 : if (id >= kStdNameCount || kStdNames[id] == NULL) {
214 0 : continue;
215 : }
216 0 : if (name_iter->platform_id == 1) {
217 0 : mac_name[id] = true;
218 0 : continue;
219 : }
220 0 : if (name_iter->platform_id == 3) {
221 0 : win_name[id] = true;
222 0 : continue;
223 : }
224 : }
225 :
226 0 : for (uint16_t i = 0; i < kStdNameCount; ++i) {
227 0 : if (kStdNames[i] == NULL) {
228 0 : continue;
229 : }
230 0 : if (!mac_name[i] && !win_name[i]) {
231 : NameRecord mac_rec(1 /* platform_id */, 0 /* encoding_id */,
232 0 : 0 /* language_id */ , i /* name_id */);
233 0 : mac_rec.text.assign(kStdNames[i]);
234 :
235 : NameRecord win_rec(3 /* platform_id */, 1 /* encoding_id */,
236 0 : 1033 /* language_id */ , i /* name_id */);
237 0 : AssignToUtf16BeFromAscii(&win_rec.text, std::string(kStdNames[i]));
238 :
239 0 : name->names.push_back(mac_rec);
240 0 : name->names.push_back(win_rec);
241 0 : sort_required = true;
242 : }
243 : }
244 :
245 0 : if (sort_required) {
246 0 : std::sort(name->names.begin(), name->names.end());
247 : }
248 :
249 0 : return true;
250 : }
251 :
252 0 : bool ots_name_should_serialise(Font *font) {
253 0 : return font->name != NULL;
254 : }
255 :
256 0 : bool ots_name_serialise(OTSStream* out, Font *font) {
257 0 : const OpenTypeNAME* name = font->name;
258 :
259 0 : uint16_t name_count = static_cast<uint16_t>(name->names.size());
260 0 : uint16_t lang_tag_count = static_cast<uint16_t>(name->lang_tags.size());
261 0 : uint16_t format = 0;
262 0 : size_t string_offset = 6 + name_count * 12;
263 :
264 0 : if (name->lang_tags.size() > 0) {
265 : // lang tags require a format-1 name table
266 0 : format = 1;
267 0 : string_offset += 2 + lang_tag_count * 4;
268 : }
269 0 : if (string_offset > 0xffff) {
270 0 : return OTS_FAILURE_MSG("Bad string offset %ld", string_offset);
271 : }
272 0 : if (!out->WriteU16(format) ||
273 0 : !out->WriteU16(name_count) ||
274 0 : !out->WriteU16(static_cast<uint16_t>(string_offset))) {
275 0 : return OTS_FAILURE_MSG("Failed to write name header");
276 : }
277 :
278 0 : std::string string_data;
279 0 : for (std::vector<NameRecord>::const_iterator name_iter = name->names.begin();
280 0 : name_iter != name->names.end(); ++name_iter) {
281 0 : const NameRecord& rec = *name_iter;
282 0 : if (string_data.size() + rec.text.size() >
283 0 : std::numeric_limits<uint16_t>::max() ||
284 0 : !out->WriteU16(rec.platform_id) ||
285 0 : !out->WriteU16(rec.encoding_id) ||
286 0 : !out->WriteU16(rec.language_id) ||
287 0 : !out->WriteU16(rec.name_id) ||
288 0 : !out->WriteU16(static_cast<uint16_t>(rec.text.size())) ||
289 0 : !out->WriteU16(static_cast<uint16_t>(string_data.size())) ) {
290 0 : return OTS_FAILURE_MSG("Faile to write name entry");
291 : }
292 0 : string_data.append(rec.text);
293 : }
294 :
295 0 : if (format == 1) {
296 0 : if (!out->WriteU16(lang_tag_count)) {
297 0 : return OTS_FAILURE_MSG("Faile to write language tag count");
298 : }
299 0 : for (std::vector<std::string>::const_iterator tag_iter =
300 0 : name->lang_tags.begin();
301 0 : tag_iter != name->lang_tags.end(); ++tag_iter) {
302 0 : if (string_data.size() + tag_iter->size() >
303 0 : std::numeric_limits<uint16_t>::max() ||
304 0 : !out->WriteU16(static_cast<uint16_t>(tag_iter->size())) ||
305 0 : !out->WriteU16(static_cast<uint16_t>(string_data.size()))) {
306 0 : return OTS_FAILURE_MSG("Failed to write string");
307 : }
308 0 : string_data.append(*tag_iter);
309 : }
310 : }
311 :
312 0 : if (!out->Write(string_data.data(), string_data.size())) {
313 0 : return OTS_FAILURE_MSG("Faile to write string data");
314 : }
315 :
316 0 : return true;
317 : }
318 :
319 0 : void ots_name_reuse(Font *font, Font *other) {
320 0 : font->name = other->name;
321 0 : font->name_reused = true;
322 0 : }
323 :
324 0 : void ots_name_free(Font *font) {
325 0 : delete font->name;
326 0 : }
327 :
328 : } // namespace
329 :
330 : #undef TABLE_NAME
|