File indexing completed on 2024-06-02 05:43:56
0001 /* 0002 SPDX-FileCopyrightText: 2003-2007 Craig Drummond <craig@kde.org> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "Misc.h" 0007 #include "config-paths.h" 0008 #include <QByteArray> 0009 #include <QDir> 0010 #include <QList> 0011 #include <QMap> 0012 #include <QProcess> 0013 #include <QSet> 0014 #include <QStandardPaths> 0015 #include <QTemporaryFile> 0016 #include <QTextStream> 0017 #include <QUrlQuery> 0018 #include <ctype.h> 0019 0020 namespace KFI 0021 { 0022 namespace Misc 0023 { 0024 QString prettyUrl(const QUrl &url) 0025 { 0026 QString u(url.url()); 0027 0028 u.replace("%20", " "); 0029 return u; 0030 } 0031 0032 QString dirSyntax(const QString &d) 0033 { 0034 if (!d.isEmpty()) { 0035 QString ds(d); 0036 0037 ds.replace("//", "/"); 0038 0039 int slashPos(ds.lastIndexOf('/')); 0040 0041 if (slashPos != (((int)ds.length()) - 1)) { 0042 ds.append('/'); 0043 } 0044 0045 return ds; 0046 } 0047 0048 return d; 0049 } 0050 0051 QString fileSyntax(const QString &d) 0052 { 0053 if (!d.isEmpty()) { 0054 QString ds(d); 0055 0056 ds.replace("//", "/"); 0057 0058 int slashPos(ds.lastIndexOf('/')); 0059 0060 if (slashPos == (((int)ds.length()) - 1)) { 0061 ds.remove(slashPos, 1); 0062 } 0063 return ds; 0064 } 0065 0066 return d; 0067 } 0068 0069 QString getDir(const QString &f) 0070 { 0071 QString d(f); 0072 0073 int slashPos(d.lastIndexOf('/')); 0074 0075 if (slashPos != -1) { 0076 d.remove(slashPos + 1, d.length()); 0077 } 0078 0079 return dirSyntax(d); 0080 } 0081 0082 QString getFile(const QString &f) 0083 { 0084 QString d(f); 0085 0086 int slashPos = d.lastIndexOf('/'); 0087 0088 if (slashPos != -1) { 0089 d.remove(0, slashPos + 1); 0090 } 0091 0092 return d; 0093 } 0094 0095 bool createDir(const QString &dir) 0096 { 0097 if (!QDir().mkpath(dir)) { 0098 return false; 0099 } 0100 // 0101 // Clear any umask before setting dir perms 0102 mode_t oldMask(umask(0000)); 0103 const QByteArray d = QFile::encodeName(dir); 0104 ::chmod(d.constData(), DIR_PERMS); 0105 // Reset umask 0106 ::umask(oldMask); 0107 return true; 0108 } 0109 0110 void setFilePerms(const QByteArray &f) 0111 { 0112 // 0113 // Clear any umask before setting file perms 0114 mode_t oldMask(umask(0000)); 0115 ::chmod(f.constData(), FILE_PERMS); 0116 // Reset umask 0117 ::umask(oldMask); 0118 } 0119 0120 bool doCmd(const QString &cmd, const QString &p1, const QString &p2, const QString &p3) 0121 { 0122 QStringList args; 0123 0124 if (!p1.isEmpty()) { 0125 args << p1; 0126 } 0127 if (!p2.isEmpty()) { 0128 args << p2; 0129 } 0130 if (!p3.isEmpty()) { 0131 args << p3; 0132 } 0133 0134 return 0 == QProcess::execute(cmd, args); 0135 } 0136 0137 QString changeExt(const QString &f, const QString &newExt) 0138 { 0139 QString newStr(f); 0140 int dotPos(newStr.lastIndexOf('.')); 0141 0142 if (-1 == dotPos) { 0143 newStr += QChar('.') + newExt; 0144 } else { 0145 newStr.remove(dotPos + 1, newStr.length()); 0146 newStr += newExt; 0147 } 0148 return newStr; 0149 } 0150 0151 // 0152 // Get a list of files associated with a file, e.g.: 0153 // 0154 // File: /home/a/courier.pfa 0155 // 0156 // Associated: /home/a/courier.afm /home/a/courier.pfm 0157 // 0158 void getAssociatedFiles(const QString &path, QStringList &files, bool afmAndPfm) 0159 { 0160 QString ext(path); 0161 int dotPos(ext.lastIndexOf('.')); 0162 bool check(false); 0163 0164 if (-1 == dotPos) { // Hmm, no extension - check anyway... 0165 check = true; 0166 } else // Cool, got an extension - see if it is a Type1 font... 0167 { 0168 ext = ext.mid(dotPos + 1); 0169 check = 0 == ext.compare("pfa", Qt::CaseInsensitive) || 0 == ext.compare("pfb", Qt::CaseInsensitive); 0170 } 0171 0172 if (check) { 0173 const char *afm[] = {"afm", "AFM", "Afm", nullptr}, *pfm[] = {"pfm", "PFM", "Pfm", nullptr}; 0174 bool gotAfm(false); 0175 int e; 0176 0177 for (e = 0; afm[e]; ++e) { 0178 QString statFile(changeExt(path, afm[e])); 0179 0180 if (fExists(statFile)) { 0181 files.append(statFile); 0182 gotAfm = true; 0183 break; 0184 } 0185 } 0186 0187 if (afmAndPfm || !gotAfm) { 0188 for (e = 0; pfm[e]; ++e) { 0189 QString statFile(changeExt(path, pfm[e])); 0190 0191 if (fExists(statFile)) { 0192 files.append(statFile); 0193 break; 0194 } 0195 } 0196 } 0197 } 0198 } 0199 0200 time_t getTimeStamp(const QString &item) 0201 { 0202 QT_STATBUF info; 0203 0204 return !item.isEmpty() && 0 == QT_LSTAT(QFile::encodeName(item), &info) ? info.st_mtime : 0; 0205 } 0206 0207 bool check(const QString &path, bool file, bool checkW) 0208 { 0209 QT_STATBUF info; 0210 QByteArray pathC(QFile::encodeName(path)); 0211 0212 return 0 == QT_LSTAT(pathC, &info) && (file ? (S_ISREG(info.st_mode) || S_ISLNK(info.st_mode)) : S_ISDIR(info.st_mode)) 0213 && (!checkW || 0 == ::access(pathC, W_OK)); 0214 } 0215 0216 QString getFolder(const QString &defaultDir, const QString &root, QStringList &dirs) 0217 { 0218 if (dirs.contains(defaultDir)) { 0219 return defaultDir; 0220 } else { 0221 QStringList::const_iterator it, end = dirs.constEnd(); 0222 bool found = false; 0223 0224 for (it = dirs.constBegin(); it != end && !found; ++it) { 0225 if (0 == (*it).indexOf(root)) { 0226 return *it; 0227 } 0228 } 0229 } 0230 0231 return defaultDir; 0232 } 0233 0234 bool checkExt(const QString &fname, const QString &ext) 0235 { 0236 QString extension('.' + ext); 0237 0238 return fname.length() > extension.length() ? 0 == fname.mid(fname.length() - extension.length()).compare(extension, Qt::CaseInsensitive) : false; 0239 } 0240 0241 bool isBitmap(const QString &str) 0242 { 0243 return checkExt(str, "pcf") || checkExt(str, "bdf") || checkExt(str, "pcf.gz") || checkExt(str, "bdf.gz"); 0244 } 0245 0246 bool isMetrics(const QString &str) 0247 { 0248 return checkExt(str, "afm") || checkExt(str, "pfm"); 0249 } 0250 0251 int getIntQueryVal(const QUrl &url, const char *key, int defVal) 0252 { 0253 QUrlQuery query(url); 0254 QString item(query.queryItemValue(key)); 0255 int val(defVal); 0256 0257 if (!item.isNull()) { 0258 val = item.toInt(); 0259 } 0260 0261 return val; 0262 } 0263 0264 bool printable(const QString &mime) 0265 { 0266 return mime == "font/otf" || mime == "font/ttf" || mime == "application/x-font-ttf" || mime == "application/x-font-otf" 0267 || mime == "application/x-font-type1"; 0268 } 0269 0270 uint qHash(const KFI::Misc::TFont &key) 0271 { 0272 // return qHash(QString(key.family+'%'+QString().setNum(key.styleInfo, 16))); 0273 const QChar *p = key.family.unicode(); 0274 int n = key.family.size(); 0275 uint h = 0, g; 0276 0277 h = (h << 4) + key.styleInfo; 0278 if ((g = (h & 0xf0000000)) != 0) { 0279 h ^= g >> 23; 0280 } 0281 h &= ~g; 0282 0283 while (n--) { 0284 h = (h << 4) + (*p++).unicode(); 0285 if ((g = (h & 0xf0000000)) != 0) { 0286 h ^= g >> 23; 0287 } 0288 h &= ~g; 0289 } 0290 return h; 0291 } 0292 0293 // Taken from qdom.cpp 0294 QString encodeText(const QString &str) 0295 { 0296 QString retval(str); 0297 int len = retval.length(), i = 0; 0298 0299 while (i < len) { 0300 const QChar ati(retval.at(i)); 0301 0302 if (ati == QLatin1Char('<')) { 0303 retval.replace(i, 1, QLatin1String("<")); 0304 len += 3; 0305 i += 4; 0306 } else if (ati == QLatin1Char('"')) { 0307 retval.replace(i, 1, QLatin1String(""")); 0308 len += 5; 0309 i += 6; 0310 } else if (ati == QLatin1Char('&')) { 0311 retval.replace(i, 1, QLatin1String("&")); 0312 len += 4; 0313 i += 5; 0314 } else if (ati == QLatin1Char('>') && i >= 2 && retval[i - 1] == QLatin1Char(']') && retval[i - 2] == QLatin1Char(']')) { 0315 retval.replace(i, 1, QLatin1String(">")); 0316 len += 3; 0317 i += 4; 0318 } else { 0319 if (ati.isPrint()) { 0320 ++i; 0321 } else { 0322 // We have to use a character reference to get it through. 0323 const ushort codepoint(ati.unicode()); 0324 const QString replacement(QLatin1String("&#x") + QString::number(codepoint, 16) + QLatin1Char(';')); 0325 retval.replace(i, 1, replacement); 0326 i += replacement.length(); 0327 len += replacement.length() - 1; 0328 } 0329 } 0330 } 0331 0332 return retval; 0333 } 0334 0335 QString contractHome(QString path) 0336 { 0337 if (!path.isEmpty() && '/' == path[0]) { 0338 QString home(QDir::homePath()); 0339 0340 if (path.startsWith(home)) { 0341 int len = home.length(); 0342 0343 if (len > 1 && (path.length() == len || path[len] == '/')) { 0344 return path.replace(0, len, QString::fromLatin1("~")); 0345 } 0346 } 0347 } 0348 0349 return path; 0350 } 0351 0352 QString expandHome(QString path) 0353 { 0354 if (!path.isEmpty() && '~' == path[0]) { 0355 return 1 == path.length() ? QDir::homePath() : path.replace(0, 1, QDir::homePath()); 0356 } 0357 0358 return path; 0359 } 0360 0361 QMap<QString, QString> getFontFileMap(const QSet<QString> &files) 0362 { 0363 QMap<QString, QString> map; 0364 QSet<QString>::ConstIterator it = files.constBegin(), end = files.constEnd(); 0365 QMap<QString, QSet<QString>> fontsFiles; 0366 0367 for (; it != end; ++it) { 0368 fontsFiles[unhide(getFile(*it))].insert(getDir(*it)); 0369 } 0370 0371 QMap<QString, QSet<QString>>::ConstIterator fIt(fontsFiles.constBegin()), fEnd(fontsFiles.constEnd()); 0372 0373 for (; fIt != fEnd; ++fIt) { 0374 if (fIt.value().count() > 1) { 0375 QList<QString> orig(fIt.value().count()), modified(fIt.value().count()); 0376 QSet<QString>::ConstIterator oIt(fIt.value().constBegin()); 0377 bool good = true; 0378 int count = fIt.value().count(); 0379 0380 for (int i = 0; i < count && good; ++i, ++oIt) { 0381 orig[i] = modified[i] = *oIt; 0382 } 0383 0384 while (good) { 0385 int end = modified[0].indexOf('/', 1); 0386 0387 if (-1 != end) { 0388 QString dir = modified[0].left(end); 0389 0390 for (int i = 1; i < count && good; ++i) { 0391 if (0 != modified[i].indexOf(dir)) { 0392 good = false; 0393 } 0394 } 0395 if (good) { 0396 for (int i = 0; i < count && good; ++i) { 0397 modified[i].remove(0, dir.length()); 0398 } 0399 } 0400 } else { 0401 good = false; 0402 } 0403 } 0404 for (int i = 0; i < count; ++i) { 0405 map[getDir(modified[i]).mid(1) + fIt.key()] = fExists(orig[i] + fIt.key()) ? orig[i] + fIt.key() : orig[i] + hide(fIt.key()); 0406 } 0407 } else { // Only 1 entry! :-) 0408 map[unhide(fIt.key())] = 0409 fExists((*fIt.value().begin()) + fIt.key()) ? (*fIt.value().begin()) + fIt.key() : (*fIt.value().begin()) + hide(fIt.key()); 0410 } 0411 } 0412 0413 return map; 0414 } 0415 0416 QString modifyName(const QString &fname) 0417 { 0418 static const char constSymbols[] = {'-', ' ', ':', ';', '/', '~', 0}; 0419 0420 QString rv(fname); 0421 0422 for (int s = 0; constSymbols[s]; ++s) { 0423 rv.replace(constSymbols[s], '_'); 0424 } 0425 0426 int dotPos(rv.lastIndexOf('.')); 0427 0428 return -1 == dotPos ? rv : rv.left(dotPos + 1) + rv.mid(dotPos + 1).toLower(); 0429 } 0430 0431 QString app(const QString &name, const char *path) 0432 { 0433 static QMap<QString, QString> apps; 0434 0435 if (!apps.contains(name)) { 0436 QStringList installPaths; 0437 if (qstrcmp(path, "libexec") == 0) { 0438 installPaths.append(KFONTINST_LIBEXEC_DIR); 0439 } 0440 apps[name] = QStandardPaths::findExecutable(name, installPaths); 0441 } 0442 return apps[name]; 0443 } 0444 0445 } // Misc:: 0446 0447 } // KFI::