• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.12 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 
33 extern int servicesDebugArea();
34 
35 KMimeTypeRepository * KMimeTypeRepository::self()
36 {
37  K_GLOBAL_STATIC(KMimeTypeRepository, s_self)
38  return s_self;
39 }
40 
41 KMimeTypeRepository::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 
55 KMimeTypeRepository::~KMimeTypeRepository()
56 {
57 }
58 
59 KMimeType::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 
78 bool 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 
85 QString KMimeTypeRepository::resolveAlias(const QString& mime)
86 {
87  return aliases().value(mime);
88 }
89 
90 QString KMimeTypeRepository::canonicalName(const QString& mime)
91 {
92  QString c = resolveAlias(mime);
93  if (c.isEmpty())
94  return mime;
95  return c;
96 }
97 
98 bool 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
145 void 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 
192 QStringList 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 
229 KMimeType::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 
278 static 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 
294 QStringList 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(7012) << 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
347 static bool mimeMagicRuleCompare(const KMimeMagicRule& lhs, const KMimeMagicRule& rhs) {
348  return lhs.priority() > rhs.priority();
349 }
350 
351 // Caller must hold m_mutex
352 void 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 
368 static 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 
389 QList<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 
550 const 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
590 void KMimeTypeRepository::parseGlobs()
591 {
592  if (!m_globsFilesParsed) {
593  m_globsFilesParsed = true;
594  KMimeGlobsFileParser parser;
595  m_globs = parser.parseGlobs();
596  }
597 }
598 
599 QStringList 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 
610 static 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 
616 void 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 
662 KMimeType::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 
681 bool 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 
695 static 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 
706 static 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 
783 int 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 }
KMimeType::Ptr
KSharedPtr< KMimeType > Ptr
Definition: kmimetype.h:50
KMimeMagicMatch::m_mask
QByteArray m_mask
Definition: kmimemagicrule_p.h:38
KMimeTypeRepository::defaultMimeTypePtr
KMimeType::Ptr defaultMimeTypePtr()
Definition: kmimetyperepository.cpp:662
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
i18n
QString i18n(const char *text)
Returns a localized version of a string.
Definition: klocalizedstring.h:630
KMimeType::ResolveAliases
Definition: kmimetype.h:105
KSharedPtr< KMimeType >
KMimeGlobsFileParser::parseGlobs
AllGlobs parseGlobs()
Definition: kmimeglobsfileparser.cpp:34
KMimeType::DontResolveAlias
Definition: kmimetype.h:105
qint64
header
const char header[]
Definition: fake/kauth-policy-gen-polkit.cpp:26
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::findMimeTypeByName
KMimeType::Ptr findMimeTypeByName(const QString &_name, KMimeType::FindByNameOption options=KMimeType::DontResolveAlias)
Creates a KMimeType.
Definition: kmimetyperepository.cpp:59
KMimeType::FindByNameOption
FindByNameOption
Definition: kmimetype.h:105
kmimetype.h
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
mask
#define mask
KFolderMimeType
Mimetype for a folder (inode/directory)
Definition: kfoldermimetype.h:34
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
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
KGlobal::dirs
KStandardDirs * dirs()
Returns the application standard dirs object.
KMimeGlobsFileParser::AllGlobs::patternsMap
PatternsMap patternsMap() const
Definition: kmimeglobsfileparser.cpp:193
KMimeMagicRule
Definition: kmimemagicrule_p.h:53
kmimetyperepository_p.h
quint32
KMimeTypeRepository::self
static KMimeTypeRepository * self()
Definition: kmimetyperepository.cpp:35
QString
QHash< QString, QString >
klocale.h
indent
QString indent(QString text, int spaces)
Definition: kconfig_compiler.cpp:1285
KMimeTypeRepository::matchFileName
static bool matchFileName(const QString &filename, const QString &pattern)
Definition: kmimetyperepository.cpp:98
MAKE_LITTLE_ENDIAN16
#define MAKE_LITTLE_ENDIAN16(val)
Definition: kmimetyperepository.cpp:381
KMimeGlobsFileParser::GlobList
Definition: kmimeglobsfileparser_p.h:54
KGlobal::config
KSharedConfigPtr config()
Returns the general config object.
Definition: kglobal.cpp:139
KMimeMagicRule::match
bool match(QIODevice *device, qint64 deviceSize, QByteArray &availableData) const
Definition: kmimemagicrule.cpp:102
KMimeGlobsFileParser::Glob::flags
int flags
Definition: kmimeglobsfileparser_p.h:49
KMimeGlobsFileParser::Glob::mimeType
QString mimeType
Definition: kmimeglobsfileparser_p.h:51
KMimeTypeRepository::parents
QStringList parents(const QString &mime)
Returns the list of parents for a given mimetype.
Definition: kmimetyperepository.cpp:294
KMimeGlobsFileParser::AllGlobs::m_highWeightGlobs
GlobList m_highWeightGlobs
Definition: kmimeglobsfileparser_p.h:93
servicesDebugArea
int servicesDebugArea()
Definition: kservice.cpp:47
KMimeMagicRule::mimetype
QString mimetype() const
Definition: kmimemagicrule_p.h:61
KMimeMagicMatch::m_data
QByteArray m_data
Definition: kmimemagicrule_p.h:37
KMimeTypeRepository::useFavIcons
bool useFavIcons()
Returns true if KMimeType::favIconForUrl should talk to kded's favicons module.
Definition: kmimetyperepository.cpp:681
KMimeGlobsFileParser
Definition: kmimeglobsfileparser_p.h:32
QStringList
KMimeMagicRule::priority
int priority() const
Definition: kmimemagicrule_p.h:62
KMessage::Error
Error message.
Definition: kmessage.h:57
ksharedconfig.h
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
errorMissingMimeTypes
static void errorMissingMimeTypes(const QStringList &_types)
Definition: kmimetyperepository.cpp:610
KMimeGlobsFileParser::Glob
Definition: kmimeglobsfileparser_p.h:45
MAKE_LITTLE_ENDIAN32
#define MAKE_LITTLE_ENDIAN32(val)
Definition: kmimetyperepository.cpp:383
KMimeMagicMatch::m_rangeLength
qint64 m_rangeLength
Definition: kmimemagicrule_p.h:36
kWarning
#define kWarning
Definition: kdebug.h:322
KConfigGroup
A class for one specific group in a KConfig object.
Definition: kconfiggroup.h:53
KMimeGlobsFileParser::AllGlobs::m_lowWeightGlobs
GlobList m_lowWeightGlobs
Definition: kmimeglobsfileparser_p.h:94
KMimeTypeRepository
Definition: kmimetyperepository_p.h:36
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
fallbackParent
static QString fallbackParent(const QString &mimeTypeName)
Definition: kmimetyperepository.cpp:278
KMimeType::defaultMimeType
static QString defaultMimeType()
Returns the name of the default mimetype.
Definition: kmimetype.cpp:597
kstandarddirs.h
KMimeTypeRepository::checkEssentialMimeTypes
void checkEssentialMimeTypes()
This function makes sure that vital mime types are installed.
Definition: kmimetyperepository.cpp:616
KMimeMagicMatch::m_rangeStart
qint64 m_rangeStart
Definition: kmimemagicrule_p.h:35
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
KMimeMagicMatch::m_subMatches
QList< KMimeMagicMatch > m_subMatches
Definition: kmimemagicrule_p.h:39
qint32
mimeDataBaseVersion
static int mimeDataBaseVersion()
Definition: kmimetyperepository.cpp:706
kDebug
#define kDebug
Definition: kdebug.h:316
KMimeType::mimeType
static Ptr mimeType(const QString &name, FindByNameOption options=ResolveAliases)
Retrieve a pointer to the mime type name.
Definition: kmimetype.cpp:58
KMimeTypeRepository::CaseSensitive
Definition: kmimetyperepository_p.h:66
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
KMimeGlobsFileParser::Glob::weight
int weight
Definition: kmimeglobsfileparser_p.h:48
QIODevice
KMimeGlobsFileParser::AllGlobs::m_fastPatterns
QHash< QString, QStringList > m_fastPatterns
Definition: kmimeglobsfileparser_p.h:92
kmessage.h
KMimeMagicMatch
Definition: kmimemagicrule_p.h:31
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
KMimeTypeRepository::canonicalName
QString canonicalName(const QString &mime)
Resolve mime if it's an alias, and return it otherwise.
Definition: kmimetyperepository.cpp:90
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
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
KMimeTypeRepository::KMimeType
friend class KMimeType
Definition: kmimetyperepository_p.h:95
QProcess
kconfiggroup.h
addPlatformSpecificPkgConfigPath
static void addPlatformSpecificPkgConfigPath(QStringList &paths)
Definition: kmimetyperepository.cpp:695
QList< KMimeMagicRule >
kfoldermimetype.h
KMimeGlobsFileParser::Glob::pattern
QString pattern
Definition: kmimeglobsfileparser_p.h:50
This file is part of the KDE documentation.
Documentation copyright © 1996-2015 The KDE developers.
Generated on Sun Sep 20 2015 17:43:42 by doxygen 1.8.9.1 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.12 API Reference

Skip menu "kdelibs-4.14.12 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