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.
10 // name - Naming Table
11 // http://www.microsoft.com/typography/otspec/name.htm
13 #define TABLE_NAME "name"
17 bool ValidInPsName(char c
) {
18 return (c
> 0x20 && c
< 0x7f && !std::strchr("[](){}<>/%", c
));
21 bool CheckPsNameAscii(const std::string
& name
) {
22 for (unsigned i
= 0; i
< name
.size(); ++i
) {
23 if (!ValidInPsName(name
[i
])) {
30 bool CheckPsNameUtf16Be(const std::string
& name
) {
31 if ((name
.size() & 1) != 0)
34 for (unsigned i
= 0; i
< name
.size(); i
+= 2) {
38 if (!ValidInPsName(name
[i
+1])) {
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
];
59 bool ots_name_parse(Font
*font
, const uint8_t* data
, size_t length
) {
60 Buffer
table(data
, length
);
62 OpenTypeNAME
* name
= new OpenTypeNAME
;
66 if (!table
.ReadU16(&format
) || format
> 1) {
67 return OTS_FAILURE_MSG("Failed to read name table format or bad format %d", format
);
71 if (!table
.ReadU16(&count
)) {
72 return OTS_FAILURE_MSG("Failed to read name count");
75 uint16_t string_offset
= 0;
76 if (!table
.ReadU16(&string_offset
) || string_offset
> length
) {
77 return OTS_FAILURE_MSG("Failed to read strings offset");
79 const char* string_base
= reinterpret_cast<const char*>(data
) +
82 NameRecord prev_record
;
83 bool sort_required
= false;
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
) {
91 uint16_t name_length
, name_offset
= 0;
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_MSG("Failed to read name entry %d", i
);
100 // check platform & encoding, discard names with unknown values
101 switch (rec
.platform_id
) {
103 if (rec
.encoding_id
> 6) {
108 if (rec
.encoding_id
> 32) {
113 if (rec
.encoding_id
> 2) {
117 case 3: // Windows: IDs 7 to 9 are "reserved"
118 if (rec
.encoding_id
> 6 && rec
.encoding_id
!= 10) {
122 case 4: // Custom (OTF Windows NT compatibility)
123 if (rec
.encoding_id
> 255) {
127 default: // unknown platform
131 const unsigned name_end
= static_cast<unsigned>(string_offset
) +
132 name_offset
+ name_length
;
133 if (name_end
> length
) {
136 rec
.text
.resize(name_length
);
137 rec
.text
.assign(string_base
+ name_offset
, name_length
);
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 (!CheckPsNameAscii(rec
.text
)) {
145 } else if (rec
.platform_id
== 0 || rec
.platform_id
== 3) {
146 if (!CheckPsNameUtf16Be(rec
.text
)) {
152 if ((i
> 0) && !(prev_record
< rec
)) {
153 OTS_WARNING("name records are not sorted.");
154 sort_required
= true;
157 name
->names
.push_back(rec
);
162 // extended name table format with language tags
163 uint16_t lang_tag_count
;
164 if (!table
.ReadU16(&lang_tag_count
)) {
165 return OTS_FAILURE_MSG("Failed to read language tag count");
167 for (unsigned i
= 0; i
< lang_tag_count
; ++i
) {
168 uint16_t tag_length
= 0;
169 uint16_t tag_offset
= 0;
170 if (!table
.ReadU16(&tag_length
) || !table
.ReadU16(&tag_offset
)) {
171 return OTS_FAILURE_MSG("Faile to read tag length or offset");
173 const unsigned tag_end
= static_cast<unsigned>(string_offset
) +
174 tag_offset
+ tag_length
;
175 if (tag_end
> length
) {
176 return OTS_FAILURE_MSG("bad end of tag %d > %ld for name entry %d", tag_end
, length
, i
);
178 std::string
tag(string_base
+ tag_offset
, tag_length
);
179 name
->lang_tags
.push_back(tag
);
183 if (table
.offset() > string_offset
) {
184 // the string storage apparently overlapped the name/tag records;
185 // consider this font to be badly broken
186 return OTS_FAILURE_MSG("Bad table offset %ld > %d", table
.offset(), string_offset
);
189 // check existence of required name strings (synthesize if necessary)
190 // [0 - copyright - skip]
193 // [3 - unique ID - skip]
196 // 6 - postscript name
197 static const uint16_t kStdNameCount
= 7;
198 static const char* kStdNames
[kStdNameCount
] = {
208 // scan the names to check whether the required "standard" ones are present;
209 // if not, we'll add our fixed versions here
210 bool mac_name
[kStdNameCount
] = { 0 };
211 bool win_name
[kStdNameCount
] = { 0 };
212 for (std::vector
<NameRecord
>::iterator name_iter
= name
->names
.begin();
213 name_iter
!= name
->names
.end(); name_iter
++) {
214 const uint16_t id
= name_iter
->name_id
;
215 if (id
>= kStdNameCount
|| kStdNames
[id
] == NULL
) {
218 if (name_iter
->platform_id
== 1) {
222 if (name_iter
->platform_id
== 3) {
228 for (uint16_t i
= 0; i
< kStdNameCount
; ++i
) {
229 if (kStdNames
[i
] == NULL
) {
232 if (!mac_name
[i
] && !win_name
[i
]) {
233 NameRecord
mac_rec(1 /* platform_id */, 0 /* encoding_id */,
234 0 /* language_id */ , i
/* name_id */);
235 mac_rec
.text
.assign(kStdNames
[i
]);
237 NameRecord
win_rec(3 /* platform_id */, 1 /* encoding_id */,
238 1033 /* language_id */ , i
/* name_id */);
239 AssignToUtf16BeFromAscii(&win_rec
.text
, std::string(kStdNames
[i
]));
241 name
->names
.push_back(mac_rec
);
242 name
->names
.push_back(win_rec
);
243 sort_required
= true;
248 std::sort(name
->names
.begin(), name
->names
.end());
254 bool ots_name_should_serialise(Font
*font
) {
255 return font
->name
!= NULL
;
258 bool ots_name_serialise(OTSStream
* out
, Font
*font
) {
259 const OpenTypeNAME
* name
= font
->name
;
261 uint16_t name_count
= static_cast<uint16_t>(name
->names
.size());
262 uint16_t lang_tag_count
= static_cast<uint16_t>(name
->lang_tags
.size());
264 size_t string_offset
= 6 + name_count
* 12;
266 if (name
->lang_tags
.size() > 0) {
267 // lang tags require a format-1 name table
269 string_offset
+= 2 + lang_tag_count
* 4;
271 if (string_offset
> 0xffff) {
272 return OTS_FAILURE_MSG("Bad string offset %ld", string_offset
);
274 if (!out
->WriteU16(format
) ||
275 !out
->WriteU16(name_count
) ||
276 !out
->WriteU16(static_cast<uint16_t>(string_offset
))) {
277 return OTS_FAILURE_MSG("Failed to write name header");
280 std::string string_data
;
281 for (std::vector
<NameRecord
>::const_iterator name_iter
= name
->names
.begin();
282 name_iter
!= name
->names
.end(); name_iter
++) {
283 const NameRecord
& rec
= *name_iter
;
284 if (string_data
.size() + rec
.text
.size() >
285 std::numeric_limits
<uint16_t>::max() ||
286 !out
->WriteU16(rec
.platform_id
) ||
287 !out
->WriteU16(rec
.encoding_id
) ||
288 !out
->WriteU16(rec
.language_id
) ||
289 !out
->WriteU16(rec
.name_id
) ||
290 !out
->WriteU16(static_cast<uint16_t>(rec
.text
.size())) ||
291 !out
->WriteU16(static_cast<uint16_t>(string_data
.size())) ) {
292 return OTS_FAILURE_MSG("Faile to write name entry");
294 string_data
.append(rec
.text
);
298 if (!out
->WriteU16(lang_tag_count
)) {
299 return OTS_FAILURE_MSG("Faile to write language tag count");
301 for (std::vector
<std::string
>::const_iterator tag_iter
=
302 name
->lang_tags
.begin();
303 tag_iter
!= name
->lang_tags
.end(); tag_iter
++) {
304 if (string_data
.size() + tag_iter
->size() >
305 std::numeric_limits
<uint16_t>::max() ||
306 !out
->WriteU16(static_cast<uint16_t>(tag_iter
->size())) ||
307 !out
->WriteU16(static_cast<uint16_t>(string_data
.size()))) {
308 return OTS_FAILURE_MSG("Failed to write string");
310 string_data
.append(*tag_iter
);
314 if (!out
->Write(string_data
.data(), string_data
.size())) {
315 return OTS_FAILURE_MSG("Faile to write string data");
321 void ots_name_reuse(Font
*font
, Font
*other
) {
322 font
->name
= other
->name
;
323 font
->name_reused
= true;
326 void ots_name_free(Font
*font
) {