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

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

Skip menu "kdelibs"
  • 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
Generated for kdelibs by doxygen 1.7.5
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