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