Line data Source code
1 : /* GRAPHITE2 LICENSING
2 :
3 : Copyright 2010, SIL International
4 : All rights reserved.
5 :
6 : This library is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU Lesser General Public License as published
8 : by the Free Software Foundation; either version 2.1 of License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : Lesser General Public License for more details.
15 :
16 : You should also have received a copy of the GNU Lesser General Public
17 : License along with this library in the file named "LICENSE".
18 : If not, write to the Free Software Foundation, 51 Franklin Street,
19 : Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
20 : internet at http://www.fsf.org/licenses/lgpl.html.
21 :
22 : Alternatively, the contents of this file may be used under the terms of the
23 : Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
24 : License, as published by the Free Software Foundation, either version 2
25 : of the License or (at your option) any later version.
26 : */
27 : #include "inc/Main.h"
28 : #include "inc/Endian.h"
29 :
30 : #include "inc/NameTable.h"
31 : #include "inc/UtfCodec.h"
32 :
33 : using namespace graphite2;
34 :
35 0 : NameTable::NameTable(const void* data, size_t length, uint16 platformId, uint16 encodingID)
36 : : m_platformId(0), m_encodingId(0), m_languageCount(0),
37 : m_platformOffset(0), m_platformLastRecord(0), m_nameDataLength(0),
38 0 : m_table(0), m_nameData(NULL)
39 : {
40 0 : void *pdata = gralloc<byte>(length);
41 0 : if (!pdata) return;
42 0 : memcpy(pdata, data, length);
43 0 : m_table = reinterpret_cast<const TtfUtil::Sfnt::FontNames*>(pdata);
44 :
45 0 : if ((length > sizeof(TtfUtil::Sfnt::FontNames)) &&
46 0 : (length > sizeof(TtfUtil::Sfnt::FontNames) +
47 0 : sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1)))
48 : {
49 0 : uint16 offset = be::swap<uint16>(m_table->string_offset);
50 0 : if (offset < length)
51 : {
52 0 : m_nameData = reinterpret_cast<const uint8*>(pdata) + offset;
53 0 : setPlatformEncoding(platformId, encodingID);
54 0 : m_nameDataLength = length - offset;
55 0 : return;
56 : }
57 : }
58 0 : free(const_cast<TtfUtil::Sfnt::FontNames*>(m_table));
59 0 : m_table = NULL;
60 : }
61 :
62 0 : uint16 NameTable::setPlatformEncoding(uint16 platformId, uint16 encodingID)
63 : {
64 0 : if (!m_nameData) return 0;
65 0 : uint16 i = 0;
66 0 : uint16 count = be::swap<uint16>(m_table->count);
67 0 : for (; i < count; i++)
68 : {
69 0 : if (be::swap<uint16>(m_table->name_record[i].platform_id) == platformId &&
70 0 : be::swap<uint16>(m_table->name_record[i].platform_specific_id) == encodingID)
71 : {
72 0 : m_platformOffset = i;
73 0 : break;
74 : }
75 : }
76 0 : while ((++i < count) &&
77 0 : (be::swap<uint16>(m_table->name_record[i].platform_id) == platformId) &&
78 0 : (be::swap<uint16>(m_table->name_record[i].platform_specific_id) == encodingID))
79 : {
80 0 : m_platformLastRecord = i;
81 : }
82 0 : m_encodingId = encodingID;
83 0 : m_platformId = platformId;
84 0 : return 0;
85 : }
86 :
87 0 : void* NameTable::getName(uint16& languageId, uint16 nameId, gr_encform enc, uint32& length)
88 : {
89 0 : uint16 anyLang = 0;
90 0 : uint16 enUSLang = 0;
91 0 : uint16 bestLang = 0;
92 0 : if (!m_table)
93 : {
94 0 : languageId = 0;
95 0 : length = 0;
96 0 : return NULL;
97 : }
98 0 : for (uint16 i = m_platformOffset; i <= m_platformLastRecord; i++)
99 : {
100 0 : if (be::swap<uint16>(m_table->name_record[i].name_id) == nameId)
101 : {
102 0 : uint16 langId = be::swap<uint16>(m_table->name_record[i].language_id);
103 0 : if (langId == languageId)
104 : {
105 0 : bestLang = i;
106 0 : break;
107 : }
108 : // MS language tags have the language in the lower byte, region in the higher
109 0 : else if ((langId & 0xFF) == (languageId & 0xFF))
110 : {
111 0 : bestLang = i;
112 : }
113 0 : else if (langId == 0x409)
114 : {
115 0 : enUSLang = i;
116 : }
117 : else
118 : {
119 0 : anyLang = i;
120 : }
121 : }
122 : }
123 0 : if (!bestLang)
124 : {
125 0 : if (enUSLang) bestLang = enUSLang;
126 : else
127 : {
128 0 : bestLang = anyLang;
129 0 : if (!anyLang)
130 : {
131 0 : languageId = 0;
132 0 : length = 0;
133 0 : return NULL;
134 : }
135 : }
136 : }
137 0 : const TtfUtil::Sfnt::NameRecord & nameRecord = m_table->name_record[bestLang];
138 0 : languageId = be::swap<uint16>(nameRecord.language_id);
139 0 : uint16 utf16Length = be::swap<uint16>(nameRecord.length);
140 0 : uint16 offset = be::swap<uint16>(nameRecord.offset);
141 0 : if(offset + utf16Length > m_nameDataLength)
142 : {
143 0 : languageId = 0;
144 0 : length = 0;
145 0 : return NULL;
146 : }
147 0 : utf16Length >>= 1; // in utf16 units
148 0 : utf16::codeunit_t * utf16Name = gralloc<utf16::codeunit_t>(utf16Length + 1);
149 0 : if (!utf16Name)
150 : {
151 0 : languageId = 0;
152 0 : length = 0;
153 0 : return NULL;
154 : }
155 0 : const uint8* pName = m_nameData + offset;
156 0 : for (size_t i = 0; i < utf16Length; i++)
157 : {
158 0 : utf16Name[i] = be::read<uint16>(pName);
159 : }
160 0 : utf16Name[utf16Length] = 0;
161 0 : if (!utf16::validate(utf16Name, utf16Name + utf16Length))
162 : {
163 0 : free(utf16Name);
164 0 : languageId = 0;
165 0 : length = 0;
166 0 : return NULL;
167 : }
168 0 : switch (enc)
169 : {
170 : case gr_utf8:
171 : {
172 0 : utf8::codeunit_t* uniBuffer = gralloc<utf8::codeunit_t>(3 * utf16Length + 1);
173 0 : if (!uniBuffer)
174 : {
175 0 : free(utf16Name);
176 0 : languageId = 0;
177 0 : length = 0;
178 0 : return NULL;
179 : }
180 0 : utf8::iterator d = uniBuffer;
181 0 : for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d)
182 0 : *d = *s;
183 0 : length = d - uniBuffer;
184 0 : uniBuffer[length] = 0;
185 0 : free(utf16Name);
186 0 : return uniBuffer;
187 : }
188 : case gr_utf16:
189 0 : length = utf16Length;
190 0 : return utf16Name;
191 : case gr_utf32:
192 : {
193 0 : utf32::codeunit_t * uniBuffer = gralloc<utf32::codeunit_t>(utf16Length + 1);
194 0 : if (!uniBuffer)
195 : {
196 0 : free(utf16Name);
197 0 : languageId = 0;
198 0 : length = 0;
199 0 : return NULL;
200 : }
201 0 : utf32::iterator d = uniBuffer;
202 0 : for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d)
203 0 : *d = *s;
204 0 : length = d - uniBuffer;
205 0 : uniBuffer[length] = 0;
206 0 : free(utf16Name);
207 0 : return uniBuffer;
208 : }
209 : }
210 0 : free(utf16Name);
211 0 : languageId = 0;
212 0 : length = 0;
213 0 : return NULL;
214 : }
215 :
216 0 : uint16 NameTable::getLanguageId(const char * bcp47Locale)
217 : {
218 0 : size_t localeLength = strlen(bcp47Locale);
219 0 : uint16 localeId = m_locale2Lang.getMsId(bcp47Locale);
220 0 : if (m_table && (be::swap<uint16>(m_table->format) == 1))
221 : {
222 0 : const uint8 * pLangEntries = reinterpret_cast<const uint8*>(m_table) +
223 : sizeof(TtfUtil::Sfnt::FontNames)
224 0 : + sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1);
225 0 : uint16 numLangEntries = be::read<uint16>(pLangEntries);
226 : const TtfUtil::Sfnt::LangTagRecord * langTag =
227 0 : reinterpret_cast<const TtfUtil::Sfnt::LangTagRecord*>(pLangEntries);
228 0 : if (pLangEntries + numLangEntries * sizeof(TtfUtil::Sfnt::LangTagRecord) <= m_nameData)
229 : {
230 0 : for (uint16 i = 0; i < numLangEntries; i++)
231 : {
232 0 : uint16 offset = be::swap<uint16>(langTag[i].offset);
233 0 : uint16 length = be::swap<uint16>(langTag[i].length);
234 0 : if ((offset + length <= m_nameDataLength) && (length == 2 * localeLength))
235 : {
236 0 : const uint8* pName = m_nameData + offset;
237 0 : bool match = true;
238 0 : for (size_t j = 0; j < localeLength; j++)
239 : {
240 0 : uint16 code = be::read<uint16>(pName);
241 0 : if ((code > 0x7F) || (code != bcp47Locale[j]))
242 : {
243 0 : match = false;
244 0 : break;
245 : }
246 : }
247 0 : if (match)
248 0 : return 0x8000 + i;
249 : }
250 : }
251 : }
252 : }
253 0 : return localeId;
254 : }
255 :
|