File indexing completed on 2024-12-22 04:40:13

0001 /*
0002     SPDX-FileCopyrightText: 2007-2009 Sergio Pistone <sergio_pistone@yahoo.com.ar>
0003     SPDX-FileCopyrightText: 2010-2022 Mladen Milinkovic <max@smoothware.net>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "commondefs.h"
0009 
0010 #include <cstdlib>
0011 #include <climits>
0012 
0013 #include <QStringBuilder>
0014 #include <QDir>
0015 #include <QFileInfo>
0016 
0017 #include <QDebug>
0018 #include <QStandardPaths>
0019 
0020 #include <kio_version.h>
0021 #include <kio/statjob.h>
0022 
0023 #ifndef Q_OS_WIN
0024 #include <unistd.h>
0025 #endif
0026 
0027 /**
0028  * String
0029  */
0030 
0031 QString
0032 String::title(const QString &text)
0033 {
0034     QString auxText = text.toLower();
0035     for(const QChar sep: QStringLiteral(" -_([:,;./\\\t\n\"")) {
0036         QStringList auxWordsList;
0037         for(const QString &word: auxText.split(sep)) {
0038             if(!word.isEmpty())
0039                 auxWordsList << (word.at(0).toUpper() + word.mid(1));
0040             else
0041                 auxWordsList << QString();
0042         }
0043         auxText = auxWordsList.join(sep);
0044     }
0045     return auxText;
0046 }
0047 
0048 QString
0049 String::capitalize(const QString &text)
0050 {
0051     return text.isEmpty() ? QString() : text.at(0).toUpper() + text.mid(1).toLower();
0052 }
0053 
0054 QString
0055 String::sentence(const QString &text)
0056 {
0057     return text.isEmpty() ? QString() : text.at(0).toUpper() + text.mid(1).toLower();
0058 }
0059 
0060 int
0061 String::rfindFunctionStart(const QString &text)
0062 {
0063     qsizetype pos[5] = {
0064         text.lastIndexOf(QLatin1String("capitalize{")),
0065         text.lastIndexOf(QLatin1String("titlecase{")),
0066         text.lastIndexOf(QLatin1String("uppercase{")),
0067         text.lastIndexOf(QLatin1String("lowercase{")),
0068         text.lastIndexOf(QLatin1String("ascii{")),
0069     };
0070 
0071     return qMax(qMax(qMax(qMax(pos[0], pos[1]), pos[2]), pos[3]), pos[4]);
0072 }
0073 
0074 int
0075 String::rfindFunctionEnd(const QString &text, int startPos)
0076 {
0077     int pos = startPos, len = text.length();
0078     while(pos < len) {
0079         // next is safe because idx will always be greater than 0
0080         if(text[pos] == '}' && text[pos - 1] != '\\')
0081             return pos;
0082         pos++;
0083     }
0084     return -1;
0085 }
0086 
0087 /**
0088  * System:
0089  */
0090 
0091 bool
0092 System::recursiveMakeDir(const QString &path, QStringList *createdDirsList)
0093 {
0094     if(createdDirsList)
0095         createdDirsList->clear();
0096 
0097     QDir parcialPath(QStringLiteral("/"));
0098 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
0099     QStringList tokens = path.split(QChar('/'), QString::SkipEmptyParts);
0100 #else
0101     QStringList tokens = path.split(QChar('/'), Qt::SkipEmptyParts);
0102 #endif
0103 
0104     for(QStringList::ConstIterator it = tokens.constBegin(), end = tokens.constEnd(); it != end; ++it) {
0105         parcialPath.setPath(parcialPath.path() + '/' + *it);
0106         if(!QFileInfo::exists(parcialPath.path())) {
0107             if(!QDir().mkdir(parcialPath.path()))
0108                 return false;
0109             if(createdDirsList)
0110                 createdDirsList->prepend(parcialPath.path());
0111         }
0112     }
0113 
0114     return true;
0115 }
0116 
0117 bool
0118 System::copy(const QString &srcPath, const QString &dstPath)
0119 {
0120     if(QFile::exists(dstPath))
0121         if(!System::remove(dstPath))
0122             return false;
0123 
0124     return QFile::copy(srcPath, dstPath);
0125 }
0126 
0127 bool
0128 System::move(const QString &srcPath, const QString &dstPath)
0129 {
0130     if(!System::copy(srcPath, dstPath)) {
0131         qDebug() << "move: error copying" << srcPath << "to" << dstPath;
0132 
0133         return false;
0134     }
0135 
0136     if(!QFile::remove(srcPath)) {
0137         qDebug() << "move: error removing" << srcPath;
0138 
0139         return false;
0140     }
0141 
0142     return true;
0143 }
0144 
0145 bool
0146 System::remove(const QString &path)
0147 {
0148     return QFile::remove(path);
0149 }
0150 
0151 bool
0152 System::isReadable(const QString &path)
0153 {
0154     QFileInfo fileInfo(path);
0155     return fileInfo.isFile() && fileInfo.isReadable();
0156 }
0157 
0158 bool
0159 System::isWritable(const QString &path)
0160 {
0161     QFileInfo fileInfo(path);
0162     return fileInfo.isFile() && fileInfo.isWritable();
0163 }
0164 
0165 QString
0166 System::homeDir()
0167 {
0168     return QDir::homePath();
0169 }
0170 
0171 QString
0172 System::tempDir()
0173 {
0174     QString tempDir = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
0175     while(tempDir.endsWith(QDir::separator()))
0176         tempDir.chop(1);
0177     return tempDir;
0178 }
0179 
0180 QUrl
0181 System::newUrl(const QUrl &baseUrl, const QString &fileName, const QString &extension, int retries)
0182 {
0183     if(retries < 0)
0184         retries = INT_MAX;
0185 
0186     QString newFileName(fileName);
0187     QString newFileNameBuilder(fileName + QStringLiteral("-%1"));
0188     if(!extension.isEmpty()) {
0189         newFileName += '.' + extension;
0190         newFileNameBuilder += '.' + extension;
0191     }
0192 
0193     QString newFileDir = baseUrl.path();
0194     if(!newFileDir.endsWith(QDir::separator()))
0195         newFileDir += QDir::separator();
0196 
0197     int i = 2;
0198     retries += i;
0199 
0200     if(baseUrl.isLocalFile()) {
0201         QFileInfo dirInfo(newFileDir);
0202         if(dirInfo.isDir() && dirInfo.isWritable()) {
0203             QString newFilePath = newFileDir + newFileName;
0204             while(i < retries && QFile::exists(newFilePath))
0205                 newFilePath = newFileDir + newFileNameBuilder.arg(i++);
0206             if(i < retries)
0207                 return QUrl::fromLocalFile(newFilePath);
0208         }
0209     } else {
0210         QUrl newUrl = baseUrl;
0211         newUrl.setPath(newFileDir + newFileName);
0212         for(;;) {
0213 #if KIO_VERSION < QT_VERSION_CHECK(5, 69, 0)
0214             KIO::Job *job = KIO::stat(newUrl, KIO::StatJob::DestinationSide, 2);
0215 #else
0216             KIO::Job *job = KIO::statDetails(newUrl, KIO::StatJob::DestinationSide, KIO::StatDefaultDetails, KIO::HideProgressInfo);
0217 #endif
0218             if(!job->exec())
0219                 return newUrl;
0220             if(i >= retries)
0221                 break;
0222             newUrl.setPath(newFileDir + newFileNameBuilder.arg(i++));
0223         }
0224     }
0225 
0226     // could not return a writable url in baseUrl so we return one in the temp dir
0227     newFileDir = tempDir() + QDir::separator();
0228 
0229     i = 2;
0230     QString newFilePath = newFileDir + newFileName;
0231     while(QFile::exists(newFilePath))
0232         newFilePath = newFileDir + newFileNameBuilder.arg(i++);
0233 
0234     return QUrl::fromLocalFile(newFilePath);
0235 }
0236 
0237 /*static*/ QUrl
0238 System::urlFromPath(const QString &path)
0239 {
0240     const QFileInfo file(path);
0241     const QUrl url(path);
0242     if(file.exists() || url.isRelative())
0243         return QUrl::fromLocalFile(file.absoluteFilePath());
0244     return url;
0245 }
0246 
0247 
0248 /*static*/ bool
0249 System::urlIsInside(const QUrl &url, const QString &path)
0250 {
0251     if(!url.scheme().isEmpty() && url.scheme() != QLatin1String("file"))
0252         return false;
0253     QString urlPath = url.toLocalFile();
0254     return urlPath.startsWith(path);
0255 }
0256 
0257 /*static*/ bool
0258 System::urlIsInside(const QUrl &url, QStringList &path)
0259 {
0260     for(QStringList::const_iterator i = path.constBegin(), end = path.constEnd(); i != end; i++) {
0261         if(urlIsInside(url, *i))
0262             return true;
0263     }
0264     return false;
0265 }