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

KDECore

kmimetype.cpp

Go to the documentation of this file.
00001 /*  This file is part of the KDE libraries
00002  *  Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
00003  *                2000-2007 David Faure <faure@kde.org>
00004  *
00005  *  This library is free software; you can redistribute it and/or
00006  *  modify it under the terms of the GNU Library General Public
00007  *  License version 2 as published by the Free Software Foundation;
00008  *
00009  *  This library is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  *  Library General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU Library General Public License
00015  *  along with this library; see the file COPYING.LIB.  If not, write to
00016  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  *  Boston, MA 02110-1301, USA.
00018  **/
00019 
00020 #include "kmimetype.h"
00021 #include "kmimetype_p.h"
00022 #include "kmimetypefactory.h"
00023 #include "kmimetyperepository_p.h"
00024 
00025 #include <kdebug.h>
00026 #include <kde_file.h> // KDE::stat
00027 #include <kdeversion.h> // KDE_MAKE_VERSION
00028 #include <klocale.h>
00029 #include <kmimetyperepository_p.h>
00030 #include <kprotocolinfo.h>
00031 #include <kprotocolinfofactory.h>
00032 #include <kstandarddirs.h>
00033 #include <kurl.h>
00034 
00035 #include <QtCore/QFile>
00036 #include <QtDBus/QtDBus>
00037 #include <QBuffer>
00038 
00039 extern int servicesDebugArea();
00040 
00041 template class KSharedPtr<KMimeType>;
00042 
00043 KMimeType::Ptr KMimeType::defaultMimeTypePtr()
00044 {
00045     return KMimeTypeRepository::self()->defaultMimeTypePtr();
00046 }
00047 
00048 bool KMimeType::isDefault() const
00049 {
00050     return name() == defaultMimeType();
00051 }
00052 
00053 void KMimeType::checkEssentialMimeTypes()
00054 {
00055     KMimeTypeRepository::self()->checkEssentialMimeTypes();
00056 }
00057 
00058 KMimeType::Ptr KMimeType::mimeType(const QString& name, FindByNameOption options)
00059 {
00060     return KMimeTypeRepository::self()->findMimeTypeByName(name, options);
00061 }
00062 
00063 KMimeType::List KMimeType::allMimeTypes()
00064 {
00065     // This could be done faster...
00066     KMimeType::List lst;
00067     Q_FOREACH(const QString& mimeType, KMimeTypeFactory::self()->allMimeTypes()) {
00068         if (!mimeType.startsWith(QLatin1String("x-scheme-handler")))
00069             lst.append(KMimeType::mimeType(mimeType));
00070     }
00071     return lst;
00072 }
00073 
00074 bool KMimeType::isBufferBinaryData(const QByteArray& data)
00075 {
00076     // Check the first 32 bytes (see shared-mime spec)
00077     const char* p = data.data();
00078     const int end = qMin(32, data.size());
00079     for (int i = 0; i < end; ++i) {
00080         if ((unsigned char)(p[i]) < 32 && p[i] != 9 && p[i] != 10 && p[i] != 13) // ASCII control character
00081             return true;
00082     }
00083     return false;
00084 }
00085 
00086 static KMimeType::Ptr findFromMode( const QString& path /*only used if is_local_file*/,
00087                                     mode_t mode /*0 if unknown*/,
00088                                     bool is_local_file )
00089 {
00090     if ( is_local_file && (mode == 0 || mode == (mode_t)-1) ) {
00091         KDE_struct_stat buff;
00092         if ( KDE::stat( path, &buff ) != -1 )
00093             mode = buff.st_mode;
00094     }
00095 
00096     if ( S_ISDIR( mode ) ) {
00097         // KDE4 TODO: use an overlay instead
00098 #if 0
00099         // Special hack for local files. We want to see whether we
00100         // are allowed to enter the directory
00101         if ( is_local_file )
00102         {
00103             if ( KDE::access( path, R_OK ) == -1 )
00104                 return KMimeType::mimeType( "inode/directory-locked" );
00105         }
00106 #endif
00107         return KMimeType::mimeType( QLatin1String("inode/directory") );
00108     }
00109     if ( S_ISCHR( mode ) )
00110         return KMimeType::mimeType( QLatin1String("inode/chardevice") );
00111     if ( S_ISBLK( mode ) )
00112         return KMimeType::mimeType( QLatin1String("inode/blockdevice") );
00113     if ( S_ISFIFO( mode ) )
00114         return KMimeType::mimeType( QLatin1String("inode/fifo") );
00115     if ( S_ISSOCK( mode ) )
00116         return KMimeType::mimeType( QLatin1String("inode/socket") );
00117 #ifdef Q_OS_WIN
00118     // FIXME: distinguish between mounted & unmounted
00119     int size = path.size();
00120     if ( size == 2 || size == 3 ) {
00121     //GetDriveTypeW is not defined in wince
00122 #ifndef _WIN32_WCE
00123         unsigned int type = GetDriveTypeW( (LPCWSTR) path.utf16() );
00124         switch( type ) {
00125             case DRIVE_REMOVABLE:
00126                 return KMimeType::mimeType( QLatin1String("media/floppy_mounted") );
00127             case DRIVE_FIXED:
00128                 return KMimeType::mimeType( QLatin1String("media/hdd_mounted") );
00129             case DRIVE_REMOTE:
00130                 return KMimeType::mimeType( QLatin1String("media/smb_mounted") );
00131             case DRIVE_CDROM:
00132                 return KMimeType::mimeType( QLatin1String("media/cdrom_mounted") );
00133             case DRIVE_RAMDISK:
00134                 return KMimeType::mimeType( QLatin1String("media/hdd_mounted") );
00135             default:
00136                 break;
00137         };
00138 #else
00139         return KMimeType::mimeType( QLatin1String("media/hdd_mounted") );
00140 #endif
00141     }
00142 #endif
00143     // remote executable file? stop here (otherwise findFromContent can do that better for local files)
00144     if ( !is_local_file && S_ISREG( mode ) && ( mode & ( S_IXUSR | S_IXGRP | S_IXOTH ) ) )
00145         return KMimeType::mimeType( QLatin1String("application/x-executable") );
00146 
00147     return KMimeType::Ptr();
00148 }
00149 
00150 /*
00151 
00152 As agreed on the XDG list (and unlike the current shared-mime spec):
00153 
00154 Glob-matching should prefer derived mimetype over base mimetype, and longer matches
00155 over shorter ones. However if two globs of the same length match the file, and the two
00156 matches are not related in the inheritance tree, then we have a "glob conflict", which
00157 will be resolved below.
00158 
00159 If only one glob matches, use that
00160 
00161 If no glob matches, sniff and use that
00162 
00163 If several globs matches, and sniffing gives a result we do:
00164   if sniffed prio >= 80, use sniffed type
00165   for glob_match in glob_matches:
00166      if glob_match is subclass or equal to sniffed_type, use glob_match
00167 
00168 If several globs matches, and sniffing fails, or doesn't help:
00169   fall back to the first glob match
00170 
00171 This algorithm only sniffs when there is some uncertainty with the
00172 extension matching (thus, it's usable for a file manager).
00173 
00174 Note: in KDE we want the file views to sniff in a delayed manner.
00175 So there's also a fast mode which is:
00176  if no glob matches, or if more than one glob matches, use default mimetype and mark as "can be refined".
00177 
00178 */
00179 
00180 KMimeType::Ptr KMimeType::findByUrlHelper( const KUrl& _url, mode_t mode,
00181                                            bool is_local_file,
00182                                            QIODevice* device,
00183                                            int* accuracy )
00184 {
00185     checkEssentialMimeTypes();
00186     const QString path = is_local_file ? _url.toLocalFile() : _url.path();
00187 
00188     if (accuracy)
00189         *accuracy = 100;
00190 
00191     // Look at mode first
00192     KMimeType::Ptr mimeFromMode = findFromMode( path, mode, is_local_file );
00193     if (mimeFromMode)
00194         return mimeFromMode;
00195 
00196     // First try to find out by looking at the filename (if there's one)
00197     const QString fileName( _url.fileName() );
00198     QStringList mimeList;
00199     if ( !fileName.isEmpty() && !path.endsWith( QLatin1Char('/') ) ) {
00200         // and if we can trust it (e.g. don't trust *.pl over HTTP, could be anything)
00201         if ( is_local_file || _url.hasSubUrl() || // Explicitly trust suburls
00202              KProtocolInfo::determineMimetypeFromExtension( _url.protocol() ) ) {
00203             mimeList = KMimeTypeRepository::self()->findFromFileName( fileName );
00204             // Found one glob match exactly: OK, use that.
00205             // We disambiguate multiple glob matches by sniffing, below.
00206             if ( mimeList.count() == 1 ) {
00207                 const QString selectedMime = mimeList.at(0);
00208                 KMimeType::Ptr mime = mimeType(selectedMime);
00209                 if (!mime) {
00210                     // #265188 - this can happen when an old globs file is lying around after
00211                     // the packages xml file was removed.
00212                     kWarning() << "Glob file refers to" << selectedMime << "but this mimetype does not exist!";
00213                     mimeList.clear();
00214                 } else {
00215                     return mime;
00216                 }
00217             }
00218         }
00219     }
00220 
00221     if ( device && !device->isOpen() ) {
00222         if ( !device->open(QIODevice::ReadOnly) ) {
00223             device = 0;
00224         }
00225     }
00226 
00227     // Try the magic matches (if we can read the data)
00228     QByteArray beginning;
00229     if ( device ) {
00230         int magicAccuracy;
00231         KMimeType::Ptr mime = KMimeTypeRepository::self()->findFromContent(device, &magicAccuracy, beginning);
00232         // mime can't be 0, except in case of install problems.
00233         // However we get magicAccuracy==0 for octet-stream, i.e. no magic match found.
00234         //kDebug(servicesDebugArea()) << "findFromContent said" << (mime?mime->name():QString()) << "with accuracy" << magicAccuracy;
00235         if (mime && magicAccuracy > 0) {
00236 
00237             // Disambiguate conflicting extensions (if magic found something and the magicrule was <80)
00238             if (magicAccuracy < 80 && !mimeList.isEmpty()) {
00239                 // "for glob_match in glob_matches:"
00240                 // "if glob_match is subclass or equal to sniffed_type, use glob_match"
00241                 const QString sniffedMime = mime->name();
00242                 foreach(const QString &m, mimeList) {
00243                     KMimeType::Ptr mimeFromPattern = KMimeType::mimeType(m);
00244                     //kDebug(servicesDebugArea()) << "sniffedMime=" << sniffedMime << "mimeFromPattern=" << mimeFromPattern->name();
00245                     if (mimeFromPattern && mimeFromPattern->is(sniffedMime)) {
00246                         // We have magic + pattern pointing to this, so it's a pretty good match
00247                         if (accuracy)
00248                             *accuracy = 100;
00249                         return mimeFromPattern;
00250                     }
00251                 }
00252             }
00253 
00254             if (accuracy)
00255                 *accuracy = magicAccuracy;
00256             return mime;
00257         }
00258     }
00259 
00260     // Not a local file, or no magic allowed, or magic found nothing
00261 
00262     // Maybe we had multiple matches from globs?
00263     if (!mimeList.isEmpty()) {
00264         if (accuracy)
00265             *accuracy = 20;
00266         // We have to pick one...
00267         // At least make this deterministic
00268         qSort(mimeList.begin(), mimeList.end());
00269         Q_FOREACH(const QString& mimeName, mimeList) {
00270             KMimeType::Ptr mime = mimeType(mimeName);
00271             if (!mime)
00272                 kWarning() << "Glob file refers to" << mimeName << "but this mimetype does not exist!";
00273             else
00274                 return mime;
00275         }
00276     }
00277 
00278     // Find a fallback from the protocol
00279     if (accuracy)
00280         *accuracy = 10;
00281     // ## this breaks with proxying; find a way to move proxying info to kdecore's kprotocolinfo?
00282     // ## or hardcode the only case of proxying that we ever had? (ftp-over-http)
00283     KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol( _url.protocol() );
00284     QString def;
00285     if (prot)
00286         def = prot->defaultMimeType();
00287     if ( !def.isEmpty() && def != defaultMimeType() ) {
00288         // The protocol says it always returns a given mimetype (e.g. text/html for "man:")
00289         KMimeType::Ptr mime = mimeType( def );
00290         if (mime)
00291             return mime;
00292     }
00293     if ( path.endsWith( QLatin1Char('/') ) || path.isEmpty() ) {
00294         // We have no filename at all. Maybe the protocol has a setting for
00295         // which mimetype this means (e.g. directory).
00296         // For HTTP (def==defaultMimeType()) we don't assume anything,
00297         // because of redirections (e.g. freshmeat downloads).
00298         if ( def.isEmpty() ) {
00299             // Assume inode/directory, if the protocol supports listing.
00300             KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol( _url.protocol() );
00301             if ( prot && prot->supportsListing() ) {
00302                 KMimeType::Ptr mime = mimeType( QLatin1String("inode/directory") );
00303                 if (mime) { // only 0 if no mimetypes installed
00304                     return mime;
00305                 }
00306             } else
00307                 return defaultMimeTypePtr(); // == 'no idea', e.g. for "data:,foo/"
00308         }
00309     }
00310 
00311     if (accuracy)
00312         *accuracy = 0;
00313     return defaultMimeTypePtr();
00314 }
00315 
00316 KMimeType::Ptr KMimeType::findByUrl( const KUrl& url, mode_t mode,
00317                                      bool is_local_file, bool fast_mode,
00318                                      int *accuracy )
00319 {
00320     if ( !is_local_file && url.isLocalFile() )
00321         is_local_file = true;
00322     if (is_local_file && !fast_mode) {
00323         QFile file(url.toLocalFile());
00324         return findByUrlHelper(url, mode, is_local_file, &file, accuracy);
00325     }
00326     return findByUrlHelper(url, mode, is_local_file, 0, accuracy);
00327 }
00328 
00329 KMimeType::Ptr KMimeType::findByPath( const QString& path, mode_t mode,
00330                                       bool fast_mode, int* accuracy )
00331 {
00332     KUrl url;
00333     url.setPath(path);
00334     return findByUrl(url, mode, true, fast_mode, accuracy);
00335 }
00336 
00337 KMimeType::Ptr KMimeType::findByNameAndContent( const QString& name, const QByteArray& data,
00338                                                 mode_t mode, int* accuracy )
00339 {
00340     KUrl url;
00341     url.setPath(name);
00342     QBuffer buffer(const_cast<QByteArray *>(&data));
00343     return findByUrlHelper(url, mode, false, &buffer, accuracy);
00344 }
00345 
00346 KMimeType::Ptr KMimeType::findByNameAndContent( const QString& name, QIODevice* device,
00347                                                 mode_t mode, int* accuracy )
00348 {
00349     KUrl url;
00350     url.setPath(name);
00351     return findByUrlHelper(url, mode, false, device, accuracy);
00352 }
00353 
00354 QString KMimeType::extractKnownExtension(const QString &fileName)
00355 {
00356     QString pattern;
00357     KMimeTypeRepository::self()->findFromFileName( fileName, &pattern );
00358     return pattern;
00359 }
00360 
00361 KMimeType::Ptr KMimeType::findByContent( const QByteArray &data, int *accuracy )
00362 {
00363     QBuffer buffer(const_cast<QByteArray *>(&data));
00364     buffer.open(QIODevice::ReadOnly);
00365     QByteArray cache;
00366     return KMimeTypeRepository::self()->findFromContent(&buffer, accuracy, cache);
00367 }
00368 
00369 KMimeType::Ptr KMimeType::findByContent( QIODevice* device, int* accuracy )
00370 {
00371     QByteArray cache;
00372     return KMimeTypeRepository::self()->findFromContent(device, accuracy, cache);
00373 }
00374 
00375 KMimeType::Ptr KMimeType::findByFileContent( const QString &fileName, int *accuracy )
00376 {
00377     checkEssentialMimeTypes();
00378 
00379     QFile device(fileName);
00380     // Look at mode first
00381     KMimeType::Ptr mimeFromMode = findFromMode( fileName, 0, true );
00382     if (mimeFromMode) {
00383         if (accuracy)
00384             *accuracy = 100;
00385         return mimeFromMode;
00386     }
00387     if (!device.open(QIODevice::ReadOnly)) {
00388         if (accuracy)
00389             *accuracy = 0;
00390         return KMimeType::defaultMimeTypePtr();
00391     }
00392 
00393     QByteArray cache;
00394     return KMimeTypeRepository::self()->findFromContent(&device, accuracy, cache);
00395 }
00396 
00397 bool KMimeType::isBinaryData( const QString &fileName )
00398 {
00399     QFile file(fileName);
00400     if (!file.open(QIODevice::ReadOnly))
00401         return false; // err, whatever
00402     const QByteArray data = file.read(32);
00403     return isBufferBinaryData(data);
00404 }
00405 
00406 KMimeType::KMimeType( KMimeTypePrivate &dd, const QString& name,
00407                       const QString& comment )
00408     : KServiceType( dd, name, comment )
00409 {
00410 }
00411 
00412 KMimeType::KMimeType( const QString & fullpath, const QString& name,
00413                       const QString& comment )
00414     : KServiceType( *new KMimeTypePrivate(fullpath), name, comment )
00415 {
00416 }
00417 
00418 KMimeType::KMimeType( KMimeTypePrivate &dd)
00419     : KServiceType(dd)
00420 {
00421 }
00422 
00423 KMimeType::KMimeType( QDataStream& _str, int offset )
00424     : KServiceType( *new KMimeTypePrivate(_str, offset ))
00425 {
00426 }
00427 
00428 void KMimeTypePrivate::save( QDataStream& _str )
00429 {
00430     KServiceTypePrivate::save( _str );
00431     // Warning adding fields here involves a binary incompatible change - update version
00432     // number in ksycoca.h. Never remove fields.
00433     _str << m_lstPatterns << QString() << QStringList() << m_iconName;
00434 }
00435 
00436 QVariant KMimeTypePrivate::property( const QString& _name ) const
00437 {
00438     if ( _name == QLatin1String("Patterns") )
00439         return QVariant( m_lstPatterns );
00440     if ( _name == QLatin1String("Icon") )
00441         return QVariant( iconName(KUrl()) );
00442 
00443     return KServiceTypePrivate::property( _name );
00444 }
00445 
00446 QStringList KMimeTypePrivate::propertyNames() const
00447 {
00448     QStringList res = KServiceTypePrivate::propertyNames();
00449     res.append( QString::fromLatin1("Patterns") );
00450     res.append( QString::fromLatin1("Icon") );
00451     return res;
00452 }
00453 
00454 KMimeType::~KMimeType()
00455 {
00456 }
00457 
00458 QString KMimeType::iconNameForUrl( const KUrl & _url, mode_t mode )
00459 {
00460     const KMimeType::Ptr mt = findByUrl( _url, mode, _url.isLocalFile(),
00461                                          false /*HACK*/);
00462     if (!mt) {
00463         return QString();
00464     }
00465     static const QString& unknown = KGlobal::staticQString("unknown");
00466     const QString mimeTypeIcon = mt->iconName( _url );
00467     QString i = mimeTypeIcon;
00468 
00469     // if we don't find an icon, maybe we can use the one for the protocol
00470     if ( i == unknown || i.isEmpty() || mt->name() == defaultMimeType()
00471         // and for the root of the protocol (e.g. trash:/) the protocol icon has priority over the mimetype icon
00472         || _url.path().length() <= 1 )
00473     {
00474         i = favIconForUrl( _url ); // maybe there is a favicon?
00475 
00476         if ( i.isEmpty() )
00477             i = KProtocolInfo::icon( _url.protocol() );
00478 
00479         // root of protocol: if we found nothing, revert to mimeTypeIcon (which is usually "folder")
00480         if ( _url.path().length() <= 1 && ( i == unknown || i.isEmpty() ) )
00481             i = mimeTypeIcon;
00482     }
00483     return !i.isEmpty() ? i : unknown;
00484 }
00485 
00486 QString KMimeType::favIconForUrl( const KUrl& url )
00487 {
00488     if (url.isLocalFile()
00489         || !url.protocol().startsWith(QLatin1String("http"))
00490         || !KMimeTypeRepository::self()->useFavIcons())
00491         return QString();
00492 
00493     QDBusInterface kded( QString::fromLatin1("org.kde.kded"),
00494                          QString::fromLatin1("/modules/favicons"),
00495                          QString::fromLatin1("org.kde.FavIcon") );
00496     QDBusReply<QString> result = kded.call( QString::fromLatin1("iconForUrl"), url.url() );
00497     return result;              // default is QString()
00498 }
00499 
00500 QString KMimeType::comment( const KUrl &url) const
00501 {
00502     Q_D(const KMimeType);
00503     return d->comment(url);
00504 }
00505 
00506 #ifndef KDE_NO_DEPRECATED
00507 QString KMimeType::parentMimeType() const
00508 {
00509     const QStringList parents = parentMimeTypes();
00510     if (!parents.isEmpty())
00511         return parents.first();
00512     return QString();
00513 }
00514 #endif
00515 
00516 bool KMimeTypePrivate::inherits(const QString& mime) const
00517 {
00518     QStack<QString> toCheck;
00519     toCheck.push(m_strName);
00520     while (!toCheck.isEmpty()) {
00521         const QString current = toCheck.pop();
00522         if (current == mime)
00523             return true;
00524         Q_FOREACH(const QString& parent, KMimeTypeRepository::self()->parents(current)) {
00525             toCheck.push(parent);
00526         }
00527     }
00528     return false;
00529 }
00530 
00531 bool KMimeType::is( const QString& mimeTypeName ) const
00532 {
00533     Q_D(const KMimeType);
00534     if (name() == mimeTypeName)
00535         return true;
00536     const QString mime = KMimeTypeRepository::self()->canonicalName(mimeTypeName);
00537     return d->inherits(mime);
00538 }
00539 
00540 QStringList KMimeType::parentMimeTypes() const
00541 {
00542     Q_D(const KMimeType);
00543     return KMimeTypeRepository::self()->parents(d->m_strName);
00544 }
00545 
00546 static void collectParentMimeTypes(const QString& mime, QStringList& allParents)
00547 {
00548     QStringList parents = KMimeTypeRepository::self()->parents(mime);
00549     Q_FOREACH(const QString& parent, parents) {
00550         // I would use QSet, but since order matters I better not
00551         if (!allParents.contains(parent))
00552             allParents.append(parent);
00553     }
00554     // We want a breadth-first search, so that the least-specific parent (octet-stream) is last
00555     // This means iterating twice, unfortunately.
00556     Q_FOREACH(const QString& parent, parents) {
00557         collectParentMimeTypes(parent, allParents);
00558     }
00559 }
00560 
00561 QStringList KMimeType::allParentMimeTypes() const
00562 {
00563     Q_D(const KMimeType);
00564     QStringList allParents;
00565     const QString canonical = KMimeTypeRepository::self()->resolveAlias(name());
00566     if (!canonical.isEmpty())
00567         allParents.append(canonical);
00568     collectParentMimeTypes(d->m_strName, allParents);
00569     return allParents;
00570 }
00571 
00572 QString KMimeType::defaultMimeType()
00573 {
00574     static const QString & s_strDefaultMimeType =
00575         KGlobal::staticQString( "application/octet-stream" );
00576     return s_strDefaultMimeType;
00577 }
00578 
00579 QString KMimeType::iconName( const KUrl& url) const
00580 {
00581     Q_D(const KMimeType);
00582     return d->iconName(url);
00583 }
00584 
00585 QStringList KMimeType::patterns() const
00586 {
00587     Q_D(const KMimeType);
00588     d->ensureXmlDataLoaded();
00589     return d->m_lstPatterns;
00590 }
00591 
00592 // loads comment, icon, mainPattern, m_lstPatterns
00593 void KMimeTypePrivate::ensureXmlDataLoaded() const
00594 {
00595     if (m_xmlDataLoaded)
00596         return;
00597 
00598     m_xmlDataLoaded = true;
00599 
00600     const QString file = m_strName + QLatin1String(".xml");
00601     const QStringList mimeFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", file);
00602     if (mimeFiles.isEmpty()) {
00603         kWarning() << "No file found for" << file << ", even though the file appeared in a directory listing.";
00604         kWarning() << "Either it was just removed, or the directory doesn't have executable permission...";
00605         kWarning() << KGlobal::dirs()->resourceDirs("xdgdata-mime");
00606         return;
00607     }
00608 
00609     QString comment;
00610     QString mainPattern;
00611     const QStringList languageList = KGlobal::locale()->languageList();
00612     QString preferredLanguage = languageList.first();
00613     QMap<QString, QString> commentsByLanguage;
00614 
00615     QListIterator<QString> mimeFilesIter(mimeFiles);
00616     mimeFilesIter.toBack();
00617     while (mimeFilesIter.hasPrevious()) { // global first, then local.
00618         const QString fullPath = mimeFilesIter.previous();
00619         QFile qfile(fullPath);
00620         if (!qfile.open(QFile::ReadOnly))
00621             continue;
00622 
00623         QXmlStreamReader xml(&qfile);
00624         if (xml.readNextStartElement()) {
00625             if (xml.name() != "mime-type") {
00626                 continue;
00627             }
00628             const QString name = xml.attributes().value(QLatin1String("type")).toString();
00629             if (name.isEmpty())
00630                 continue;
00631             if (name != m_strName) {
00632                 kWarning() << "Got name" << name << "in file" << file << "expected" << m_strName;
00633             }
00634 
00635             while (xml.readNextStartElement()) {
00636                 const QStringRef tag = xml.name();
00637                 if (tag == "comment") {
00638                     QString lang = xml.attributes().value(QLatin1String("xml:lang")).toString();
00639                     const QString text = xml.readElementText();
00640                     if (lang.isEmpty()) {
00641                         lang = QLatin1String("en_US");
00642                     }
00643                     if (lang == preferredLanguage) {
00644                         comment = text;
00645                     } else {
00646                         commentsByLanguage.insert(lang, text);
00647                     }
00648                     continue; // we called readElementText, so we're at the EndElement already.
00649                 } else if (tag == "icon") { // as written out by shared-mime-info >= 0.40
00650                     m_iconName = xml.attributes().value(QLatin1String("name")).toString();
00651                 } else if (tag == "glob-deleteall") { // as written out by shared-mime-info >= 0.70
00652                     mainPattern.clear();
00653                     m_lstPatterns.clear();
00654                 } else if (tag == "glob") { // as written out by shared-mime-info >= 0.70
00655                     const QString pattern = xml.attributes().value(QLatin1String("pattern")).toString();
00656                     if (mainPattern.isEmpty() && pattern.startsWith(QLatin1Char('*'))) {
00657                         mainPattern = pattern;
00658                     }
00659                     if (!m_lstPatterns.contains(pattern))
00660                         m_lstPatterns.append(pattern);
00661                 }
00662                 xml.skipCurrentElement();
00663             }
00664             if (xml.name() != "mime-type") {
00665                 kFatal() << "Programming error in KMimeType XML loading, please create a bug report on http://bugs.kde.org and attach the file" << fullPath;
00666             }
00667         }
00668     }
00669 
00670     if (comment.isEmpty()) {
00671         Q_FOREACH(const QString& lang, languageList) {
00672             const QString comm = commentsByLanguage.value(lang);
00673             if (!comm.isEmpty()) {
00674                 comment = comm;
00675                 break;
00676             }
00677             const int pos = lang.indexOf(QLatin1Char('_'));
00678             if (pos != -1) {
00679                 // "pt_BR" not found? try just "pt"
00680                 const QString shortLang = lang.left(pos);
00681                 const QString comm = commentsByLanguage.value(shortLang);
00682                 if (!comm.isEmpty()) {
00683                     comment = comm;
00684                     break;
00685                 }
00686             }
00687         }
00688         if (comment.isEmpty()) {
00689             kWarning() << "Missing <comment> field in" << file;
00690         }
00691     }
00692     m_strComment = comment;
00693 
00694     const bool globsInXml = (KMimeType::sharedMimeInfoVersion() >= KDE_MAKE_VERSION(0, 70, 0));
00695     if (globsInXml) {
00696         if (!mainPattern.isEmpty() && m_lstPatterns.first() != mainPattern) {
00697             // ensure it's first in the list of patterns
00698             m_lstPatterns.removeAll(mainPattern);
00699             m_lstPatterns.prepend(mainPattern);
00700         }
00701     } else {
00702         // Fallback: get the patterns from the globs file
00703         m_lstPatterns = KMimeTypeRepository::self()->patternsForMimetype(m_strName);
00704     }
00705 }
00706 
00707 QString KMimeType::userSpecifiedIconName() const
00708 {
00709     Q_D(const KMimeType);
00710     d->ensureXmlDataLoaded();
00711     return d->m_iconName;
00712 }
00713 
00714 int KMimeType::sharedMimeInfoVersion()
00715 {
00716     return KMimeTypeRepository::self()->sharedMimeInfoVersion();
00717 }
00718 
00719 QString KMimeType::mainExtension() const
00720 {
00721     Q_D(const KMimeType);
00722 
00723 #if 1 // HACK START - can be removed once shared-mime-info >= 0.70 is used/required.
00724     // The idea was: first usable pattern from m_lstPatterns.
00725     // But update-mime-database makes a mess of the order of the patterns,
00726     // because it uses a hash internally.
00727     static const struct { const char* mime; const char* extension; } s_hardcodedMimes[] = {
00728         { "text/plain", ".txt" } };
00729     if (d->m_lstPatterns.count() > 1) {
00730         const QByteArray me = name().toLatin1();
00731         for (uint i = 0; i < sizeof(s_hardcodedMimes)/sizeof(*s_hardcodedMimes); ++i) {
00732             if (me == s_hardcodedMimes[i].mime)
00733                 return QString::fromLatin1(s_hardcodedMimes[i].extension);
00734         }
00735     }
00736 #endif // HACK END
00737 
00738      Q_FOREACH(const QString& pattern, patterns()) {
00739         // Skip if if looks like: README or *. or *.*
00740         // or *.JP*G or *.JP?
00741         if (pattern.startsWith(QLatin1String("*.")) &&
00742             pattern.length() > 2 &&
00743             pattern.indexOf(QLatin1Char('*'), 2) < 0 && pattern.indexOf(QLatin1Char('?'), 2) < 0) {
00744             return pattern.mid(1);
00745         }
00746     }
00747     // TODO we should also look into the parent mimetype's patterns, no?
00748     return QString();
00749 }
00750 
00751 bool KMimeType::matchFileName( const QString &filename, const QString &pattern )
00752 {
00753     return KMimeTypeRepository::matchFileName( filename, pattern );
00754 }
00755 
00756 int KMimeTypePrivate::serviceOffersOffset() const
00757 {
00758     return KMimeTypeFactory::self()->serviceOffersOffset(name());
00759 }

KDECore

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • 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
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal