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

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