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

KDECore

  • kdecore
  • services
kmimetype.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  * Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
3  * 2000-2007 David Faure <faure@kde.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License version 2 as published by the Free Software Foundation;
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 "kmimetype.h"
21 #include "kmimetype_p.h"
22 #include "kmimetypefactory.h"
23 #include "kmimetyperepository_p.h"
24 
25 #include <kdebug.h>
26 #include <kde_file.h> // KDE::stat
27 #include <kdeversion.h> // KDE_MAKE_VERSION
28 #include <klocale.h>
29 #include <kprotocolinfo.h>
30 #include <kprotocolinfofactory.h>
31 #include <kstandarddirs.h>
32 #include <kurl.h>
33 
34 #include <QtCore/QFile>
35 #include <QtDBus/QtDBus>
36 #include <QBuffer>
37 
38 extern int servicesDebugArea();
39 
40 template class KSharedPtr<KMimeType>;
41 
42 KMimeType::Ptr KMimeType::defaultMimeTypePtr()
43 {
44  return KMimeTypeRepository::self()->defaultMimeTypePtr();
45 }
46 
47 bool KMimeType::isDefault() const
48 {
49  return name() == defaultMimeType();
50 }
51 
52 void KMimeType::checkEssentialMimeTypes()
53 {
54  KMimeTypeRepository::self()->checkEssentialMimeTypes();
55 }
56 
57 KMimeType::Ptr KMimeType::mimeType(const QString& name, FindByNameOption options)
58 {
59  return KMimeTypeRepository::self()->findMimeTypeByName(name, options);
60 }
61 
62 KMimeType::List KMimeType::allMimeTypes()
63 {
64  // This could be done faster...
65  KMimeType::List lst;
66  Q_FOREACH(const QString& mimeType, KMimeTypeFactory::self()->allMimeTypes()) {
67  if (!mimeType.startsWith(QLatin1String("x-scheme-handler")))
68  lst.append(KMimeType::mimeType(mimeType));
69  }
70  return lst;
71 }
72 
73 bool KMimeType::isBufferBinaryData(const QByteArray& data)
74 {
75  // Check the first 32 bytes (see shared-mime spec)
76  const char* p = data.data();
77  const int end = qMin(32, data.size());
78  for (int i = 0; i < end; ++i) {
79  if ((unsigned char)(p[i]) < 32 && p[i] != 9 && p[i] != 10 && p[i] != 13) // ASCII control character
80  return true;
81  }
82  return false;
83 }
84 
85 static KMimeType::Ptr findFromMode( const QString& path /*only used if is_local_file*/,
86  mode_t mode /*0 if unknown*/,
87  bool is_local_file )
88 {
89  if ( is_local_file && (mode == 0 || mode == (mode_t)-1) ) {
90  KDE_struct_stat buff;
91  if ( KDE::stat( path, &buff ) != -1 )
92  mode = buff.st_mode;
93  }
94 
95  if ( S_ISDIR( mode ) ) {
96  // KDE4 TODO: use an overlay instead
97 #if 0
98  // Special hack for local files. We want to see whether we
99  // are allowed to enter the directory
100  if ( is_local_file )
101  {
102  if ( KDE::access( path, R_OK ) == -1 )
103  return KMimeType::mimeType( "inode/directory-locked" );
104  }
105 #endif
106  return KMimeType::mimeType( QLatin1String("inode/directory") );
107  }
108  if ( S_ISCHR( mode ) )
109  return KMimeType::mimeType( QLatin1String("inode/chardevice") );
110  if ( S_ISBLK( mode ) )
111  return KMimeType::mimeType( QLatin1String("inode/blockdevice") );
112  if ( S_ISFIFO( mode ) )
113  return KMimeType::mimeType( QLatin1String("inode/fifo") );
114  if ( S_ISSOCK( mode ) )
115  return KMimeType::mimeType( QLatin1String("inode/socket") );
116 #ifdef Q_OS_WIN
117  // FIXME: distinguish between mounted & unmounted
118  int size = path.size();
119  if ( size == 2 || size == 3 ) {
120  //GetDriveTypeW is not defined in wince
121 #ifndef _WIN32_WCE
122  unsigned int type = GetDriveTypeW( (LPCWSTR) path.utf16() );
123  switch( type ) {
124  case DRIVE_REMOVABLE:
125  return KMimeType::mimeType( QLatin1String("media/floppy_mounted") );
126  case DRIVE_FIXED:
127  return KMimeType::mimeType( QLatin1String("media/hdd_mounted") );
128  case DRIVE_REMOTE:
129  return KMimeType::mimeType( QLatin1String("media/smb_mounted") );
130  case DRIVE_CDROM:
131  return KMimeType::mimeType( QLatin1String("media/cdrom_mounted") );
132  case DRIVE_RAMDISK:
133  return KMimeType::mimeType( QLatin1String("media/hdd_mounted") );
134  default:
135  break;
136  };
137 #else
138  return KMimeType::mimeType( QLatin1String("media/hdd_mounted") );
139 #endif
140  }
141 #endif
142  // remote executable file? stop here (otherwise findFromContent can do that better for local files)
143  if ( !is_local_file && S_ISREG( mode ) && ( mode & ( S_IXUSR | S_IXGRP | S_IXOTH ) ) )
144  return KMimeType::mimeType( QLatin1String("application/x-executable") );
145 
146  return KMimeType::Ptr();
147 }
148 
149 /*
150 
151 As agreed on the XDG list (and unlike the current shared-mime spec):
152 
153 Glob-matching should prefer derived mimetype over base mimetype, and longer matches
154 over shorter ones. However if two globs of the same length match the file, and the two
155 matches are not related in the inheritance tree, then we have a "glob conflict", which
156 will be resolved below.
157 
158 If only one glob matches, use that
159 
160 If no glob matches, sniff and use that
161 
162 If several globs matches, and sniffing gives a result we do:
163  if sniffed prio >= 80, use sniffed type
164  for glob_match in glob_matches:
165  if glob_match is subclass or equal to sniffed_type, use glob_match
166 
167 If several globs matches, and sniffing fails, or doesn't help:
168  fall back to the first glob match
169 
170 This algorithm only sniffs when there is some uncertainty with the
171 extension matching (thus, it's usable for a file manager).
172 
173 Note: in KDE we want the file views to sniff in a delayed manner.
174 So there's also a fast mode which is:
175  if no glob matches, or if more than one glob matches, use default mimetype and mark as "can be refined".
176 
177 */
178 
179 KMimeType::Ptr KMimeType::findByUrlHelper( const KUrl& _url, mode_t mode,
180  bool is_local_file,
181  QIODevice* device,
182  int* accuracy )
183 {
184  checkEssentialMimeTypes();
185  const QString path = is_local_file ? _url.toLocalFile() : _url.path();
186 
187  if (accuracy)
188  *accuracy = 100;
189 
190  // Look at mode first
191  KMimeType::Ptr mimeFromMode = findFromMode( path, mode, is_local_file );
192  if (mimeFromMode)
193  return mimeFromMode;
194 
195  // First try to find out by looking at the filename (if there's one)
196  const QString fileName( _url.fileName() );
197  QStringList mimeList;
198  if ( !fileName.isEmpty() && !path.endsWith( QLatin1Char('/') ) ) {
199  // and if we can trust it (e.g. don't trust *.pl over HTTP, could be anything)
200  if ( is_local_file || _url.hasSubUrl() || // Explicitly trust suburls
201  KProtocolInfo::determineMimetypeFromExtension( _url.protocol() ) ) {
202  mimeList = KMimeTypeRepository::self()->findFromFileName( fileName );
203  // Found one glob match exactly: OK, use that.
204  // We disambiguate multiple glob matches by sniffing, below.
205  if ( mimeList.count() == 1 ) {
206  const QString selectedMime = mimeList.at(0);
207  KMimeType::Ptr mime = mimeType(selectedMime);
208  if (!mime) {
209  // #265188 - this can happen when an old globs file is lying around after
210  // the packages xml file was removed.
211  kWarning() << "Glob file refers to" << selectedMime << "but this mimetype does not exist!";
212  mimeList.clear();
213  } else {
214  return mime;
215  }
216  }
217  }
218  }
219 
220  if ( device && !device->isOpen() ) {
221  if ( !device->open(QIODevice::ReadOnly) ) {
222  device = 0;
223  }
224  }
225 
226  // Try the magic matches (if we can read the data)
227  QByteArray beginning;
228  if ( device ) {
229  int magicAccuracy;
230  KMimeType::Ptr mime = KMimeTypeRepository::self()->findFromContent(device, &magicAccuracy, beginning);
231  // mime can't be 0, except in case of install problems.
232  // However we get magicAccuracy==0 for octet-stream, i.e. no magic match found.
233  //kDebug(servicesDebugArea()) << "findFromContent said" << (mime?mime->name():QString()) << "with accuracy" << magicAccuracy;
234  if (mime && magicAccuracy > 0) {
235 
236  // Disambiguate conflicting extensions (if magic found something and the magicrule was <80)
237  if (magicAccuracy < 80 && !mimeList.isEmpty()) {
238  // "for glob_match in glob_matches:"
239  // "if glob_match is subclass or equal to sniffed_type, use glob_match"
240  const QString sniffedMime = mime->name();
241  foreach(const QString &m, mimeList) {
242  KMimeType::Ptr mimeFromPattern = KMimeType::mimeType(m);
243  //kDebug(servicesDebugArea()) << "sniffedMime=" << sniffedMime << "mimeFromPattern=" << mimeFromPattern->name();
244  if (mimeFromPattern && mimeFromPattern->is(sniffedMime)) {
245  // We have magic + pattern pointing to this, so it's a pretty good match
246  if (accuracy)
247  *accuracy = 100;
248  return mimeFromPattern;
249  }
250  }
251  }
252 
253  if (accuracy)
254  *accuracy = magicAccuracy;
255  return mime;
256  }
257  }
258 
259  // Not a local file, or no magic allowed, or magic found nothing
260 
261  // Maybe we had multiple matches from globs?
262  if (!mimeList.isEmpty()) {
263  if (accuracy)
264  *accuracy = 20;
265  // We have to pick one...
266  // At least make this deterministic
267  qSort(mimeList.begin(), mimeList.end());
268  Q_FOREACH(const QString& mimeName, mimeList) {
269  KMimeType::Ptr mime = mimeType(mimeName);
270  if (!mime)
271  kWarning() << "Glob file refers to" << mimeName << "but this mimetype does not exist!";
272  else
273  return mime;
274  }
275  }
276 
277  // Find a fallback from the protocol
278  if (accuracy)
279  *accuracy = 10;
280  // ## this breaks with proxying; find a way to move proxying info to kdecore's kprotocolinfo?
281  // ## or hardcode the only case of proxying that we ever had? (ftp-over-http)
282  KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol( _url.protocol() );
283  QString def;
284  if (prot)
285  def = prot->defaultMimeType();
286  if ( !def.isEmpty() && def != defaultMimeType() ) {
287  // The protocol says it always returns a given mimetype (e.g. text/html for "man:")
288  KMimeType::Ptr mime = mimeType( def );
289  if (mime)
290  return mime;
291  }
292  if ( path.endsWith( QLatin1Char('/') ) || path.isEmpty() ) {
293  // We have no filename at all. Maybe the protocol has a setting for
294  // which mimetype this means (e.g. directory).
295  // For HTTP (def==defaultMimeType()) we don't assume anything,
296  // because of redirections (e.g. freshmeat downloads).
297  if ( def.isEmpty() ) {
298  // Assume inode/directory, if the protocol supports listing.
299  KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol( _url.protocol() );
300  if ( prot && prot->supportsListing() ) {
301  KMimeType::Ptr mime = mimeType( QLatin1String("inode/directory") );
302  if (mime) { // only 0 if no mimetypes installed
303  return mime;
304  }
305  } else
306  return defaultMimeTypePtr(); // == 'no idea', e.g. for "data:,foo/"
307  }
308  }
309 
310  if (accuracy)
311  *accuracy = 0;
312  return defaultMimeTypePtr();
313 }
314 
315 KMimeType::Ptr KMimeType::findByUrl( const KUrl& url, mode_t mode,
316  bool is_local_file, bool fast_mode,
317  int *accuracy )
318 {
319  if ( !is_local_file && url.isLocalFile() )
320  is_local_file = true;
321  if (is_local_file && !fast_mode) {
322  QFile file(url.toLocalFile());
323  return findByUrlHelper(url, mode, is_local_file, &file, accuracy);
324  }
325  return findByUrlHelper(url, mode, is_local_file, 0, accuracy);
326 }
327 
328 KMimeType::Ptr KMimeType::findByPath( const QString& path, mode_t mode,
329  bool fast_mode, int* accuracy )
330 {
331  KUrl url;
332  url.setPath(path);
333  return findByUrl(url, mode, true, fast_mode, accuracy);
334 }
335 
336 KMimeType::Ptr KMimeType::findByNameAndContent( const QString& name, const QByteArray& data,
337  mode_t mode, int* accuracy )
338 {
339  KUrl url;
340  url.setPath(name);
341  QBuffer buffer(const_cast<QByteArray *>(&data));
342  return findByUrlHelper(url, mode, false, &buffer, accuracy);
343 }
344 
345 KMimeType::Ptr KMimeType::findByNameAndContent( const QString& name, QIODevice* device,
346  mode_t mode, int* accuracy )
347 {
348  KUrl url;
349  url.setPath(name);
350  return findByUrlHelper(url, mode, false, device, accuracy);
351 }
352 
353 QString KMimeType::extractKnownExtension(const QString &fileName)
354 {
355  QString pattern;
356  KMimeTypeRepository::self()->findFromFileName( fileName, &pattern );
357  return pattern;
358 }
359 
360 KMimeType::Ptr KMimeType::findByContent( const QByteArray &data, int *accuracy )
361 {
362  QBuffer buffer(const_cast<QByteArray *>(&data));
363  buffer.open(QIODevice::ReadOnly);
364  QByteArray cache;
365  return KMimeTypeRepository::self()->findFromContent(&buffer, accuracy, cache);
366 }
367 
368 KMimeType::Ptr KMimeType::findByContent( QIODevice* device, int* accuracy )
369 {
370  QByteArray cache;
371  return KMimeTypeRepository::self()->findFromContent(device, accuracy, cache);
372 }
373 
374 KMimeType::Ptr KMimeType::findByFileContent( const QString &fileName, int *accuracy )
375 {
376  checkEssentialMimeTypes();
377 
378  QFile device(fileName);
379  // Look at mode first
380  KMimeType::Ptr mimeFromMode = findFromMode( fileName, 0, true );
381  if (mimeFromMode) {
382  if (accuracy)
383  *accuracy = 100;
384  return mimeFromMode;
385  }
386  if (!device.open(QIODevice::ReadOnly)) {
387  if (accuracy)
388  *accuracy = 0;
389  return KMimeType::defaultMimeTypePtr();
390  }
391 
392  QByteArray cache;
393  return KMimeTypeRepository::self()->findFromContent(&device, accuracy, cache);
394 }
395 
396 bool KMimeType::isBinaryData( const QString &fileName )
397 {
398  QFile file(fileName);
399  if (!file.open(QIODevice::ReadOnly))
400  return false; // err, whatever
401  const QByteArray data = file.read(32);
402  return isBufferBinaryData(data);
403 }
404 
405 KMimeType::KMimeType( KMimeTypePrivate &dd, const QString& name,
406  const QString& comment )
407  : KServiceType( dd, name, comment )
408 {
409 }
410 
411 KMimeType::KMimeType( const QString & fullpath, const QString& name,
412  const QString& comment )
413  : KServiceType( *new KMimeTypePrivate(fullpath), name, comment )
414 {
415 }
416 
417 KMimeType::KMimeType( KMimeTypePrivate &dd)
418  : KServiceType(dd)
419 {
420 }
421 
422 KMimeType::KMimeType( QDataStream& _str, int offset )
423  : KServiceType( *new KMimeTypePrivate(_str, offset ))
424 {
425 }
426 
427 void KMimeTypePrivate::save( QDataStream& _str )
428 {
429  KServiceTypePrivate::save( _str );
430  // Warning adding fields here involves a binary incompatible change - update version
431  // number in ksycoca.h. Never remove fields.
432  _str << m_lstPatterns << QString() << QStringList() << m_iconName;
433 }
434 
435 QVariant KMimeTypePrivate::property( const QString& _name ) const
436 {
437  if ( _name == QLatin1String("Patterns") )
438  return QVariant( m_lstPatterns );
439  if ( _name == QLatin1String("Icon") )
440  return QVariant( iconName(KUrl()) );
441 
442  return KServiceTypePrivate::property( _name );
443 }
444 
445 QStringList KMimeTypePrivate::propertyNames() const
446 {
447  QStringList res = KServiceTypePrivate::propertyNames();
448  res.append( QString::fromLatin1("Patterns") );
449  res.append( QString::fromLatin1("Icon") );
450  return res;
451 }
452 
453 KMimeType::~KMimeType()
454 {
455 }
456 
457 QString KMimeType::iconNameForUrl( const KUrl & _url, mode_t mode )
458 {
459  const KMimeType::Ptr mt = findByUrl( _url, mode, _url.isLocalFile(),
460  false /*HACK*/);
461  if (!mt) {
462  return QString();
463  }
464  static const QString& unknown = KGlobal::staticQString("unknown");
465  const QString mimeTypeIcon = mt->iconName( _url );
466  QString i = mimeTypeIcon;
467 
468  // if we don't find an icon, maybe we can use the one for the protocol
469  if ( i == unknown || i.isEmpty() || mt->name() == defaultMimeType()
470  // and for the root of the protocol (e.g. trash:/) the protocol icon has priority over the mimetype icon
471  || _url.path().length() <= 1 )
472  {
473  i = favIconForUrl( _url ); // maybe there is a favicon?
474 
475  if ( i.isEmpty() )
476  i = KProtocolInfo::icon( _url.protocol() );
477 
478  // root of protocol: if we found nothing, revert to mimeTypeIcon (which is usually "folder")
479  if ( _url.path().length() <= 1 && ( i == unknown || i.isEmpty() ) )
480  i = mimeTypeIcon;
481  }
482  return !i.isEmpty() ? i : unknown;
483 }
484 
485 QString KMimeType::favIconForUrl( const KUrl& url )
486 {
487  if (url.isLocalFile()
488  || !url.protocol().startsWith(QLatin1String("http"))
489  || !KMimeTypeRepository::self()->useFavIcons())
490  return QString();
491 
492  QDBusInterface kded( QString::fromLatin1("org.kde.kded"),
493  QString::fromLatin1("/modules/favicons"),
494  QString::fromLatin1("org.kde.FavIcon") );
495  QDBusReply<QString> result = kded.call( QString::fromLatin1("iconForUrl"), url.url() );
496  return result; // default is QString()
497 }
498 
499 QString KMimeType::comment( const KUrl &url) const
500 {
501  Q_D(const KMimeType);
502  return d->comment(url);
503 }
504 
505 #ifndef KDE_NO_DEPRECATED
506 QString KMimeType::parentMimeType() const
507 {
508  const QStringList parents = parentMimeTypes();
509  if (!parents.isEmpty())
510  return parents.first();
511  return QString();
512 }
513 #endif
514 
515 bool KMimeTypePrivate::inherits(const QString& mime) const
516 {
517  QStack<QString> toCheck;
518  toCheck.push(m_strName);
519  while (!toCheck.isEmpty()) {
520  const QString current = toCheck.pop();
521  if (current == mime)
522  return true;
523  Q_FOREACH(const QString& parent, KMimeTypeRepository::self()->parents(current)) {
524  toCheck.push(parent);
525  }
526  }
527  return false;
528 }
529 
530 bool KMimeType::is( const QString& mimeTypeName ) const
531 {
532  Q_D(const KMimeType);
533  if (name() == mimeTypeName)
534  return true;
535  const QString mime = KMimeTypeRepository::self()->canonicalName(mimeTypeName);
536  return d->inherits(mime);
537 }
538 
539 QStringList KMimeType::parentMimeTypes() const
540 {
541  Q_D(const KMimeType);
542  return KMimeTypeRepository::self()->parents(d->m_strName);
543 }
544 
545 static void collectParentMimeTypes(const QString& mime, QStringList& allParents)
546 {
547  QStringList parents = KMimeTypeRepository::self()->parents(mime);
548  Q_FOREACH(const QString& parent, parents) {
549  // I would use QSet, but since order matters I better not
550  if (!allParents.contains(parent))
551  allParents.append(parent);
552  }
553  // We want a breadth-first search, so that the least-specific parent (octet-stream) is last
554  // This means iterating twice, unfortunately.
555  Q_FOREACH(const QString& parent, parents) {
556  collectParentMimeTypes(parent, allParents);
557  }
558 }
559 
560 QStringList KMimeType::allParentMimeTypes() const
561 {
562  Q_D(const KMimeType);
563  QStringList allParents;
564  const QString canonical = KMimeTypeRepository::self()->resolveAlias(name());
565  if (!canonical.isEmpty())
566  allParents.append(canonical);
567  collectParentMimeTypes(d->m_strName, allParents);
568  return allParents;
569 }
570 
571 QString KMimeType::defaultMimeType()
572 {
573  static const QString & s_strDefaultMimeType =
574  KGlobal::staticQString( "application/octet-stream" );
575  return s_strDefaultMimeType;
576 }
577 
578 QString KMimeType::iconName( const KUrl& url) const
579 {
580  Q_D(const KMimeType);
581  return d->iconName(url);
582 }
583 
584 QStringList KMimeType::patterns() const
585 {
586  Q_D(const KMimeType);
587  d->ensureXmlDataLoaded();
588  return d->m_lstPatterns;
589 }
590 
591 // loads comment, icon, mainPattern, m_lstPatterns
592 void KMimeTypePrivate::ensureXmlDataLoaded() const
593 {
594  if (m_xmlDataLoaded)
595  return;
596 
597  m_xmlDataLoaded = true;
598 
599  const QString file = m_strName + QLatin1String(".xml");
600  const QStringList mimeFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", file);
601  if (mimeFiles.isEmpty()) {
602  kWarning() << "No file found for" << file << ", even though the file appeared in a directory listing.";
603  kWarning() << "Either it was just removed, or the directory doesn't have executable permission...";
604  kWarning() << KGlobal::dirs()->resourceDirs("xdgdata-mime");
605  return;
606  }
607 
608  QString comment;
609  QString mainPattern;
610  const QStringList languageList = KGlobal::locale()->languageList();
611  QString preferredLanguage = languageList.first();
612  QMap<QString, QString> commentsByLanguage;
613 
614  QListIterator<QString> mimeFilesIter(mimeFiles);
615  mimeFilesIter.toBack();
616  while (mimeFilesIter.hasPrevious()) { // global first, then local.
617  const QString fullPath = mimeFilesIter.previous();
618  QFile qfile(fullPath);
619  if (!qfile.open(QFile::ReadOnly))
620  continue;
621 
622  QXmlStreamReader xml(&qfile);
623  if (xml.readNextStartElement()) {
624  if (xml.name() != "mime-type") {
625  continue;
626  }
627  const QString name = xml.attributes().value(QLatin1String("type")).toString();
628  if (name.isEmpty())
629  continue;
630  if (name != m_strName) {
631  kWarning() << "Got name" << name << "in file" << file << "expected" << m_strName;
632  }
633 
634  while (xml.readNextStartElement()) {
635  const QStringRef tag = xml.name();
636  if (tag == "comment") {
637  QString lang = xml.attributes().value(QLatin1String("xml:lang")).toString();
638  const QString text = xml.readElementText();
639  if (lang.isEmpty()) {
640  lang = QLatin1String("en_US");
641  }
642  if (lang == preferredLanguage) {
643  comment = text;
644  } else {
645  commentsByLanguage.insert(lang, text);
646  }
647  continue; // we called readElementText, so we're at the EndElement already.
648  } else if (tag == "icon") { // as written out by shared-mime-info >= 0.40
649  m_iconName = xml.attributes().value(QLatin1String("name")).toString();
650  } else if (tag == "glob-deleteall") { // as written out by shared-mime-info >= 0.70
651  mainPattern.clear();
652  m_lstPatterns.clear();
653  } else if (tag == "glob") { // as written out by shared-mime-info >= 0.70
654  const QString pattern = xml.attributes().value(QLatin1String("pattern")).toString();
655  if (mainPattern.isEmpty() && pattern.startsWith(QLatin1Char('*'))) {
656  mainPattern = pattern;
657  }
658  if (!m_lstPatterns.contains(pattern))
659  m_lstPatterns.append(pattern);
660  }
661  xml.skipCurrentElement();
662  }
663  if (xml.name() != "mime-type") {
664  kFatal() << "Programming error in KMimeType XML loading, please create a bug report on http://bugs.kde.org and attach the file" << fullPath;
665  }
666  }
667  }
668 
669  if (comment.isEmpty()) {
670  Q_FOREACH(const QString& lang, languageList) {
671  const QString comm = commentsByLanguage.value(lang);
672  if (!comm.isEmpty()) {
673  comment = comm;
674  break;
675  }
676  const int pos = lang.indexOf(QLatin1Char('_'));
677  if (pos != -1) {
678  // "pt_BR" not found? try just "pt"
679  const QString shortLang = lang.left(pos);
680  const QString comm = commentsByLanguage.value(shortLang);
681  if (!comm.isEmpty()) {
682  comment = comm;
683  break;
684  }
685  }
686  }
687  if (comment.isEmpty()) {
688  kWarning() << "Missing <comment> field in" << file;
689  }
690  }
691  m_strComment = comment;
692 
693  const bool globsInXml = (KMimeType::sharedMimeInfoVersion() >= KDE_MAKE_VERSION(0, 70, 0));
694  if (globsInXml) {
695  if (!mainPattern.isEmpty() && m_lstPatterns.first() != mainPattern) {
696  // ensure it's first in the list of patterns
697  m_lstPatterns.removeAll(mainPattern);
698  m_lstPatterns.prepend(mainPattern);
699  }
700  } else {
701  // Fallback: get the patterns from the globs file
702  m_lstPatterns = KMimeTypeRepository::self()->patternsForMimetype(m_strName);
703  }
704 }
705 
706 QString KMimeType::userSpecifiedIconName() const
707 {
708  Q_D(const KMimeType);
709  d->ensureXmlDataLoaded();
710  return d->m_iconName;
711 }
712 
713 int KMimeType::sharedMimeInfoVersion()
714 {
715  return KMimeTypeRepository::self()->sharedMimeInfoVersion();
716 }
717 
718 QString KMimeType::mainExtension() const
719 {
720  Q_D(const KMimeType);
721 
722 #if 1 // HACK START - can be removed once shared-mime-info >= 0.70 is used/required.
723  // The idea was: first usable pattern from m_lstPatterns.
724  // But update-mime-database makes a mess of the order of the patterns,
725  // because it uses a hash internally.
726  static const struct { const char* mime; const char* extension; } s_hardcodedMimes[] = {
727  { "text/plain", ".txt" } };
728  if (d->m_lstPatterns.count() > 1) {
729  const QByteArray me = name().toLatin1();
730  for (uint i = 0; i < sizeof(s_hardcodedMimes)/sizeof(*s_hardcodedMimes); ++i) {
731  if (me == s_hardcodedMimes[i].mime)
732  return QString::fromLatin1(s_hardcodedMimes[i].extension);
733  }
734  }
735 #endif // HACK END
736 
737  Q_FOREACH(const QString& pattern, patterns()) {
738  // Skip if if looks like: README or *. or *.*
739  // or *.JP*G or *.JP?
740  if (pattern.startsWith(QLatin1String("*.")) &&
741  pattern.length() > 2 &&
742  pattern.indexOf(QLatin1Char('*'), 2) < 0 && pattern.indexOf(QLatin1Char('?'), 2) < 0) {
743  return pattern.mid(1);
744  }
745  }
746  // TODO we should also look into the parent mimetype's patterns, no?
747  return QString();
748 }
749 
750 bool KMimeType::matchFileName( const QString &filename, const QString &pattern )
751 {
752  return KMimeTypeRepository::matchFileName( filename, pattern );
753 }
754 
755 int KMimeTypePrivate::serviceOffersOffset() const
756 {
757  return KMimeTypeFactory::self()->serviceOffersOffset(name());
758 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Fri Nov 16 2012 14:49:03 by doxygen 1.8.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.8.5 API Reference

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