1 /*
2 * Copyright 2011 Google Inc. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "sfntly/table/core/name_table.h"
18
19 #include <stdio.h>
20 #include <string.h>
21
22 #include "sfntly/font.h"
23 #include "sfntly/port/exception_type.h"
24
25 namespace sfntly {
26 /******************************************************************************
27 * NameTable::NameEntryId class
28 ******************************************************************************/
NameEntryId()29 NameTable::NameEntryId::NameEntryId()
30 : platform_id_(0),
31 encoding_id_(0),
32 language_id_(0),
33 name_id_(0) {
34 }
35
NameEntryId(int32_t platform_id,int32_t encoding_id,int32_t language_id,int32_t name_id)36 NameTable::NameEntryId::NameEntryId(int32_t platform_id,
37 int32_t encoding_id,
38 int32_t language_id,
39 int32_t name_id)
40 : platform_id_(platform_id),
41 encoding_id_(encoding_id),
42 language_id_(language_id),
43 name_id_(name_id) {
44 }
45
NameEntryId(const NameTable::NameEntryId & rhs)46 NameTable::NameEntryId::NameEntryId(const NameTable::NameEntryId& rhs) {
47 *this = rhs;
48 }
49
50 const NameTable::NameEntryId&
operator =(const NameTable::NameEntryId & rhs) const51 NameTable::NameEntryId::operator=(const NameTable::NameEntryId& rhs) const {
52 platform_id_ = rhs.platform_id_;
53 encoding_id_ = rhs.encoding_id_;
54 language_id_ = rhs.language_id_;
55 name_id_ = rhs.name_id_;
56 return *this;
57 }
58
operator ==(const NameEntryId & rhs) const59 bool NameTable::NameEntryId::operator==(const NameEntryId& rhs) const {
60 return platform_id_ == rhs.platform_id_ &&
61 encoding_id_ == rhs.encoding_id_ &&
62 language_id_ == rhs.language_id_ &&
63 name_id_ == rhs.name_id_;
64 }
65
operator <(const NameEntryId & rhs) const66 bool NameTable::NameEntryId::operator<(const NameEntryId& rhs) const {
67 if (platform_id_ != rhs.platform_id_) return platform_id_ < rhs.platform_id_;
68 if (encoding_id_ != rhs.encoding_id_) return encoding_id_ < rhs.encoding_id_;
69 if (language_id_ != rhs.language_id_) return language_id_ < rhs.language_id_;
70 return name_id_ < rhs.name_id_;
71 }
72
73 /******************************************************************************
74 * NameTable::NameEntry class
75 ******************************************************************************/
NameEntry()76 NameTable::NameEntry::NameEntry() {
77 Init(0, 0, 0, 0, NULL);
78 }
79
NameEntry(const NameEntryId & name_entry_id,const std::vector<uint8_t> & name_bytes)80 NameTable::NameEntry::NameEntry(const NameEntryId& name_entry_id,
81 const std::vector<uint8_t>& name_bytes) {
82 Init(name_entry_id.platform_id(),
83 name_entry_id.encoding_id(),
84 name_entry_id.language_id(),
85 name_entry_id.name_id(),
86 &name_bytes);
87 }
88
NameEntry(int32_t platform_id,int32_t encoding_id,int32_t language_id,int32_t name_id,const std::vector<uint8_t> & name_bytes)89 NameTable::NameEntry::NameEntry(int32_t platform_id,
90 int32_t encoding_id,
91 int32_t language_id,
92 int32_t name_id,
93 const std::vector<uint8_t>& name_bytes) {
94 Init(platform_id, encoding_id, language_id, name_id, &name_bytes);
95 }
96
~NameEntry()97 NameTable::NameEntry::~NameEntry() {}
98
NameAsBytes()99 std::vector<uint8_t>* NameTable::NameEntry::NameAsBytes() {
100 return &name_bytes_;
101 }
102
NameBytesLength()103 int32_t NameTable::NameEntry::NameBytesLength() {
104 return name_bytes_.size();
105 }
106
Name()107 UChar* NameTable::NameEntry::Name() {
108 return NameTable::ConvertFromNameBytes(&name_bytes_,
109 platform_id(),
110 encoding_id());
111 }
112
operator ==(const NameEntry & rhs) const113 bool NameTable::NameEntry::operator==(const NameEntry& rhs) const {
114 return (name_entry_id_ == rhs.name_entry_id_ &&
115 name_bytes_ == rhs.name_bytes_);
116 }
117
Init(int32_t platform_id,int32_t encoding_id,int32_t language_id,int32_t name_id,const std::vector<uint8_t> * name_bytes)118 void NameTable::NameEntry::Init(int32_t platform_id,
119 int32_t encoding_id,
120 int32_t language_id,
121 int32_t name_id,
122 const std::vector<uint8_t>* name_bytes) {
123 name_entry_id_ = NameEntryId(platform_id, encoding_id, language_id, name_id);
124 if (name_bytes) {
125 name_bytes_ = *name_bytes;
126 } else {
127 name_bytes_.clear();
128 }
129 }
130
131 /******************************************************************************
132 * NameTable::NameEntryBuilder class
133 ******************************************************************************/
NameEntryBuilder()134 NameTable::NameEntryBuilder::NameEntryBuilder() {
135 Init(0, 0, 0, 0, NULL);
136 }
137
NameEntryBuilder(const NameEntryId & name_entry_id,const std::vector<uint8_t> & name_bytes)138 NameTable::NameEntryBuilder::NameEntryBuilder(const NameEntryId& name_entry_id,
139 const std::vector<uint8_t>& name_bytes) {
140 Init(name_entry_id.platform_id(),
141 name_entry_id.encoding_id(),
142 name_entry_id.language_id(),
143 name_entry_id.name_id(),
144 &name_bytes);
145 }
146
NameEntryBuilder(const NameEntryId & name_entry_id)147 NameTable::NameEntryBuilder::NameEntryBuilder(
148 const NameEntryId& name_entry_id) {
149 Init(name_entry_id.platform_id(),
150 name_entry_id.encoding_id(),
151 name_entry_id.language_id(),
152 name_entry_id.name_id(),
153 NULL);
154 }
155
NameEntryBuilder(NameEntry * b)156 NameTable::NameEntryBuilder::NameEntryBuilder(NameEntry* b) {
157 Init(b->platform_id(),
158 b->encoding_id(),
159 b->language_id(),
160 b->name_id(),
161 b->NameAsBytes());
162 }
163
~NameEntryBuilder()164 NameTable::NameEntryBuilder::~NameEntryBuilder() {}
165
SetName(const UChar * name)166 void NameTable::NameEntryBuilder::SetName(const UChar* name) {
167 if (name == NULL) {
168 name_entry_->name_bytes_.clear();
169 return;
170 }
171 NameTable::ConvertToNameBytes(name,
172 name_entry_->platform_id(),
173 name_entry_->encoding_id(),
174 &name_entry_->name_bytes_);
175 }
176
SetName(const std::vector<uint8_t> & name_bytes)177 void NameTable::NameEntryBuilder::SetName(const std::vector<uint8_t>& name_bytes) {
178 name_entry_->name_bytes_.clear();
179 std::copy(name_bytes.begin(),
180 name_bytes.end(),
181 name_entry_->name_bytes_.begin());
182 }
183
SetName(const std::vector<uint8_t> & name_bytes,int32_t offset,int32_t length)184 void NameTable::NameEntryBuilder::SetName(const std::vector<uint8_t>& name_bytes,
185 int32_t offset,
186 int32_t length) {
187 name_entry_->name_bytes_.clear();
188 std::copy(name_bytes.begin() + offset,
189 name_bytes.begin() + offset + length,
190 name_entry_->name_bytes_.begin());
191 }
192
Init(int32_t platform_id,int32_t encoding_id,int32_t language_id,int32_t name_id,const std::vector<uint8_t> * name_bytes)193 void NameTable::NameEntryBuilder::Init(int32_t platform_id,
194 int32_t encoding_id,
195 int32_t language_id,
196 int32_t name_id,
197 const std::vector<uint8_t>* name_bytes) {
198 name_entry_ = new NameEntry();
199 name_entry_->Init(platform_id, encoding_id, language_id, name_id, name_bytes);
200 }
201
202 /******************************************************************************
203 * NameTable::NameEntryFilterInPlace class (C++ port only)
204 ******************************************************************************/
NameEntryFilterInPlace(int32_t platform_id,int32_t encoding_id,int32_t language_id,int32_t name_id)205 NameTable::NameEntryFilterInPlace::NameEntryFilterInPlace(int32_t platform_id,
206 int32_t encoding_id,
207 int32_t language_id,
208 int32_t name_id)
209 : platform_id_(platform_id),
210 encoding_id_(encoding_id),
211 language_id_(language_id),
212 name_id_(name_id) {
213 }
214
Accept(int32_t platform_id,int32_t encoding_id,int32_t language_id,int32_t name_id)215 bool NameTable::NameEntryFilterInPlace::Accept(int32_t platform_id,
216 int32_t encoding_id,
217 int32_t language_id,
218 int32_t name_id) {
219 return (platform_id_ == platform_id &&
220 encoding_id_ == encoding_id &&
221 language_id_ == language_id &&
222 name_id_ == name_id);
223 }
224
225 /******************************************************************************
226 * NameTable::NameEntryIterator class
227 ******************************************************************************/
NameEntryIterator(NameTable * table)228 NameTable::NameEntryIterator::NameEntryIterator(NameTable* table)
229 : RefIterator<NameEntry, NameTable>(table),
230 name_index_(0),
231 filter_(NULL) {
232 }
233
NameEntryIterator(NameTable * table,NameEntryFilter * filter)234 NameTable::NameEntryIterator::NameEntryIterator(NameTable* table,
235 NameEntryFilter* filter)
236 : RefIterator<NameEntry, NameTable>(table),
237 name_index_(0),
238 filter_(filter) {
239 }
240
HasNext()241 bool NameTable::NameEntryIterator::HasNext() {
242 if (!filter_) {
243 if (name_index_ < container()->NameCount()) {
244 return true;
245 }
246 return false;
247 }
248 for (; name_index_ < container()->NameCount(); ++name_index_) {
249 if (filter_->Accept(container()->PlatformId(name_index_),
250 container()->EncodingId(name_index_),
251 container()->LanguageId(name_index_),
252 container()->NameId(name_index_))) {
253 return true;
254 }
255 }
256 return false;
257 }
258
Next()259 CALLER_ATTACH NameTable::NameEntry* NameTable::NameEntryIterator::Next() {
260 if (!HasNext())
261 return NULL;
262 return container()->GetNameEntry(name_index_++);
263 }
264
265 /******************************************************************************
266 * NameTable::Builder class
267 ******************************************************************************/
Builder(Header * header,WritableFontData * data)268 NameTable::Builder::Builder(Header* header, WritableFontData* data)
269 : SubTableContainerTable::Builder(header, data) {
270 }
271
Builder(Header * header,ReadableFontData * data)272 NameTable::Builder::Builder(Header* header, ReadableFontData* data)
273 : SubTableContainerTable::Builder(header, data) {
274 }
275
276 CALLER_ATTACH NameTable::Builder*
CreateBuilder(Header * header,WritableFontData * data)277 NameTable::Builder::CreateBuilder(Header* header,
278 WritableFontData* data) {
279 Ptr<NameTable::Builder> builder;
280 builder = new NameTable::Builder(header, data);
281 return builder.Detach();
282 }
283
RevertNames()284 void NameTable::Builder::RevertNames() {
285 name_entry_map_.clear();
286 set_model_changed(false);
287 }
288
BuilderCount()289 int32_t NameTable::Builder::BuilderCount() {
290 GetNameBuilders(); // Ensure name_entry_map_ is built.
291 return (int32_t)name_entry_map_.size();
292 }
293
Has(int32_t platform_id,int32_t encoding_id,int32_t language_id,int32_t name_id)294 bool NameTable::Builder::Has(int32_t platform_id,
295 int32_t encoding_id,
296 int32_t language_id,
297 int32_t name_id) {
298 NameEntryId probe(platform_id, encoding_id, language_id, name_id);
299 GetNameBuilders(); // Ensure name_entry_map_ is built.
300 return (name_entry_map_.find(probe) != name_entry_map_.end());
301 }
302
303 CALLER_ATTACH NameTable::NameEntryBuilder*
NameBuilder(int32_t platform_id,int32_t encoding_id,int32_t language_id,int32_t name_id)304 NameTable::Builder::NameBuilder(int32_t platform_id,
305 int32_t encoding_id,
306 int32_t language_id,
307 int32_t name_id) {
308 NameEntryId probe(platform_id, encoding_id, language_id, name_id);
309 NameEntryBuilderMap builders;
310 GetNameBuilders(); // Ensure name_entry_map_ is built.
311 if (name_entry_map_.find(probe) != name_entry_map_.end()) {
312 return name_entry_map_[probe];
313 }
314 NameEntryBuilderPtr builder = new NameEntryBuilder(probe);
315 name_entry_map_[probe] = builder;
316 return builder.Detach();
317 }
318
Remove(int32_t platform_id,int32_t encoding_id,int32_t language_id,int32_t name_id)319 bool NameTable::Builder::Remove(int32_t platform_id,
320 int32_t encoding_id,
321 int32_t language_id,
322 int32_t name_id) {
323 NameEntryId probe(platform_id, encoding_id, language_id, name_id);
324 GetNameBuilders(); // Ensure name_entry_map_ is built.
325 NameEntryBuilderMap::iterator position = name_entry_map_.find(probe);
326 if (position != name_entry_map_.end()) {
327 name_entry_map_.erase(position);
328 return true;
329 }
330 return false;
331 }
332
333 CALLER_ATTACH FontDataTable*
SubBuildTable(ReadableFontData * data)334 NameTable::Builder::SubBuildTable(ReadableFontData* data) {
335 FontDataTablePtr table = new NameTable(header(), data);
336 return table.Detach();
337 }
338
SubDataSet()339 void NameTable::Builder::SubDataSet() {
340 name_entry_map_.clear();
341 set_model_changed(false);
342 }
343
SubDataSizeToSerialize()344 int32_t NameTable::Builder::SubDataSizeToSerialize() {
345 if (name_entry_map_.empty()) {
346 return 0;
347 }
348
349 int32_t size = NameTable::Offset::kNameRecordStart +
350 name_entry_map_.size() * NameTable::Offset::kNameRecordSize;
351 for (NameEntryBuilderMap::iterator b = name_entry_map_.begin(),
352 end = name_entry_map_.end();
353 b != end; ++b) {
354 NameEntryBuilderPtr p = b->second;
355 NameEntry* entry = p->name_entry();
356 size += entry->NameBytesLength();
357 }
358 return size;
359 }
360
SubReadyToSerialize()361 bool NameTable::Builder::SubReadyToSerialize() {
362 return !name_entry_map_.empty();
363 }
364
SubSerialize(WritableFontData * new_data)365 int32_t NameTable::Builder::SubSerialize(WritableFontData* new_data) {
366 int32_t string_table_start_offset =
367 NameTable::Offset::kNameRecordStart +
368 name_entry_map_.size() * NameTable::Offset::kNameRecordSize;
369
370 // Header
371 new_data->WriteUShort(NameTable::Offset::kFormat, 0);
372 new_data->WriteUShort(NameTable::Offset::kCount, name_entry_map_.size());
373 new_data->WriteUShort(NameTable::Offset::kStringOffset,
374 string_table_start_offset);
375 int32_t name_record_offset = NameTable::Offset::kNameRecordStart;
376 int32_t string_offset = 0;
377 // Note: we offered operator< in NameEntryId, which will be used by std::less,
378 // and therefore our map will act like TreeMap in Java to provide
379 // sorted key set.
380 for (NameEntryBuilderMap::iterator b = name_entry_map_.begin(),
381 end = name_entry_map_.end();
382 b != end; ++b) {
383 new_data->WriteUShort(
384 name_record_offset + NameTable::Offset::kNameRecordPlatformId,
385 b->first.platform_id());
386 new_data->WriteUShort(
387 name_record_offset + NameTable::Offset::kNameRecordEncodingId,
388 b->first.encoding_id());
389 new_data->WriteUShort(
390 name_record_offset + NameTable::Offset::kNameRecordLanguageId,
391 b->first.language_id());
392 new_data->WriteUShort(
393 name_record_offset + NameTable::Offset::kNameRecordNameId,
394 b->first.name_id());
395 NameEntry* builder_entry = b->second->name_entry();
396 new_data->WriteUShort(
397 name_record_offset + NameTable::Offset::kNameRecordStringLength,
398 builder_entry->NameBytesLength());
399 new_data->WriteUShort(
400 name_record_offset + NameTable::Offset::kNameRecordStringOffset,
401 string_offset);
402 name_record_offset += NameTable::Offset::kNameRecordSize;
403 string_offset += new_data->WriteBytes(
404 string_offset + string_table_start_offset,
405 builder_entry->NameAsBytes());
406 }
407
408 return string_offset + string_table_start_offset;
409 }
410
Initialize(ReadableFontData * data)411 void NameTable::Builder::Initialize(ReadableFontData* data) {
412 if (data) {
413 NameTablePtr table = new NameTable(header(), data);
414 Ptr<NameEntryIterator> name_iter;
415 name_iter.Attach(table->Iterator());
416 while (name_iter->HasNext()) {
417 NameEntryPtr name_entry;
418 name_entry.Attach(name_iter->Next());
419 NameEntryBuilderPtr name_entry_builder = new NameEntryBuilder(name_entry);
420 NameEntry* builder_entry = name_entry_builder->name_entry();
421 NameEntryId probe = builder_entry->name_entry_id();
422 name_entry_map_[probe] = name_entry_builder;
423 }
424 }
425 }
426
GetNameBuilders()427 NameTable::NameEntryBuilderMap* NameTable::Builder::GetNameBuilders() {
428 if (name_entry_map_.empty()) {
429 Initialize(InternalReadData());
430 }
431 set_model_changed();
432 return &name_entry_map_;
433 }
434
435 /******************************************************************************
436 * NameTable class
437 ******************************************************************************/
~NameTable()438 NameTable::~NameTable() {}
439
Format()440 int32_t NameTable::Format() {
441 return data_->ReadUShort(Offset::kFormat);
442 }
443
NameCount()444 int32_t NameTable::NameCount() {
445 return data_->ReadUShort(Offset::kCount);
446 }
447
PlatformId(int32_t index)448 int32_t NameTable::PlatformId(int32_t index) {
449 return data_->ReadUShort(Offset::kNameRecordPlatformId +
450 OffsetForNameRecord(index));
451 }
452
EncodingId(int32_t index)453 int32_t NameTable::EncodingId(int32_t index) {
454 return data_->ReadUShort(Offset::kNameRecordEncodingId +
455 OffsetForNameRecord(index));
456 }
457
LanguageId(int32_t index)458 int32_t NameTable::LanguageId(int32_t index) {
459 return data_->ReadUShort(Offset::kNameRecordLanguageId +
460 OffsetForNameRecord(index));
461 }
462
NameId(int32_t index)463 int32_t NameTable::NameId(int32_t index) {
464 return data_->ReadUShort(Offset::kNameRecordNameId +
465 OffsetForNameRecord(index));
466 }
467
NameAsBytes(int32_t index,std::vector<uint8_t> * b)468 void NameTable::NameAsBytes(int32_t index, std::vector<uint8_t>* b) {
469 assert(b);
470 b->clear();
471
472 int32_t length = NameLength(index);
473 if (length <= 0)
474 return;
475
476 int32_t offset = NameOffset(index);
477 if (offset < 0)
478 return;
479
480 b->resize(length);
481 data_->ReadBytes(offset, &((*b)[0]), 0, length);
482 }
483
NameAsBytes(int32_t platform_id,int32_t encoding_id,int32_t language_id,int32_t name_id,std::vector<uint8_t> * b)484 void NameTable::NameAsBytes(int32_t platform_id,
485 int32_t encoding_id,
486 int32_t language_id,
487 int32_t name_id,
488 std::vector<uint8_t>* b) {
489 assert(b);
490 NameEntryPtr entry;
491 entry.Attach(GetNameEntry(platform_id, encoding_id, language_id, name_id));
492 if (entry) {
493 std::vector<uint8_t>* name = entry->NameAsBytes();
494 std::copy(name->begin(), name->end(), b->begin());
495 }
496 }
497
Name(int32_t index)498 UChar* NameTable::Name(int32_t index) {
499 std::vector<uint8_t> b;
500 NameAsBytes(index, &b);
501 return ConvertFromNameBytes(&b, PlatformId(index), EncodingId(index));
502 }
503
Name(int32_t platform_id,int32_t encoding_id,int32_t language_id,int32_t name_id)504 UChar* NameTable::Name(int32_t platform_id,
505 int32_t encoding_id,
506 int32_t language_id,
507 int32_t name_id) {
508 NameEntryPtr entry;
509 entry.Attach(GetNameEntry(platform_id, encoding_id, language_id, name_id));
510 if (entry) {
511 return entry->Name();
512 }
513 return NULL;
514 }
515
GetNameEntry(int32_t index)516 CALLER_ATTACH NameTable::NameEntry* NameTable::GetNameEntry(int32_t index) {
517 std::vector<uint8_t> b;
518 NameAsBytes(index, &b);
519 NameEntryPtr instance = new NameEntry(PlatformId(index),
520 EncodingId(index),
521 LanguageId(index),
522 NameId(index), b);
523 return instance.Detach();
524 }
525
GetNameEntry(int32_t platform_id,int32_t encoding_id,int32_t language_id,int32_t name_id)526 CALLER_ATTACH NameTable::NameEntry* NameTable::GetNameEntry(int32_t platform_id,
527 int32_t encoding_id,
528 int32_t language_id,
529 int32_t name_id) {
530 NameTable::NameEntryFilterInPlace
531 filter(platform_id, encoding_id, language_id, name_id);
532 Ptr<NameTable::NameEntryIterator> name_entry_iter;
533 name_entry_iter.Attach(Iterator(&filter));
534 NameEntryPtr result;
535 if (name_entry_iter->HasNext()) {
536 result = name_entry_iter->Next();
537 }
538 return result;
539 }
540
Iterator()541 CALLER_ATTACH NameTable::NameEntryIterator* NameTable::Iterator() {
542 Ptr<NameEntryIterator> output = new NameTable::NameEntryIterator(this);
543 return output.Detach();
544 }
545
546 CALLER_ATTACH
Iterator(NameEntryFilter * filter)547 NameTable::NameEntryIterator* NameTable::Iterator(NameEntryFilter* filter) {
548 Ptr<NameEntryIterator> output =
549 new NameTable::NameEntryIterator(this, filter);
550 return output.Detach();
551 }
552
NameTable(Header * header,ReadableFontData * data)553 NameTable::NameTable(Header* header, ReadableFontData* data)
554 : SubTableContainerTable(header, data) {}
555
StringOffset()556 int32_t NameTable::StringOffset() {
557 return data_->ReadUShort(Offset::kStringOffset);
558 }
559
OffsetForNameRecord(int32_t index)560 int32_t NameTable::OffsetForNameRecord(int32_t index) {
561 return Offset::kNameRecordStart + index * Offset::kNameRecordSize;
562 }
563
NameLength(int32_t index)564 int32_t NameTable::NameLength(int32_t index) {
565 return data_->ReadUShort(Offset::kNameRecordStringLength +
566 OffsetForNameRecord(index));
567 }
568
NameOffset(int32_t index)569 int32_t NameTable::NameOffset(int32_t index) {
570 return data_->ReadUShort(Offset::kNameRecordStringOffset +
571 OffsetForNameRecord(index)) + StringOffset();
572 }
573
GetEncodingName(int32_t platform_id,int32_t encoding_id)574 const char* NameTable::GetEncodingName(int32_t platform_id,
575 int32_t encoding_id) {
576 switch (platform_id) {
577 case PlatformId::kUnicode:
578 return "UTF-16BE";
579 case PlatformId::kMacintosh:
580 switch (encoding_id) {
581 case MacintoshEncodingId::kRoman:
582 return "MacRoman";
583 case MacintoshEncodingId::kJapanese:
584 return "Shift-JIS";
585 case MacintoshEncodingId::kChineseTraditional:
586 return "Big5";
587 case MacintoshEncodingId::kKorean:
588 return "EUC-KR";
589 case MacintoshEncodingId::kArabic:
590 return "MacArabic";
591 case MacintoshEncodingId::kHebrew:
592 return "MacHebrew";
593 case MacintoshEncodingId::kGreek:
594 return "MacGreek";
595 case MacintoshEncodingId::kRussian:
596 return "MacCyrillic";
597 case MacintoshEncodingId::kRSymbol:
598 return "MacSymbol";
599 case MacintoshEncodingId::kThai:
600 return "MacThai";
601 case MacintoshEncodingId::kChineseSimplified:
602 return "EUC-CN";
603 default: // Note: unknown/unconfirmed cases are not ported.
604 break;
605 }
606 break;
607 case PlatformId::kISO:
608 break;
609 case PlatformId::kWindows:
610 switch (encoding_id) {
611 case WindowsEncodingId::kSymbol:
612 case WindowsEncodingId::kUnicodeUCS2:
613 return "UTF-16BE";
614 case WindowsEncodingId::kShiftJIS:
615 return "windows-933";
616 case WindowsEncodingId::kPRC:
617 return "windows-936";
618 case WindowsEncodingId::kBig5:
619 return "windows-950";
620 case WindowsEncodingId::kWansung:
621 return "windows-949";
622 case WindowsEncodingId::kJohab:
623 return "ms1361";
624 case WindowsEncodingId::kUnicodeUCS4:
625 return "UCS-4";
626 }
627 break;
628 case PlatformId::kCustom:
629 break;
630 default:
631 break;
632 }
633 return NULL;
634 }
635
GetCharset(int32_t platform_id,int32_t encoding_id)636 UConverter* NameTable::GetCharset(int32_t platform_id, int32_t encoding_id) {
637 UErrorCode error_code = U_ZERO_ERROR;
638 UConverter* conv = ucnv_open(GetEncodingName(platform_id, encoding_id),
639 &error_code);
640 if (U_SUCCESS(error_code)) {
641 return conv;
642 }
643
644 if (conv) {
645 ucnv_close(conv);
646 }
647 return NULL;
648 }
649
ConvertToNameBytes(const UChar * name,int32_t platform_id,int32_t encoding_id,std::vector<uint8_t> * b)650 void NameTable::ConvertToNameBytes(const UChar* name,
651 int32_t platform_id,
652 int32_t encoding_id,
653 std::vector<uint8_t>* b) {
654 assert(b);
655 assert(name);
656 b->clear();
657 UConverter* cs = GetCharset(platform_id, encoding_id);
658 if (cs == NULL) {
659 return;
660 }
661
662 // Preflight to get buffer size.
663 UErrorCode error_code = U_ZERO_ERROR;
664 int32_t length = ucnv_fromUChars(cs, NULL, 0, name, -1, &error_code);
665 b->resize(length + 4); // The longest termination "\0" is 4 bytes.
666 memset(&((*b)[0]), 0, length + 4);
667 error_code = U_ZERO_ERROR;
668 ucnv_fromUChars(cs,
669 reinterpret_cast<char*>(&((*b)[0])),
670 length + 4,
671 name,
672 -1,
673 &error_code);
674 if (!U_SUCCESS(error_code)) {
675 b->clear();
676 }
677 ucnv_close(cs);
678 }
679
ConvertFromNameBytes(std::vector<uint8_t> * name_bytes,int32_t platform_id,int32_t encoding_id)680 UChar* NameTable::ConvertFromNameBytes(std::vector<uint8_t>* name_bytes,
681 int32_t platform_id,
682 int32_t encoding_id) {
683 if (name_bytes == NULL || name_bytes->size() == 0) {
684 return NULL;
685 }
686 UConverter* cs = GetCharset(platform_id, encoding_id);
687 UErrorCode error_code = U_ZERO_ERROR;
688 if (cs == NULL) {
689 char buffer[11] = {0};
690 #if defined (WIN32)
691 _itoa_s(platform_id, buffer, 16);
692 #else
693 snprintf(buffer, sizeof(buffer), "%x", platform_id);
694 #endif
695 UChar* result = new UChar[12];
696 memset(result, 0, sizeof(UChar) * 12);
697 cs = ucnv_open("utf-8", &error_code);
698 if (U_SUCCESS(error_code)) {
699 ucnv_toUChars(cs, result, 12, buffer, 11, &error_code);
700 ucnv_close(cs);
701 if (U_SUCCESS(error_code)) {
702 return result;
703 }
704 }
705 delete[] result;
706 return NULL;
707 }
708
709 // No preflight needed here, we will be bigger.
710 UChar* output_buffer = new UChar[name_bytes->size() + 1];
711 memset(output_buffer, 0, sizeof(UChar) * (name_bytes->size() + 1));
712 int32_t length = ucnv_toUChars(cs,
713 output_buffer,
714 name_bytes->size(),
715 reinterpret_cast<char*>(&((*name_bytes)[0])),
716 name_bytes->size(),
717 &error_code);
718 ucnv_close(cs);
719 if (length > 0) {
720 return output_buffer;
721 }
722
723 delete[] output_buffer;
724 return NULL;
725 }
726
727 } // namespace sfntly
728