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