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 : :
37 : m_platformId(0), m_encodingId(0), m_languageCount(0),
38 : m_platformOffset(0), m_platformLastRecord(0), m_nameDataLength(0),
39 0 : m_table(0), m_nameData(NULL)
40 : {
41 0 : void *pdata = malloc(length);
42 0 : if (!pdata) return;
43 0 : memcpy(pdata, data, length);
44 0 : m_table = reinterpret_cast<const TtfUtil::Sfnt::FontNames*>(pdata);
45 :
46 0 : if ((length > sizeof(TtfUtil::Sfnt::FontNames)) &&
47 : (length > sizeof(TtfUtil::Sfnt::FontNames) +
48 0 : sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1)))
49 : {
50 0 : uint16 offset = be::swap<uint16>(m_table->string_offset);
51 0 : m_nameData = reinterpret_cast<const uint8*>(pdata) + offset;
52 0 : setPlatformEncoding(platformId, encodingID);
53 0 : m_nameDataLength = length - offset;
54 : }
55 : else
56 : {
57 0 : free(const_cast<TtfUtil::Sfnt::FontNames*>(m_table));
58 0 : m_table = NULL;
59 : }
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);
149 0 : const uint8* pName = m_nameData + offset;
150 0 : for (size_t i = 0; i < utf16Length; i++)
151 : {
152 0 : utf16Name[i] = be::read<uint16>(pName);
153 : }
154 0 : switch (enc)
155 : {
156 : case gr_utf8:
157 : {
158 0 : utf8::codeunit_t* uniBuffer = gralloc<utf8::codeunit_t>(3 * utf16Length + 1);
159 0 : utf8::iterator d = uniBuffer;
160 0 : for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d)
161 0 : *d = *s;
162 0 : length = d - uniBuffer;
163 0 : uniBuffer[length] = 0;
164 0 : return uniBuffer;
165 : }
166 : case gr_utf16:
167 0 : length = utf16Length;
168 0 : return utf16Name;
169 : case gr_utf32:
170 : {
171 0 : utf32::codeunit_t * uniBuffer = gralloc<utf32::codeunit_t>(utf16Length + 1);
172 0 : utf32::iterator d = uniBuffer;
173 0 : for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d)
174 0 : *d = *s;
175 0 : length = d - uniBuffer;
176 0 : uniBuffer[length] = 0;
177 0 : return uniBuffer;
178 : }
179 : }
180 0 : length = 0;
181 0 : return NULL;
182 : }
183 :
184 0 : uint16 NameTable::getLanguageId(const char * bcp47Locale)
185 : {
186 0 : size_t localeLength = strlen(bcp47Locale);
187 0 : uint16 localeId = m_locale2Lang.getMsId(bcp47Locale);
188 0 : if (m_table && (be::swap<uint16>(m_table->format) == 1))
189 : {
190 : const uint8 * pLangEntries = reinterpret_cast<const uint8*>(m_table) +
191 : sizeof(TtfUtil::Sfnt::FontNames)
192 0 : + sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1);
193 0 : uint16 numLangEntries = be::read<uint16>(pLangEntries);
194 : const TtfUtil::Sfnt::LangTagRecord * langTag =
195 0 : reinterpret_cast<const TtfUtil::Sfnt::LangTagRecord*>(pLangEntries);
196 0 : if (pLangEntries + numLangEntries * sizeof(TtfUtil::Sfnt::LangTagRecord) <= m_nameData)
197 : {
198 0 : for (uint16 i = 0; i < numLangEntries; i++)
199 : {
200 0 : uint16 offset = be::swap<uint16>(langTag[i].offset);
201 0 : uint16 length = be::swap<uint16>(langTag[i].length);
202 0 : if ((offset + length <= m_nameDataLength) && (length == 2 * localeLength))
203 : {
204 0 : const uint8* pName = m_nameData + offset;
205 0 : bool match = true;
206 0 : for (size_t j = 0; j < localeLength; j++)
207 : {
208 0 : uint16 code = be::read<uint16>(pName);
209 0 : if ((code > 0x7F) || (code != bcp47Locale[j]))
210 : {
211 0 : match = false;
212 0 : break;
213 : }
214 : }
215 0 : if (match)
216 0 : return 0x8000 + i;
217 : }
218 : }
219 : }
220 : }
221 0 : return localeId;
222 : }
223 :
|