mirror of
https://bitbucket.org/smil3y/kde-workspace.git
synced 2025-02-25 19:32:52 +00:00
483 lines
12 KiB
C++
483 lines
12 KiB
C++
/*
|
|
* KFontInst - KDE Font Installer
|
|
*
|
|
* Copyright 2003-2007 Craig Drummond <craig@kde.org>
|
|
*
|
|
* ----
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "Misc.h"
|
|
#include <QtCore/QSet>
|
|
#include <QtCore/QMap>
|
|
#include <QtCore/QVector>
|
|
#include <QtCore/QDir>
|
|
#include <QtCore/QFile>
|
|
#include <QtCore/QByteArray>
|
|
#include <QtCore/QTextCodec>
|
|
#include <QtCore/QTextStream>
|
|
#include <QtCore/QProcess>
|
|
#include <QtCore/QTemporaryFile>
|
|
#include <KStandardDirs>
|
|
#include <kde_file.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
|
|
namespace KFI
|
|
{
|
|
|
|
namespace Misc
|
|
{
|
|
|
|
QString prettyUrl(const KUrl &url)
|
|
{
|
|
QString u(url.prettyUrl());
|
|
|
|
u.replace("%20", " ");
|
|
return u;
|
|
}
|
|
|
|
QString dirSyntax(const QString &d)
|
|
{
|
|
if(!d.isEmpty())
|
|
{
|
|
QString ds(d);
|
|
|
|
ds.replace("//", "/");
|
|
|
|
int slashPos(ds.lastIndexOf('/'));
|
|
|
|
if(slashPos!=(((int)ds.length())-1))
|
|
ds.append('/');
|
|
|
|
return ds;
|
|
}
|
|
|
|
return d;
|
|
}
|
|
|
|
QString fileSyntax(const QString &d)
|
|
{
|
|
if(!d.isEmpty())
|
|
{
|
|
QString ds(d);
|
|
|
|
ds.replace("//", "/");
|
|
|
|
int slashPos(ds.lastIndexOf('/'));
|
|
|
|
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('/'));
|
|
|
|
if(slashPos!=-1)
|
|
d.remove(slashPos+1, d.length());
|
|
|
|
return dirSyntax(d);
|
|
}
|
|
|
|
QString getFile(const QString &f)
|
|
{
|
|
QString d(f);
|
|
|
|
int slashPos=d.lastIndexOf('/');
|
|
|
|
if(slashPos!=-1)
|
|
d.remove(0, slashPos+1);
|
|
|
|
return d;
|
|
}
|
|
|
|
bool createDir(const QString &dir)
|
|
{
|
|
//
|
|
// Clear any umask before dir is created
|
|
mode_t oldMask(umask(0000));
|
|
bool status(KStandardDirs::makeDir(dir, DIR_PERMS));
|
|
// Reset umask
|
|
::umask(oldMask);
|
|
return status;
|
|
}
|
|
|
|
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, const QString &newExt)
|
|
{
|
|
QString newStr(f);
|
|
int dotPos(newStr.lastIndexOf('.'));
|
|
|
|
if(-1==dotPos)
|
|
newStr+=QChar('.')+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('.'));
|
|
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("pfa", Qt::CaseInsensitive) ||
|
|
0==ext.compare("pfb", Qt::CaseInsensitive);
|
|
}
|
|
|
|
if(check)
|
|
{
|
|
const char *afm[]={"afm", "AFM", "Afm", NULL},
|
|
*pfm[]={"pfm", "PFM", "Pfm", NULL};
|
|
bool gotAfm(false);
|
|
int e;
|
|
|
|
for(e=0; afm[e]; ++e)
|
|
{
|
|
QString statFile(changeExt(path, afm[e]));
|
|
|
|
if(fExists(statFile))
|
|
{
|
|
files.append(statFile);
|
|
gotAfm=true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(afmAndPfm || !gotAfm)
|
|
for(e=0; pfm[e]; ++e)
|
|
{
|
|
QString statFile(changeExt(path, pfm[e]));
|
|
|
|
if(fExists(statFile))
|
|
{
|
|
files.append(statFile);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
time_t getTimeStamp(const QString &item)
|
|
{
|
|
KDE_struct_stat info;
|
|
|
|
return !item.isEmpty() && 0==KDE_lstat(QFile::encodeName(item), &info) ? info.st_mtime : 0;
|
|
}
|
|
|
|
|
|
bool check(const QString &path, bool file, bool checkW)
|
|
{
|
|
KDE_struct_stat info;
|
|
QByteArray pathC(QFile::encodeName(path));
|
|
|
|
return 0==KDE_lstat(pathC, &info) &&
|
|
(file ? (S_ISREG(info.st_mode) || S_ISLNK(info.st_mode))
|
|
: S_ISDIR(info.st_mode)) &&
|
|
(!checkW || 0==::access(pathC, 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, const QString &ext)
|
|
{
|
|
QString extension('.'+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, "pcf") || checkExt(str, "bdf") || checkExt(str, "pcf.gz") || checkExt(str, "bdf.gz");
|
|
}
|
|
|
|
bool isMetrics(const QString &str)
|
|
{
|
|
return checkExt(str, "afm") || checkExt(str, "pfm");
|
|
}
|
|
|
|
int getIntQueryVal(const KUrl &url, const char *key, int defVal)
|
|
{
|
|
QString item(url.queryItem(key));
|
|
int val(defVal);
|
|
|
|
if(!item.isNull())
|
|
val=item.toInt();
|
|
|
|
return val;
|
|
}
|
|
|
|
bool printable(const QString &mime)
|
|
{
|
|
return "application/x-font-type1"==mime || "application/x-font-ttf"==mime ||
|
|
"application/x-font-otf"==mime || "application/x-font-type1"==mime;
|
|
}
|
|
|
|
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, QTextStream &s)
|
|
{
|
|
const QTextCodec *const codec = s.codec();
|
|
|
|
Q_ASSERT(codec);
|
|
|
|
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(codec->canEncode(ati))
|
|
++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() && '/'==path[0])
|
|
{
|
|
QString home(QDir::homePath());
|
|
|
|
if(path.startsWith(home))
|
|
{
|
|
int len = home.length();
|
|
|
|
if(len>1 && (path.length() == len || path[len] == '/'))
|
|
return path.replace(0, len, QString::fromLatin1("~"));
|
|
}
|
|
}
|
|
|
|
return path;
|
|
}
|
|
|
|
QString expandHome(QString path)
|
|
{
|
|
if(!path.isEmpty() && '~'==path[0])
|
|
return 1==path.length() ? QDir::homePath() : path.replace(0, 1, QDir::homePath());
|
|
|
|
return path;
|
|
}
|
|
|
|
QMap<QString, QString> getFontFileMap(const QSet<QString> &files)
|
|
{
|
|
QMap<QString, QString> map;
|
|
QSet<QString>::ConstIterator it=files.constBegin(),
|
|
end=files.constEnd();
|
|
QMap<QString, QSet<QString> > fontsFiles;
|
|
|
|
for(;it!=end; ++it)
|
|
fontsFiles[unhide(getFile(*it))].insert(getDir(*it));
|
|
|
|
QMap<QString, QSet<QString> >::ConstIterator fIt(fontsFiles.constBegin()),
|
|
fEnd(fontsFiles.constEnd());
|
|
|
|
for(; fIt!=fEnd; ++fIt)
|
|
if(fIt.value().count()>1)
|
|
{
|
|
QVector<QString> orig(fIt.value().count()),
|
|
modified(fIt.value().count());
|
|
QSet<QString>::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('/', 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]=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())
|
|
? orig[i]+fIt.key()
|
|
: orig[i]+hide(fIt.key());
|
|
}
|
|
else // Only 1 entry! :-)
|
|
map[unhide(fIt.key())]=fExists((*fIt.value().begin())+fIt.key())
|
|
? (*fIt.value().begin())+fIt.key()
|
|
: (*fIt.value().begin())+hide(fIt.key());
|
|
|
|
return map;
|
|
}
|
|
|
|
QString modifyName(const QString &fname)
|
|
{
|
|
static const char constSymbols[]={ '-', ' ', ':', ';', '/', '~', 0 };
|
|
|
|
QString rv(fname);
|
|
|
|
for(int s=0; constSymbols[s]; ++s)
|
|
rv=rv.replace(constSymbols[s], '_');
|
|
|
|
int dotPos(rv.lastIndexOf('.'));
|
|
|
|
return -1==dotPos
|
|
? rv
|
|
: rv.left(dotPos+1)+rv.mid(dotPos+1).toLower();
|
|
}
|
|
|
|
QString app(const QString &name, const char *path)
|
|
{
|
|
static QMap<QString, QString> apps;
|
|
|
|
if(!apps.contains(name))
|
|
apps[name]=KStandardDirs::findExe(name, path ? KStandardDirs::installPath(path) : QString());
|
|
return apps[name];
|
|
}
|
|
|
|
} // Misc::
|
|
|
|
} // KFI::
|