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