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