1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the utils of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 #include <QtCore>
29 #include <QtXml>
30 
31 class XKBLayout
32 {
33 public:
34     QString name;
35     QString description;
36     QStringList variants;
37 };
38 
find(const QString & tagName,const QDomElement & e)39 QDomElement find(const QString &tagName, const QDomElement &e)
40 {
41     QDomNodeList children = e.childNodes();
42     for (int i = 0; i < children.size(); ++i) {
43         const QDomNode &n = children.at(i);
44         if (n.isElement()) {
45             QDomElement c = n.toElement();
46             if (c.tagName() == tagName)
47                 return c;
48         }
49     }
50     return QDomElement();
51 }
52 
parseVariant(const QDomElement & e)53 QString parseVariant(const QDomElement &e)
54 {
55     QDomElement configItem = find("configItem", e);
56     return find("name", configItem).text();
57 }
58 
findVariants(const QDomElement & e)59 QStringList findVariants(const QDomElement &e)
60 {
61     QStringList variants;
62 
63     QDomNodeList children = e.childNodes();
64     for (int i = 0; i < children.size(); ++i) {
65         const QDomNode &n = children.at(i);
66         if (n.isElement())
67             variants += parseVariant(n.toElement());
68     }
69 
70     return variants;
71 }
72 
parseLayout(const QDomElement & e)73 XKBLayout parseLayout(const QDomElement &e)
74 {
75     QDomElement configItem = find("configItem", e);
76 
77     XKBLayout layout;
78     layout.name = find("name", configItem).text();
79     layout.description = find("description", configItem).text();
80 
81     QDomElement variantList = find("variantList", e);
82     if (!variantList.isNull())
83         layout.variants = findVariants(variantList);
84 
85     return layout;
86 }
87 
findLayouts(const QDomElement & layoutList)88 QList<XKBLayout> findLayouts(const QDomElement &layoutList)
89 {
90     QList<XKBLayout> layouts;
91 
92     QDomNodeList children = layoutList.childNodes();
93     for (int i = 0; i < children.size(); ++i) {
94         const QDomNode &n = children.at(i);
95         if (n.isElement())
96             layouts += parseLayout(n.toElement());
97     }
98 
99     return layouts;
100 }
101 
mapCountry(const QString & v)102 QString mapCountry(const QString &v)
103 {
104     static QMap<QString, QString> map;
105     static bool initialized = false;
106     if (!initialized) {
107         map["U.S. English"] = "UnitedStates";
108         map["PC-98xx Series"] = "Japan";
109         map["Bosnia and Herzegovina"] = "BosniaAndHerzegowina";
110         map["Czechia"] = "CzechRepublic";
111         map["Faroe Islands"] = "FaroeIslands";
112         map["Laos"] = "Laos";
113         map["Latin American"] = "Mexico";
114         map["Russia"] = "Russia";
115         map["Syria"] = "Syria";
116         map["Sri Lanka"] = "SriLanka";
117         map["United Kingdom"] = "UnitedKingdom";
118         map["Vietnam"] = "Vietnam";
119         map["Macedonian"] = "Macedonia";
120         map["Serbian"] = "Serbia";
121         map["Turkish "] = "Turkey";
122         map["Maori"] = "NewZealand";
123         map["Arabic"] = "UnitedArabEmirates";
124         initialized = true;
125     }
126     return map.value(v, v);
127 }
128 
mapLanguage(const QString & v)129 QString mapLanguage(const QString &v)
130 {
131     static QMap<QString, QString> map;
132     static bool initialized = false;
133     if (!initialized) {
134         map["us"] = "English";
135         map["us:intl"] = "English";
136         map["us:alt-intl"] = "English";
137         map["us:dvorak"] = "English";
138         map["us:rus"] = "Russian";
139         map["ara"] = "Arabic";
140         map["ara:azerty"] = "Arabic";
141         map["ara:azerty_digits"] = "Arabic";
142         map["ara:digits"] = "Arabic";
143         map["ara:qwerty"] = "Arabic";
144         map["ara:qwerty_digits"] = "Arabic";
145         map["al"] = "Albanian";
146         map["am"] = "Armenian";
147         map["am:phonetic"] = "Armenian";
148         map["az"] = "Azerbaijani";
149         map["az:cyrillic"] = "Azerbaijani";
150         map["by"] = "Belarusian";
151         map["by:winkeys"] = "Belarusian";
152         map["be"] = "Dutch";
153         map["be:iso-alternate"] = "Dutch";
154         map["be:nodeadkeys"] = "Dutch";
155         map["be:sundeadkeys"] = "Dutch";
156         map["bd"] = "Bengali";
157         map["bd:probhat"] = "Bengali";
158         map["in"] = "Hindi";
159         map["in:ben"] = "Bengali";
160         map["in:ben_probhat"] = "Bengali";
161         map["in:guj"] = "Gujarati";
162         map["in:guru"] = "Punjabi";
163         map["in:kan"] = "Kannada";
164         map["in:mal"] = "Malayalam";
165         map["in:ori"] = "Oriya";
166         map["in:tam_unicode"] = "Tamil";
167         map["in:tam_TAB"] = "Tamil";
168         map["in:tam_TSCII"] = "Tamil";
169         map["in:tam"] = "Tamil";
170         map["in:tel"] = "Telugu";
171         map["in:urd"] = "Urdu";
172         map["ba"] = "Bosnian";
173         map["br"] = "Portuguese";
174         map["br:nodeadkeys"] = "Portuguese";
175         map["bg"] = "Bulgarian";
176         map["bg:phonetic"] = "Bulgarian";
177         map["mm"] = "Burmese";
178         map["ca"] = "English";
179         map["ca:fr-dvorak"] = "French";
180         map["ca:fr-legacy"] = "French";
181         map["ca:multi"] = "English";
182         map["ca:multi-2gr"] = "English";
183         map["ca:ike"] = "Inuktitut";
184         map["hr"] = "Croatian";
185         map["hr:us"] = "Croatian";
186         map["cz"] = "Czech";
187         map["cz:bksl"] = "Czech";
188         map["cz:qwerty"] = "Czech";
189         map["cz:qwerty_bksl"] = "Czech";
190         map["dk"] = "Danish";
191         map["dk:nodeadkeys"] = "Danish";
192         map["nl"] = "Dutch";
193         map["bt"] = "Bhutani";
194         map["ee"] = "Estonian";
195         map["ee:nodeadkeys"] = "Estonian";
196         map["ir"] = "Persian";
197         map["fo"] = "Faroese";
198         map["fo:nodeadkeys"] = "Faroese";
199         map["fi"] = "Finnish";
200         map["fi:nodeadkeys"] = "Finnish";
201         map["fi:smi"] = "Finnish";
202         map["fr"] = "French";
203         map["fr:nodeadkeys"] = "French";
204         map["fr:sundeadkeys"] = "French";
205         map["fr:latin9"] = "French";
206         map["fr:latin9_nodeadkeys"] = "French";
207         map["fr:latin9_sundeadkeys"] = "French";
208         map["fr:dvorak"] = "French";
209         map["ge"] = "Georgian";
210         map["ge:ru"] = "Russian";
211         map["de"] = "German";
212         map["de:deadacute"] = "German";
213         map["de:deadgraveacute"] = "German";
214         map["de:nodeadkeys"] = "German";
215         map["de:ro"] = "Romanian";
216         map["de:ro_nodeadkeys"] = "Romanian";
217         map["de:dvorak"] = "German";
218         map["gr"] = "Greek";
219         map["gr:extended"] = "Greek";
220         map["gr:nodeadkeys"] = "Greek";
221         map["gr:polytonic"] = "Greek";
222         map["hu"] = "Hungarian";
223         map["hu:standard"] = "Hungarian";
224         map["hu:nodeadkeys"] = "Hungarian";
225         map["hu:qwerty"] = "Hungarian";
226         map["hu:101_qwertz_comma_dead"] = "Hungarian";
227         map["hu:101_qwertz_comma_nodead"] = "Hungarian";
228         map["hu:101_qwertz_dot_dead"] = "Hungarian";
229         map["hu:101_qwertz_dot_nodead"] = "Hungarian";
230         map["hu:101_qwerty_comma_dead"] = "Hungarian";
231         map["hu:101_qwerty_comma_nodead"] = "Hungarian";
232         map["hu:101_qwerty_dot_dead"] = "Hungarian";
233         map["hu:101_qwerty_dot_nodead"] = "Hungarian";
234         map["hu:102_qwertz_comma_dead"] = "Hungarian";
235         map["hu:102_qwertz_comma_nodead"] = "Hungarian";
236         map["hu:102_qwertz_dot_dead"] = "Hungarian";
237         map["hu:102_qwertz_dot_nodead"] = "Hungarian";
238         map["hu:102_qwerty_comma_dead"] = "Hungarian";
239         map["hu:102_qwerty_comma_nodead"] = "Hungarian";
240         map["hu:102_qwerty_dot_dead"] = "Hungarian";
241         map["hu:102_qwerty_dot_nodead"] = "Hungarian";
242         map["is"] = "Icelandic";
243         map["is:Sundeadkeys"] = "Icelandic";
244         map["is:nodeadkeys"] = "Icelandic";
245         map["il"] = "Hebrew";
246         map["il:lyx"] = "Hebrew";
247         map["il:si1452"] = "Hebrew";
248         map["il:phonetic"] = "Hebrew";
249         map["it"] = "Italian";
250         map["it:nodeadkeys"] = "Italian";
251         map["jp"] = "Japanese";
252         map["kg"] = "Kirghiz";
253         map["la"] = "Laothian";
254         map["latam"] = "Spanish";
255         map["latam:nodeadkeys"] = "Spanish";
256         map["latam:sundeadkeys"] = "Spanish";
257         map["lt"] = "Lithuanian";
258         map["lt:std"] = "Lithuanian";
259         map["lt:us"] = "Lithuanian";
260         map["lv"] = "Latvian";
261         map["lv:apostrophe"] = "Latvian";
262         map["lv:tilde"] = "Latvian";
263         map["lv:fkey"] = "Latvian";
264         map["mao"] = "Maori";
265         map["mkd"] = "Macedonian";
266         map["mkd:nodeadkeys"] = "Macedonian";
267         map["mt"] = "Maltese";
268         map["mt:us"] = "Maltese";
269         map["mn"] = "Mongolian";
270         map["no"] = "Norwegian";
271         map["no:nodeadkeys"] = "Norwegian";
272         map["no:dvorak"] = "Norwegian";
273         map["no:smi"] = "Norwegian";
274         map["no:smi_nodeadkeys"] = "Norwegian";
275         map["pl"] = "Polish";
276         map["pl:qwertz"] = "Polish";
277         map["pl:dvorak"] = "Polish";
278         map["pl:dvorak_quotes"] = "Polish";
279         map["pl:dvorak_altquotes"] = "Polish";
280         map["pt"] = "Portuguese";
281         map["pt:nodeadkeys"] = "Portuguese";
282         map["pt:sundeadkeys"] = "Portuguese";
283         map["ro"] = "Romanian";
284         map["ro:us"] = "English";
285         map["ro:de"] = "German";
286         map["ru"] = "Russian";
287         map["ru:phonetic"] = "Russian";
288         map["ru:typewriter"] = "Russian";
289         map["ru:winkeys"] = "Russian";
290         map["srp"] = "Serbian";
291         map["srp:yz"] = "Serbian";
292         map["srp:latin"] = "Serbian";
293         map["srp:latinunicode"] = "Serbian";
294         map["srp:latinyz"] = "Serbian";
295         map["srp:latinunicodeyz"] = "Serbian";
296         map["srp:alternatequotes"] = "Serbian";
297         map["srp:latinalternatequotes"] = "Serbian";
298         map["si"] = "Slovenian";
299         map["sk"] = "Slovak";
300         map["sk:bksl"] = "Slovak";
301         map["sk:qwerty"] = "Slovak";
302         map["sk:qwerty_bksl"] = "Slovak";
303         map["es"] = "Spanish";
304         map["es:nodeadkeys"] = "Spanish";
305         map["es:sundeadkeys"] = "Spanish";
306         map["es:dvorak"] = "Spanish";
307         map["se"] = "Swedish";
308         map["se:nodeadkeys"] = "Swedish";
309         map["se:dvorak"] = "Swedish";
310         map["se:rus"] = "Russian";
311         map["se:rus_nodeadkeys"] = "Russian";
312         map["se:smi"] = "Swedish";
313         map["ch"] = "German";
314         map["ch:de_nodeadkeys"] = "German";
315         map["ch:de_sundeadkeys"] = "German";
316         map["ch:fr"] = "French";
317         map["ch:fr_nodeadkeys"] = "French";
318         map["ch:fr_sundeadkeys"] = "French";
319         map["sy"] = "Arabic";
320         map["sy:syc"] = "Arabic";
321         map["sy:syc_phonetic"] = "Arabic";
322         map["tj"] = "Tajik";
323         map["lk"] = "Sinhala";
324         map["lk:tam_unicode"] = "Tamil";
325         map["lk:tam_TAB"] = "Tamil";
326         map["lk:tam_TSCII"] = "Tamil";
327         map["lk:sin_phonetic"] = "Sinhala";
328         map["th"] = "Thai";
329         map["th:tis"] = "Thai";
330         map["th:pat"] = "Thai";
331         map["tr"] = "Turkish";
332         map["tr:f"] = "Turkish";
333         map["tr:alt"] = "Turkish";
334         map["ua"] = "Ukrainian";
335         map["ua:phonetic"] = "Ukrainian";
336         map["ua:typewriter"] = "Ukrainian";
337         map["ua:winkeys"] = "Ukrainian";
338         map["ua:rstu"] = "Ukrainian";
339         map["ua:rstu_ru"] = "Ukrainian";
340         map["gb"] = "English";
341         map["gb:intl"] = "English";
342         map["gb:dvorak"] = "English";
343         map["uz"] = "Uzbek";
344         map["vn"] = "Vietnamese";
345         map["nec_vndr/jp"] = "Japanese";
346         map["ie"] = "Irish";
347         map["ie:CloGaelach"] = "Gaelic";
348         map["ie:UnicodeExpert"] = "Irish";
349         map["ie:ogam"] = "Gaelic";
350         map["ie:ogam_is434"] = "Gaelic";
351         map["pk"] = "Urdu";
352         initialized = true;
353     }
354     return map.value(v, v);
355 }
356 
mapDirection(const QString & v)357 QString mapDirection(const QString &v)
358 {
359     static QMap<QString, QString> map;
360     static bool initialized = false;
361     if (!initialized) {
362         // 1. xkbdata-X11R7.0-1.0.1/symbols% grep -l '\([Hh]ebrew\|[Aa]rabic\)' **/*
363         map["Arabic"] = "Qt::RightToLeft";
364         map["Persian"] = "Qt::RightToLeft";
365         map["Urdu"] = "Qt::RightToLeft";
366         initialized = true;
367     }
368     return map.value(v, "Qt::LeftToRight");
369 }
370 
main(int argc,char ** argv)371 int main(int argc, char **argv)
372 {
373     if (argc != 2) {
374         fprintf(stderr, "usage: %s <xml input file>\n", argv[0]);
375         return 1;
376     }
377 
378     QCoreApplication app(argc, argv);
379 
380     QFile file;
381     file.setFileName(argv[1]);
382     if (!file.open(QIODevice::ReadOnly)) {
383         fprintf(stderr, "cannot open %s: %s\n", qPrintable(file.fileName()), qPrintable(file.errorString()));
384         return 1;
385     }
386 
387     QDomDocument dom;
388     dom.setContent(&file);
389 
390     if (dom.documentElement().tagName() != QLatin1String("xkbConfigRegistry")) {
391         fprintf(stderr, "cannot parse %s, this is not an XKB config file\n", qPrintable(file.fileName()));
392         return 1;
393     }
394 
395     QDomElement layoutList = find("layoutList", dom.documentElement());
396     if (layoutList.isNull()) {
397         fprintf(stderr, "cannot parse %s, this is not an XKB config file\n", qPrintable(file.fileName()));
398         return 1;
399     }
400 
401     QList<XKBLayout> layouts = findLayouts(layoutList);
402 
403     // copyright and stuff
404     printf("/****************************************************************************\n"
405            "**\n"
406            "** Copyright (C) 2016 The Qt Company Ltd.\n"
407            "** Contact: https://www.qt.io/licensing/\n"
408            "**\n"
409            "** This file is part of the QtGui module of the Qt Toolkit.\n"
410            "**\n"
411            "** $QT_BEGIN_LICENSE:LGPL$\n"
412            "** Commercial License Usage\n"
413            "** Licensees holding valid commercial Qt licenses may use this file in\n"
414            "** accordance with the commercial license agreement provided with the\n"
415            "** Software or, alternatively, in accordance with the terms contained in\n"
416            "** a written agreement between you and The Qt Company. For licensing terms\n"
417            "** and conditions see https://www.qt.io/terms-conditions. For further\n"
418            "** information use the contact form at https://www.qt.io/contact-us.\n"
419            "**\n"
420            "** GNU Lesser General Public License Usage\n"
421            "** Alternatively, this file may be used under the terms of the GNU Lesser\n"
422            "** General Public License version 3 as published by the Free Software\n"
423            "** Foundation and appearing in the file LICENSE.LGPL3 included in the\n"
424            "** packaging of this file. Please review the following information to\n"
425            "** ensure the GNU Lesser General Public License version 3 requirements\n"
426            "** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.\n"
427            "**\n"
428            "** GNU General Public License Usage\n"
429            "** Alternatively, this file may be used under the terms of the GNU\n"
430            "** General Public License version 2.0 or (at your option) the GNU General\n"
431            "** Public license version 3 or any later version approved by the KDE Free\n"
432            "** Qt Foundation. The licenses are as published by the Free Software\n"
433            "** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3\n"
434            "** included in the packaging of this file. Please review the following\n"
435            "** information to ensure the GNU General Public License requirements will\n"
436            "** be met: https://www.gnu.org/licenses/gpl-2.0.html and\n"
437            "** https://www.gnu.org/licenses/gpl-3.0.html.\n"
438            "**\n"
439            "** $QT_END_LICENSE$\n"
440            "**\n"
441            "****************************************************************************/\n"
442            "\n"
443            "// This file is auto-generated, do not edit!\n"
444            "// (Generated using util/xkbdatagen)\n"
445            "\n");
446 
447     // data structure
448     printf("static struct {\n"
449            "    const char *layout;\n"
450            "    const char *variant; // 0 means any variant\n"
451            "    Qt::LayoutDirection direction;\n"
452            "    QLocale::Language language;\n"
453            "    QLocale::Country country;\n"
454            "} xkbLayoutData[] = {\n");
455 
456     // contents
457     foreach (const XKBLayout &l, layouts) {
458         const QString country = mapCountry(l.description);
459         QString lang = mapLanguage(l.name);
460         if (lang.isEmpty())
461             lang = "C";
462         printf("    // name = %s, description = %s\n"
463                "    { \"%s\", \"\", %s, QLocale::%s, QLocale::%s },\n",
464                l.name.toLatin1().constData(),
465                l.description.toLatin1().constData(),
466                l.name.toLatin1().constData(),
467                mapDirection(lang).toLatin1().constData(),
468                lang.toLatin1().constData(),
469                country.toLatin1().constData());
470         foreach (const QString &v, l.variants) {
471             QString vlang = mapLanguage(l.name + ":" + v);
472             if (vlang.isEmpty())
473                 vlang = "C";
474             printf("    // name = %s:%s, description = %s\n"
475                    "    { \"%s\", \"%s\", %s, QLocale::%s, QLocale::%s },\n",
476                    l.name.toLatin1().constData(),
477                    v.toLatin1().constData(),
478                    l.description.toLatin1().constData(),
479                    l.name.toLatin1().constData(),
480                    v.toLatin1().constData(),
481                    mapDirection(vlang).toLatin1().constData(),
482                    vlang.toLatin1().constData(),
483                    country.toLatin1().constData());
484         }
485     }
486 
487     // wrapping up
488     printf("    { 0, 0, Qt::LeftToRight, QLocale::C, QLocale::AnyCountry }\n"
489            "};\n");
490 
491     return 0;
492 }
493