/* SPDX-FileCopyrightText: 2003-2007 Craig Drummond SPDX-License-Identifier: GPL-2.0-or-later */ #include "Misc.h" #include "config-paths.h" #include #include #include #include #include #include #include #include #include #include #include using namespace Qt::StringLiterals; namespace KFI { namespace Misc { QString prettyUrl(const QUrl &url) { QString u(url.url()); u.replace("%20"_L1, " "_L1); return u; } QString dirSyntax(const QString &d) { if (!d.isEmpty()) { QString ds(d); ds.replace("//"_L1, "/"_L1); int slashPos(ds.lastIndexOf(u'/')); if (slashPos != (((int)ds.length()) - 1)) { ds.append(u'/'); } return ds; } return d; } QString fileSyntax(const QString &d) { if (!d.isEmpty()) { QString ds(d); ds.replace("//"_L1, "/"_L1); int slashPos(ds.lastIndexOf(u'/')); if (slashPos == (((int)ds.length()) - 1)) { ds.remove(slashPos, 1); } return ds; } return d; } QString getDir(const QString &f) { QString d(f); int slashPos(d.lastIndexOf(u'/')); if (slashPos != -1) { d.remove(slashPos + 1, d.length()); } return dirSyntax(d); } QString getFile(const QString &f) { QString d(f); int slashPos = d.lastIndexOf(u'/'); if (slashPos != -1) { d.remove(0, slashPos + 1); } return d; } bool createDir(const QString &dir) { if (!QDir().mkpath(dir)) { return false; } // // Clear any umask before setting dir perms mode_t oldMask(umask(0000)); const QByteArray d = QFile::encodeName(dir); ::chmod(d.constData(), DIR_PERMS); // Reset umask ::umask(oldMask); return true; } void setFilePerms(const QByteArray &f) { // // Clear any umask before setting file perms mode_t oldMask(umask(0000)); ::chmod(f.constData(), FILE_PERMS); // Reset umask ::umask(oldMask); } bool doCmd(const QString &cmd, const QString &p1, const QString &p2, const QString &p3) { QStringList args; if (!p1.isEmpty()) { args << p1; } if (!p2.isEmpty()) { args << p2; } if (!p3.isEmpty()) { args << p3; } return 0 == QProcess::execute(cmd, args); } QString changeExt(const QString &f, QLatin1String newExt) { QString newStr(f); int dotPos(newStr.lastIndexOf(u'.')); if (-1 == dotPos) { newStr += u'.' + newExt; } else { newStr.remove(dotPos + 1, newStr.length()); newStr += newExt; } return newStr; } // // Get a list of files associated with a file, e.g.: // // File: /home/a/courier.pfa // // Associated: /home/a/courier.afm /home/a/courier.pfm // void getAssociatedFiles(const QString &path, QStringList &files, bool afmAndPfm) { QString ext(path); int dotPos(ext.lastIndexOf(u'.')); bool check(false); if (-1 == dotPos) { // Hmm, no extension - check anyway... check = true; } else // Cool, got an extension - see if it is a Type1 font... { ext = ext.mid(dotPos + 1); check = 0 == ext.compare(u"pfa", Qt::CaseInsensitive) || 0 == ext.compare(u"pfb", Qt::CaseInsensitive); } if (check) { constexpr const char *afm[] = {"afm", "AFM", "Afm", nullptr}, *pfm[] = {"pfm", "PFM", "Pfm", nullptr}; bool gotAfm(false); int e; for (e = 0; afm[e]; ++e) { QString statFile(changeExt(path, QLatin1String(afm[e]))); if (fExists(statFile)) { files.append(statFile); gotAfm = true; break; } } if (afmAndPfm || !gotAfm) { for (e = 0; pfm[e]; ++e) { QString statFile(changeExt(path, QLatin1String(pfm[e]))); if (fExists(statFile)) { files.append(statFile); break; } } } } } time_t getTimeStamp(const QString &item) { QT_STATBUF info; return !item.isEmpty() && 0 == QT_LSTAT(QFile::encodeName(item).constData(), &info) ? info.st_mtime : 0; } bool check(const QString &path, bool file, bool checkW) { QT_STATBUF info; QByteArray pathC(QFile::encodeName(path)); return 0 == QT_LSTAT(pathC.constData(), &info) && (file ? (S_ISREG(info.st_mode) || S_ISLNK(info.st_mode)) : S_ISDIR(info.st_mode)) && (!checkW || 0 == ::access(pathC.constData(), W_OK)); } QString getFolder(const QString &defaultDir, const QString &root, QStringList &dirs) { if (dirs.contains(defaultDir)) { return defaultDir; } else { QStringList::const_iterator it, end = dirs.constEnd(); bool found = false; for (it = dirs.constBegin(); it != end && !found; ++it) { if (0 == (*it).indexOf(root)) { return *it; } } } return defaultDir; } bool checkExt(const QString &fname, QStringView ext) { QString extension(u'.' + ext); return fname.length() > extension.length() ? 0 == fname.mid(fname.length() - extension.length()).compare(extension, Qt::CaseInsensitive) : false; } bool isBitmap(const QString &str) { return checkExt(str, u"pcf") || checkExt(str, u"bdf") || checkExt(str, u"pcf.gz") || checkExt(str, u"bdf.gz"); } bool isMetrics(const QString &str) { return checkExt(str, u"afm") || checkExt(str, u"pfm"); } int getIntQueryVal(const QUrl &url, const char *key, int defVal) { QUrlQuery query(url); QString item(query.queryItemValue(QString::fromLocal8Bit(key))); int val(defVal); if (!item.isNull()) { val = item.toInt(); } return val; } bool printable(const QString &mime) { return mime == u"font/otf" || mime == u"font/ttf" || mime == u"application/x-font-ttf" || mime == u"application/x-font-otf" || mime == u"application/x-font-type1"; } uint qHash(const KFI::Misc::TFont &key) { // return qHash(QString(key.family+'%'+QString().setNum(key.styleInfo, 16))); const QChar *p = key.family.unicode(); int n = key.family.size(); uint h = 0, g; h = (h << 4) + key.styleInfo; if ((g = (h & 0xf0000000)) != 0) { h ^= g >> 23; } h &= ~g; while (n--) { h = (h << 4) + (*p++).unicode(); if ((g = (h & 0xf0000000)) != 0) { h ^= g >> 23; } h &= ~g; } return h; } // Taken from qdom.cpp QString encodeText(const QString &str) { QString retval(str); int len = retval.length(), i = 0; while (i < len) { const QChar ati(retval.at(i)); if (ati == QLatin1Char('<')) { retval.replace(i, 1, QLatin1String("<")); len += 3; i += 4; } else if (ati == QLatin1Char('"')) { retval.replace(i, 1, QLatin1String(""")); len += 5; i += 6; } else if (ati == QLatin1Char('&')) { retval.replace(i, 1, QLatin1String("&")); len += 4; i += 5; } else if (ati == QLatin1Char('>') && i >= 2 && retval[i - 1] == QLatin1Char(']') && retval[i - 2] == QLatin1Char(']')) { retval.replace(i, 1, QLatin1String(">")); len += 3; i += 4; } else { if (ati.isPrint()) { ++i; } else { // We have to use a character reference to get it through. const ushort codepoint(ati.unicode()); const QString replacement(QLatin1String("&#x") + QString::number(codepoint, 16) + QLatin1Char(';')); retval.replace(i, 1, replacement); i += replacement.length(); len += replacement.length() - 1; } } } return retval; } QString contractHome(QString path) { if (!path.isEmpty() && u'/' == path[0]) { QString home(QDir::homePath()); if (path.startsWith(home)) { int len = home.length(); if (len > 1 && (path.length() == len || path[len] == u'/')) { return path.replace(0, len, u'~'); } } } return path; } QString expandHome(QString path) { if (!path.isEmpty() && u'~' == path[0]) { return 1 == path.length() ? QDir::homePath() : path.replace(0, 1, QDir::homePath()); } return path; } QMap getFontFileMap(const QSet &files) { QMap map; QSet::ConstIterator it = files.constBegin(), end = files.constEnd(); QMap> fontsFiles; for (; it != end; ++it) { fontsFiles[unhide(getFile(*it))].insert(getDir(*it)); } QMap>::ConstIterator fIt(fontsFiles.constBegin()), fEnd(fontsFiles.constEnd()); for (; fIt != fEnd; ++fIt) { if (fIt.value().count() > 1) { QList orig(fIt.value().count()), modified(fIt.value().count()); QSet::ConstIterator oIt(fIt.value().constBegin()); bool good = true; int count = fIt.value().count(); for (int i = 0; i < count && good; ++i, ++oIt) { orig[i] = modified[i] = *oIt; } while (good) { int end = modified[0].indexOf(u'/', 1); if (-1 != end) { QString dir = modified[0].left(end); for (int i = 1; i < count && good; ++i) { if (0 != modified[i].indexOf(dir)) { good = false; } } if (good) { for (int i = 0; i < count && good; ++i) { modified[i].remove(0, dir.length()); } } } else { good = false; } } for (int i = 0; i < count; ++i) { map[getDir(modified[i]).mid(1) + fIt.key()] = fExists(orig[i] + fIt.key()) ? QString(orig[i] + fIt.key()) : QString(orig[i] + hide(fIt.key())); } } else { // Only 1 entry! :-) map[unhide(fIt.key())] = fExists((*fIt.value().begin()) + fIt.key()) ? QString((*fIt.value().begin()) + fIt.key()) : QString((*fIt.value().begin()) + hide(fIt.key())); } } return map; } QString modifyName(const QString &fname) { static constexpr char16_t constSymbols[] = {u'-', u' ', u':', u';', u'/', u'~', 0}; QString rv(fname); for (int s = 0; constSymbols[s]; ++s) { rv.replace(constSymbols[s], u'_'); } int dotPos(rv.lastIndexOf(u'.')); return -1 == dotPos ? rv : rv.left(dotPos + 1) + rv.mid(dotPos + 1).toLower(); } QString app(const QString &name, const char *path) { static QMap apps; if (!apps.contains(name)) { QStringList installPaths; if (qstrcmp(path, "libexec") == 0) { installPaths.append(QString::fromLocal8Bit(KFONTINST_LIBEXEC_DIR)); } apps[name] = QStandardPaths::findExecutable(name, installPaths); } return apps[name]; } } // Misc:: } // KFI::