• 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 "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