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 #include <cassert>
23 #include <cstdio>
24 #include <cstdlib>
25 #include <cstring>
26 #include <graphite2/Types.h>
27 #include "inc/Main.h"
28 #include "inc/Endian.h"
29 #include "inc/TtfTypes.h"
30 #include "inc/NameTable.h"
31 
32 using namespace graphite2;
33 
34 #pragma pack(push, 1)
35 struct NameTestA
36 {
37     TtfUtil::Sfnt::FontNames m_nameHeader;
38     TtfUtil::Sfnt::NameRecord m_records[5];
39     uint8 m_textData[27];
40 };
41 
42 struct NameTestB
43 {
44     TtfUtil::Sfnt::FontNames m_nameHeader;
45     TtfUtil::Sfnt::NameRecord m_records[7];
46     uint16 m_langTagCount;
47     TtfUtil::Sfnt::LangTagRecord m_languages[2];
48     uint8 m_textData[59];
49 };
50 #pragma pack(pop)
51 
52 
53 NameTestA testA = {
54     {0, 6, (5 * sizeof(TtfUtil::Sfnt::NameRecord)) +
55         sizeof(TtfUtil::Sfnt::FontNames), {{0, 0, 0, 1, 1, 0}}},
56     {
57         {3, 1, 0x409, 1, 4, 1},
58         {3, 1, 0x409, 7, 6, 5},
59         {3, 1, 0x455, 7, 4, 11},
60         {3, 1, 0x809, 1, 4, 15},
61         {3, 1, 0x809, 7, 8, 19}
62     },
63     {0x41,
64      0,0x41,0,0x61,
65      0,0x41,0,0x42,0,0x43,
66      0x10,0x00,0x10,0x01,
67      0,0x61,0,0x61,
68      0,0x61,0,0x62,0,0x63,0,0x64}
69 };
70 
71 NameTestB testB = {
72     {1, 8, (7 * sizeof(TtfUtil::Sfnt::NameRecord)) +
73         sizeof(TtfUtil::Sfnt::FontNames) +
74         2 + 2 * sizeof(TtfUtil::Sfnt::LangTagRecord),
75         {{0, 0, 0, 1, 1, 0}}},
76     {
77         {3, 1, 0x409, 1, 4, 1},
78         {3, 1, 0x409, 7, 6, 5},
79         {3, 1, 0x455, 7, 4, 11},
80         {3, 1, 0x809, 1, 4, 15},
81         {3, 1, 0x809, 7, 8, 19},
82         {3, 1, 0x8000, 7, 6, 27},
83         {3, 1, 0x8001, 7, 2, 33}
84     },
85     2,
86     {
87         {12,35},{12,47}
88     },
89     {0x41,
90      0,0x41,0,0x61,
91      0,0x41,0,0x42,0,0x43,
92      0x10,0x00,0x10,0x01,
93      0,0x61,0,0x61,
94      0,0x61,0,0x62,0,0x63,0,0x64,
95      0x10,0x00,0x10,0x62,0x10,0x64,
96      0x10,0x5c,
97      0,0x6b,0,0x73,0,0x77,0,0x2d,0,0x4d,0,0x4d,
98      0,0x6d,0,0x6e,0,0x77,0,0x2d,0,0x4d,0,0x4d
99     }
100 };
101 
testName(void * data,size_t length,uint16 langId,uint16 actualLang,uint16 nameId,const char * utf8Text)102 void testName(void * data, size_t length, uint16 langId,
103               uint16 actualLang, uint16 nameId, const char * utf8Text)
104 {
105     NameTable name(data, length);
106     uint16 lang = langId;
107     uint32 strLen = 0;
108     char * n = reinterpret_cast<char*>(name.getName(lang, nameId, gr_utf8, strLen));
109     if ((n == NULL) || (strncmp(n, utf8Text, strLen) != 0))
110     {
111         fprintf(stderr, "name=%s expected=%s\n", n, utf8Text);
112         free(n);
113         exit(1);
114     }
115     free(n);
116     if (lang != actualLang)
117     {
118         fprintf(stderr, "lang=%x actual=%x\n", lang, actualLang);
119         exit(1);
120     }
121 }
122 
testLangId(void * data,size_t length,const char * id,uint16 expected)123 void testLangId(void * data, size_t length, const char * id, uint16 expected)
124 {
125     NameTable table(data, length);
126     uint16 lId = table.getLanguageId(id);
127     if (lId != expected)
128     {
129         fprintf(stderr, "%s lang id: %d expected: %d\n", id, lId, expected);
130     }
131 }
132 
toBigEndian(T & table)133 template <class T> T * toBigEndian(T & table)
134 {
135     T * bigEndian = gralloc<T>(1);
136     bigEndian->m_nameHeader.format = be::swap<uint16>(table.m_nameHeader.format);
137     bigEndian->m_nameHeader.count = be::swap<uint16>(table.m_nameHeader.count);
138     bigEndian->m_nameHeader.string_offset = be::swap<uint16>(table.m_nameHeader.string_offset);
139 
140     for (uint16 i = 0; i < table.m_nameHeader.count; i++)
141     {
142         bigEndian->m_records[i].platform_id = be::swap<uint16>(table.m_records[i].platform_id);
143         bigEndian->m_records[i].platform_specific_id = be::swap<uint16>(table.m_records[i].platform_specific_id);
144         bigEndian->m_records[i].language_id = be::swap<uint16>(table.m_records[i].language_id);
145         bigEndian->m_records[i].name_id = be::swap<uint16>(table.m_records[i].name_id);
146         bigEndian->m_records[i].length = be::swap<uint16>(table.m_records[i].length);
147         bigEndian->m_records[i].offset = be::swap<uint16>(table.m_records[i].offset);
148     }
149 
150     bigEndian->m_nameHeader.name_record[0].platform_id = be::swap<uint16>(table.m_nameHeader.name_record[0].platform_id);
151     bigEndian->m_nameHeader.name_record[0].platform_specific_id = be::swap<uint16>(table.m_nameHeader.name_record[0].platform_specific_id);
152     bigEndian->m_nameHeader.name_record[0].language_id = be::swap<uint16>(table.m_nameHeader.name_record[0].language_id);
153     bigEndian->m_nameHeader.name_record[0].name_id = be::swap<uint16>(table.m_nameHeader.name_record[0].name_id);
154     bigEndian->m_nameHeader.name_record[0].length = be::swap<uint16>(table.m_nameHeader.name_record[0].length);
155     bigEndian->m_nameHeader.name_record[0].offset = be::swap<uint16>(table.m_nameHeader.name_record[0].offset);
156 
157     memcpy(bigEndian->m_textData, table.m_textData, sizeof(table.m_textData) );
158     return bigEndian;
159 }
160 
toBigEndian1(T & table)161 template <class T> T * toBigEndian1(T & table)
162 {
163     T * bigEndian = toBigEndian<T>(table);
164     bigEndian->m_langTagCount = be::swap<uint16>(table.m_langTagCount);
165     for (size_t i = 0; i < table.m_langTagCount; i++)
166     {
167         bigEndian->m_languages[i] = be::swap<uint16>(table.m_languages[i]);
168         bigEndian->m_languages[i] = be::swap<uint16>(table.m_languages[i]);
169     }
170 }
171 
main(int,char **)172 int main(int, char **)
173 {
174     struct NameTestA* testAData = toBigEndian<struct NameTestA>(testA);
175     testName(testAData, sizeof(NameTestA), 0x409, 0x409, 1, "Aa");
176     testName(testAData, sizeof(NameTestA), 0x809, 0x809, 1, "aa");
177     testName(testAData, sizeof(NameTestA), 0x455, 0x409, 1, "Aa");
178 
179     testName(testAData, sizeof(NameTestA), 0x409, 0x409, 7, "ABC");
180     testName(testAData, sizeof(NameTestA), 0x809, 0x809, 7, "abcd");
181     testName(testAData, sizeof(NameTestA), 0x455, 0x455, 7, "ကခ");
182 
183     testLangId(testAData, sizeof(NameTestA), "en-US", 0x409);
184     testLangId(testAData, sizeof(NameTestA), "en", 0x409);
185     testLangId(testAData, sizeof(NameTestA), "en-GB", 0x809);
186     testLangId(testAData, sizeof(NameTestA), "en-Latn-GB", 0x809);
187     testLangId(testAData, sizeof(NameTestA), "en-Latn-GB-Cockney", 0x809);
188     testLangId(testAData, sizeof(NameTestA), "my-MM", 0x455);
189     testLangId(testAData, sizeof(NameTestA), "my-Mymr", 0x455);
190     testLangId(testAData, sizeof(NameTestA), "my-Mymr-MM", 0x455);
191     testLangId(testAData, sizeof(NameTestA), "en-GB-Cockney", 0x809);
192     free(testAData);
193 
194     struct NameTestB* testBData = toBigEndian<struct NameTestB>(testB);
195     testLangId(testBData, sizeof(NameTestB), "en-US", 0x409);
196     testLangId(testBData, sizeof(NameTestB), "en-GB", 0x809);
197     testLangId(testBData, sizeof(NameTestB), "ksw-MM", 0x8000);
198     testLangId(testBData, sizeof(NameTestB), "mnw-MM", 0x8001);
199     testName(testBData, sizeof(NameTestB), 0x809, 0x809, 7, "abcd");
200     testName(testBData, sizeof(NameTestB), 0x455, 0x455, 7, "ကခ");
201     testName(testBData, sizeof(NameTestB), 0x8000, 0x8000, 7, "ကၢၤ");
202     testName(testBData, sizeof(NameTestB), 0x8001, 0x8001, 7, "ၜ");
203     testName(testBData, sizeof(NameTestB), 0x8002, 0x409, 1, "Aa");
204     free(testBData);
205 
206     return 0;
207 }
208