File indexing completed on 2024-04-28 04:50:48
0001 /* 0002 * iso-codes.cpp 0003 * 0004 * Copyright (C) 2017 Mauro Carvalho Chehab <mchehab+samsung@kernel.org> 0005 * Copyright (C) 2017 Pino Toscano <pino@kde.org> 0006 * 0007 * This program is free software; you can redistribute it and/or modify 0008 * it under the terms of the GNU General Public License as published by 0009 * the Free Software Foundation; either version 2 of the License, or 0010 * (at your option) any later version. 0011 * 0012 * This program is distributed in the hope that it will be useful, 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0015 * GNU General Public License for more details. 0016 */ 0017 0018 #include "log.h" 0019 0020 #include <KLocalizedString> 0021 #include <QFile> 0022 #include <QLocale> 0023 #include <QRegularExpression> 0024 #include <QStandardPaths> 0025 #include <QXmlStreamReader> 0026 0027 #include "iso-codes.h" 0028 0029 namespace IsoCodes 0030 { 0031 static void load(QHash<QString, QString> *code_3letters, 0032 QHash<QString, QString> *code_2letters, 0033 QString file, 0034 QString main_key, 0035 QString entry_key, 0036 QString code_3_key, 0037 QString code_2_key, 0038 QString name_key) 0039 { 0040 if (!code_3letters->isEmpty()) 0041 return; 0042 0043 const QString fileName = QStandardPaths::locate(QStandardPaths::GenericDataLocation, file); 0044 if (fileName.isEmpty()) { 0045 qCInfo(logConfig, 0046 "Could not locate %s (is iso-codes installed?)", 0047 qPrintable(file)); 0048 return; 0049 } 0050 0051 QFile f(fileName); 0052 if (!f.open(QIODevice::ReadOnly)) { 0053 qCWarning(logConfig, 0054 "Could not open %s (%s)", 0055 qPrintable(fileName), 0056 qPrintable(f.errorString())); 0057 return; 0058 } 0059 0060 QXmlStreamReader r(&f); 0061 bool inDoc = false; 0062 while (!r.atEnd()) { 0063 const QXmlStreamReader::TokenType t = r.readNext(); 0064 QStringRef name; 0065 switch (t) { 0066 case QXmlStreamReader::StartElement: 0067 name = r.name(); 0068 if (inDoc && name == entry_key) { 0069 const QXmlStreamAttributes attrs = r.attributes(); 0070 const QString code3 = attrs.value(code_3_key).toString().toUpper(); 0071 const QString lang = attrs.value(name_key).toString(); 0072 code_3letters->insert(code3, lang); 0073 if (code_2letters) { 0074 const QString code2 = attrs.value(code_2_key).toString().toUpper(); 0075 if (!code2.isEmpty()) 0076 code_2letters->insert(code2, code3); 0077 } 0078 } else if (name == main_key) { 0079 inDoc = true; 0080 } 0081 break; 0082 case QXmlStreamReader::EndElement: 0083 name = r.name(); 0084 if (inDoc && name == main_key) { 0085 inDoc = false; 0086 } 0087 break; 0088 case QXmlStreamReader::NoToken: 0089 case QXmlStreamReader::Invalid: 0090 case QXmlStreamReader::StartDocument: 0091 case QXmlStreamReader::EndDocument: 0092 case QXmlStreamReader::Characters: 0093 case QXmlStreamReader::Comment: 0094 case QXmlStreamReader::DTD: 0095 case QXmlStreamReader::EntityReference: 0096 case QXmlStreamReader::ProcessingInstruction: 0097 break; 0098 } 0099 } 0100 if (code_3letters->isEmpty()) 0101 qCWarning(logConfig, 0102 "Error parsing %s: no entries found.", 0103 qPrintable(fileName)); 0104 } 0105 0106 /* 0107 * ISO 639-2 language codes 0108 * Loaded and translated at runtime from iso-codes. 0109 */ 0110 static QHash<QString, QString> iso639_2_codes; 0111 0112 /* 0113 * ISO 639-1 to ISO 639-2 language code conversion 0114 * Loaded and translated at runtime from iso-codes. 0115 */ 0116 static QHash<QString, QString> iso639_1_codes; 0117 0118 bool getLanguage(const QString &iso_code, QString *language) 0119 { 0120 static bool first = true; 0121 0122 QString code = iso_code.toUpper(); 0123 0124 if (code == "QAA") { 0125 *language = i18n("Original Language"); 0126 return true; 0127 } 0128 0129 if (first) { 0130 load(&iso639_2_codes, 0131 &iso639_1_codes, 0132 QString("xml/iso-codes/iso_639-2.xml"), 0133 QLatin1String("iso_639_entries"), 0134 QLatin1String("iso_639_entry"), 0135 QLatin1String("iso_639_2B_code"), 0136 QLatin1String("iso_639_1_code"), 0137 QLatin1String("name")); 0138 first = false; 0139 } 0140 0141 QHash<QString, QString>::ConstIterator it = iso639_2_codes.constFind(code); 0142 if (it == iso639_2_codes.constEnd()) { 0143 /* 0144 * The ETSI EN 300 468 Annex F spec defines the 0145 * original audio soundtrack code to be "QAA". Yet, 0146 * TV bundle providers could use something else. 0147 * 0148 * At least here, my provider actually uses "ORG" 0149 * instead. Currently, this is an unused ISO 639 0150 * code, so we can safely accept it as well, 0151 * at least as a fallback code while ISO doesn't 0152 * define it. 0153 */ 0154 if (code == "ORG") { 0155 *language = i18n("Original Language"); 0156 return true; 0157 } 0158 return false; 0159 } 0160 0161 if (language) { 0162 *language = i18nd("iso_639-2", it.value().toUtf8().constData()); 0163 } 0164 return true; 0165 } 0166 0167 const QString code2Convert(const QString &code2) 0168 { 0169 static bool first = true; 0170 0171 QString code = code2.toUpper(); 0172 0173 /* Ignore any embedded Country data */ 0174 code.remove(QRegularExpression("_.*")); 0175 0176 if (first) { 0177 load(&iso639_2_codes, 0178 &iso639_1_codes, 0179 QString("xml/iso-codes/iso_639-2.xml"), 0180 QLatin1String("iso_639_entries"), 0181 QLatin1String("iso_639_entry"), 0182 QLatin1String("iso_639_2B_code"), 0183 QLatin1String("iso_639_1_code"), 0184 QLatin1String("name")); 0185 first = false; 0186 } 0187 0188 QHash<QString, QString>::ConstIterator it = iso639_1_codes.constFind(code); 0189 if (it == iso639_1_codes.constEnd()) { 0190 return "QAA"; 0191 } 0192 return it.value().toUtf8().constData(); 0193 } 0194 0195 /* 0196 * ISO 3166-1 Alpha 3 Country codes 0197 * Loaded and translated at runtime from iso-codes. 0198 */ 0199 static QHash<QString, QString> iso3166_1_codes, iso3166_2_codes; 0200 0201 bool getCountry(const QString &_code, QString *country) 0202 { 0203 static bool first = true; 0204 QString code; 0205 0206 if (first) { 0207 load(&iso3166_1_codes, 0208 &iso3166_2_codes, 0209 QString("xml/iso-codes/iso_3166-1.xml"), 0210 QLatin1String("iso_3166_entries"), 0211 QLatin1String("iso_3166_entry"), 0212 QLatin1String("alpha_3_code"), 0213 QString("alpha_2_code"), 0214 QLatin1String("name")); 0215 first = false; 0216 } 0217 0218 if (_code.size() == 2) { 0219 QHash<QString, QString>::ConstIterator it = iso3166_1_codes.constFind(code); 0220 if (it == iso3166_2_codes.constEnd()) 0221 return false; 0222 code = it.value(); 0223 } else { 0224 code = _code; 0225 } 0226 0227 QHash<QString, QString>::ConstIterator it = iso3166_1_codes.constFind(code); 0228 if (it == iso3166_1_codes.constEnd()) { 0229 return false; 0230 } 0231 0232 if (country) { 0233 *country = i18nd("iso_3166-1", it.value().toUtf8().constData()); 0234 } 0235 return true; 0236 } 0237 }