| /* |
| * Copyright 2011 Google Inc. All Rights Reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "sfntly/table/core/name_table.h" |
| |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include <unicode/unistr.h> |
| |
| #include "sfntly/font.h" |
| #include "sfntly/port/exception_type.h" |
| |
| namespace sfntly { |
| /****************************************************************************** |
| * NameTable::NameEntryId class |
| ******************************************************************************/ |
| NameTable::NameEntryId::NameEntryId() |
| : platform_id_(0), |
| encoding_id_(0), |
| language_id_(0), |
| name_id_(0) { |
| } |
| |
| NameTable::NameEntryId::NameEntryId(int32_t platform_id, |
| int32_t encoding_id, |
| int32_t language_id, |
| int32_t name_id) |
| : platform_id_(platform_id), |
| encoding_id_(encoding_id), |
| language_id_(language_id), |
| name_id_(name_id) { |
| } |
| |
| NameTable::NameEntryId::NameEntryId(const NameTable::NameEntryId& rhs) { |
| *this = rhs; |
| } |
| |
| const NameTable::NameEntryId& |
| NameTable::NameEntryId::operator=(const NameTable::NameEntryId& rhs) const { |
| platform_id_ = rhs.platform_id_; |
| encoding_id_ = rhs.encoding_id_; |
| language_id_ = rhs.language_id_; |
| name_id_ = rhs.name_id_; |
| return *this; |
| } |
| |
| bool NameTable::NameEntryId::operator==(const NameEntryId& rhs) const { |
| return platform_id_ == rhs.platform_id_ && |
| encoding_id_ == rhs.encoding_id_ && |
| language_id_ == rhs.language_id_ && |
| name_id_ == rhs.name_id_; |
| } |
| |
| bool NameTable::NameEntryId::operator<(const NameEntryId& rhs) const { |
| if (platform_id_ != rhs.platform_id_) return platform_id_ < rhs.platform_id_; |
| if (encoding_id_ != rhs.encoding_id_) return encoding_id_ < rhs.encoding_id_; |
| if (language_id_ != rhs.language_id_) return language_id_ < rhs.language_id_; |
| return name_id_ < rhs.name_id_; |
| } |
| |
| /****************************************************************************** |
| * NameTable::NameEntry class |
| ******************************************************************************/ |
| NameTable::NameEntry::NameEntry() { |
| Init(0, 0, 0, 0, NULL); |
| } |
| |
| NameTable::NameEntry::NameEntry(const NameEntryId& name_entry_id, |
| const ByteVector& name_bytes) { |
| Init(name_entry_id.platform_id(), |
| name_entry_id.encoding_id(), |
| name_entry_id.language_id(), |
| name_entry_id.name_id(), |
| &name_bytes); |
| } |
| |
| NameTable::NameEntry::NameEntry(int32_t platform_id, |
| int32_t encoding_id, |
| int32_t language_id, |
| int32_t name_id, |
| const ByteVector& name_bytes) { |
| Init(platform_id, encoding_id, language_id, name_id, &name_bytes); |
| } |
| |
| NameTable::NameEntry::~NameEntry() {} |
| |
| ByteVector* NameTable::NameEntry::NameAsBytes() { |
| return &name_bytes_; |
| } |
| |
| int32_t NameTable::NameEntry::NameBytesLength() { |
| return name_bytes_.size(); |
| } |
| |
| UChar* NameTable::NameEntry::Name() { |
| return NameTable::ConvertFromNameBytes(&name_bytes_, |
| platform_id(), |
| encoding_id()); |
| } |
| |
| bool NameTable::NameEntry::operator==(const NameEntry& rhs) const { |
| return (name_entry_id_ == rhs.name_entry_id_ && |
| name_bytes_ == rhs.name_bytes_); |
| } |
| |
| void NameTable::NameEntry::Init(int32_t platform_id, |
| int32_t encoding_id, |
| int32_t language_id, |
| int32_t name_id, |
| const ByteVector* name_bytes) { |
| name_entry_id_ = NameEntryId(platform_id, encoding_id, language_id, name_id); |
| if (name_bytes) { |
| name_bytes_ = *name_bytes; |
| } else { |
| name_bytes_.clear(); |
| } |
| } |
| |
| /****************************************************************************** |
| * NameTable::NameEntryBuilder class |
| ******************************************************************************/ |
| NameTable::NameEntryBuilder::NameEntryBuilder() { |
| Init(0, 0, 0, 0, NULL); |
| } |
| |
| NameTable::NameEntryBuilder::NameEntryBuilder(const NameEntryId& name_entry_id, |
| const ByteVector& name_bytes) { |
| Init(name_entry_id.platform_id(), |
| name_entry_id.encoding_id(), |
| name_entry_id.language_id(), |
| name_entry_id.name_id(), |
| &name_bytes); |
| } |
| |
| NameTable::NameEntryBuilder::NameEntryBuilder( |
| const NameEntryId& name_entry_id) { |
| Init(name_entry_id.platform_id(), |
| name_entry_id.encoding_id(), |
| name_entry_id.language_id(), |
| name_entry_id.name_id(), |
| NULL); |
| } |
| |
| NameTable::NameEntryBuilder::NameEntryBuilder(NameEntry* b) { |
| Init(b->platform_id(), |
| b->encoding_id(), |
| b->language_id(), |
| b->name_id(), |
| b->NameAsBytes()); |
| } |
| |
| NameTable::NameEntryBuilder::~NameEntryBuilder() {} |
| |
| void NameTable::NameEntryBuilder::SetName(const UChar* name) { |
| if (name == NULL) { |
| name_entry_->name_bytes_.clear(); |
| return; |
| } |
| NameTable::ConvertToNameBytes(name, |
| name_entry_->platform_id(), |
| name_entry_->encoding_id(), |
| &name_entry_->name_bytes_); |
| } |
| |
| void NameTable::NameEntryBuilder::SetName(const ByteVector& name_bytes) { |
| name_entry_->name_bytes_.clear(); |
| std::copy(name_bytes.begin(), |
| name_bytes.end(), |
| name_entry_->name_bytes_.begin()); |
| } |
| |
| void NameTable::NameEntryBuilder::SetName(const ByteVector& name_bytes, |
| int32_t offset, |
| int32_t length) { |
| name_entry_->name_bytes_.clear(); |
| std::copy(name_bytes.begin() + offset, |
| name_bytes.begin() + offset + length, |
| name_entry_->name_bytes_.begin()); |
| } |
| |
| void NameTable::NameEntryBuilder::Init(int32_t platform_id, |
| int32_t encoding_id, |
| int32_t language_id, |
| int32_t name_id, |
| const ByteVector* name_bytes) { |
| name_entry_ = new NameEntry(); |
| name_entry_->Init(platform_id, encoding_id, language_id, name_id, name_bytes); |
| } |
| |
| /****************************************************************************** |
| * NameTable::NameEntryFilterInPlace class (C++ port only) |
| ******************************************************************************/ |
| NameTable::NameEntryFilterInPlace::NameEntryFilterInPlace(int32_t platform_id, |
| int32_t encoding_id, |
| int32_t language_id, |
| int32_t name_id) |
| : platform_id_(platform_id), |
| encoding_id_(encoding_id), |
| language_id_(language_id), |
| name_id_(name_id) { |
| } |
| |
| bool NameTable::NameEntryFilterInPlace::Accept(int32_t platform_id, |
| int32_t encoding_id, |
| int32_t language_id, |
| int32_t name_id) { |
| return (platform_id_ == platform_id && |
| encoding_id_ == encoding_id && |
| language_id_ == language_id && |
| name_id_ == name_id); |
| } |
| |
| /****************************************************************************** |
| * NameTable::NameEntryIterator class |
| ******************************************************************************/ |
| NameTable::NameEntryIterator::NameEntryIterator(NameTable* table) |
| : RefIterator<NameEntry, NameTable>(table), |
| name_index_(0), |
| filter_(NULL) { |
| } |
| |
| NameTable::NameEntryIterator::NameEntryIterator(NameTable* table, |
| NameEntryFilter* filter) |
| : RefIterator<NameEntry, NameTable>(table), |
| name_index_(0), |
| filter_(filter) { |
| } |
| |
| bool NameTable::NameEntryIterator::HasNext() { |
| if (!filter_) { |
| if (name_index_ < container()->NameCount()) { |
| return true; |
| } |
| return false; |
| } |
| for (; name_index_ < container()->NameCount(); ++name_index_) { |
| if (filter_->Accept(container()->PlatformId(name_index_), |
| container()->EncodingId(name_index_), |
| container()->LanguageId(name_index_), |
| container()->NameId(name_index_))) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| CALLER_ATTACH NameTable::NameEntry* NameTable::NameEntryIterator::Next() { |
| if (!HasNext()) |
| return NULL; |
| return container()->GetNameEntry(name_index_++); |
| } |
| |
| /****************************************************************************** |
| * NameTable::Builder class |
| ******************************************************************************/ |
| NameTable::Builder::Builder(Header* header, WritableFontData* data) |
| : SubTableContainerTable::Builder(header, data) { |
| } |
| |
| NameTable::Builder::Builder(Header* header, ReadableFontData* data) |
| : SubTableContainerTable::Builder(header, data) { |
| } |
| |
| CALLER_ATTACH NameTable::Builder* |
| NameTable::Builder::CreateBuilder(Header* header, |
| WritableFontData* data) { |
| Ptr<NameTable::Builder> builder; |
| builder = new NameTable::Builder(header, data); |
| return builder.Detach(); |
| } |
| |
| void NameTable::Builder::RevertNames() { |
| name_entry_map_.clear(); |
| set_model_changed(false); |
| } |
| |
| int32_t NameTable::Builder::BuilderCount() { |
| GetNameBuilders(); // Ensure name_entry_map_ is built. |
| return (int32_t)name_entry_map_.size(); |
| } |
| |
| bool NameTable::Builder::Has(int32_t platform_id, |
| int32_t encoding_id, |
| int32_t language_id, |
| int32_t name_id) { |
| NameEntryId probe(platform_id, encoding_id, language_id, name_id); |
| GetNameBuilders(); // Ensure name_entry_map_ is built. |
| return (name_entry_map_.find(probe) != name_entry_map_.end()); |
| } |
| |
| CALLER_ATTACH NameTable::NameEntryBuilder* |
| NameTable::Builder::NameBuilder(int32_t platform_id, |
| int32_t encoding_id, |
| int32_t language_id, |
| int32_t name_id) { |
| NameEntryId probe(platform_id, encoding_id, language_id, name_id); |
| NameEntryBuilderMap builders; |
| GetNameBuilders(); // Ensure name_entry_map_ is built. |
| if (name_entry_map_.find(probe) != name_entry_map_.end()) { |
| return name_entry_map_[probe]; |
| } |
| NameEntryBuilderPtr builder = new NameEntryBuilder(probe); |
| name_entry_map_[probe] = builder; |
| return builder.Detach(); |
| } |
| |
| bool NameTable::Builder::Remove(int32_t platform_id, |
| int32_t encoding_id, |
| int32_t language_id, |
| int32_t name_id) { |
| NameEntryId probe(platform_id, encoding_id, language_id, name_id); |
| GetNameBuilders(); // Ensure name_entry_map_ is built. |
| NameEntryBuilderMap::iterator position = name_entry_map_.find(probe); |
| if (position != name_entry_map_.end()) { |
| name_entry_map_.erase(position); |
| return true; |
| } |
| return false; |
| } |
| |
| CALLER_ATTACH FontDataTable* |
| NameTable::Builder::SubBuildTable(ReadableFontData* data) { |
| FontDataTablePtr table = new NameTable(header(), data); |
| return table.Detach(); |
| } |
| |
| void NameTable::Builder::SubDataSet() { |
| name_entry_map_.clear(); |
| set_model_changed(false); |
| } |
| |
| int32_t NameTable::Builder::SubDataSizeToSerialize() { |
| if (name_entry_map_.empty()) { |
| return 0; |
| } |
| |
| int32_t size = NameTable::Offset::kNameRecordStart + |
| name_entry_map_.size() * NameTable::Offset::kNameRecordSize; |
| for (NameEntryBuilderMap::iterator b = name_entry_map_.begin(), |
| end = name_entry_map_.end(); |
| b != end; ++b) { |
| NameEntryBuilderPtr p = b->second; |
| NameEntry* entry = p->name_entry(); |
| size += entry->NameBytesLength(); |
| } |
| return size; |
| } |
| |
| bool NameTable::Builder::SubReadyToSerialize() { |
| return !name_entry_map_.empty(); |
| } |
| |
| int32_t NameTable::Builder::SubSerialize(WritableFontData* new_data) { |
| int32_t string_table_start_offset = |
| NameTable::Offset::kNameRecordStart + |
| name_entry_map_.size() * NameTable::Offset::kNameRecordSize; |
| |
| // Header |
| new_data->WriteUShort(NameTable::Offset::kFormat, 0); |
| new_data->WriteUShort(NameTable::Offset::kCount, name_entry_map_.size()); |
| new_data->WriteUShort(NameTable::Offset::kStringOffset, |
| string_table_start_offset); |
| int32_t name_record_offset = NameTable::Offset::kNameRecordStart; |
| int32_t string_offset = 0; |
| // Note: we offered operator< in NameEntryId, which will be used by std::less, |
| // and therefore our map will act like TreeMap in Java to provide |
| // sorted key set. |
| for (NameEntryBuilderMap::iterator b = name_entry_map_.begin(), |
| end = name_entry_map_.end(); |
| b != end; ++b) { |
| new_data->WriteUShort( |
| name_record_offset + NameTable::Offset::kNameRecordPlatformId, |
| b->first.platform_id()); |
| new_data->WriteUShort( |
| name_record_offset + NameTable::Offset::kNameRecordEncodingId, |
| b->first.encoding_id()); |
| new_data->WriteUShort( |
| name_record_offset + NameTable::Offset::kNameRecordLanguageId, |
| b->first.language_id()); |
| new_data->WriteUShort( |
| name_record_offset + NameTable::Offset::kNameRecordNameId, |
| b->first.name_id()); |
| NameEntry* builder_entry = b->second->name_entry(); |
| new_data->WriteUShort( |
| name_record_offset + NameTable::Offset::kNameRecordStringLength, |
| builder_entry->NameBytesLength()); |
| new_data->WriteUShort( |
| name_record_offset + NameTable::Offset::kNameRecordStringOffset, |
| string_offset); |
| name_record_offset += NameTable::Offset::kNameRecordSize; |
| string_offset += new_data->WriteBytes( |
| string_offset + string_table_start_offset, |
| builder_entry->NameAsBytes()); |
| } |
| |
| return string_offset + string_table_start_offset; |
| } |
| |
| void NameTable::Builder::Initialize(ReadableFontData* data) { |
| if (data) { |
| NameTablePtr table = new NameTable(header(), data); |
| Ptr<NameEntryIterator> name_iter; |
| name_iter.Attach(table->Iterator()); |
| while (name_iter->HasNext()) { |
| NameEntryPtr name_entry; |
| name_entry.Attach(name_iter->Next()); |
| NameEntryBuilderPtr name_entry_builder = new NameEntryBuilder(name_entry); |
| NameEntry* builder_entry = name_entry_builder->name_entry(); |
| NameEntryId probe = builder_entry->name_entry_id(); |
| name_entry_map_[probe] = name_entry_builder; |
| } |
| } |
| } |
| |
| NameTable::NameEntryBuilderMap* NameTable::Builder::GetNameBuilders() { |
| if (name_entry_map_.empty()) { |
| Initialize(InternalReadData()); |
| } |
| set_model_changed(); |
| return &name_entry_map_; |
| } |
| |
| /****************************************************************************** |
| * NameTable class |
| ******************************************************************************/ |
| NameTable::~NameTable() {} |
| |
| int32_t NameTable::Format() { |
| return data_->ReadUShort(Offset::kFormat); |
| } |
| |
| int32_t NameTable::NameCount() { |
| return data_->ReadUShort(Offset::kCount); |
| } |
| |
| int32_t NameTable::PlatformId(int32_t index) { |
| return data_->ReadUShort(Offset::kNameRecordPlatformId + |
| OffsetForNameRecord(index)); |
| } |
| |
| int32_t NameTable::EncodingId(int32_t index) { |
| return data_->ReadUShort(Offset::kNameRecordEncodingId + |
| OffsetForNameRecord(index)); |
| } |
| |
| int32_t NameTable::LanguageId(int32_t index) { |
| return data_->ReadUShort(Offset::kNameRecordLanguageId + |
| OffsetForNameRecord(index)); |
| } |
| |
| int32_t NameTable::NameId(int32_t index) { |
| return data_->ReadUShort(Offset::kNameRecordNameId + |
| OffsetForNameRecord(index)); |
| } |
| |
| void NameTable::NameAsBytes(int32_t index, ByteVector* b) { |
| assert(b); |
| int32_t length = NameLength(index); |
| b->clear(); |
| b->resize(length); |
| if (length > 0) { |
| data_->ReadBytes(NameOffset(index), &((*b)[0]), 0, length); |
| } |
| } |
| |
| void NameTable::NameAsBytes(int32_t platform_id, |
| int32_t encoding_id, |
| int32_t language_id, |
| int32_t name_id, |
| ByteVector* b) { |
| assert(b); |
| NameEntryPtr entry; |
| entry.Attach(GetNameEntry(platform_id, encoding_id, language_id, name_id)); |
| if (entry) { |
| ByteVector* name = entry->NameAsBytes(); |
| std::copy(name->begin(), name->end(), b->begin()); |
| } |
| } |
| |
| UChar* NameTable::Name(int32_t index) { |
| ByteVector b; |
| NameAsBytes(index, &b); |
| return ConvertFromNameBytes(&b, PlatformId(index), EncodingId(index)); |
| } |
| |
| UChar* NameTable::Name(int32_t platform_id, |
| int32_t encoding_id, |
| int32_t language_id, |
| int32_t name_id) { |
| NameEntryPtr entry; |
| entry.Attach(GetNameEntry(platform_id, encoding_id, language_id, name_id)); |
| if (entry) { |
| return entry->Name(); |
| } |
| return NULL; |
| } |
| |
| CALLER_ATTACH NameTable::NameEntry* NameTable::GetNameEntry(int32_t index) { |
| ByteVector b; |
| NameAsBytes(index, &b); |
| NameEntryPtr instance = new NameEntry(PlatformId(index), |
| EncodingId(index), |
| LanguageId(index), |
| NameId(index), b); |
| return instance.Detach(); |
| } |
| |
| CALLER_ATTACH NameTable::NameEntry* NameTable::GetNameEntry(int32_t platform_id, |
| int32_t encoding_id, |
| int32_t language_id, |
| int32_t name_id) { |
| NameTable::NameEntryFilterInPlace |
| filter(platform_id, encoding_id, language_id, name_id); |
| Ptr<NameTable::NameEntryIterator> name_entry_iter; |
| name_entry_iter.Attach(Iterator(&filter)); |
| NameEntryPtr result; |
| if (name_entry_iter->HasNext()) { |
| result = name_entry_iter->Next(); |
| } |
| return result; |
| } |
| |
| CALLER_ATTACH NameTable::NameEntryIterator* NameTable::Iterator() { |
| Ptr<NameEntryIterator> output = new NameTable::NameEntryIterator(this); |
| return output.Detach(); |
| } |
| |
| CALLER_ATTACH |
| NameTable::NameEntryIterator* NameTable::Iterator(NameEntryFilter* filter) { |
| Ptr<NameEntryIterator> output = |
| new NameTable::NameEntryIterator(this, filter); |
| return output.Detach(); |
| } |
| |
| NameTable::NameTable(Header* header, ReadableFontData* data) |
| : SubTableContainerTable(header, data) {} |
| |
| int32_t NameTable::StringOffset() { |
| return data_->ReadUShort(Offset::kStringOffset); |
| } |
| |
| int32_t NameTable::OffsetForNameRecord(int32_t index) { |
| return Offset::kNameRecordStart + index * Offset::kNameRecordSize; |
| } |
| |
| int32_t NameTable::NameLength(int32_t index) { |
| return data_->ReadUShort(Offset::kNameRecordStringLength + |
| OffsetForNameRecord(index)); |
| } |
| |
| int32_t NameTable::NameOffset(int32_t index) { |
| return data_->ReadUShort(Offset::kNameRecordStringOffset + |
| OffsetForNameRecord(index)) + StringOffset(); |
| } |
| |
| const char* NameTable::GetEncodingName(int32_t platform_id, |
| int32_t encoding_id) { |
| switch (platform_id) { |
| case PlatformId::kUnicode: |
| return "UTF-16BE"; |
| case PlatformId::kMacintosh: |
| switch (encoding_id) { |
| case MacintoshEncodingId::kRoman: |
| return "MacRoman"; |
| case MacintoshEncodingId::kJapanese: |
| return "Shift-JIS"; |
| case MacintoshEncodingId::kChineseTraditional: |
| return "Big5"; |
| case MacintoshEncodingId::kKorean: |
| return "EUC-KR"; |
| case MacintoshEncodingId::kArabic: |
| return "MacArabic"; |
| case MacintoshEncodingId::kHebrew: |
| return "MacHebrew"; |
| case MacintoshEncodingId::kGreek: |
| return "MacGreek"; |
| case MacintoshEncodingId::kRussian: |
| return "MacCyrillic"; |
| case MacintoshEncodingId::kRSymbol: |
| return "MacSymbol"; |
| case MacintoshEncodingId::kThai: |
| return "MacThai"; |
| case MacintoshEncodingId::kChineseSimplified: |
| return "EUC-CN"; |
| default: // Note: unknown/unconfirmed cases are not ported. |
| break; |
| } |
| break; |
| case PlatformId::kISO: |
| break; |
| case PlatformId::kWindows: |
| switch (encoding_id) { |
| case WindowsEncodingId::kSymbol: |
| case WindowsEncodingId::kUnicodeUCS2: |
| return "UTF-16BE"; |
| case WindowsEncodingId::kShiftJIS: |
| return "windows-933"; |
| case WindowsEncodingId::kPRC: |
| return "windows-936"; |
| case WindowsEncodingId::kBig5: |
| return "windows-950"; |
| case WindowsEncodingId::kWansung: |
| return "windows-949"; |
| case WindowsEncodingId::kJohab: |
| return "ms1361"; |
| case WindowsEncodingId::kUnicodeUCS4: |
| return "UCS-4"; |
| } |
| break; |
| case PlatformId::kCustom: |
| break; |
| default: |
| break; |
| } |
| return NULL; |
| } |
| |
| UConverter* NameTable::GetCharset(int32_t platform_id, int32_t encoding_id) { |
| UErrorCode error_code = U_ZERO_ERROR; |
| UConverter* conv = ucnv_open(GetEncodingName(platform_id, encoding_id), |
| &error_code); |
| if (U_SUCCESS(error_code)) { |
| return conv; |
| } |
| |
| if (conv) { |
| ucnv_close(conv); |
| } |
| return NULL; |
| } |
| |
| void NameTable::ConvertToNameBytes(const UChar* name, |
| int32_t platform_id, |
| int32_t encoding_id, |
| ByteVector* b) { |
| assert(b); |
| assert(name); |
| b->clear(); |
| UConverter* cs = GetCharset(platform_id, encoding_id); |
| if (cs == NULL) { |
| return; |
| } |
| |
| // Preflight to get buffer size. |
| UErrorCode error_code = U_ZERO_ERROR; |
| int32_t length = ucnv_fromUChars(cs, NULL, 0, name, -1, &error_code); |
| b->resize(length + 4); // The longest termination "\0" is 4 bytes. |
| memset(&((*b)[0]), 0, length + 4); |
| error_code = U_ZERO_ERROR; |
| ucnv_fromUChars(cs, |
| reinterpret_cast<char*>(&((*b)[0])), |
| length + 4, |
| name, |
| -1, |
| &error_code); |
| if (!U_SUCCESS(error_code)) { |
| b->clear(); |
| } |
| ucnv_close(cs); |
| } |
| |
| UChar* NameTable::ConvertFromNameBytes(ByteVector* name_bytes, |
| int32_t platform_id, |
| int32_t encoding_id) { |
| if (name_bytes == NULL || name_bytes->size() == 0) { |
| return NULL; |
| } |
| UConverter* cs = GetCharset(platform_id, encoding_id); |
| UErrorCode error_code = U_ZERO_ERROR; |
| if (cs == NULL) { |
| char buffer[11] = {0}; |
| #if defined (WIN32) |
| _itoa_s(platform_id, buffer, 16); |
| #else |
| snprintf(buffer, sizeof(buffer), "%x", platform_id); |
| #endif |
| UChar* result = new UChar[12]; |
| memset(result, 0, sizeof(UChar) * 12); |
| cs = ucnv_open("utf-8", &error_code); |
| if (U_SUCCESS(error_code)) { |
| ucnv_toUChars(cs, result, 12, buffer, 11, &error_code); |
| ucnv_close(cs); |
| if (U_SUCCESS(error_code)) { |
| return result; |
| } |
| } |
| delete[] result; |
| return NULL; |
| } |
| |
| // No preflight needed here, we will be bigger. |
| UChar* output_buffer = new UChar[name_bytes->size() + 1]; |
| memset(output_buffer, 0, sizeof(UChar) * (name_bytes->size() + 1)); |
| int32_t length = ucnv_toUChars(cs, |
| output_buffer, |
| name_bytes->size(), |
| reinterpret_cast<char*>(&((*name_bytes)[0])), |
| name_bytes->size(), |
| &error_code); |
| ucnv_close(cs); |
| if (length > 0) { |
| return output_buffer; |
| } |
| |
| delete[] output_buffer; |
| return NULL; |
| } |
| |
| } // namespace sfntly |