Home | History | Annotate | Download | only in core
      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  ******************************************************************************/
     31 NameTable::NameEntryId::NameEntryId()
     32     : platform_id_(0),
     33       encoding_id_(0),
     34       language_id_(0),
     35       name_id_(0) {
     36 }
     37 
     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 
     48 NameTable::NameEntryId::NameEntryId(const NameTable::NameEntryId& rhs) {
     49   *this = rhs;
     50 }
     51 
     52 const NameTable::NameEntryId&
     53     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 
     61 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 
     68 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  ******************************************************************************/
     78 NameTable::NameEntry::NameEntry() {
     79   Init(0, 0, 0, 0, NULL);
     80 }
     81 
     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 
     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 
     99 NameTable::NameEntry::~NameEntry() {}
    100 
    101 ByteVector* NameTable::NameEntry::NameAsBytes() {
    102   return &name_bytes_;
    103 }
    104 
    105 int32_t NameTable::NameEntry::NameBytesLength() {
    106   return name_bytes_.size();
    107 }
    108 
    109 UChar* NameTable::NameEntry::Name() {
    110   return NameTable::ConvertFromNameBytes(&name_bytes_,
    111                                          platform_id(),
    112                                          encoding_id());
    113 }
    114 
    115 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 
    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  ******************************************************************************/
    136 NameTable::NameEntryBuilder::NameEntryBuilder() {
    137   Init(0, 0, 0, 0, NULL);
    138 }
    139 
    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 
    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 
    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 
    166 NameTable::NameEntryBuilder::~NameEntryBuilder() {}
    167 
    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 
    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 
    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 
    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  ******************************************************************************/
    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 
    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  ******************************************************************************/
    230 NameTable::NameEntryIterator::NameEntryIterator(NameTable* table)
    231     : RefIterator<NameEntry, NameTable>(table),
    232       name_index_(0),
    233       filter_(NULL) {
    234 }
    235 
    236 NameTable::NameEntryIterator::NameEntryIterator(NameTable* table,
    237                                                 NameEntryFilter* filter)
    238     : RefIterator<NameEntry, NameTable>(table),
    239       name_index_(0),
    240       filter_(filter) {
    241 }
    242 
    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 
    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  ******************************************************************************/
    270 NameTable::Builder::Builder(Header* header, WritableFontData* data)
    271     : SubTableContainerTable::Builder(header, data) {
    272 }
    273 
    274 NameTable::Builder::Builder(Header* header, ReadableFontData* data)
    275     : SubTableContainerTable::Builder(header, data) {
    276 }
    277 
    278 CALLER_ATTACH NameTable::Builder*
    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 
    286 void NameTable::Builder::RevertNames() {
    287   name_entry_map_.clear();
    288   set_model_changed(false);
    289 }
    290 
    291 int32_t NameTable::Builder::BuilderCount() {
    292   GetNameBuilders();  // Ensure name_entry_map_ is built.
    293   return (int32_t)name_entry_map_.size();
    294 }
    295 
    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*
    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 
    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*
    336     NameTable::Builder::SubBuildTable(ReadableFontData* data) {
    337   FontDataTablePtr table = new NameTable(header(), data);
    338   return table.Detach();
    339 }
    340 
    341 void NameTable::Builder::SubDataSet() {
    342   name_entry_map_.clear();
    343   set_model_changed(false);
    344 }
    345 
    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 
    363 bool NameTable::Builder::SubReadyToSerialize() {
    364   return !name_entry_map_.empty();
    365 }
    366 
    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 
    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 
    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  ******************************************************************************/
    440 NameTable::~NameTable() {}
    441 
    442 int32_t NameTable::Format() {
    443   return data_->ReadUShort(Offset::kFormat);
    444 }
    445 
    446 int32_t NameTable::NameCount() {
    447   return data_->ReadUShort(Offset::kCount);
    448 }
    449 
    450 int32_t NameTable::PlatformId(int32_t index) {
    451   return data_->ReadUShort(Offset::kNameRecordPlatformId +
    452                            OffsetForNameRecord(index));
    453 }
    454 
    455 int32_t NameTable::EncodingId(int32_t index) {
    456   return data_->ReadUShort(Offset::kNameRecordEncodingId +
    457                            OffsetForNameRecord(index));
    458 }
    459 
    460 int32_t NameTable::LanguageId(int32_t index) {
    461   return data_->ReadUShort(Offset::kNameRecordLanguageId +
    462                            OffsetForNameRecord(index));
    463 }
    464 
    465 int32_t NameTable::NameId(int32_t index) {
    466   return data_->ReadUShort(Offset::kNameRecordNameId +
    467                            OffsetForNameRecord(index));
    468 }
    469 
    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 
    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 
    496 UChar* NameTable::Name(int32_t index) {
    497   ByteVector b;
    498   NameAsBytes(index, &b);
    499   return ConvertFromNameBytes(&b, PlatformId(index), EncodingId(index));
    500 }
    501 
    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 
    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 
    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 
    539 CALLER_ATTACH NameTable::NameEntryIterator* NameTable::Iterator() {
    540   Ptr<NameEntryIterator> output = new NameTable::NameEntryIterator(this);
    541   return output.Detach();
    542 }
    543 
    544 CALLER_ATTACH
    545 NameTable::NameEntryIterator* NameTable::Iterator(NameEntryFilter* filter) {
    546   Ptr<NameEntryIterator> output =
    547       new NameTable::NameEntryIterator(this, filter);
    548   return output.Detach();
    549 }
    550 
    551 NameTable::NameTable(Header* header, ReadableFontData* data)
    552     : SubTableContainerTable(header, data) {}
    553 
    554 int32_t NameTable::StringOffset() {
    555   return data_->ReadUShort(Offset::kStringOffset);
    556 }
    557 
    558 int32_t NameTable::OffsetForNameRecord(int32_t index) {
    559   return Offset::kNameRecordStart + index * Offset::kNameRecordSize;
    560 }
    561 
    562 int32_t NameTable::NameLength(int32_t index) {
    563   return data_->ReadUShort(Offset::kNameRecordStringLength +
    564                            OffsetForNameRecord(index));
    565 }
    566 
    567 int32_t NameTable::NameOffset(int32_t index) {
    568   return data_->ReadUShort(Offset::kNameRecordStringOffset +
    569                            OffsetForNameRecord(index)) + StringOffset();
    570 }
    571 
    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 
    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 
    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 
    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