1 /* 2 * Copyright 2011 Google Inc. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "sfntly/table/core/name_table.h" 18 19 #include <stdio.h> 20 #include <string.h> 21 22 #include <unicode/unistr.h> 23 24 #include "sfntly/font.h" 25 #include "sfntly/port/exception_type.h" 26 27 namespace sfntly { 28 /****************************************************************************** 29 * NameTable::NameEntryId class 30 ******************************************************************************/ 31 NameTable::NameEntryId::NameEntryId() 32 : platform_id_(0), 33 encoding_id_(0), 34 language_id_(0), 35 name_id_(0) { 36 } 37 38 NameTable::NameEntryId::NameEntryId(int32_t platform_id, 39 int32_t encoding_id, 40 int32_t language_id, 41 int32_t name_id) 42 : platform_id_(platform_id), 43 encoding_id_(encoding_id), 44 language_id_(language_id), 45 name_id_(name_id) { 46 } 47 48 NameTable::NameEntryId::NameEntryId(const NameTable::NameEntryId& rhs) { 49 *this = rhs; 50 } 51 52 const NameTable::NameEntryId& 53 NameTable::NameEntryId::operator=(const NameTable::NameEntryId& rhs) const { 54 platform_id_ = rhs.platform_id_; 55 encoding_id_ = rhs.encoding_id_; 56 language_id_ = rhs.language_id_; 57 name_id_ = rhs.name_id_; 58 return *this; 59 } 60 61 bool NameTable::NameEntryId::operator==(const NameEntryId& rhs) const { 62 return platform_id_ == rhs.platform_id_ && 63 encoding_id_ == rhs.encoding_id_ && 64 language_id_ == rhs.language_id_ && 65 name_id_ == rhs.name_id_; 66 } 67 68 bool NameTable::NameEntryId::operator<(const NameEntryId& rhs) const { 69 if (platform_id_ != rhs.platform_id_) return platform_id_ < rhs.platform_id_; 70 if (encoding_id_ != rhs.encoding_id_) return encoding_id_ < rhs.encoding_id_; 71 if (language_id_ != rhs.language_id_) return language_id_ < rhs.language_id_; 72 return name_id_ < rhs.name_id_; 73 } 74 75 /****************************************************************************** 76 * NameTable::NameEntry class 77 ******************************************************************************/ 78 NameTable::NameEntry::NameEntry() { 79 Init(0, 0, 0, 0, NULL); 80 } 81 82 NameTable::NameEntry::NameEntry(const NameEntryId& name_entry_id, 83 const ByteVector& name_bytes) { 84 Init(name_entry_id.platform_id(), 85 name_entry_id.encoding_id(), 86 name_entry_id.language_id(), 87 name_entry_id.name_id(), 88 &name_bytes); 89 } 90 91 NameTable::NameEntry::NameEntry(int32_t platform_id, 92 int32_t encoding_id, 93 int32_t language_id, 94 int32_t name_id, 95 const ByteVector& name_bytes) { 96 Init(platform_id, encoding_id, language_id, name_id, &name_bytes); 97 } 98 99 NameTable::NameEntry::~NameEntry() {} 100 101 ByteVector* NameTable::NameEntry::NameAsBytes() { 102 return &name_bytes_; 103 } 104 105 int32_t NameTable::NameEntry::NameBytesLength() { 106 return name_bytes_.size(); 107 } 108 109 UChar* NameTable::NameEntry::Name() { 110 return NameTable::ConvertFromNameBytes(&name_bytes_, 111 platform_id(), 112 encoding_id()); 113 } 114 115 bool NameTable::NameEntry::operator==(const NameEntry& rhs) const { 116 return (name_entry_id_ == rhs.name_entry_id_ && 117 name_bytes_ == rhs.name_bytes_); 118 } 119 120 void NameTable::NameEntry::Init(int32_t platform_id, 121 int32_t encoding_id, 122 int32_t language_id, 123 int32_t name_id, 124 const ByteVector* name_bytes) { 125 name_entry_id_ = NameEntryId(platform_id, encoding_id, language_id, name_id); 126 if (name_bytes) { 127 name_bytes_ = *name_bytes; 128 } else { 129 name_bytes_.clear(); 130 } 131 } 132 133 /****************************************************************************** 134 * NameTable::NameEntryBuilder class 135 ******************************************************************************/ 136 NameTable::NameEntryBuilder::NameEntryBuilder() { 137 Init(0, 0, 0, 0, NULL); 138 } 139 140 NameTable::NameEntryBuilder::NameEntryBuilder(const NameEntryId& name_entry_id, 141 const ByteVector& name_bytes) { 142 Init(name_entry_id.platform_id(), 143 name_entry_id.encoding_id(), 144 name_entry_id.language_id(), 145 name_entry_id.name_id(), 146 &name_bytes); 147 } 148 149 NameTable::NameEntryBuilder::NameEntryBuilder( 150 const NameEntryId& name_entry_id) { 151 Init(name_entry_id.platform_id(), 152 name_entry_id.encoding_id(), 153 name_entry_id.language_id(), 154 name_entry_id.name_id(), 155 NULL); 156 } 157 158 NameTable::NameEntryBuilder::NameEntryBuilder(NameEntry* b) { 159 Init(b->platform_id(), 160 b->encoding_id(), 161 b->language_id(), 162 b->name_id(), 163 b->NameAsBytes()); 164 } 165 166 NameTable::NameEntryBuilder::~NameEntryBuilder() {} 167 168 void NameTable::NameEntryBuilder::SetName(const UChar* name) { 169 if (name == NULL) { 170 name_entry_->name_bytes_.clear(); 171 return; 172 } 173 NameTable::ConvertToNameBytes(name, 174 name_entry_->platform_id(), 175 name_entry_->encoding_id(), 176 &name_entry_->name_bytes_); 177 } 178 179 void NameTable::NameEntryBuilder::SetName(const ByteVector& name_bytes) { 180 name_entry_->name_bytes_.clear(); 181 std::copy(name_bytes.begin(), 182 name_bytes.end(), 183 name_entry_->name_bytes_.begin()); 184 } 185 186 void NameTable::NameEntryBuilder::SetName(const ByteVector& name_bytes, 187 int32_t offset, 188 int32_t length) { 189 name_entry_->name_bytes_.clear(); 190 std::copy(name_bytes.begin() + offset, 191 name_bytes.begin() + offset + length, 192 name_entry_->name_bytes_.begin()); 193 } 194 195 void NameTable::NameEntryBuilder::Init(int32_t platform_id, 196 int32_t encoding_id, 197 int32_t language_id, 198 int32_t name_id, 199 const ByteVector* name_bytes) { 200 name_entry_ = new NameEntry(); 201 name_entry_->Init(platform_id, encoding_id, language_id, name_id, name_bytes); 202 } 203 204 /****************************************************************************** 205 * NameTable::NameEntryFilterInPlace class (C++ port only) 206 ******************************************************************************/ 207 NameTable::NameEntryFilterInPlace::NameEntryFilterInPlace(int32_t platform_id, 208 int32_t encoding_id, 209 int32_t language_id, 210 int32_t name_id) 211 : platform_id_(platform_id), 212 encoding_id_(encoding_id), 213 language_id_(language_id), 214 name_id_(name_id) { 215 } 216 217 bool NameTable::NameEntryFilterInPlace::Accept(int32_t platform_id, 218 int32_t encoding_id, 219 int32_t language_id, 220 int32_t name_id) { 221 return (platform_id_ == platform_id && 222 encoding_id_ == encoding_id && 223 language_id_ == language_id && 224 name_id_ == name_id); 225 } 226 227 /****************************************************************************** 228 * NameTable::NameEntryIterator class 229 ******************************************************************************/ 230 NameTable::NameEntryIterator::NameEntryIterator(NameTable* table) 231 : RefIterator<NameEntry, NameTable>(table), 232 name_index_(0), 233 filter_(NULL) { 234 } 235 236 NameTable::NameEntryIterator::NameEntryIterator(NameTable* table, 237 NameEntryFilter* filter) 238 : RefIterator<NameEntry, NameTable>(table), 239 name_index_(0), 240 filter_(filter) { 241 } 242 243 bool NameTable::NameEntryIterator::HasNext() { 244 if (!filter_) { 245 if (name_index_ < container()->NameCount()) { 246 return true; 247 } 248 return false; 249 } 250 for (; name_index_ < container()->NameCount(); ++name_index_) { 251 if (filter_->Accept(container()->PlatformId(name_index_), 252 container()->EncodingId(name_index_), 253 container()->LanguageId(name_index_), 254 container()->NameId(name_index_))) { 255 return true; 256 } 257 } 258 return false; 259 } 260 261 CALLER_ATTACH NameTable::NameEntry* NameTable::NameEntryIterator::Next() { 262 if (!HasNext()) 263 return NULL; 264 return container()->GetNameEntry(name_index_++); 265 } 266 267 /****************************************************************************** 268 * NameTable::Builder class 269 ******************************************************************************/ 270 NameTable::Builder::Builder(Header* header, WritableFontData* data) 271 : SubTableContainerTable::Builder(header, data) { 272 } 273 274 NameTable::Builder::Builder(Header* header, ReadableFontData* data) 275 : SubTableContainerTable::Builder(header, data) { 276 } 277 278 CALLER_ATTACH NameTable::Builder* 279 NameTable::Builder::CreateBuilder(Header* header, 280 WritableFontData* data) { 281 Ptr<NameTable::Builder> builder; 282 builder = new NameTable::Builder(header, data); 283 return builder.Detach(); 284 } 285 286 void NameTable::Builder::RevertNames() { 287 name_entry_map_.clear(); 288 set_model_changed(false); 289 } 290 291 int32_t NameTable::Builder::BuilderCount() { 292 GetNameBuilders(); // Ensure name_entry_map_ is built. 293 return (int32_t)name_entry_map_.size(); 294 } 295 296 bool NameTable::Builder::Has(int32_t platform_id, 297 int32_t encoding_id, 298 int32_t language_id, 299 int32_t name_id) { 300 NameEntryId probe(platform_id, encoding_id, language_id, name_id); 301 GetNameBuilders(); // Ensure name_entry_map_ is built. 302 return (name_entry_map_.find(probe) != name_entry_map_.end()); 303 } 304 305 CALLER_ATTACH NameTable::NameEntryBuilder* 306 NameTable::Builder::NameBuilder(int32_t platform_id, 307 int32_t encoding_id, 308 int32_t language_id, 309 int32_t name_id) { 310 NameEntryId probe(platform_id, encoding_id, language_id, name_id); 311 NameEntryBuilderMap builders; 312 GetNameBuilders(); // Ensure name_entry_map_ is built. 313 if (name_entry_map_.find(probe) != name_entry_map_.end()) { 314 return name_entry_map_[probe]; 315 } 316 NameEntryBuilderPtr builder = new NameEntryBuilder(probe); 317 name_entry_map_[probe] = builder; 318 return builder.Detach(); 319 } 320 321 bool NameTable::Builder::Remove(int32_t platform_id, 322 int32_t encoding_id, 323 int32_t language_id, 324 int32_t name_id) { 325 NameEntryId probe(platform_id, encoding_id, language_id, name_id); 326 GetNameBuilders(); // Ensure name_entry_map_ is built. 327 NameEntryBuilderMap::iterator position = name_entry_map_.find(probe); 328 if (position != name_entry_map_.end()) { 329 name_entry_map_.erase(position); 330 return true; 331 } 332 return false; 333 } 334 335 CALLER_ATTACH FontDataTable* 336 NameTable::Builder::SubBuildTable(ReadableFontData* data) { 337 FontDataTablePtr table = new NameTable(header(), data); 338 return table.Detach(); 339 } 340 341 void NameTable::Builder::SubDataSet() { 342 name_entry_map_.clear(); 343 set_model_changed(false); 344 } 345 346 int32_t NameTable::Builder::SubDataSizeToSerialize() { 347 if (name_entry_map_.empty()) { 348 return 0; 349 } 350 351 int32_t size = NameTable::Offset::kNameRecordStart + 352 name_entry_map_.size() * NameTable::Offset::kNameRecordSize; 353 for (NameEntryBuilderMap::iterator b = name_entry_map_.begin(), 354 end = name_entry_map_.end(); 355 b != end; ++b) { 356 NameEntryBuilderPtr p = b->second; 357 NameEntry* entry = p->name_entry(); 358 size += entry->NameBytesLength(); 359 } 360 return size; 361 } 362 363 bool NameTable::Builder::SubReadyToSerialize() { 364 return !name_entry_map_.empty(); 365 } 366 367 int32_t NameTable::Builder::SubSerialize(WritableFontData* new_data) { 368 int32_t string_table_start_offset = 369 NameTable::Offset::kNameRecordStart + 370 name_entry_map_.size() * NameTable::Offset::kNameRecordSize; 371 372 // Header 373 new_data->WriteUShort(NameTable::Offset::kFormat, 0); 374 new_data->WriteUShort(NameTable::Offset::kCount, name_entry_map_.size()); 375 new_data->WriteUShort(NameTable::Offset::kStringOffset, 376 string_table_start_offset); 377 int32_t name_record_offset = NameTable::Offset::kNameRecordStart; 378 int32_t string_offset = 0; 379 // Note: we offered operator< in NameEntryId, which will be used by std::less, 380 // and therefore our map will act like TreeMap in Java to provide 381 // sorted key set. 382 for (NameEntryBuilderMap::iterator b = name_entry_map_.begin(), 383 end = name_entry_map_.end(); 384 b != end; ++b) { 385 new_data->WriteUShort( 386 name_record_offset + NameTable::Offset::kNameRecordPlatformId, 387 b->first.platform_id()); 388 new_data->WriteUShort( 389 name_record_offset + NameTable::Offset::kNameRecordEncodingId, 390 b->first.encoding_id()); 391 new_data->WriteUShort( 392 name_record_offset + NameTable::Offset::kNameRecordLanguageId, 393 b->first.language_id()); 394 new_data->WriteUShort( 395 name_record_offset + NameTable::Offset::kNameRecordNameId, 396 b->first.name_id()); 397 NameEntry* builder_entry = b->second->name_entry(); 398 new_data->WriteUShort( 399 name_record_offset + NameTable::Offset::kNameRecordStringLength, 400 builder_entry->NameBytesLength()); 401 new_data->WriteUShort( 402 name_record_offset + NameTable::Offset::kNameRecordStringOffset, 403 string_offset); 404 name_record_offset += NameTable::Offset::kNameRecordSize; 405 string_offset += new_data->WriteBytes( 406 string_offset + string_table_start_offset, 407 builder_entry->NameAsBytes()); 408 } 409 410 return string_offset + string_table_start_offset; 411 } 412 413 void NameTable::Builder::Initialize(ReadableFontData* data) { 414 if (data) { 415 NameTablePtr table = new NameTable(header(), data); 416 Ptr<NameEntryIterator> name_iter; 417 name_iter.Attach(table->Iterator()); 418 while (name_iter->HasNext()) { 419 NameEntryPtr name_entry; 420 name_entry.Attach(name_iter->Next()); 421 NameEntryBuilderPtr name_entry_builder = new NameEntryBuilder(name_entry); 422 NameEntry* builder_entry = name_entry_builder->name_entry(); 423 NameEntryId probe = builder_entry->name_entry_id(); 424 name_entry_map_[probe] = name_entry_builder; 425 } 426 } 427 } 428 429 NameTable::NameEntryBuilderMap* NameTable::Builder::GetNameBuilders() { 430 if (name_entry_map_.empty()) { 431 Initialize(InternalReadData()); 432 } 433 set_model_changed(); 434 return &name_entry_map_; 435 } 436 437 /****************************************************************************** 438 * NameTable class 439 ******************************************************************************/ 440 NameTable::~NameTable() {} 441 442 int32_t NameTable::Format() { 443 return data_->ReadUShort(Offset::kFormat); 444 } 445 446 int32_t NameTable::NameCount() { 447 return data_->ReadUShort(Offset::kCount); 448 } 449 450 int32_t NameTable::PlatformId(int32_t index) { 451 return data_->ReadUShort(Offset::kNameRecordPlatformId + 452 OffsetForNameRecord(index)); 453 } 454 455 int32_t NameTable::EncodingId(int32_t index) { 456 return data_->ReadUShort(Offset::kNameRecordEncodingId + 457 OffsetForNameRecord(index)); 458 } 459 460 int32_t NameTable::LanguageId(int32_t index) { 461 return data_->ReadUShort(Offset::kNameRecordLanguageId + 462 OffsetForNameRecord(index)); 463 } 464 465 int32_t NameTable::NameId(int32_t index) { 466 return data_->ReadUShort(Offset::kNameRecordNameId + 467 OffsetForNameRecord(index)); 468 } 469 470 void NameTable::NameAsBytes(int32_t index, ByteVector* b) { 471 assert(b); 472 int32_t length = NameLength(index); 473 b->clear(); 474 b->resize(length); 475 if (length > 0) { 476 data_->ReadBytes(NameOffset(index), &((*b)[0]), 0, length); 477 } 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