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.
12 // name - Naming Table
13 // http://www.microsoft.com/typography/otspec/name.htm
15 #define TABLE_NAME "name"
19 bool ValidInPsName(char c
) {
20 return (c
> 0x20 && c
< 0x7f && !std::strchr("[](){}<>/%", c
));
23 bool CheckPsNameAscii(const std::string
& name
) {
24 for (unsigned i
= 0; i
< name
.size(); ++i
) {
25 if (!ValidInPsName(name
[i
])) {
32 bool CheckPsNameUtf16Be(const std::string
& name
) {
33 if ((name
.size() & 1) != 0)
36 for (unsigned i
= 0; i
< name
.size(); i
+= 2) {
40 if (!ValidInPsName(name
[i
+1])) {
47 void AssignToUtf16BeFromAscii(std::string
* target
,
48 const std::string
& source
) {
49 target
->resize(source
.size() * 2);
50 for (unsigned i
= 0, j
= 0; i
< source
.size(); i
++) {
51 (*target
)[j
++] = '\0';
52 (*target
)[j
++] = source
[i
];
61 bool ots_name_parse(OpenTypeFile
* file
, const uint8_t* data
, size_t length
) {
62 Buffer
table(data
, length
);
64 OpenTypeNAME
* name
= new OpenTypeNAME
;
68 if (!table
.ReadU16(&format
) || format
> 1) {
69 return OTS_FAILURE_MSG("Failed to read name table format or bad format %d", format
);
73 if (!table
.ReadU16(&count
)) {
74 return OTS_FAILURE_MSG("Failed to read name count");
77 uint16_t string_offset
= 0;
78 if (!table
.ReadU16(&string_offset
) || string_offset
> length
) {
79 return OTS_FAILURE_MSG("Failed to read strings offset");
81 const char* string_base
= reinterpret_cast<const char*>(data
) +
84 NameRecord prev_record
;
85 bool sort_required
= false;
87 // Read all the names, discarding any with invalid IDs,
88 // and any where the offset/length would be outside the table.
89 // A stricter alternative would be to reject the font if there
90 // are invalid name records, but it's not clear that is necessary.
91 for (unsigned i
= 0; i
< count
; ++i
) {
93 uint16_t name_length
, name_offset
= 0;
94 if (!table
.ReadU16(&rec
.platform_id
) ||
95 !table
.ReadU16(&rec
.encoding_id
) ||
96 !table
.ReadU16(&rec
.language_id
) ||
97 !table
.ReadU16(&rec
.name_id
) ||
98 !table
.ReadU16(&name_length
) ||
99 !table
.ReadU16(&name_offset
)) {
100 return OTS_FAILURE_MSG("Failed to read name entry %d", i
);
102 // check platform & encoding, discard names with unknown values
103 switch (rec
.platform_id
) {
105 if (rec
.encoding_id
> 6) {
110 if (rec
.encoding_id
> 32) {
115 if (rec
.encoding_id
> 2) {
119 case 3: // Windows: IDs 7 to 9 are "reserved"
120 if (rec
.encoding_id
> 6 && rec
.encoding_id
!= 10) {
124 case 4: // Custom (OTF Windows NT compatibility)
125 if (rec
.encoding_id
> 255) {
129 default: // unknown platform
133 const unsigned name_end
= static_cast<unsigned>(string_offset
) +
134 name_offset
+ name_length
;
135 if (name_end
> length
) {
138 rec
.text
.resize(name_length
);
139 rec
.text
.assign(string_base
+ name_offset
, name_length
);
141 if (rec
.name_id
== 6) {
142 // PostScript name: check that it is valid, if not then discard it
143 if (rec
.platform_id
== 1) {
144 if (file
->cff
&& !file
->cff
->name
.empty()) {
145 rec
.text
= file
->cff
->name
;
146 } else if (!CheckPsNameAscii(rec
.text
)) {
149 } else if (rec
.platform_id
== 0 || rec
.platform_id
== 3) {
150 if (file
->cff
&& !file
->cff
->name
.empty()) {
151 AssignToUtf16BeFromAscii(&rec
.text
, file
->cff
->name
);
152 } else if (!CheckPsNameUtf16Be(rec
.text
)) {
158 if ((i
> 0) && !(prev_record
< rec
)) {
159 OTS_WARNING("name records are not sorted.");
160 sort_required
= true;
163 name
->names
.push_back(rec
);
168 // extended name table format with language tags
169 uint16_t lang_tag_count
;
170 if (!table
.ReadU16(&lang_tag_count
)) {
171 return OTS_FAILURE_MSG("Failed to read language tag count");
173 for (unsigned i
= 0; i
< lang_tag_count
; ++i
) {
174 uint16_t tag_length
= 0;
175 uint16_t tag_offset
= 0;
176 if (!table
.ReadU16(&tag_length
) || !table
.ReadU16(&tag_offset
)) {
177 return OTS_FAILURE_MSG("Faile to read tag length or offset");
179 const unsigned tag_end
= static_cast<unsigned>(string_offset
) +
180 tag_offset
+ tag_length
;
181 if (tag_end
> length
) {
182 return OTS_FAILURE_MSG("bad end of tag %d > %ld for name entry %d", tag_end
, length
, i
);
184 std::string
tag(string_base
+ tag_offset
, tag_length
);
185 name
->lang_tags
.push_back(tag
);
189 if (table
.offset() > string_offset
) {
190 // the string storage apparently overlapped the name/tag records;
191 // consider this font to be badly broken
192 return OTS_FAILURE_MSG("Bad table offset %ld > %d", table
.offset(), string_offset
);
195 // check existence of required name strings (synthesize if necessary)
196 // [0 - copyright - skip]
199 // [3 - unique ID - skip]
202 // 6 - postscript name
203 static const uint16_t kStdNameCount
= 7;
204 static const char* kStdNames
[kStdNameCount
] = {
213 // The spec says that "In CFF OpenType fonts, these two name strings, when
214 // translated to ASCII, must also be identical to the font name as stored in
215 // the CFF's Name INDEX." And actually, Mac OS X's font parser requires that.
216 if (file
->cff
&& !file
->cff
->name
.empty()) {
217 kStdNames
[6] = file
->cff
->name
.c_str();
220 // scan the names to check whether the required "standard" ones are present;
221 // if not, we'll add our fixed versions here
222 bool mac_name
[kStdNameCount
] = { 0 };
223 bool win_name
[kStdNameCount
] = { 0 };
224 for (std::vector
<NameRecord
>::iterator name_iter
= name
->names
.begin();
225 name_iter
!= name
->names
.end(); name_iter
++) {
226 const uint16_t id
= name_iter
->name_id
;
227 if (id
>= kStdNameCount
|| kStdNames
[id
] == NULL
) {
230 if (name_iter
->platform_id
== 1) {
234 if (name_iter
->platform_id
== 3) {
240 for (uint16_t i
= 0; i
< kStdNameCount
; ++i
) {
241 if (kStdNames
[i
] == NULL
) {
245 NameRecord
rec(1 /* platform_id */, 0 /* encoding_id */,
246 0 /* language_id */ , i
/* name_id */);
247 rec
.text
.assign(kStdNames
[i
]);
248 name
->names
.push_back(rec
);
249 sort_required
= true;
252 NameRecord
rec(3 /* platform_id */, 1 /* encoding_id */,
253 1033 /* language_id */ , i
/* name_id */);
254 AssignToUtf16BeFromAscii(&rec
.text
, std::string(kStdNames
[i
]));
255 name
->names
.push_back(rec
);
256 sort_required
= true;
261 std::sort(name
->names
.begin(), name
->names
.end());
267 bool ots_name_should_serialise(OpenTypeFile
* file
) {
268 return file
->name
!= NULL
;
271 bool ots_name_serialise(OTSStream
* out
, OpenTypeFile
* file
) {
272 const OpenTypeNAME
* name
= file
->name
;
274 uint16_t name_count
= static_cast<uint16_t>(name
->names
.size());
275 uint16_t lang_tag_count
= static_cast<uint16_t>(name
->lang_tags
.size());
277 size_t string_offset
= 6 + name_count
* 12;
279 if (name
->lang_tags
.size() > 0) {
280 // lang tags require a format-1 name table
282 string_offset
+= 2 + lang_tag_count
* 4;
284 if (string_offset
> 0xffff) {
285 return OTS_FAILURE_MSG("Bad string offset %ld", string_offset
);
287 if (!out
->WriteU16(format
) ||
288 !out
->WriteU16(name_count
) ||
289 !out
->WriteU16(static_cast<uint16_t>(string_offset
))) {
290 return OTS_FAILURE_MSG("Failed to write name header");
293 std::string string_data
;
294 for (std::vector
<NameRecord
>::const_iterator name_iter
= name
->names
.begin();
295 name_iter
!= name
->names
.end(); name_iter
++) {
296 const NameRecord
& rec
= *name_iter
;
297 if (string_data
.size() + rec
.text
.size() >
298 std::numeric_limits
<uint16_t>::max() ||
299 !out
->WriteU16(rec
.platform_id
) ||
300 !out
->WriteU16(rec
.encoding_id
) ||
301 !out
->WriteU16(rec
.language_id
) ||
302 !out
->WriteU16(rec
.name_id
) ||
303 !out
->WriteU16(static_cast<uint16_t>(rec
.text
.size())) ||
304 !out
->WriteU16(static_cast<uint16_t>(string_data
.size())) ) {
305 return OTS_FAILURE_MSG("Faile to write name entry");
307 string_data
.append(rec
.text
);
311 if (!out
->WriteU16(lang_tag_count
)) {
312 return OTS_FAILURE_MSG("Faile to write language tag count");
314 for (std::vector
<std::string
>::const_iterator tag_iter
=
315 name
->lang_tags
.begin();
316 tag_iter
!= name
->lang_tags
.end(); tag_iter
++) {
317 if (string_data
.size() + tag_iter
->size() >
318 std::numeric_limits
<uint16_t>::max() ||
319 !out
->WriteU16(static_cast<uint16_t>(tag_iter
->size())) ||
320 !out
->WriteU16(static_cast<uint16_t>(string_data
.size()))) {
321 return OTS_FAILURE_MSG("Failed to write string");
323 string_data
.append(*tag_iter
);
327 if (!out
->Write(string_data
.data(), string_data
.size())) {
328 return OTS_FAILURE_MSG("Faile to write string data");
334 void ots_name_free(OpenTypeFile
* file
) {