Coverage Report

Created: 2026-06-30 11:14

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