• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KDECore

  • kdecore
  • services
kmimetyperepository.cpp
Go to the documentation of this file.
1/* This file is part of the KDE libraries
2 * Copyright (C) 2006-2007, 2010 David Faure <faure@kde.org>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#include "kmimetyperepository_p.h"
21#include <kstandarddirs.h>
22#include <ksharedconfig.h>
23#include <kconfiggroup.h>
24#include "kmimetype.h"
25#include <kdeversion.h> // KDE_MAKE_VERSION
26#include <kmessage.h>
27#include <klocale.h>
28#include "kfoldermimetype.h"
29#include <QFile>
30#include <QProcess>
31#include <QtEndian>
32
33extern int servicesDebugArea();
34
35KMimeTypeRepository * KMimeTypeRepository::self()
36{
37 K_GLOBAL_STATIC(KMimeTypeRepository, s_self)
38 return s_self;
39}
40
41KMimeTypeRepository::KMimeTypeRepository()
42 : m_parentsMapLoaded(false),
43 m_magicFilesParsed(false),
44 m_aliasFilesParsed(false),
45 m_globsFilesParsed(false),
46 m_patternsMapCalculated(false),
47 m_mimeTypesChecked(false),
48 m_useFavIcons(true),
49 m_useFavIconsChecked(false),
50 m_sharedMimeInfoVersion(0),
51 m_mutex(QReadWriteLock::Recursive)
52{
53}
54
55KMimeTypeRepository::~KMimeTypeRepository()
56{
57}
58
59KMimeType::Ptr KMimeTypeRepository::findMimeTypeByName(const QString &_name, KMimeType::FindByNameOption options)
60{
61 QString name = _name;
62 if (options & KMimeType::ResolveAliases) {
63 name = canonicalName(name);
64 }
65
66 const QString filename = name + QLatin1String(".xml");
67
68 if (KStandardDirs::locate("xdgdata-mime", filename).isEmpty()) {
69 return KMimeType::Ptr(); // Not found
70 }
71
72 if (name == QLatin1String("inode/directory"))
73 return KMimeType::Ptr(new KFolderMimeType(filename, name, QString() /*comment*/));
74 else
75 return KMimeType::Ptr(new KMimeType(filename, name, QString() /*comment*/));
76}
77
78bool KMimeTypeRepository::checkMimeTypes()
79{
80 // check if there are mimetypes
81 const QStringList globFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", QLatin1String("globs"));
82 return !globFiles.isEmpty();
83}
84
85QString KMimeTypeRepository::resolveAlias(const QString& mime)
86{
87 return aliases().value(mime);
88}
89
90QString KMimeTypeRepository::canonicalName(const QString& mime)
91{
92 QString c = resolveAlias(mime);
93 if (c.isEmpty())
94 return mime;
95 return c;
96}
97
98bool KMimeTypeRepository::matchFileName( const QString &filename, const QString &pattern )
99{
100 const int pattern_len = pattern.length();
101 if (!pattern_len)
102 return false;
103 const int len = filename.length();
104
105 const int starCount = pattern.count(QLatin1Char('*'));
106
107 // Patterns like "*~", "*.extension"
108 if (pattern[0] == QLatin1Char('*') && pattern.indexOf(QLatin1Char('[')) == -1 && starCount == 1)
109 {
110 if ( len + 1 < pattern_len ) return false;
111
112 const QChar *c1 = pattern.unicode() + pattern_len - 1;
113 const QChar *c2 = filename.unicode() + len - 1;
114 int cnt = 1;
115 while (cnt < pattern_len && *c1-- == *c2--)
116 ++cnt;
117 return cnt == pattern_len;
118 }
119
120 // Patterns like "README*" (well this is currently the only one like that...)
121 if (starCount == 1 && pattern[pattern_len - 1] == QLatin1Char('*')) {
122 if ( len + 1 < pattern_len ) return false;
123 if (pattern[0] == QLatin1Char('*'))
124 return filename.indexOf(pattern.mid(1, pattern_len - 2)) != -1;
125
126 const QChar *c1 = pattern.unicode();
127 const QChar *c2 = filename.unicode();
128 int cnt = 1;
129 while (cnt < pattern_len && *c1++ == *c2++)
130 ++cnt;
131 return cnt == pattern_len;
132 }
133
134 // Names without any wildcards like "README"
135 if (pattern.indexOf(QLatin1Char('[')) == -1 && starCount == 0 && pattern.indexOf(QLatin1Char('?')))
136 return (pattern == filename);
137
138 // Other (quite rare) patterns, like "*.anim[1-9j]": use slow but correct method
139 QRegExp rx(pattern);
140 rx.setPatternSyntax(QRegExp::Wildcard);
141 return rx.exactMatch(filename);
142}
143
144// Helper for findFromFileName
145void KMimeTypeRepository::findFromOtherPatternList(QStringList& matchingMimeTypes,
146 const QString &fileName,
147 QString& foundExt,
148 bool highWeight)
149{
150 KMimeGlobsFileParser::GlobList& patternList = highWeight ? m_globs.m_highWeightGlobs : m_globs.m_lowWeightGlobs;
151
152 int matchingPatternLength = 0;
153 qint32 lastMatchedWeight = 0;
154 if (!highWeight && !matchingMimeTypes.isEmpty()) {
155 // We found matches in the fast pattern dict already:
156 matchingPatternLength = foundExt.length() + 2; // *.foo -> length=5
157 lastMatchedWeight = 50;
158 }
159
160 // "Applications MUST match globs case-insensitively, except when the case-sensitive
161 // attribute is set to true."
162 // KMimeGlobsFileParser takes care of putting case-insensitive patterns in lowercase.
163 const QString lowerCaseFileName = fileName.toLower();
164
165 KMimeGlobsFileParser::GlobList::const_iterator it = patternList.constBegin();
166 const KMimeGlobsFileParser::GlobList::const_iterator end = patternList.constEnd();
167 for ( ; it != end; ++it ) {
168 const KMimeGlobsFileParser::Glob& glob = *it;
169 if ( matchFileName( (glob.flags & CaseSensitive) ? fileName : lowerCaseFileName, glob.pattern ) ) {
170 // Is this a lower-weight pattern than the last match? Stop here then.
171 if (glob.weight < lastMatchedWeight)
172 break;
173 if (lastMatchedWeight > 0 && glob.weight > lastMatchedWeight) // can't happen
174 kWarning(servicesDebugArea()) << "Assumption failed; globs2 weights not sorted correctly"
175 << glob.weight << ">" << lastMatchedWeight;
176 // Is this a shorter or a longer match than an existing one, or same length?
177 if (glob.pattern.length() < matchingPatternLength) {
178 continue; // too short, ignore
179 } else if (glob.pattern.length() > matchingPatternLength) {
180 // longer: clear any previous match (like *.bz2, when pattern is *.tar.bz2)
181 matchingMimeTypes.clear();
182 // remember the new "longer" length
183 matchingPatternLength = glob.pattern.length();
184 }
185 matchingMimeTypes.push_back(glob.mimeType);
186 if (glob.pattern.startsWith(QLatin1String("*.")))
187 foundExt = glob.pattern.mid(2);
188 }
189 }
190}
191
192QStringList KMimeTypeRepository::findFromFileName(const QString &fileName, QString *pMatchingExtension)
193{
194 m_mutex.lockForWrite();
195 parseGlobs();
196 m_mutex.unlock();
197
198 QReadLocker lock(&m_mutex);
199 // First try the high weight matches (>50), if any.
200 QStringList matchingMimeTypes;
201 QString foundExt;
202 findFromOtherPatternList(matchingMimeTypes, fileName, foundExt, true);
203 if (matchingMimeTypes.isEmpty()) {
204
205 // Now use the "fast patterns" dict, for simple *.foo patterns with weight 50
206 // (which is most of them, so this optimization is definitely worth it)
207 const int lastDot = fileName.lastIndexOf(QLatin1Char('.'));
208 if (lastDot != -1) { // if no '.', skip the extension lookup
209 const int ext_len = fileName.length() - lastDot - 1;
210 const QString simpleExtension = fileName.right( ext_len ).toLower();
211 // (toLower because fast matterns are always case-insensitive and saved as lowercase)
212
213 matchingMimeTypes = m_globs.m_fastPatterns.value(simpleExtension);
214 if (!matchingMimeTypes.isEmpty()) {
215 foundExt = simpleExtension;
216 // Can't return yet; *.tar.bz2 has to win over *.bz2, so we need the low-weight mimetypes anyway,
217 // at least those with weight 50.
218 }
219 }
220
221 // Finally, try the low weight matches (<=50)
222 findFromOtherPatternList(matchingMimeTypes, fileName, foundExt, false);
223 }
224 if (pMatchingExtension)
225 *pMatchingExtension = foundExt;
226 return matchingMimeTypes;
227}
228
229KMimeType::Ptr KMimeTypeRepository::findFromContent(QIODevice* device, int* accuracy, QByteArray& beginning)
230{
231 Q_ASSERT(device->isOpen());
232 const qint64 deviceSize = device->size();
233 if (deviceSize == 0) {
234 if (accuracy)
235 *accuracy = 100;
236 return findMimeTypeByName(QLatin1String("application/x-zerosize"));
237 }
238 if (beginning.isEmpty()) {
239 // check if we can really read the data; also provide enough data for most rules
240 const qint64 dataNeeded = qMin(deviceSize, (qint64) 16384);
241 beginning.resize(dataNeeded);
242 if (!device->seek(0) || device->read(beginning.data(), dataNeeded) == -1) {
243 return defaultMimeTypePtr(); // don't bother detecting unreadable file
244 }
245 }
246
247 m_mutex.lockForWrite();
248 if (!m_magicFilesParsed) {
249 parseMagic();
250 m_magicFilesParsed = true;
251 }
252 m_mutex.unlock();
253
254 // Apply magic rules
255 {
256 QReadLocker lock(&m_mutex);
257 Q_FOREACH ( const KMimeMagicRule& rule, m_magicRules ) {
258 if (rule.match(device, deviceSize, beginning)) {
259 if (accuracy)
260 *accuracy = rule.priority();
261 return findMimeTypeByName(rule.mimetype());
262 }
263 }
264 }
265
266 // Do fallback code so that we never return 0
267 // Nothing worked, check if the file contents looks like binary or text
268 if (!KMimeType::isBufferBinaryData(beginning)) {
269 if (accuracy)
270 *accuracy = 5;
271 return findMimeTypeByName(QLatin1String("text/plain"));
272 }
273 if (accuracy)
274 *accuracy = 0;
275 return defaultMimeTypePtr();
276}
277
278static QString fallbackParent(const QString& mimeTypeName)
279{
280 const QString myGroup = mimeTypeName.left(mimeTypeName.indexOf(QLatin1Char('/')));
281 // All text/* types are subclasses of text/plain.
282 if (myGroup == QLatin1String("text") && mimeTypeName != QLatin1String("text/plain"))
283 return QLatin1String("text/plain");
284 // All real-file mimetypes implicitly derive from application/octet-stream
285 if (myGroup != QLatin1String("inode") &&
286 // kde extensions
287 myGroup != QLatin1String("all") && myGroup != QLatin1String("fonts") && myGroup != QLatin1String("print") && myGroup != QLatin1String("uri")
288 && mimeTypeName != QLatin1String("application/octet-stream")) {
289 return QLatin1String("application/octet-stream");
290 }
291 return QString();
292}
293
294QStringList KMimeTypeRepository::parents(const QString& mime)
295{
296 QWriteLocker lock(&m_mutex);
297 if (!m_parentsMapLoaded) {
298 m_parentsMapLoaded = true;
299 Q_ASSERT(m_parents.isEmpty());
300
301 const QStringList subclassFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", QLatin1String("subclasses"));
302 //kDebug() << subclassFiles;
303 Q_FOREACH(const QString& fileName, subclassFiles) {
304
305 QFile qfile( fileName );
306 //kDebug(7021) << "Now parsing" << fileName;
307 if (qfile.open(QIODevice::ReadOnly)) {
308 QTextStream stream(&qfile);
309 stream.setCodec("ISO 8859-1");
310 while (!stream.atEnd()) {
311 const QString line = stream.readLine();
312 if (line.isEmpty() || line[0] == QLatin1Char('#'))
313 continue;
314 const int pos = line.indexOf(QLatin1Char(' '));
315 if (pos == -1) // syntax error
316 continue;
317 const QString derivedTypeName = line.left(pos);
318 KMimeType::Ptr derivedType = findMimeTypeByName(derivedTypeName, KMimeType::ResolveAliases);
319 if (!derivedType)
320 kDebug() << fileName << " refers to unknown mimetype " << derivedTypeName;
321 else {
322 const QString parentTypeName = line.mid(pos+1);
323 Q_ASSERT(!parentTypeName.isEmpty());
324 //derivedType->setParentMimeType(parentTypeName);
325 m_parents[derivedTypeName].append(parentTypeName);
326 }
327 }
328 }
329 }
330 }
331 QStringList parents = m_parents.value(mime);
332
333 if (parents.isEmpty()) {
334 const QString myParent = fallbackParent(mime);
335 if (!myParent.isEmpty())
336 parents.append(myParent);
337 }
338
339 return parents;
340}
341
342#include <arpa/inet.h> // for ntohs
343#include <kstandarddirs.h>
344#include <QFile>
345
346// Sort them in descending order of priority
347static bool mimeMagicRuleCompare(const KMimeMagicRule& lhs, const KMimeMagicRule& rhs) {
348 return lhs.priority() > rhs.priority();
349}
350
351// Caller must hold m_mutex
352void KMimeTypeRepository::parseMagic()
353{
354 const QStringList magicFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", QLatin1String("magic"));
355 //kDebug() << magicFiles;
356 QListIterator<QString> magicIter( magicFiles );
357 magicIter.toBack();
358 while (magicIter.hasPrevious()) { // global first, then local. Turns out it doesn't matter though.
359 const QString fileName = magicIter.previous();
360 QFile magicFile(fileName);
361 //kDebug(servicesDebugArea()) << "Now parsing " << fileName;
362 if (magicFile.open(QIODevice::ReadOnly))
363 m_magicRules += parseMagicFile(&magicFile, fileName);
364 }
365 qSort(m_magicRules.begin(), m_magicRules.end(), mimeMagicRuleCompare);
366}
367
368static char readNumber(qint64& value, QIODevice* file)
369{
370 char ch;
371 while (file->getChar(&ch)) {
372 if (ch < '0' || ch > '9')
373 return ch;
374 value = 10 * value + ch - '0';
375 }
376 // eof
377 return '\0';
378}
379
380
381#define MAKE_LITTLE_ENDIAN16(val) val = (quint16)(((quint16)(val) << 8)|((quint16)(val) >> 8))
382
383#define MAKE_LITTLE_ENDIAN32(val) \
384 val = (((quint32)(val) & 0xFF000000U) >> 24) | \
385 (((quint32)(val) & 0x00FF0000U) >> 8) | \
386 (((quint32)(val) & 0x0000FF00U) << 8) | \
387 (((quint32)(val) & 0x000000FFU) << 24)
388
389QList<KMimeMagicRule> KMimeTypeRepository::parseMagicFile(QIODevice* file, const QString& fileName) const
390{
391 QList<KMimeMagicRule> rules;
392 QByteArray header = file->read(12);
393 if (header != QByteArray::fromRawData("MIME-Magic\0\n", 12)) {
394 kWarning(servicesDebugArea()) << "Invalid magic file " << fileName << " starts with " << header;
395 return rules;
396 }
397 QList<KMimeMagicMatch> matches; // toplevel matches (indent==0)
398 int priority = 0; // to avoid warning
399 QString mimeTypeName;
400
401 Q_FOREVER {
402 char ch = '\0';
403 bool chOk = file->getChar(&ch);
404
405 if (!chOk || ch == '[') {
406 // Finish previous section
407 if (!mimeTypeName.isEmpty()) {
408 rules.append(KMimeMagicRule(mimeTypeName, priority, matches));
409 matches.clear();
410 mimeTypeName.clear();
411 }
412 if (file->atEnd())
413 break; // done
414
415 // Parse new section
416 const QString line = QString::fromLatin1(file->readLine());
417 const int pos = line.indexOf(QLatin1Char(':'));
418 if (pos == -1) { // syntax error
419 kWarning(servicesDebugArea()) << "Syntax error in " << mimeTypeName
420 << " ':' not present in section name" << endl;
421 break;
422 }
423 priority = line.left(pos).toInt();
424 mimeTypeName = line.mid(pos+1);
425 mimeTypeName = mimeTypeName.left(mimeTypeName.length()-2); // remove ']\n'
426 //kDebug(servicesDebugArea()) << "New rule for " << mimeTypeName
427 // << " with priority " << priority << endl;
428 } else {
429 // Parse line in the section
430 // [ indent ] ">" start-offset "=" value
431 // [ "&" mask ] [ "~" word-size ] [ "+" range-length ] "\n"
432 qint64 indent = 0;
433 if (ch != '>') {
434 indent = ch - '0';
435 ch = readNumber(indent, file);
436 if (ch != '>') {
437 kWarning(servicesDebugArea()) << "Invalid magic file " << fileName << " '>' not found, got " << ch << " at pos " << file->pos();
438 break;
439 }
440 }
441
442 KMimeMagicMatch match;
443 match.m_rangeStart = 0;
444 ch = readNumber(match.m_rangeStart, file);
445 if (ch != '=') {
446 kWarning(servicesDebugArea()) << "Invalid magic file " << fileName << " '=' not found";
447 break;
448 }
449
450 qint16 lengthBuffer;
451 if (file->read(reinterpret_cast<char*>(&lengthBuffer), 2) != 2)
452 break;
453 const qint16 valueLength = qFromBigEndian(lengthBuffer);
454 //kDebug() << "indent=" << indent << " rangeStart=" << match.m_rangeStart
455 // << " valueLength=" << valueLength << endl;
456
457 match.m_data.resize(valueLength);
458 if (file->read(match.m_data.data(), valueLength) != valueLength)
459 break;
460
461 match.m_rangeLength = 1;
462 bool invalidLine = false;
463
464 if (!file->getChar(&ch))
465 break;
466 qint64 wordSize = 1;
467
468 Q_FOREVER {
469 // We get 'ch' before coming here, or as part of the parsing in each case below.
470 switch (ch) {
471 case '\n':
472 break;
473 case '&':
474 match.m_mask.resize(valueLength);
475 if (file->read(match.m_mask.data(), valueLength) != valueLength)
476 invalidLine = true;
477 if (!file->getChar(&ch))
478 invalidLine = true;
479 break;
480 case '~': {
481 wordSize = 0;
482 ch = readNumber(wordSize, file);
483 //kDebug() << "wordSize=" << wordSize;
484 break;
485 }
486 case '+':
487 // Parse range length
488 match.m_rangeLength = 0;
489 ch = readNumber(match.m_rangeLength, file);
490 if (ch == '\n')
491 break;
492 // fall-through intended
493 default:
494 // "If an unknown character is found where a newline is expected
495 // then the whole line should be ignored (there will be no binary
496 // data after the new character, so the next line starts after the
497 // next "\n" character). This is for future extensions.", says spec
498 while (ch != '\n' && !file->atEnd()) {
499 file->getChar(&ch);
500 }
501 invalidLine = true;
502 kDebug(servicesDebugArea()) << "invalid line - garbage found - ch=" << ch;
503 break;
504 }
505 if (ch == '\n' || invalidLine)
506 break;
507 }
508 if (!invalidLine) {
509 // Finish match, doing byte-swapping on little endian hosts
510#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
511 if (wordSize > 1) {
512 //kDebug() << "data before swapping: " << match.m_data;;
513 if ((wordSize != 2 && wordSize != 4) || (valueLength % wordSize != 0))
514 continue; // invalid word size
515 char* data = match.m_data.data();
516 char* mask = match.m_mask.data();
517 for (int i = 0; i < valueLength; i += wordSize) {
518 if (wordSize == 2)
519 MAKE_LITTLE_ENDIAN16( *((quint16 *) data + i) );
520 else if (wordSize == 4)
521 MAKE_LITTLE_ENDIAN32( *((quint32 *) data + i) );
522 if (!match.m_mask.isEmpty()) {
523 if (wordSize == 2)
524 MAKE_LITTLE_ENDIAN16( *((quint16 *) mask + i) );
525 else if (wordSize == 4)
526 MAKE_LITTLE_ENDIAN32( *((quint32 *) mask + i) );
527 }
528 }
529 //kDebug() << "data after swapping: " << match.m_data;
530 }
531#endif
532 // Append match at the right place depending on indent:
533 if (indent == 0) {
534 matches.append(match);
535 } else {
536 KMimeMagicMatch* m = &matches.last();
537 Q_ASSERT(m);
538 for (int i = 1 /* nothing to do for indent==1 */; i < indent; ++i) {
539 m = &m->m_subMatches.last();
540 Q_ASSERT(m);
541 }
542 m->m_subMatches.append(match);
543 }
544 }
545 }
546 }
547 return rules;
548}
549
550const KMimeTypeRepository::AliasesMap& KMimeTypeRepository::aliases()
551{
552 QWriteLocker lock(&m_mutex);
553 if (!m_aliasFilesParsed) {
554 m_aliasFilesParsed = true;
555
556 const QStringList aliasFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", QLatin1String("aliases"));
557 Q_FOREACH(const QString& fileName, aliasFiles) {
558 QFile qfile(fileName);
559 //kDebug(7021) << "Now parsing" << fileName;
560 if (qfile.open(QIODevice::ReadOnly)) {
561 QTextStream stream(&qfile);
562 stream.setCodec("ISO 8859-1");
563 while (!stream.atEnd()) {
564 const QString line = stream.readLine();
565 if (line.isEmpty() || line[0] == QLatin1Char('#'))
566 continue;
567 const int pos = line.indexOf(QLatin1Char(' '));
568 if (pos == -1) // syntax error
569 continue;
570 const QString aliasTypeName = line.left(pos);
571 const QString parentTypeName = line.mid(pos+1);
572 Q_ASSERT(!aliasTypeName.isEmpty());
573 Q_ASSERT(!parentTypeName.isEmpty());
574
575 const KMimeType::Ptr realMimeType =
576 findMimeTypeByName(aliasTypeName, KMimeType::DontResolveAlias);
577 if (realMimeType) {
578 //kDebug(servicesDebugArea()) << "Ignoring alias" << aliasTypeName << "because also defined as a real mimetype";
579 } else {
580 m_aliases.insert(aliasTypeName, parentTypeName);
581 }
582 }
583 }
584 }
585 }
586 return m_aliases;
587}
588
589// Caller must lock m_mutex for write
590void KMimeTypeRepository::parseGlobs()
591{
592 if (!m_globsFilesParsed) {
593 m_globsFilesParsed = true;
594 KMimeGlobsFileParser parser;
595 m_globs = parser.parseGlobs();
596 }
597}
598
599QStringList KMimeTypeRepository::patternsForMimetype(const QString& mimeType)
600{
601 QWriteLocker lock(&m_mutex);
602 if (!m_patternsMapCalculated) {
603 m_patternsMapCalculated = true;
604 parseGlobs();
605 m_patterns = m_globs.patternsMap();
606 }
607 return m_patterns.value(mimeType);
608}
609
610static void errorMissingMimeTypes( const QStringList& _types )
611{
612 KMessage::message( KMessage::Error, i18np( "Could not find mime type <resource>%2</resource>",
613 "Could not find mime types:\n<resource>%2</resource>", _types.count(), _types.join(QLatin1String("</resource>\n<resource>")) ) );
614}
615
616void KMimeTypeRepository::checkEssentialMimeTypes()
617{
618 QWriteLocker lock(&m_mutex);
619 if (m_mimeTypesChecked) // already done
620 return;
621
622 m_mimeTypesChecked = true; // must be done before building mimetypes
623
624 // No Mime-Types installed ?
625 // Lets do some rescue here.
626 if (!checkMimeTypes()) {
627 // Note that this messagebox is queued, so it will only be shown once getting back to the event loop
628
629 // No mimetypes installed? Are you setting XDG_DATA_DIRS without including /usr/share in it?
630 KMessage::message(KMessage::Error, i18n("No mime types installed. "
631 "Check that shared-mime-info is installed, and that XDG_DATA_DIRS is not set, or includes /usr/share."));
632 return; // no point in going any further
633 }
634
635 QStringList missingMimeTypes;
636
637 if (!KMimeType::mimeType(QLatin1String("inode/directory")))
638 missingMimeTypes.append(QLatin1String("inode/directory"));
639#ifndef Q_OS_WIN
640 //if (!KMimeType::mimeType(QLatin1String("inode/directory-locked")))
641 // missingMimeTypes.append(QLatin1String("inode/directory-locked"));
642 if (!KMimeType::mimeType(QLatin1String("inode/blockdevice")))
643 missingMimeTypes.append(QLatin1String("inode/blockdevice"));
644 if (!KMimeType::mimeType(QLatin1String("inode/chardevice")))
645 missingMimeTypes.append(QLatin1String("inode/chardevice"));
646 if (!KMimeType::mimeType(QLatin1String("inode/socket")))
647 missingMimeTypes.append(QLatin1String("inode/socket"));
648 if (!KMimeType::mimeType(QLatin1String("inode/fifo")))
649 missingMimeTypes.append(QLatin1String("inode/fifo"));
650#endif
651 if (!KMimeType::mimeType(QLatin1String("application/x-shellscript")))
652 missingMimeTypes.append(QLatin1String("application/x-shellscript"));
653 if (!KMimeType::mimeType(QLatin1String("application/x-executable")))
654 missingMimeTypes.append(QLatin1String("application/x-executable"));
655 if (!KMimeType::mimeType(QLatin1String("application/x-desktop")))
656 missingMimeTypes.append(QLatin1String("application/x-desktop"));
657
658 if (!missingMimeTypes.isEmpty())
659 errorMissingMimeTypes(missingMimeTypes);
660}
661
662KMimeType::Ptr KMimeTypeRepository::defaultMimeTypePtr()
663{
664 QWriteLocker lock(&m_mutex);
665 if (!m_defaultMimeType) {
666 // Try to find the default type
667 KMimeType::Ptr mime = findMimeTypeByName(KMimeType::defaultMimeType());
668 if (mime) {
669 m_defaultMimeType = mime;
670 } else {
671 const QString defaultMimeType = KMimeType::defaultMimeType();
672 errorMissingMimeTypes(QStringList(defaultMimeType));
673 const QString pathDefaultMimeType = KGlobal::dirs()->locateLocal("xdgdata-mime", defaultMimeType+QLatin1String(".xml"));
674 m_defaultMimeType = new KMimeType(pathDefaultMimeType, defaultMimeType, QLatin1String("mime"));
675 }
676 }
677 return m_defaultMimeType;
678
679}
680
681bool KMimeTypeRepository::useFavIcons()
682{
683 // this method will be called quite often, so better not read the config
684 // again and again.
685 m_mutex.lockForWrite();
686 if (!m_useFavIconsChecked) {
687 m_useFavIconsChecked = true;
688 KConfigGroup cg( KGlobal::config(), "HTML Settings" );
689 m_useFavIcons = cg.readEntry("EnableFavicon", true);
690 }
691 m_mutex.unlock();
692 return m_useFavIcons;
693}
694
695static void addPlatformSpecificPkgConfigPath(QStringList& paths)
696{
697#if defined (Q_OS_FREEBSD)
698 paths << QLatin1String("/usr/local/libdata/pkgconfig"); // FreeBSD
699#elif defined(Q_OS_OPENBSD) || defined(Q_OS_NETBSD) || defined(Q_OS_SOLARIS)
700 paths << QLatin1String("/usr/local/lib/pkgconfig"); // {Net,Open}BSD/OpenSolaris
701#elif defined (Q_OS_UNIX)
702 paths << QLatin1String("/usr/share/pkgconfig"); // Linux and all other unix
703#endif
704}
705
706static int mimeDataBaseVersion()
707{
708 // shared-mime-info installs a "version" file since 0.91
709 const QStringList versionFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", QLatin1String("version"));
710 if (!versionFiles.isEmpty()) {
711 QFile file(versionFiles.first()); // Look at the global file, not at a possibly old local one
712 if (file.open(QIODevice::ReadOnly)) {
713 const QByteArray line = file.readLine().simplified();
714 QRegExp versionRe(QString::fromLatin1("(\\d+)\\.(\\d+)(\\.(\\d+))?"));
715 if (versionRe.indexIn(QString::fromLocal8Bit(line)) > -1) {
716 return KDE_MAKE_VERSION(versionRe.cap(1).toInt(), versionRe.cap(2).toInt(), versionRe.cap(4).toInt());
717 }
718 }
719 }
720
721 // TODO: Remove the #idef'ed code below once the issue is fixed
722 // in QProcess or when we require s-m-i >= 0.91
723#ifdef Q_OS_UNIX
724 // Try to read the version number from the shared-mime-info.pc file
725 QStringList paths;
726 const QByteArray pkgConfigPath = qgetenv("PKG_CONFIG_PATH");
727 if (!pkgConfigPath.isEmpty()) {
728 paths << QFile::decodeName(pkgConfigPath).split(QLatin1Char(':'), QString::SkipEmptyParts);
729 }
730
731 // Add platform specific hard-coded default paths to the list...
732 addPlatformSpecificPkgConfigPath(paths);
733
734 Q_FOREACH(const QString& path, paths) {
735 const QString fileName = path + QLatin1String("/shared-mime-info.pc");
736 if (!QFile::exists(fileName)) {
737 continue;
738 }
739
740 QFile file (fileName);
741 if (!file.open(QIODevice::ReadOnly)) {
742 break;
743 }
744
745 while (!file.atEnd()) {
746 const QByteArray line = file.readLine().simplified();
747 if (!line.startsWith("Version")) { // krazy:exclude=strings
748 continue;
749 }
750 QRegExp versionRe(QString::fromLatin1("Version: (\\d+)\\.(\\d+)(\\.(\\d+))?"));
751 if (versionRe.indexIn(QString::fromLocal8Bit(line)) > -1) {
752 return KDE_MAKE_VERSION(versionRe.cap(1).toInt(), versionRe.cap(2).toInt(), versionRe.cap(4).toInt());
753 }
754 }
755 }
756#endif
757
758 // Execute "update-mime-database -v" to determine version number.
759 // NOTE: On *nix, the code below is known to cause freezes/hangs in apps
760 // that block signals. See https://bugs.kde.org/show_bug.cgi?id=260719.
761 const QString umd = KStandardDirs::findExe(QString::fromLatin1("update-mime-database"));
762 if (umd.isEmpty()) {
763 kWarning(servicesDebugArea()) << "update-mime-database not found!";
764 return -1;
765 }
766
767 QProcess smi;
768 smi.start(umd, QStringList() << QString::fromLatin1("-v"));
769 if (smi.waitForStarted() && smi.waitForFinished()) {
770 const QString out = QString::fromLocal8Bit(smi.readAllStandardError());
771 QRegExp versionRe(QString::fromLatin1("update-mime-database \\(shared-mime-info\\) (\\d+)\\.(\\d+)(\\.(\\d+))?"));
772 if (versionRe.indexIn(out) > -1) {
773 return KDE_MAKE_VERSION(versionRe.cap(1).toInt(), versionRe.cap(2).toInt(), versionRe.cap(4).toInt());
774 }
775 kWarning(servicesDebugArea()) << "Unexpected version scheme from update-mime-database -v: got" << out;
776 } else {
777 kWarning(servicesDebugArea()) << "Error running update-mime-database -v";
778 }
779
780 return -1;
781}
782
783int KMimeTypeRepository::sharedMimeInfoVersion()
784{
785 m_mutex.lockForWrite();
786 if (m_sharedMimeInfoVersion == 0)
787 m_sharedMimeInfoVersion = mimeDataBaseVersion();
788 m_mutex.unlock();
789 return m_sharedMimeInfoVersion;
790}
KConfigGroup
A class for one specific group in a KConfig object.
Definition: kconfiggroup.h:54
KConfigGroup::readEntry
T readEntry(const QString &key, const T &aDefault) const
Reads the value of an entry specified by pKey in the current group.
Definition: kconfiggroup.h:248
KFolderMimeType
Mimetype for a folder (inode/directory)
Definition: kfoldermimetype.h:35
KMimeGlobsFileParser::AllGlobs::patternsMap
PatternsMap patternsMap() const
Definition: kmimeglobsfileparser.cpp:193
KMimeGlobsFileParser::AllGlobs::m_highWeightGlobs
GlobList m_highWeightGlobs
Definition: kmimeglobsfileparser_p.h:93
KMimeGlobsFileParser::AllGlobs::m_fastPatterns
QHash< QString, QStringList > m_fastPatterns
Definition: kmimeglobsfileparser_p.h:92
KMimeGlobsFileParser::AllGlobs::m_lowWeightGlobs
GlobList m_lowWeightGlobs
Definition: kmimeglobsfileparser_p.h:94
KMimeGlobsFileParser::GlobList
Definition: kmimeglobsfileparser_p.h:55
KMimeGlobsFileParser
Definition: kmimeglobsfileparser_p.h:33
KMimeGlobsFileParser::parseGlobs
AllGlobs parseGlobs()
Definition: kmimeglobsfileparser.cpp:34
KMimeMagicRule
Definition: kmimemagicrule_p.h:54
KMimeMagicRule::match
bool match(QIODevice *device, qint64 deviceSize, QByteArray &availableData) const
Definition: kmimemagicrule.cpp:102
KMimeMagicRule::priority
int priority() const
Definition: kmimemagicrule_p.h:62
KMimeMagicRule::mimetype
QString mimetype() const
Definition: kmimemagicrule_p.h:61
KMimeTypeRepository
Definition: kmimetyperepository_p.h:37
KMimeTypeRepository::useFavIcons
bool useFavIcons()
Returns true if KMimeType::favIconForUrl should talk to kded's favicons module.
Definition: kmimetyperepository.cpp:681
KMimeTypeRepository::parents
QStringList parents(const QString &mime)
Returns the list of parents for a given mimetype.
Definition: kmimetyperepository.cpp:294
KMimeTypeRepository::sharedMimeInfoVersion
int sharedMimeInfoVersion()
Definition: kmimetyperepository.cpp:783
KMimeTypeRepository::resolveAlias
QString resolveAlias(const QString &mime)
Check if mime is an alias, and return the canonical name for it if it is, otherwise empty.
Definition: kmimetyperepository.cpp:85
KMimeTypeRepository::findMimeTypeByName
KMimeType::Ptr findMimeTypeByName(const QString &_name, KMimeType::FindByNameOption options=KMimeType::DontResolveAlias)
Creates a KMimeType.
Definition: kmimetyperepository.cpp:59
KMimeTypeRepository::patternsForMimetype
QStringList patternsForMimetype(const QString &mimeType)
Return the patterns (globs) for a given mimetype TEMPORARY method, it will go away once we can requir...
Definition: kmimetyperepository.cpp:599
KMimeTypeRepository::checkEssentialMimeTypes
void checkEssentialMimeTypes()
This function makes sure that vital mime types are installed.
Definition: kmimetyperepository.cpp:616
KMimeTypeRepository::CaseSensitive
@ CaseSensitive
Definition: kmimetyperepository_p.h:66
KMimeTypeRepository::matchFileName
static bool matchFileName(const QString &filename, const QString &pattern)
Definition: kmimetyperepository.cpp:98
KMimeTypeRepository::canonicalName
QString canonicalName(const QString &mime)
Resolve mime if it's an alias, and return it otherwise.
Definition: kmimetyperepository.cpp:90
KMimeTypeRepository::defaultMimeTypePtr
KMimeType::Ptr defaultMimeTypePtr()
Definition: kmimetyperepository.cpp:662
KMimeTypeRepository::KMimeType
friend class KMimeType
Definition: kmimetyperepository_p.h:95
KMimeTypeRepository::self
static KMimeTypeRepository * self()
Definition: kmimetyperepository.cpp:35
KMimeType::isBufferBinaryData
static bool isBufferBinaryData(const QByteArray &data)
Returns whether a buffer has an internal format that is not human readable.
Definition: kmimetype.cpp:74
KMimeType::FindByNameOption
FindByNameOption
Definition: kmimetype.h:105
KMimeType::DontResolveAlias
@ DontResolveAlias
Definition: kmimetype.h:105
KMimeType::ResolveAliases
@ ResolveAliases
Definition: kmimetype.h:105
KMimeType::defaultMimeType
static QString defaultMimeType()
Returns the name of the default mimetype.
Definition: kmimetype.cpp:597
KMimeType::mimeType
static Ptr mimeType(const QString &name, FindByNameOption options=ResolveAliases)
Retrieve a pointer to the mime type name.
Definition: kmimetype.cpp:58
KMimeType::Ptr
KSharedPtr< KMimeType > Ptr
Definition: kmimetype.h:50
KSharedPtr< KMimeType >
KStandardDirs::findExe
static QString findExe(const QString &appname, const QString &pathstr=QString(), SearchOptions options=NoSearchOptions)
Finds the executable in the system path.
Definition: kstandarddirs.cpp:1334
KStandardDirs::findAllResources
QStringList findAllResources(const char *type, const QString &filter=QString(), SearchOptions options=NoSearchOptions) const
Tries to find all resources with the specified type.
Definition: kstandarddirs.cpp:900
KStandardDirs::locateLocal
static QString locateLocal(const char *type, const QString &filename, const KComponentData &cData=KGlobal::mainComponent())
This function is much like locate.
Definition: kstandarddirs.cpp:2097
KStandardDirs::locate
static QString locate(const char *type, const QString &filename, const KComponentData &cData=KGlobal::mainComponent())
This function is just for convenience.
Definition: kstandarddirs.cpp:2091
QHash< QString, QString >
QIODevice
QList
Definition: kaboutdata.h:33
QProcess
QStringList
QString
qint32
qint64
quint32
header
const char header[]
Definition: fake/kauth-policy-gen-polkit.cpp:26
K_GLOBAL_STATIC
#define K_GLOBAL_STATIC(TYPE, NAME)
This macro makes it easy to use non-POD types as global statics.
Definition: kglobal.h:221
kDebug
#define kDebug
Definition: kdebug.h:316
kWarning
#define kWarning
Definition: kdebug.h:322
mask
#define mask
indent
QString indent(QString text, int spaces)
Definition: kconfig_compiler.cpp:1285
kconfiggroup.h
kfoldermimetype.h
klocale.h
i18n
QString i18n(const char *text)
Returns a localized version of a string.
Definition: klocalizedstring.h:630
i18np
QString i18np(const char *sing, const char *plur, const A1 &a1)
Returns a localized version of a string with 1 argument using correct plural form.
Definition: klocalizedstring.h:966
kmessage.h
servicesDebugArea
int servicesDebugArea()
Definition: kservice.cpp:47
kmimetype.h
readNumber
static char readNumber(qint64 &value, QIODevice *file)
Definition: kmimetyperepository.cpp:368
mimeMagicRuleCompare
static bool mimeMagicRuleCompare(const KMimeMagicRule &lhs, const KMimeMagicRule &rhs)
Definition: kmimetyperepository.cpp:347
fallbackParent
static QString fallbackParent(const QString &mimeTypeName)
Definition: kmimetyperepository.cpp:278
mimeDataBaseVersion
static int mimeDataBaseVersion()
Definition: kmimetyperepository.cpp:706
MAKE_LITTLE_ENDIAN32
#define MAKE_LITTLE_ENDIAN32(val)
Definition: kmimetyperepository.cpp:383
addPlatformSpecificPkgConfigPath
static void addPlatformSpecificPkgConfigPath(QStringList &paths)
Definition: kmimetyperepository.cpp:695
servicesDebugArea
int servicesDebugArea()
Definition: kservice.cpp:47
errorMissingMimeTypes
static void errorMissingMimeTypes(const QStringList &_types)
Definition: kmimetyperepository.cpp:610
MAKE_LITTLE_ENDIAN16
#define MAKE_LITTLE_ENDIAN16(val)
Definition: kmimetyperepository.cpp:381
kmimetyperepository_p.h
ksharedconfig.h
kstandarddirs.h
KGlobal::dirs
KStandardDirs * dirs()
Returns the application standard dirs object.
KGlobal::config
KSharedConfigPtr config()
Returns the general config object.
Definition: kglobal.cpp:139
KMessage::message
void message(KMessage::MessageType messageType, const QString &text, const QString &caption=QString())
Display a long message of a certain type.
Definition: kmessage.cpp:92
KMessage::Error
@ Error
Error message.
Definition: kmessage.h:57
KMimeGlobsFileParser::Glob
Definition: kmimeglobsfileparser_p.h:45
KMimeGlobsFileParser::Glob::pattern
QString pattern
Definition: kmimeglobsfileparser_p.h:50
KMimeGlobsFileParser::Glob::mimeType
QString mimeType
Definition: kmimeglobsfileparser_p.h:51
KMimeGlobsFileParser::Glob::weight
int weight
Definition: kmimeglobsfileparser_p.h:48
KMimeGlobsFileParser::Glob::flags
int flags
Definition: kmimeglobsfileparser_p.h:49
KMimeMagicMatch
Definition: kmimemagicrule_p.h:32
KMimeMagicMatch::m_subMatches
QList< KMimeMagicMatch > m_subMatches
Definition: kmimemagicrule_p.h:39
KMimeMagicMatch::m_data
QByteArray m_data
Definition: kmimemagicrule_p.h:37
KMimeMagicMatch::m_rangeStart
qint64 m_rangeStart
Definition: kmimemagicrule_p.h:35
KMimeMagicMatch::m_mask
QByteArray m_mask
Definition: kmimemagicrule_p.h:38
KMimeMagicMatch::m_rangeLength
qint64 m_rangeLength
Definition: kmimemagicrule_p.h:36
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

Skip menu "KDECore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal