Path: blob/master/thirdparty/graphite/src/NameTable.cpp
9903 views
// SPDX-License-Identifier: MIT OR MPL-2.0 OR LGPL-2.1-or-later OR GPL-2.0-or-later1// Copyright 2010, SIL International, All rights reserved.23#include "inc/Main.h"4#include "inc/Endian.h"56#include "inc/NameTable.h"7#include "inc/UtfCodec.h"89using namespace graphite2;1011NameTable::NameTable(const void* data, size_t length, uint16 platformId, uint16 encodingID)12: m_platformId(0), m_encodingId(0), m_languageCount(0),13m_platformOffset(0), m_platformLastRecord(0), m_nameDataLength(0),14m_table(0), m_nameData(NULL)15{16void *pdata = gralloc<byte>(length);17if (!pdata) return;18memcpy(pdata, data, length);19m_table = reinterpret_cast<const TtfUtil::Sfnt::FontNames*>(pdata);2021if ((length > sizeof(TtfUtil::Sfnt::FontNames)) &&22(length > sizeof(TtfUtil::Sfnt::FontNames) +23sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1)))24{25uint16 offset = be::swap<uint16>(m_table->string_offset);26if (offset < length)27{28m_nameData = reinterpret_cast<const uint8*>(pdata) + offset;29setPlatformEncoding(platformId, encodingID);30m_nameDataLength = uint16(length - offset);31return;32}33}34free(const_cast<TtfUtil::Sfnt::FontNames*>(m_table));35m_table = NULL;36}3738uint16 NameTable::setPlatformEncoding(uint16 platformId, uint16 encodingID)39{40if (!m_nameData) return 0;41uint16 i = 0;42uint16 count = be::swap<uint16>(m_table->count);43for (; i < count; i++)44{45if (be::swap<uint16>(m_table->name_record[i].platform_id) == platformId &&46be::swap<uint16>(m_table->name_record[i].platform_specific_id) == encodingID)47{48m_platformOffset = i;49break;50}51}52while ((++i < count) &&53(be::swap<uint16>(m_table->name_record[i].platform_id) == platformId) &&54(be::swap<uint16>(m_table->name_record[i].platform_specific_id) == encodingID))55{56m_platformLastRecord = i;57}58m_encodingId = encodingID;59m_platformId = platformId;60return 0;61}6263void* NameTable::getName(uint16& languageId, uint16 nameId, gr_encform enc, uint32& length)64{65uint16 anyLang = 0;66uint16 enUSLang = 0;67uint16 bestLang = 0;68if (!m_table)69{70languageId = 0;71length = 0;72return NULL;73}74for (uint16 i = m_platformOffset; i <= m_platformLastRecord; i++)75{76if (be::swap<uint16>(m_table->name_record[i].name_id) == nameId)77{78uint16 langId = be::swap<uint16>(m_table->name_record[i].language_id);79if (langId == languageId)80{81bestLang = i;82break;83}84// MS language tags have the language in the lower byte, region in the higher85else if ((langId & 0xFF) == (languageId & 0xFF))86{87bestLang = i;88}89else if (langId == 0x409)90{91enUSLang = i;92}93else94{95anyLang = i;96}97}98}99if (!bestLang)100{101if (enUSLang) bestLang = enUSLang;102else103{104bestLang = anyLang;105if (!anyLang)106{107languageId = 0;108length = 0;109return NULL;110}111}112}113const TtfUtil::Sfnt::NameRecord & nameRecord = m_table->name_record[bestLang];114languageId = be::swap<uint16>(nameRecord.language_id);115uint16 utf16Length = be::swap<uint16>(nameRecord.length);116uint16 offset = be::swap<uint16>(nameRecord.offset);117if(offset + utf16Length > m_nameDataLength)118{119languageId = 0;120length = 0;121return NULL;122}123utf16Length >>= 1; // in utf16 units124utf16::codeunit_t * utf16Name = gralloc<utf16::codeunit_t>(utf16Length + 1);125if (!utf16Name)126{127languageId = 0;128length = 0;129return NULL;130}131const uint8* pName = m_nameData + offset;132for (size_t i = 0; i < utf16Length; i++)133{134utf16Name[i] = be::read<uint16>(pName);135}136utf16Name[utf16Length] = 0;137if (!utf16::validate(utf16Name, utf16Name + utf16Length))138{139free(utf16Name);140languageId = 0;141length = 0;142return NULL;143}144switch (enc)145{146case gr_utf8:147{148utf8::codeunit_t* uniBuffer = gralloc<utf8::codeunit_t>(3 * utf16Length + 1);149if (!uniBuffer)150{151free(utf16Name);152languageId = 0;153length = 0;154return NULL;155}156utf8::iterator d = uniBuffer;157for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d)158*d = *s;159length = uint32(d - uniBuffer);160uniBuffer[length] = 0;161free(utf16Name);162return uniBuffer;163}164case gr_utf16:165length = utf16Length;166return utf16Name;167case gr_utf32:168{169utf32::codeunit_t * uniBuffer = gralloc<utf32::codeunit_t>(utf16Length + 1);170if (!uniBuffer)171{172free(utf16Name);173languageId = 0;174length = 0;175return NULL;176}177utf32::iterator d = uniBuffer;178for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d)179*d = *s;180length = uint32(d - uniBuffer);181uniBuffer[length] = 0;182free(utf16Name);183return uniBuffer;184}185}186free(utf16Name);187languageId = 0;188length = 0;189return NULL;190}191192uint16 NameTable::getLanguageId(const char * bcp47Locale)193{194size_t localeLength = strlen(bcp47Locale);195uint16 localeId = m_locale2Lang.getMsId(bcp47Locale);196if (m_table && (be::swap<uint16>(m_table->format) == 1))197{198const uint8 * pLangEntries = reinterpret_cast<const uint8*>(m_table) +199sizeof(TtfUtil::Sfnt::FontNames)200+ sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1);201uint16 numLangEntries = be::read<uint16>(pLangEntries);202const TtfUtil::Sfnt::LangTagRecord * langTag =203reinterpret_cast<const TtfUtil::Sfnt::LangTagRecord*>(pLangEntries);204if (pLangEntries + numLangEntries * sizeof(TtfUtil::Sfnt::LangTagRecord) <= m_nameData)205{206for (uint16 i = 0; i < numLangEntries; i++)207{208uint16 offset = be::swap<uint16>(langTag[i].offset);209uint16 length = be::swap<uint16>(langTag[i].length);210if ((offset + length <= m_nameDataLength) && (length == 2 * localeLength))211{212const uint8* pName = m_nameData + offset;213bool match = true;214for (size_t j = 0; j < localeLength; j++)215{216uint16 code = be::read<uint16>(pName);217if ((code > 0x7F) || (code != bcp47Locale[j]))218{219match = false;220break;221}222}223if (match)224return 0x8000 + i;225}226}227}228}229return localeId;230}231232233