2
* KFontInst - KDE Font Installer
4
* Copyright 2003-2007 Craig Drummond <craig@kde.org>
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program; see the file COPYING. If not, write to
20
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21
* Boston, MA 02110-1301, USA.
25
#include <QtCore/QSet>
26
#include <QtCore/QMap>
27
#include <QtCore/QVector>
28
#include <QtCore/QDir>
29
#include <QtCore/QFile>
30
#include <QtCore/QByteArray>
31
#include <QtCore/QTextCodec>
32
#include <QtCore/QTextStream>
33
#include <QtCore/QProcess>
34
#include <QtCore/QTemporaryFile>
35
#include <KDE/KStandardDirs>
46
QString prettyUrl(const KUrl &url)
48
QString u(url.prettyUrl());
50
u.replace("%20", " ");
54
QString dirSyntax(const QString &d)
60
ds.replace("//", "/");
62
int slashPos(ds.lastIndexOf('/'));
64
if(slashPos!=(((int)ds.length())-1))
73
QString fileSyntax(const QString &d)
79
ds.replace("//", "/");
81
int slashPos(ds.lastIndexOf('/'));
83
if(slashPos==(((int)ds.length())-1))
84
ds.remove(slashPos, 1);
91
QString getDir(const QString &f)
95
int slashPos(d.lastIndexOf('/'));
98
d.remove(slashPos+1, d.length());
103
QString getFile(const QString &f)
107
int slashPos=d.lastIndexOf('/');
110
d.remove(0, slashPos+1);
115
bool createDir(const QString &dir)
118
// Clear any umask before dir is created
119
mode_t oldMask(umask(0000));
120
bool status(KStandardDirs::makeDir(dir, DIR_PERMS));
126
void setFilePerms(const QByteArray &f)
129
// Clear any umask before setting file perms
130
mode_t oldMask(umask(0000));
131
::chmod(f.constData(), FILE_PERMS);
136
bool doCmd(const QString &cmd, const QString &p1, const QString &p2, const QString &p3)
147
return 0==QProcess::execute(cmd, args);
150
QString changeExt(const QString &f, const QString &newExt)
153
int dotPos(newStr.lastIndexOf('.'));
156
newStr+=QChar('.')+newExt;
159
newStr.remove(dotPos+1, newStr.length());
166
// Get a list of files associated with a file, e.g.:
168
// File: /home/a/courier.pfa
170
// Associated: /home/a/courier.afm /home/a/courier.pfm
172
void getAssociatedFiles(const QString &path, QStringList &files, bool afmAndPfm)
175
int dotPos(ext.lastIndexOf('.'));
178
if(-1==dotPos) // Hmm, no extension - check anyway...
180
else // Cool, got an extension - see if it is a Type1 font...
182
ext=ext.mid(dotPos+1);
183
check=0==ext.compare("pfa", Qt::CaseInsensitive) ||
184
0==ext.compare("pfb", Qt::CaseInsensitive);
189
const char *afm[]={"afm", "AFM", "Afm", NULL},
190
*pfm[]={"pfm", "PFM", "Pfm", NULL};
194
for(e=0; afm[e]; ++e)
196
QString statFile(changeExt(path, afm[e]));
198
if(fExists(statFile))
200
files.append(statFile);
206
if(afmAndPfm || !gotAfm)
207
for(e=0; pfm[e]; ++e)
209
QString statFile(changeExt(path, pfm[e]));
211
if(fExists(statFile))
213
files.append(statFile);
220
time_t getTimeStamp(const QString &item)
222
KDE_struct_stat info;
224
return !item.isEmpty() && 0==KDE_lstat(QFile::encodeName(item), &info) ? info.st_mtime : 0;
228
bool check(const QString &path, bool file, bool checkW)
230
KDE_struct_stat info;
231
QByteArray pathC(QFile::encodeName(path));
233
return 0==KDE_lstat(pathC, &info) &&
234
(file ? (S_ISREG(info.st_mode) || S_ISLNK(info.st_mode))
235
: S_ISDIR(info.st_mode)) &&
236
(!checkW || 0==::access(pathC, W_OK));
239
QString getFolder(const QString &defaultDir, const QString &root, QStringList &dirs)
241
if(dirs.contains(defaultDir))
245
QStringList::const_iterator it,
249
for(it=dirs.constBegin(); it!=end && !found; ++it)
250
if(0==(*it).indexOf(root))
257
bool checkExt(const QString &fname, const QString &ext)
259
QString extension('.'+ext);
261
return fname.length()>extension.length()
262
? 0==fname.mid(fname.length()-extension.length()).compare(extension, Qt::CaseInsensitive)
266
bool isBitmap(const QString &str)
268
return checkExt(str, "pcf") || checkExt(str, "bdf") || checkExt(str, "pcf.gz") || checkExt(str, "bdf.gz");
271
bool isMetrics(const QString &str)
273
return checkExt(str, "afm") || checkExt(str, "pfm");
276
int getIntQueryVal(const KUrl &url, const char *key, int defVal)
278
QString item(url.queryItem(key));
287
bool printable(const QString &mime)
289
return "application/x-font-type1"==mime || "application/x-font-ttf"==mime ||
290
"application/x-font-otf"==mime || "application/x-font-type1"==mime;
293
uint qHash(const KFI::Misc::TFont &key)
295
//return qHash(QString(key.family+'%'+QString().setNum(key.styleInfo, 16)));
296
const QChar *p = key.family.unicode();
297
int n = key.family.size();
301
h = (h << 4) + key.styleInfo;
302
if ((g = (h & 0xf0000000)) != 0)
308
h = (h << 4) + (*p++).unicode();
309
if ((g = (h & 0xf0000000)) != 0)
316
// Taken from qdom.cpp
317
QString encodeText(const QString &str, QTextStream &s)
319
const QTextCodec *const codec = s.codec();
324
int len = retval.length(),
329
const QChar ati(retval.at(i));
331
if (ati == QLatin1Char('<'))
333
retval.replace(i, 1, QLatin1String("<"));
337
else if (ati == QLatin1Char('"'))
339
retval.replace(i, 1, QLatin1String("""));
343
else if (ati == QLatin1Char('&'))
345
retval.replace(i, 1, QLatin1String("&"));
349
else if (ati == QLatin1Char('>') && i >= 2 && retval[i - 1] == QLatin1Char(']') && retval[i - 2] == QLatin1Char(']'))
351
retval.replace(i, 1, QLatin1String(">"));
357
if(codec->canEncode(ati))
361
// We have to use a character reference to get it through.
362
const ushort codepoint(ati.unicode());
363
const QString replacement(QLatin1String("&#x") + QString::number(codepoint, 16) + QLatin1Char(';'));
364
retval.replace(i, 1, replacement);
365
i += replacement.length();
366
len += replacement.length() - 1;
374
QString contractHome(QString path)
376
if (!path.isEmpty() && '/'==path[0])
378
QString home(QDir::homePath());
380
if(path.startsWith(home))
382
int len = home.length();
384
if(len>1 && (path.length() == len || path[len] == '/'))
385
return path.replace(0, len, QString::fromLatin1("~"));
392
QString expandHome(QString path)
394
if(!path.isEmpty() && '~'==path[0])
395
return 1==path.length() ? QDir::homePath() : path.replace(0, 1, QDir::homePath());
400
QMap<QString, QString> getFontFileMap(const QSet<QString> &files)
402
QMap<QString, QString> map;
403
QSet<QString>::ConstIterator it=files.constBegin(),
404
end=files.constEnd();
405
QMap<QString, QSet<QString> > fontsFiles;
408
fontsFiles[unhide(getFile(*it))].insert(getDir(*it));
410
QMap<QString, QSet<QString> >::ConstIterator fIt(fontsFiles.constBegin()),
411
fEnd(fontsFiles.constEnd());
413
for(; fIt!=fEnd; ++fIt)
414
if(fIt.value().count()>1)
416
QVector<QString> orig(fIt.value().count()),
417
modified(fIt.value().count());
418
QSet<QString>::ConstIterator oIt(fIt.value().constBegin()),
419
oEnd(fIt.value().constEnd());
421
int count=fIt.value().count();
423
for(int i=0; i<count && good; ++i, ++oIt)
424
orig[i]=modified[i]=*oIt;
428
int end=modified[0].indexOf('/', 1);
432
QString dir=modified[0].left(end);
434
for(int i=1; i<count && good; ++i)
435
if(0!=modified[i].indexOf(dir))
438
for(int i=0; i<count && good; ++i)
439
modified[i]=modified[i].remove(0, dir.length());
444
for(int i=0; i<count; ++i)
445
map[getDir(modified[i]).mid(1)+fIt.key()]=fExists(orig[i]+fIt.key())
447
: orig[i]+hide(fIt.key());
449
else // Only 1 entry! :-)
450
map[unhide(fIt.key())]=fExists((*fIt.value().begin())+fIt.key())
451
? (*fIt.value().begin())+fIt.key()
452
: (*fIt.value().begin())+hide(fIt.key());