|
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 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 m_table(0), m_nameData(NULL) |
|
39 { |
|
40 void *pdata = gralloc<byte>(length); |
|
41 if (!pdata) return; |
|
42 memcpy(pdata, data, length); |
|
43 m_table = reinterpret_cast<const TtfUtil::Sfnt::FontNames*>(pdata); |
|
44 |
|
45 if ((length > sizeof(TtfUtil::Sfnt::FontNames)) && |
|
46 (length > sizeof(TtfUtil::Sfnt::FontNames) + |
|
47 sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1))) |
|
48 { |
|
49 uint16 offset = be::swap<uint16>(m_table->string_offset); |
|
50 m_nameData = reinterpret_cast<const uint8*>(pdata) + offset; |
|
51 setPlatformEncoding(platformId, encodingID); |
|
52 m_nameDataLength = length - offset; |
|
53 } |
|
54 else |
|
55 { |
|
56 free(const_cast<TtfUtil::Sfnt::FontNames*>(m_table)); |
|
57 m_table = NULL; |
|
58 } |
|
59 } |
|
60 |
|
61 uint16 NameTable::setPlatformEncoding(uint16 platformId, uint16 encodingID) |
|
62 { |
|
63 if (!m_nameData) return 0; |
|
64 uint16 i = 0; |
|
65 uint16 count = be::swap<uint16>(m_table->count); |
|
66 for (; i < count; i++) |
|
67 { |
|
68 if (be::swap<uint16>(m_table->name_record[i].platform_id) == platformId && |
|
69 be::swap<uint16>(m_table->name_record[i].platform_specific_id) == encodingID) |
|
70 { |
|
71 m_platformOffset = i; |
|
72 break; |
|
73 } |
|
74 } |
|
75 while ((++i < count) && |
|
76 (be::swap<uint16>(m_table->name_record[i].platform_id) == platformId) && |
|
77 (be::swap<uint16>(m_table->name_record[i].platform_specific_id) == encodingID)) |
|
78 { |
|
79 m_platformLastRecord = i; |
|
80 } |
|
81 m_encodingId = encodingID; |
|
82 m_platformId = platformId; |
|
83 return 0; |
|
84 } |
|
85 |
|
86 void* NameTable::getName(uint16& languageId, uint16 nameId, gr_encform enc, uint32& length) |
|
87 { |
|
88 uint16 anyLang = 0; |
|
89 uint16 enUSLang = 0; |
|
90 uint16 bestLang = 0; |
|
91 if (!m_table) |
|
92 { |
|
93 languageId = 0; |
|
94 length = 0; |
|
95 return NULL; |
|
96 } |
|
97 for (uint16 i = m_platformOffset; i <= m_platformLastRecord; i++) |
|
98 { |
|
99 if (be::swap<uint16>(m_table->name_record[i].name_id) == nameId) |
|
100 { |
|
101 uint16 langId = be::swap<uint16>(m_table->name_record[i].language_id); |
|
102 if (langId == languageId) |
|
103 { |
|
104 bestLang = i; |
|
105 break; |
|
106 } |
|
107 // MS language tags have the language in the lower byte, region in the higher |
|
108 else if ((langId & 0xFF) == (languageId & 0xFF)) |
|
109 { |
|
110 bestLang = i; |
|
111 } |
|
112 else if (langId == 0x409) |
|
113 { |
|
114 enUSLang = i; |
|
115 } |
|
116 else |
|
117 { |
|
118 anyLang = i; |
|
119 } |
|
120 } |
|
121 } |
|
122 if (!bestLang) |
|
123 { |
|
124 if (enUSLang) bestLang = enUSLang; |
|
125 else |
|
126 { |
|
127 bestLang = anyLang; |
|
128 if (!anyLang) |
|
129 { |
|
130 languageId = 0; |
|
131 length = 0; |
|
132 return NULL; |
|
133 } |
|
134 } |
|
135 } |
|
136 const TtfUtil::Sfnt::NameRecord & nameRecord = m_table->name_record[bestLang]; |
|
137 languageId = be::swap<uint16>(nameRecord.language_id); |
|
138 uint16 utf16Length = be::swap<uint16>(nameRecord.length); |
|
139 uint16 offset = be::swap<uint16>(nameRecord.offset); |
|
140 if(offset + utf16Length > m_nameDataLength) |
|
141 { |
|
142 languageId = 0; |
|
143 length = 0; |
|
144 return NULL; |
|
145 } |
|
146 utf16Length >>= 1; // in utf16 units |
|
147 utf16::codeunit_t * utf16Name = gralloc<utf16::codeunit_t>(utf16Length); |
|
148 if (!utf16Name) |
|
149 { |
|
150 languageId = 0; |
|
151 length = 0; |
|
152 return NULL; |
|
153 } |
|
154 const uint8* pName = m_nameData + offset; |
|
155 for (size_t i = 0; i < utf16Length; i++) |
|
156 { |
|
157 utf16Name[i] = be::read<uint16>(pName); |
|
158 } |
|
159 switch (enc) |
|
160 { |
|
161 case gr_utf8: |
|
162 { |
|
163 utf8::codeunit_t* uniBuffer = gralloc<utf8::codeunit_t>(3 * utf16Length + 1); |
|
164 if (!uniBuffer) |
|
165 { |
|
166 free(utf16Name); |
|
167 languageId = 0; |
|
168 length = 0; |
|
169 return NULL; |
|
170 } |
|
171 utf8::iterator d = uniBuffer; |
|
172 for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d) |
|
173 *d = *s; |
|
174 length = d - uniBuffer; |
|
175 uniBuffer[length] = 0; |
|
176 free(utf16Name); |
|
177 return uniBuffer; |
|
178 } |
|
179 case gr_utf16: |
|
180 length = utf16Length; |
|
181 return utf16Name; |
|
182 case gr_utf32: |
|
183 { |
|
184 utf32::codeunit_t * uniBuffer = gralloc<utf32::codeunit_t>(utf16Length + 1); |
|
185 if (!uniBuffer) |
|
186 { |
|
187 free(utf16Name); |
|
188 languageId = 0; |
|
189 length = 0; |
|
190 return NULL; |
|
191 } |
|
192 utf32::iterator d = uniBuffer; |
|
193 for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d) |
|
194 *d = *s; |
|
195 length = d - uniBuffer; |
|
196 uniBuffer[length] = 0; |
|
197 free(utf16Name); |
|
198 return uniBuffer; |
|
199 } |
|
200 } |
|
201 free(utf16Name); |
|
202 languageId = 0; |
|
203 length = 0; |
|
204 return NULL; |
|
205 } |
|
206 |
|
207 uint16 NameTable::getLanguageId(const char * bcp47Locale) |
|
208 { |
|
209 size_t localeLength = strlen(bcp47Locale); |
|
210 uint16 localeId = m_locale2Lang.getMsId(bcp47Locale); |
|
211 if (m_table && (be::swap<uint16>(m_table->format) == 1)) |
|
212 { |
|
213 const uint8 * pLangEntries = reinterpret_cast<const uint8*>(m_table) + |
|
214 sizeof(TtfUtil::Sfnt::FontNames) |
|
215 + sizeof(TtfUtil::Sfnt::NameRecord) * ( be::swap<uint16>(m_table->count) - 1); |
|
216 uint16 numLangEntries = be::read<uint16>(pLangEntries); |
|
217 const TtfUtil::Sfnt::LangTagRecord * langTag = |
|
218 reinterpret_cast<const TtfUtil::Sfnt::LangTagRecord*>(pLangEntries); |
|
219 if (pLangEntries + numLangEntries * sizeof(TtfUtil::Sfnt::LangTagRecord) <= m_nameData) |
|
220 { |
|
221 for (uint16 i = 0; i < numLangEntries; i++) |
|
222 { |
|
223 uint16 offset = be::swap<uint16>(langTag[i].offset); |
|
224 uint16 length = be::swap<uint16>(langTag[i].length); |
|
225 if ((offset + length <= m_nameDataLength) && (length == 2 * localeLength)) |
|
226 { |
|
227 const uint8* pName = m_nameData + offset; |
|
228 bool match = true; |
|
229 for (size_t j = 0; j < localeLength; j++) |
|
230 { |
|
231 uint16 code = be::read<uint16>(pName); |
|
232 if ((code > 0x7F) || (code != bcp47Locale[j])) |
|
233 { |
|
234 match = false; |
|
235 break; |
|
236 } |
|
237 } |
|
238 if (match) |
|
239 return 0x8000 + i; |
|
240 } |
|
241 } |
|
242 } |
|
243 } |
|
244 return localeId; |
|
245 } |
|
246 |