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 "sfntly/font.h"
     23 #include "sfntly/port/exception_type.h"
     24 
     25 namespace sfntly {
     26 /******************************************************************************
     27  * NameTable::NameEntryId class
     28  ******************************************************************************/
     29 NameTable::NameEntryId::NameEntryId()
     30     : platform_id_(0),
     31       encoding_id_(0),
     32       language_id_(0),
     33       name_id_(0) {
     34 }
     35 
     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 
     46 NameTable::NameEntryId::NameEntryId(const NameTable::NameEntryId& rhs) {
     47   *this = rhs;
     48 }
     49 
     50 const NameTable::NameEntryId&
     51     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 
     59 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 
     66 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  ******************************************************************************/
     76 NameTable::NameEntry::NameEntry() {
     77   Init(0, 0, 0, 0, NULL);
     78 }
     79 
     80 NameTable::NameEntry::NameEntry(const NameEntryId& name_entry_id,
     81                                 const ByteVector& 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 
     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 ByteVector& name_bytes) {
     94   Init(platform_id, encoding_id, language_id, name_id, &name_bytes);
     95 }
     96 
     97 NameTable::NameEntry::~NameEntry() {}
     98 
     99 ByteVector* NameTable::NameEntry::NameAsBytes() {
    100   return &name_bytes_;
    101 }
    102 
    103 int32_t NameTable::NameEntry::NameBytesLength() {
    104   return name_bytes_.size();
    105 }
    106 
    107 UChar* NameTable::NameEntry::Name() {
    108   return NameTable::ConvertFromNameBytes(&name_bytes_,
    109                                          platform_id(),
    110                                          encoding_id());
    111 }
    112 
    113 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 
    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 ByteVector* 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  ******************************************************************************/
    134 NameTable::NameEntryBuilder::NameEntryBuilder() {
    135   Init(0, 0, 0, 0, NULL);
    136 }
    137 
    138 NameTable::NameEntryBuilder::NameEntryBuilder(const NameEntryId& name_entry_id,
    139                                               const ByteVector& 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 
    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 
    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 
    164 NameTable::NameEntryBuilder::~NameEntryBuilder() {}
    165 
    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 
    177 void NameTable::NameEntryBuilder::SetName(const ByteVector& 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 
    184 void NameTable::NameEntryBuilder::SetName(const ByteVector& 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 
    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 ByteVector* 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  ******************************************************************************/
    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 
    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  ******************************************************************************/
    228 NameTable::NameEntryIterator::NameEntryIterator(NameTable* table)
    229     : RefIterator<NameEntry, NameTable>(table),
    230       name_index_(0),
    231       filter_(NULL) {
    232 }
    233 
    234 NameTable::NameEntryIterator::NameEntryIterator(NameTable* table,
    235                                                 NameEntryFilter* filter)
    236     : RefIterator<NameEntry, NameTable>(table),
    237       name_index_(0),
    238       filter_(filter) {
    239 }
    240 
    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 
    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  ******************************************************************************/
    268 NameTable::Builder::Builder(Header* header, WritableFontData* data)
    269     : SubTableContainerTable::Builder(header, data) {
    270 }
    271 
    272 NameTable::Builder::Builder(Header* header, ReadableFontData* data)
    273     : SubTableContainerTable::Builder(header, data) {
    274 }
    275 
    276 CALLER_ATTACH NameTable::Builder*
    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 
    284 void NameTable::Builder::RevertNames() {
    285   name_entry_map_.clear();
    286   set_model_changed(false);
    287 }
    288 
    289 int32_t NameTable::Builder::BuilderCount() {
    290   GetNameBuilders();  // Ensure name_entry_map_ is built.
    291   return (int32_t)name_entry_map_.size();
    292 }
    293 
    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*
    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 
    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*
    334     NameTable::Builder::SubBuildTable(ReadableFontData* data) {
    335   FontDataTablePtr table = new NameTable(header(), data);
    336   return table.Detach();
    337 }
    338 
    339 void NameTable::Builder::SubDataSet() {
    340   name_entry_map_.clear();
    341   set_model_changed(false);
    342 }
    343 
    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 
    361 bool NameTable::Builder::SubReadyToSerialize() {
    362   return !name_entry_map_.empty();
    363 }
    364 
    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 
    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 
    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  ******************************************************************************/
    438 NameTable::~NameTable() {}
    439 
    440 int32_t NameTable::Format() {
    441   return data_->ReadUShort(Offset::kFormat);
    442 }
    443 
    444 int32_t NameTable::NameCount() {
    445   return data_->ReadUShort(Offset::kCount);
    446 }
    447 
    448 int32_t NameTable::PlatformId(int32_t index) {
    449   return data_->ReadUShort(Offset::kNameRecordPlatformId +
    450                            OffsetForNameRecord(index));
    451 }
    452 
    453 int32_t NameTable::EncodingId(int32_t index) {
    454   return data_->ReadUShort(Offset::kNameRecordEncodingId +
    455                            OffsetForNameRecord(index));
    456 }
    457 
    458 int32_t NameTable::LanguageId(int32_t index) {
    459   return data_->ReadUShort(Offset::kNameRecordLanguageId +
    460                            OffsetForNameRecord(index));
    461 }
    462 
    463 int32_t NameTable::NameId(int32_t index) {
    464   return data_->ReadUShort(Offset::kNameRecordNameId +
    465                            OffsetForNameRecord(index));
    466 }
    467 
    468 void NameTable::NameAsBytes(int32_t index, ByteVector* b) {
    469   assert(b);
    470   b->clear();
    471 
    472   int32_t length = NameLength(index);
    473   if (length <= 0)
    474     return;
    475 
    476   b->resize(length);
    477   data_->ReadBytes(NameOffset(index), &((*b)[0]), 0, length);
    478 }
    479 
    480 void NameTable::NameAsBytes(int32_t platform_id,
    481                             int32_t encoding_id,
    482                             int32_t language_id,
    483                             int32_t name_id,
    484                             ByteVector* b) {
    485   assert(b);
    486   NameEntryPtr entry;
    487   entry.Attach(GetNameEntry(platform_id, encoding_id, language_id, name_id));
    488   if (entry) {
    489     ByteVector* name = entry->NameAsBytes();
    490     std::copy(name->begin(), name->end(), b->begin());
    491   }
    492 }
    493 
    494 UChar* NameTable::Name(int32_t index) {
    495   ByteVector b;
    496   NameAsBytes(index, &b);
    497   return ConvertFromNameBytes(&b, PlatformId(index), EncodingId(index));
    498 }
    499 
    500 UChar* NameTable::Name(int32_t platform_id,
    501                        int32_t encoding_id,
    502                        int32_t language_id,
    503                        int32_t name_id) {
    504   NameEntryPtr entry;
    505   entry.Attach(GetNameEntry(platform_id, encoding_id, language_id, name_id));
    506   if (entry) {
    507     return entry->Name();
    508   }
    509   return NULL;
    510 }
    511 
    512 CALLER_ATTACH NameTable::NameEntry* NameTable::GetNameEntry(int32_t index) {
    513   ByteVector b;
    514   NameAsBytes(index, &b);
    515   NameEntryPtr instance = new NameEntry(PlatformId(index),
    516                                         EncodingId(index),
    517                                         LanguageId(index),
    518                                         NameId(index), b);
    519   return instance.Detach();
    520 }
    521 
    522 CALLER_ATTACH NameTable::NameEntry* NameTable::GetNameEntry(int32_t platform_id,
    523                                                             int32_t encoding_id,
    524                                                             int32_t language_id,
    525                                                             int32_t name_id) {
    526   NameTable::NameEntryFilterInPlace
    527       filter(platform_id, encoding_id, language_id, name_id);
    528   Ptr<NameTable::NameEntryIterator> name_entry_iter;
    529   name_entry_iter.Attach(Iterator(&filter));
    530   NameEntryPtr result;
    531   if (name_entry_iter->HasNext()) {
    532     result = name_entry_iter->Next();
    533   }
    534   return result;
    535 }
    536 
    537 CALLER_ATTACH NameTable::NameEntryIterator* NameTable::Iterator() {
    538   Ptr<NameEntryIterator> output = new NameTable::NameEntryIterator(this);
    539   return output.Detach();
    540 }
    541 
    542 CALLER_ATTACH
    543 NameTable::NameEntryIterator* NameTable::Iterator(NameEntryFilter* filter) {
    544   Ptr<NameEntryIterator> output =
    545       new NameTable::NameEntryIterator(this, filter);
    546   return output.Detach();
    547 }
    548 
    549 NameTable::NameTable(Header* header, ReadableFontData* data)
    550     : SubTableContainerTable(header, data) {}
    551 
    552 int32_t NameTable::StringOffset() {
    553   return data_->ReadUShort(Offset::kStringOffset);
    554 }
    555 
    556 int32_t NameTable::OffsetForNameRecord(int32_t index) {
    557   return Offset::kNameRecordStart + index * Offset::kNameRecordSize;
    558 }
    559 
    560 int32_t NameTable::NameLength(int32_t index) {
    561   return data_->ReadUShort(Offset::kNameRecordStringLength +
    562                            OffsetForNameRecord(index));
    563 }
    564 
    565 int32_t NameTable::NameOffset(int32_t index) {
    566   return data_->ReadUShort(Offset::kNameRecordStringOffset +
    567                            OffsetForNameRecord(index)) + StringOffset();
    568 }
    569 
    570 const char* NameTable::GetEncodingName(int32_t platform_id,
    571                                        int32_t encoding_id) {
    572   switch (platform_id) {
    573     case PlatformId::kUnicode:
    574       return "UTF-16BE";
    575     case PlatformId::kMacintosh:
    576       switch (encoding_id) {
    577         case MacintoshEncodingId::kRoman:
    578           return "MacRoman";
    579         case MacintoshEncodingId::kJapanese:
    580           return "Shift-JIS";
    581         case MacintoshEncodingId::kChineseTraditional:
    582           return "Big5";
    583         case MacintoshEncodingId::kKorean:
    584           return "EUC-KR";
    585         case MacintoshEncodingId::kArabic:
    586           return "MacArabic";
    587         case MacintoshEncodingId::kHebrew:
    588           return "MacHebrew";
    589         case MacintoshEncodingId::kGreek:
    590           return "MacGreek";
    591         case MacintoshEncodingId::kRussian:
    592           return "MacCyrillic";
    593         case MacintoshEncodingId::kRSymbol:
    594           return "MacSymbol";
    595         case MacintoshEncodingId::kThai:
    596           return "MacThai";
    597         case MacintoshEncodingId::kChineseSimplified:
    598           return "EUC-CN";
    599         default:  // Note: unknown/unconfirmed cases are not ported.
    600           break;
    601       }
    602       break;
    603     case PlatformId::kISO:
    604       break;
    605     case PlatformId::kWindows:
    606       switch (encoding_id) {
    607         case WindowsEncodingId::kSymbol:
    608         case WindowsEncodingId::kUnicodeUCS2:
    609           return "UTF-16BE";
    610         case WindowsEncodingId::kShiftJIS:
    611           return "windows-933";
    612         case WindowsEncodingId::kPRC:
    613           return "windows-936";
    614         case WindowsEncodingId::kBig5:
    615           return "windows-950";
    616         case WindowsEncodingId::kWansung:
    617           return "windows-949";
    618         case WindowsEncodingId::kJohab:
    619           return "ms1361";
    620         case WindowsEncodingId::kUnicodeUCS4:
    621           return "UCS-4";
    622       }
    623       break;
    624     case PlatformId::kCustom:
    625       break;
    626     default:
    627       break;
    628   }
    629   return NULL;
    630 }
    631 
    632 UConverter* NameTable::GetCharset(int32_t platform_id, int32_t encoding_id) {
    633   UErrorCode error_code = U_ZERO_ERROR;
    634   UConverter* conv = ucnv_open(GetEncodingName(platform_id, encoding_id),
    635                                &error_code);
    636   if (U_SUCCESS(error_code)) {
    637     return conv;
    638   }
    639 
    640   if (conv) {
    641     ucnv_close(conv);
    642   }
    643   return NULL;
    644 }
    645 
    646 void NameTable::ConvertToNameBytes(const UChar* name,
    647                                    int32_t platform_id,
    648                                    int32_t encoding_id,
    649                                    ByteVector* b) {
    650   assert(b);
    651   assert(name);
    652   b->clear();
    653   UConverter* cs = GetCharset(platform_id, encoding_id);
    654   if (cs == NULL) {
    655     return;
    656   }
    657 
    658   // Preflight to get buffer size.
    659   UErrorCode error_code = U_ZERO_ERROR;
    660   int32_t length = ucnv_fromUChars(cs, NULL, 0, name, -1, &error_code);
    661   b->resize(length + 4);  // The longest termination "\0" is 4 bytes.
    662   memset(&((*b)[0]), 0, length + 4);
    663   error_code = U_ZERO_ERROR;
    664   ucnv_fromUChars(cs,
    665                   reinterpret_cast<char*>(&((*b)[0])),
    666                   length + 4,
    667                   name,
    668                   -1,
    669                   &error_code);
    670   if (!U_SUCCESS(error_code)) {
    671     b->clear();
    672   }
    673   ucnv_close(cs);
    674 }
    675 
    676 UChar* NameTable::ConvertFromNameBytes(ByteVector* name_bytes,
    677                                        int32_t platform_id,
    678                                        int32_t encoding_id) {
    679   if (name_bytes == NULL || name_bytes->size() == 0) {
    680     return NULL;
    681   }
    682   UConverter* cs = GetCharset(platform_id, encoding_id);
    683   UErrorCode error_code = U_ZERO_ERROR;
    684   if (cs == NULL) {
    685     char buffer[11] = {0};
    686 #if defined (WIN32)
    687     _itoa_s(platform_id, buffer, 16);
    688 #else
    689     snprintf(buffer, sizeof(buffer), "%x", platform_id);
    690 #endif
    691     UChar* result = new UChar[12];
    692     memset(result, 0, sizeof(UChar) * 12);
    693     cs = ucnv_open("utf-8", &error_code);
    694     if (U_SUCCESS(error_code)) {
    695       ucnv_toUChars(cs, result, 12, buffer, 11, &error_code);
    696       ucnv_close(cs);
    697       if (U_SUCCESS(error_code)) {
    698         return result;
    699       }
    700     }
    701     delete[] result;
    702     return NULL;
    703   }
    704 
    705   // No preflight needed here, we will be bigger.
    706   UChar* output_buffer = new UChar[name_bytes->size() + 1];
    707   memset(output_buffer, 0, sizeof(UChar) * (name_bytes->size() + 1));
    708   int32_t length = ucnv_toUChars(cs,
    709                                  output_buffer,
    710                                  name_bytes->size(),
    711                                  reinterpret_cast<char*>(&((*name_bytes)[0])),
    712                                  name_bytes->size(),
    713                                  &error_code);
    714   ucnv_close(cs);
    715   if (length > 0) {
    716     return output_buffer;
    717   }
    718 
    719   delete[] output_buffer;
    720   return NULL;
    721 }
    722 
    723 }  // namespace sfntly
    724