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