1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/graphite2/src/NameTable.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,246 @@ 1.4 +/* GRAPHITE2 LICENSING 1.5 + 1.6 + Copyright 2010, SIL International 1.7 + All rights reserved. 1.8 + 1.9 + This library is free software; you can redistribute it and/or modify 1.10 + it under the terms of the GNU Lesser General Public License as published 1.11 + by the Free Software Foundation; either version 2.1 of License, or 1.12 + (at your option) any later version. 1.13 + 1.14 + This program is distributed in the hope that it will be useful, 1.15 + but WITHOUT ANY WARRANTY; without even the implied warranty of 1.16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1.17 + Lesser General Public License for more details. 1.18 + 1.19 + You should also have received a copy of the GNU Lesser General Public 1.20 + License along with this library in the file named "LICENSE". 1.21 + If not, write to the Free Software Foundation, 51 Franklin Street, 1.22 + Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 1.23 + internet at http://www.fsf.org/licenses/lgpl.html. 1.24 + 1.25 +Alternatively, the contents of this file may be used under the terms of the 1.26 +Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public 1.27 +License, as published by the Free Software Foundation, either version 2 1.28 +of the License or (at your option) any later version. 1.29 +*/ 1.30 +#include "inc/Main.h" 1.31 +#include "inc/Endian.h" 1.32 + 1.33 +#include "inc/NameTable.h" 1.34 +#include "inc/UtfCodec.h" 1.35 + 1.36 +using namespace graphite2; 1.37 + 1.38 +NameTable::NameTable(const void* data, size_t length, uint16 platformId, uint16 encodingID) 1.39 + : m_platformId(0), m_encodingId(0), m_languageCount(0), 1.40 + m_platformOffset(0), m_platformLastRecord(0), m_nameDataLength(0), 1.41 + m_table(0), m_nameData(NULL) 1.42 +{ 1.43 + void *pdata = gralloc<byte>(length); 1.44 + if (!pdata) return; 1.45 + memcpy(pdata, data, length); 1.46 + m_table = reinterpret_cast<const TtfUtil::Sfnt::FontNames*>(pdata); 1.47 + 1.48 + if ((length > sizeof(TtfUtil::Sfnt::FontNames)) && 1.49 + (length > sizeof(TtfUtil::Sfnt::FontNames) + 1.50 + sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1))) 1.51 + { 1.52 + uint16 offset = be::swap<uint16>(m_table->string_offset); 1.53 + m_nameData = reinterpret_cast<const uint8*>(pdata) + offset; 1.54 + setPlatformEncoding(platformId, encodingID); 1.55 + m_nameDataLength = length - offset; 1.56 + } 1.57 + else 1.58 + { 1.59 + free(const_cast<TtfUtil::Sfnt::FontNames*>(m_table)); 1.60 + m_table = NULL; 1.61 + } 1.62 +} 1.63 + 1.64 +uint16 NameTable::setPlatformEncoding(uint16 platformId, uint16 encodingID) 1.65 +{ 1.66 + if (!m_nameData) return 0; 1.67 + uint16 i = 0; 1.68 + uint16 count = be::swap<uint16>(m_table->count); 1.69 + for (; i < count; i++) 1.70 + { 1.71 + if (be::swap<uint16>(m_table->name_record[i].platform_id) == platformId && 1.72 + be::swap<uint16>(m_table->name_record[i].platform_specific_id) == encodingID) 1.73 + { 1.74 + m_platformOffset = i; 1.75 + break; 1.76 + } 1.77 + } 1.78 + while ((++i < count) && 1.79 + (be::swap<uint16>(m_table->name_record[i].platform_id) == platformId) && 1.80 + (be::swap<uint16>(m_table->name_record[i].platform_specific_id) == encodingID)) 1.81 + { 1.82 + m_platformLastRecord = i; 1.83 + } 1.84 + m_encodingId = encodingID; 1.85 + m_platformId = platformId; 1.86 + return 0; 1.87 +} 1.88 + 1.89 +void* NameTable::getName(uint16& languageId, uint16 nameId, gr_encform enc, uint32& length) 1.90 +{ 1.91 + uint16 anyLang = 0; 1.92 + uint16 enUSLang = 0; 1.93 + uint16 bestLang = 0; 1.94 + if (!m_table) 1.95 + { 1.96 + languageId = 0; 1.97 + length = 0; 1.98 + return NULL; 1.99 + } 1.100 + for (uint16 i = m_platformOffset; i <= m_platformLastRecord; i++) 1.101 + { 1.102 + if (be::swap<uint16>(m_table->name_record[i].name_id) == nameId) 1.103 + { 1.104 + uint16 langId = be::swap<uint16>(m_table->name_record[i].language_id); 1.105 + if (langId == languageId) 1.106 + { 1.107 + bestLang = i; 1.108 + break; 1.109 + } 1.110 + // MS language tags have the language in the lower byte, region in the higher 1.111 + else if ((langId & 0xFF) == (languageId & 0xFF)) 1.112 + { 1.113 + bestLang = i; 1.114 + } 1.115 + else if (langId == 0x409) 1.116 + { 1.117 + enUSLang = i; 1.118 + } 1.119 + else 1.120 + { 1.121 + anyLang = i; 1.122 + } 1.123 + } 1.124 + } 1.125 + if (!bestLang) 1.126 + { 1.127 + if (enUSLang) bestLang = enUSLang; 1.128 + else 1.129 + { 1.130 + bestLang = anyLang; 1.131 + if (!anyLang) 1.132 + { 1.133 + languageId = 0; 1.134 + length = 0; 1.135 + return NULL; 1.136 + } 1.137 + } 1.138 + } 1.139 + const TtfUtil::Sfnt::NameRecord & nameRecord = m_table->name_record[bestLang]; 1.140 + languageId = be::swap<uint16>(nameRecord.language_id); 1.141 + uint16 utf16Length = be::swap<uint16>(nameRecord.length); 1.142 + uint16 offset = be::swap<uint16>(nameRecord.offset); 1.143 + if(offset + utf16Length > m_nameDataLength) 1.144 + { 1.145 + languageId = 0; 1.146 + length = 0; 1.147 + return NULL; 1.148 + } 1.149 + utf16Length >>= 1; // in utf16 units 1.150 + utf16::codeunit_t * utf16Name = gralloc<utf16::codeunit_t>(utf16Length); 1.151 + if (!utf16Name) 1.152 + { 1.153 + languageId = 0; 1.154 + length = 0; 1.155 + return NULL; 1.156 + } 1.157 + const uint8* pName = m_nameData + offset; 1.158 + for (size_t i = 0; i < utf16Length; i++) 1.159 + { 1.160 + utf16Name[i] = be::read<uint16>(pName); 1.161 + } 1.162 + switch (enc) 1.163 + { 1.164 + case gr_utf8: 1.165 + { 1.166 + utf8::codeunit_t* uniBuffer = gralloc<utf8::codeunit_t>(3 * utf16Length + 1); 1.167 + if (!uniBuffer) 1.168 + { 1.169 + free(utf16Name); 1.170 + languageId = 0; 1.171 + length = 0; 1.172 + return NULL; 1.173 + } 1.174 + utf8::iterator d = uniBuffer; 1.175 + for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d) 1.176 + *d = *s; 1.177 + length = d - uniBuffer; 1.178 + uniBuffer[length] = 0; 1.179 + free(utf16Name); 1.180 + return uniBuffer; 1.181 + } 1.182 + case gr_utf16: 1.183 + length = utf16Length; 1.184 + return utf16Name; 1.185 + case gr_utf32: 1.186 + { 1.187 + utf32::codeunit_t * uniBuffer = gralloc<utf32::codeunit_t>(utf16Length + 1); 1.188 + if (!uniBuffer) 1.189 + { 1.190 + free(utf16Name); 1.191 + languageId = 0; 1.192 + length = 0; 1.193 + return NULL; 1.194 + } 1.195 + utf32::iterator d = uniBuffer; 1.196 + for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d) 1.197 + *d = *s; 1.198 + length = d - uniBuffer; 1.199 + uniBuffer[length] = 0; 1.200 + free(utf16Name); 1.201 + return uniBuffer; 1.202 + } 1.203 + } 1.204 + free(utf16Name); 1.205 + languageId = 0; 1.206 + length = 0; 1.207 + return NULL; 1.208 +} 1.209 + 1.210 +uint16 NameTable::getLanguageId(const char * bcp47Locale) 1.211 +{ 1.212 + size_t localeLength = strlen(bcp47Locale); 1.213 + uint16 localeId = m_locale2Lang.getMsId(bcp47Locale); 1.214 + if (m_table && (be::swap<uint16>(m_table->format) == 1)) 1.215 + { 1.216 + const uint8 * pLangEntries = reinterpret_cast<const uint8*>(m_table) + 1.217 + sizeof(TtfUtil::Sfnt::FontNames) 1.218 + + sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1); 1.219 + uint16 numLangEntries = be::read<uint16>(pLangEntries); 1.220 + const TtfUtil::Sfnt::LangTagRecord * langTag = 1.221 + reinterpret_cast<const TtfUtil::Sfnt::LangTagRecord*>(pLangEntries); 1.222 + if (pLangEntries + numLangEntries * sizeof(TtfUtil::Sfnt::LangTagRecord) <= m_nameData) 1.223 + { 1.224 + for (uint16 i = 0; i < numLangEntries; i++) 1.225 + { 1.226 + uint16 offset = be::swap<uint16>(langTag[i].offset); 1.227 + uint16 length = be::swap<uint16>(langTag[i].length); 1.228 + if ((offset + length <= m_nameDataLength) && (length == 2 * localeLength)) 1.229 + { 1.230 + const uint8* pName = m_nameData + offset; 1.231 + bool match = true; 1.232 + for (size_t j = 0; j < localeLength; j++) 1.233 + { 1.234 + uint16 code = be::read<uint16>(pName); 1.235 + if ((code > 0x7F) || (code != bcp47Locale[j])) 1.236 + { 1.237 + match = false; 1.238 + break; 1.239 + } 1.240 + } 1.241 + if (match) 1.242 + return 0x8000 + i; 1.243 + } 1.244 + } 1.245 + } 1.246 + } 1.247 + return localeId; 1.248 +} 1.249 +