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/QDir>
26 #include <QtCore/QFile>
27 #include <QtCore/QByteArray>
28 #include <QtCore/QTextCodec>
29 #include <QtCore/QTextStream>
30 #include <QtCore/QProcess>
31 #include <QtCore/QTemporaryFile>
32 #include <KDE/KStandardDirs>
43 QString
prettyUrl(const KUrl
&url
)
45 QString
u(url
.prettyUrl());
47 u
.replace("%20", " ");
51 QString
dirSyntax(const QString
&d
)
57 ds
.replace("//", "/");
59 int slashPos(ds
.lastIndexOf('/'));
61 if(slashPos
!=(((int)ds
.length())-1))
70 QString
fileSyntax(const QString
&d
)
76 ds
.replace("//", "/");
78 int slashPos(ds
.lastIndexOf('/'));
80 if(slashPos
==(((int)ds
.length())-1))
81 ds
.remove(slashPos
, 1);
88 QString
getDir(const QString
&f
)
92 int slashPos(d
.lastIndexOf('/'));
95 d
.remove(slashPos
+1, d
.length());
100 QString
getFile(const QString
&f
)
104 int slashPos
=d
.lastIndexOf('/');
107 d
.remove(0, slashPos
+1);
112 bool createDir(const QString
&dir
)
115 // Clear any umask before dir is created
116 mode_t
oldMask(umask(0000));
117 bool status(KStandardDirs::makeDir(dir
, DIR_PERMS
));
123 void setFilePerms(const QByteArray
&f
)
126 // Clear any umask before setting file perms
127 mode_t
oldMask(umask(0000));
128 ::chmod(f
.constData(), FILE_PERMS
);
133 bool doCmd(const QString
&cmd
, const QString
&p1
, const QString
&p2
, const QString
&p3
)
144 return 0==QProcess::execute(cmd
, args
);
147 QString
changeExt(const QString
&f
, const QString
&newExt
)
150 int dotPos(newStr
.lastIndexOf('.'));
153 newStr
+=QChar('.')+newExt
;
156 newStr
.remove(dotPos
+1, newStr
.length());
163 // Get a list of files associated with a file, e.g.:
165 // File: /home/a/courier.pfa
167 // Associated: /home/a/courier.afm /home/a/courier.pfm
169 void getAssociatedFiles(const QString
&path
, QStringList
&files
, bool afmAndPfm
)
172 int dotPos(ext
.lastIndexOf('.'));
175 if(-1==dotPos
) // Hmm, no extension - check anyway...
177 else // Cool, got an extension - see if its a Type1 font...
179 ext
=ext
.mid(dotPos
+1);
180 check
=0==ext
.compare("pfa", Qt::CaseInsensitive
) ||
181 0==ext
.compare("pfb", Qt::CaseInsensitive
);
186 const char *afm
[]={"afm", "AFM", "Afm", NULL
},
187 *pfm
[]={"pfm", "PFM", "Pfm", NULL
};
191 for(e
=0; afm
[e
]; ++e
)
193 QString
statFile(changeExt(path
, afm
[e
]));
195 if(fExists(statFile
))
197 files
.append(statFile
);
203 if(afmAndPfm
|| !gotAfm
)
204 for(e
=0; pfm
[e
]; ++e
)
206 QString
statFile(changeExt(path
, pfm
[e
]));
208 if(fExists(statFile
))
210 files
.append(statFile
);
217 time_t getTimeStamp(const QString
&item
)
219 KDE_struct_stat info
;
221 return !item
.isEmpty() && 0==KDE_lstat(QFile::encodeName(item
), &info
) ? info
.st_mtime
: 0;
225 bool check(const QString
&path
, bool file
, bool checkW
)
227 KDE_struct_stat info
;
228 QByteArray
pathC(QFile::encodeName(path
));
230 return 0==KDE_lstat(pathC
, &info
) &&
231 (file
? (S_ISREG(info
.st_mode
) || S_ISLNK(info
.st_mode
))
232 : S_ISDIR(info
.st_mode
)) &&
233 (!checkW
|| 0==::access(pathC
, W_OK
));
236 QString
getFolder(const QString
&defaultDir
, const QString
&root
, QStringList
&dirs
)
238 if(dirs
.contains(defaultDir
))
242 QStringList::const_iterator it
,
246 for(it
=dirs
.constBegin(); it
!=end
&& !found
; ++it
)
247 if(0==(*it
).indexOf(root
))
254 bool checkExt(const QString
&fname
, const QString
&ext
)
256 QString
extension('.'+ext
);
258 return fname
.length()>extension
.length()
259 ? 0==fname
.mid(fname
.length()-extension
.length()).compare(extension
, Qt::CaseInsensitive
)
263 bool isMetrics(const QString
&str
)
265 return checkExt(str
, "afm") || checkExt(str
, "pfm");
268 int getIntQueryVal(const KUrl
&url
, const char *key
, int defVal
)
270 QString
item(url
.queryItem(key
));
279 bool printable(const QString
&mime
)
281 return "application/x-font-type1"==mime
|| "application/x-font-ttf"==mime
||
282 "application/x-font-otf"==mime
|| "application/x-font-type1"==mime
;
285 uint
qHash(const KFI::Misc::TFont
&key
)
287 //return qHash(QString(key.family+'%'+QString().setNum(key.styleInfo, 16)));
288 const QChar
*p
= key
.family
.unicode();
289 int n
= key
.family
.size();
293 h
= (h
<< 4) + key
.styleInfo
;
294 if ((g
= (h
& 0xf0000000)) != 0)
300 h
= (h
<< 4) + (*p
++).unicode();
301 if ((g
= (h
& 0xf0000000)) != 0)
309 // mkfontscale doesn't ingore hidden files :-(
310 static void removeHiddenEntries(const QString
&file
)
315 if(f
.open(QIODevice::ReadOnly
))
317 QTextStream
stream(&f
);
320 int lineCount
=stream
.readLine().toInt(); // Ignore line count...
322 while(!stream
.atEnd())
324 line
=stream
.readLine();
325 if(line
.length() && '.'!=line
[0])
330 if(lineCount
!=lines
.count())
334 temp
.setAutoRemove(false);
339 QFile
out(temp
.fileName());
341 if(out
.open(QIODevice::WriteOnly
))
343 QTextStream
stream(&out
);
344 QStringList::ConstIterator
it(lines
.begin()),
347 stream
<< lines
.count() << endl
;
349 stream
<< (*it
).toLocal8Bit() << endl
;
351 out
.setPermissions(QFile::ReadOwner
|QFile::WriteOwner
|
352 QFile::ReadGroup
|QFile::ReadOther
);
354 ::rename(QFile::encodeName(out
.fileName()), QFile::encodeName(file
));
357 temp
.setAutoRemove(true);
362 bool configureForX11(const QString
&dir
)
365 // On systems without mkfontscale, the following will fail, so cant base
366 // return value upon that - hence only check return value of mkfontdir
367 doCmd("mkfontscale", QFile::encodeName(dir
));
368 removeHiddenEntries(dir
+"fonts.scale");
369 bool rv
=doCmd("mkfontdir", QFile::encodeName(dir
));
370 removeHiddenEntries(dir
+"fonts.dir");
374 // Taken from qdom.cpp
375 QString
encodeText(const QString
&str
, QTextStream
&s
)
377 const QTextCodec
*const codec
= s
.codec();
382 int len
= retval
.length(),
387 const QChar
ati(retval
.at(i
));
389 if (ati
== QLatin1Char('<'))
391 retval
.replace(i
, 1, QLatin1String("<"));
395 else if (ati
== QLatin1Char('"'))
397 retval
.replace(i
, 1, QLatin1String("""));
401 else if (ati
== QLatin1Char('&'))
403 retval
.replace(i
, 1, QLatin1String("&"));
407 else if (ati
== QLatin1Char('>') && i
>= 2 && retval
[i
- 1] == QLatin1Char(']') && retval
[i
- 2] == QLatin1Char(']'))
409 retval
.replace(i
, 1, QLatin1String(">"));
415 if(codec
->canEncode(ati
))
419 // We have to use a character reference to get it through.
420 const ushort
codepoint(ati
.unicode());
421 const QString
replacement(QLatin1String("&#x") + QString::number(codepoint
, 16) + QLatin1Char(';'));
422 retval
.replace(i
, 1, replacement
);
423 i
+= replacement
.length();
424 len
+= replacement
.length() - 1;
432 QString
contractHome(QString path
)
434 if (!path
.isEmpty() && '/'==path
[0])
436 QString
home(QDir::homePath());
438 if(path
.startsWith(home
))
440 int len
= home
.length();
442 if(len
>1 && (path
.length() == len
|| path
[len
] == '/'))
443 return path
.replace(0, len
, QString::fromLatin1("~"));