• 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 <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                 return mimeType(mimeList.first());
00207             }
00208         }
00209     }
00210 
00211     if ( device && !device->isOpen() ) {
00212         if ( !device->open(QIODevice::ReadOnly) ) {
00213             device = 0;
00214         }
00215     }
00216 
00217     // Try the magic matches (if we can read the data)
00218     QByteArray beginning;
00219     if ( device ) {
00220         int magicAccuracy;
00221         KMimeType::Ptr mime = KMimeTypeRepository::self()->findFromContent(device, &magicAccuracy, beginning);
00222         // mime can't be 0, except in case of install problems.
00223         // However we get magicAccuracy==0 for octet-stream, i.e. no magic match found.
00224         //kDebug(servicesDebugArea()) << "findFromContent said" << (mime?mime->name():QString()) << "with accuracy" << magicAccuracy;
00225         if (mime && magicAccuracy > 0) {
00226 
00227             // Disambiguate conflicting extensions (if magic found something and the magicrule was <80)
00228             if (magicAccuracy < 80 && !mimeList.isEmpty()) {
00229                 // "for glob_match in glob_matches:"
00230                 // "if glob_match is subclass or equal to sniffed_type, use glob_match"
00231                 const QString sniffedMime = mime->name();
00232                 foreach(const QString &m, mimeList) {
00233                     KMimeType::Ptr mimeFromPattern = KMimeType::mimeType(m);
00234                     //kDebug(servicesDebugArea()) << "sniffedMime=" << sniffedMime << "mimeFromPattern=" << mimeFromPattern->name();
00235                     if (mimeFromPattern->is(sniffedMime)) {
00236                         // We have magic + pattern pointing to this, so it's a pretty good match
00237                         if (accuracy)
00238                             *accuracy = 100;
00239                         return mimeFromPattern;
00240                     }
00241                 }
00242             }
00243 
00244             if (accuracy)
00245                 *accuracy = magicAccuracy;
00246             return mime;
00247         }
00248     }
00249 
00250     // Not a local file, or no magic allowed, or magic found nothing
00251 
00252     // Maybe we had multiple matches from globs?
00253     if (!mimeList.isEmpty()) {
00254         if (accuracy)
00255             *accuracy = 20;
00256         // We have to pick one...
00257         // At least make this deterministic
00258         qSort(mimeList.begin(), mimeList.end());
00259         return mimeType(mimeList.first());
00260     }
00261 
00262     // Find a fallback from the protocol
00263     if (accuracy)
00264         *accuracy = 10;
00265     // ## this breaks with proxying; find a way to move proxying info to kdecore's kprotocolinfo?
00266     // ## or hardcode the only case of proxying that we ever had? (ftp-over-http)
00267     KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol( _url.protocol() );
00268     QString def;
00269     if (prot)
00270         def = prot->defaultMimeType();
00271     if ( !def.isEmpty() && def != defaultMimeType() ) {
00272         // The protocol says it always returns a given mimetype (e.g. text/html for "man:")
00273         KMimeType::Ptr mime = mimeType( def );
00274         if (mime)
00275             return mime;
00276     }
00277     if ( path.endsWith( QLatin1Char('/') ) || path.isEmpty() ) {
00278         // We have no filename at all. Maybe the protocol has a setting for
00279         // which mimetype this means (e.g. directory).
00280         // For HTTP (def==defaultMimeType()) we don't assume anything,
00281         // because of redirections (e.g. freshmeat downloads).
00282         if ( def.isEmpty() ) {
00283             // Assume inode/directory, if the protocol supports listing.
00284             KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol( _url.protocol() );
00285             if ( prot && prot->supportsListing() ) {
00286                 KMimeType::Ptr mime = mimeType( QLatin1String("inode/directory") );
00287                 if (mime) { // only 0 if no mimetypes installed
00288                     return mime;
00289                 }
00290             } else
00291                 return defaultMimeTypePtr(); // == 'no idea', e.g. for "data:,foo/"
00292         }
00293     }
00294 
00295     if (accuracy)
00296         *accuracy = 0;
00297     return defaultMimeTypePtr();
00298 }
00299 
00300 KMimeType::Ptr KMimeType::findByUrl( const KUrl& url, mode_t mode,
00301                                      bool is_local_file, bool fast_mode,
00302                                      int *accuracy )
00303 {
00304     if ( !is_local_file && url.isLocalFile() )
00305         is_local_file = true;
00306     if (is_local_file && !fast_mode) {
00307         QFile file(url.toLocalFile());
00308         return findByUrlHelper(url, mode, is_local_file, &file, accuracy);
00309     }
00310     return findByUrlHelper(url, mode, is_local_file, 0, accuracy);
00311 }
00312 
00313 KMimeType::Ptr KMimeType::findByPath( const QString& path, mode_t mode,
00314                                       bool fast_mode, int* accuracy )
00315 {
00316     KUrl url;
00317     url.setPath(path);
00318     return findByUrl(url, mode, true, fast_mode, accuracy);
00319 }
00320 
00321 KMimeType::Ptr KMimeType::findByNameAndContent( const QString& name, const QByteArray& data,
00322                                                 mode_t mode, int* accuracy )
00323 {
00324     KUrl url;
00325     url.setPath(name);
00326     QBuffer buffer(const_cast<QByteArray *>(&data));
00327     return findByUrlHelper(url, mode, false, &buffer, accuracy);
00328 }
00329 
00330 KMimeType::Ptr KMimeType::findByNameAndContent( const QString& name, QIODevice* device,
00331                                                 mode_t mode, int* accuracy )
00332 {
00333     KUrl url;
00334     url.setPath(name);
00335     return findByUrlHelper(url, mode, false, device, accuracy);
00336 }
00337 
00338 QString KMimeType::extractKnownExtension(const QString &fileName)
00339 {
00340     QString pattern;
00341     KMimeTypeRepository::self()->findFromFileName( fileName, &pattern );
00342     return pattern;
00343 }
00344 
00345 KMimeType::Ptr KMimeType::findByContent( const QByteArray &data, int *accuracy )
00346 {
00347     QBuffer buffer(const_cast<QByteArray *>(&data));
00348     buffer.open(QIODevice::ReadOnly);
00349     QByteArray cache;
00350     return KMimeTypeRepository::self()->findFromContent(&buffer, accuracy, cache);
00351 }
00352 
00353 KMimeType::Ptr KMimeType::findByContent( QIODevice* device, int* accuracy )
00354 {
00355     QByteArray cache;
00356     return KMimeTypeRepository::self()->findFromContent(device, accuracy, cache);
00357 }
00358 
00359 KMimeType::Ptr KMimeType::findByFileContent( const QString &fileName, int *accuracy )
00360 {
00361     checkEssentialMimeTypes();
00362 
00363     QFile device(fileName);
00364     // Look at mode first
00365     KMimeType::Ptr mimeFromMode = findFromMode( fileName, 0, true );
00366     if (mimeFromMode) {
00367         if (accuracy)
00368             *accuracy = 100;
00369         return mimeFromMode;
00370     }
00371     if (!device.open(QIODevice::ReadOnly)) {
00372         if (accuracy)
00373             *accuracy = 0;
00374         return KMimeType::defaultMimeTypePtr();
00375     }
00376 
00377     QByteArray cache;
00378     return KMimeTypeRepository::self()->findFromContent(&device, accuracy, cache);
00379 }
00380 
00381 bool KMimeType::isBinaryData( const QString &fileName )
00382 {
00383     QFile file(fileName);
00384     if (!file.open(QIODevice::ReadOnly))
00385         return false; // err, whatever
00386     const QByteArray data = file.read(32);
00387     return isBufferBinaryData(data);
00388 }
00389 
00390 KMimeType::KMimeType( KMimeTypePrivate &dd, const QString& name,
00391                       const QString& comment )
00392     : KServiceType( dd, name, comment )
00393 {
00394 }
00395 
00396 KMimeType::KMimeType( const QString & fullpath, const QString& name,
00397                       const QString& comment )
00398     : KServiceType( *new KMimeTypePrivate(fullpath), name, comment )
00399 {
00400 }
00401 
00402 KMimeType::KMimeType( KMimeTypePrivate &dd)
00403     : KServiceType(dd)
00404 {
00405 }
00406 
00407 KMimeType::KMimeType( QDataStream& _str, int offset )
00408     : KServiceType( *new KMimeTypePrivate(_str, offset ))
00409 {
00410 }
00411 
00412 void KMimeTypePrivate::save( QDataStream& _str )
00413 {
00414     KServiceTypePrivate::save( _str );
00415     // Warning adding fields here involves a binary incompatible change - update version
00416     // number in ksycoca.h. Never remove fields.
00417     _str << m_lstPatterns << QString() << QStringList() << m_iconName;
00418 }
00419 
00420 QVariant KMimeTypePrivate::property( const QString& _name ) const
00421 {
00422     if ( _name == QLatin1String("Patterns") )
00423         return QVariant( m_lstPatterns );
00424     if ( _name == QLatin1String("Icon") )
00425         return QVariant( iconName(KUrl()) );
00426 
00427     return KServiceTypePrivate::property( _name );
00428 }
00429 
00430 QStringList KMimeTypePrivate::propertyNames() const
00431 {
00432     QStringList res = KServiceTypePrivate::propertyNames();
00433     res.append( QString::fromLatin1("Patterns") );
00434     res.append( QString::fromLatin1("Icon") );
00435     return res;
00436 }
00437 
00438 KMimeType::~KMimeType()
00439 {
00440 }
00441 
00442 QString KMimeType::iconNameForUrl( const KUrl & _url, mode_t mode )
00443 {
00444     const KMimeType::Ptr mt = findByUrl( _url, mode, _url.isLocalFile(),
00445                                          false /*HACK*/);
00446     if (!mt) {
00447         return QString();
00448     }
00449     static const QString& unknown = KGlobal::staticQString("unknown");
00450     const QString mimeTypeIcon = mt->iconName( _url );
00451     QString i = mimeTypeIcon;
00452 
00453     // if we don't find an icon, maybe we can use the one for the protocol
00454     if ( i == unknown || i.isEmpty() || mt->name() == defaultMimeType()
00455         // and for the root of the protocol (e.g. trash:/) the protocol icon has priority over the mimetype icon
00456         || _url.path().length() <= 1 )
00457     {
00458         i = favIconForUrl( _url ); // maybe there is a favicon?
00459 
00460         if ( i.isEmpty() )
00461             i = KProtocolInfo::icon( _url.protocol() );
00462 
00463         // root of protocol: if we found nothing, revert to mimeTypeIcon (which is usually "folder")
00464         if ( _url.path().length() <= 1 && ( i == unknown || i.isEmpty() ) )
00465             i = mimeTypeIcon;
00466     }
00467     return !i.isEmpty() ? i : unknown;
00468 }
00469 
00470 QString KMimeType::favIconForUrl( const KUrl& url )
00471 {
00472     if (url.isLocalFile()
00473         || !url.protocol().startsWith(QLatin1String("http"))
00474         || !KMimeTypeRepository::self()->useFavIcons())
00475         return QString();
00476 
00477     QDBusInterface kded( QString::fromLatin1("org.kde.kded"),
00478                          QString::fromLatin1("/modules/favicons"),
00479                          QString::fromLatin1("org.kde.FavIcon") );
00480     QDBusReply<QString> result = kded.call( QString::fromLatin1("iconForUrl"), url.url() );
00481     return result;              // default is QString()
00482 }
00483 
00484 QString KMimeType::comment( const KUrl &url) const
00485 {
00486     Q_D(const KMimeType);
00487     return d->comment(url);
00488 }
00489 
00490 #ifndef KDE_NO_DEPRECATED
00491 QString KMimeType::parentMimeType() const
00492 {
00493     const QStringList parents = parentMimeTypes();
00494     if (!parents.isEmpty())
00495         return parents.first();
00496     return QString();
00497 }
00498 #endif
00499 
00500 bool KMimeTypePrivate::inherits(const QString& mime) const
00501 {
00502     QStack<QString> toCheck;
00503     toCheck.push(m_strName);
00504     while (!toCheck.isEmpty()) {
00505         const QString current = toCheck.pop();
00506         if (current == mime)
00507             return true;
00508         Q_FOREACH(const QString& parent, KMimeTypeRepository::self()->parents(current)) {
00509             toCheck.push(parent);
00510         }
00511     }
00512     return false;
00513 }
00514 
00515 bool KMimeType::is( const QString& mimeTypeName ) const
00516 {
00517     Q_D(const KMimeType);
00518     if (name() == mimeTypeName)
00519         return true;
00520     const QString mime = KMimeTypeRepository::self()->canonicalName(mimeTypeName);
00521     return d->inherits(mime);
00522 }
00523 
00524 QStringList KMimeType::parentMimeTypes() const
00525 {
00526     Q_D(const KMimeType);
00527     return KMimeTypeRepository::self()->parents(d->m_strName);
00528 }
00529 
00530 static void collectParentMimeTypes(const QString& mime, QStringList& allParents)
00531 {
00532     QStringList parents = KMimeTypeRepository::self()->parents(mime);
00533     Q_FOREACH(const QString& parent, parents) {
00534         // I would use QSet, but since order matters I better not
00535         if (!allParents.contains(parent))
00536             allParents.append(parent);
00537     }
00538     // We want a breadth-first search, so that the least-specific parent (octet-stream) is last
00539     // This means iterating twice, unfortunately.
00540     Q_FOREACH(const QString& parent, parents) {
00541         collectParentMimeTypes(parent, allParents);
00542     }
00543 }
00544 
00545 QStringList KMimeType::allParentMimeTypes() const
00546 {
00547     Q_D(const KMimeType);
00548     QStringList allParents;
00549     const QString canonical = KMimeTypeRepository::self()->resolveAlias(name());
00550     if (!canonical.isEmpty())
00551         allParents.append(canonical);
00552     collectParentMimeTypes(d->m_strName, allParents);
00553     return allParents;
00554 }
00555 
00556 QString KMimeType::defaultMimeType()
00557 {
00558     static const QString & s_strDefaultMimeType =
00559         KGlobal::staticQString( "application/octet-stream" );
00560     return s_strDefaultMimeType;
00561 }
00562 
00563 QString KMimeType::iconName( const KUrl& url) const
00564 {
00565     Q_D(const KMimeType);
00566     return d->iconName(url);
00567 }
00568 
00569 QStringList KMimeType::patterns() const
00570 {
00571     Q_D(const KMimeType);
00572     d->ensureXmlDataLoaded();
00573     return d->m_lstPatterns;
00574 }
00575 
00576 // loads comment, icon, mainPattern, m_lstPatterns
00577 void KMimeTypePrivate::ensureXmlDataLoaded() const
00578 {
00579     if (m_xmlDataLoaded)
00580         return;
00581 
00582     m_xmlDataLoaded = true;
00583 
00584     const QString file = m_strName + QLatin1String(".xml");
00585     const QStringList mimeFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", file);
00586     if (mimeFiles.isEmpty()) {
00587         kWarning() << "No file found for" << file << ", even though the file appeared in a directory listing.";
00588         kWarning() << "Either it was just removed, or the directory doesn't have executable permission...";
00589         kWarning() << KGlobal::dirs()->resourceDirs("xdgdata-mime");
00590         return;
00591     }
00592 
00593     QString comment;
00594     QString mainPattern;
00595     const QStringList languageList = KGlobal::locale()->languageList();
00596     QString preferredLanguage = languageList.first();
00597     QMap<QString, QString> commentsByLanguage;
00598 
00599     QListIterator<QString> mimeFilesIter(mimeFiles);
00600     mimeFilesIter.toBack();
00601     while (mimeFilesIter.hasPrevious()) { // global first, then local.
00602         const QString fullPath = mimeFilesIter.previous();
00603         QFile qfile(fullPath);
00604         if (!qfile.open(QFile::ReadOnly))
00605             continue;
00606 
00607         QXmlStreamReader xml(&qfile);
00608         if (xml.readNextStartElement()) {
00609             if (xml.name() != "mime-type") {
00610                 continue;
00611             }
00612             const QString name = xml.attributes().value(QLatin1String("type")).toString();
00613             if (name.isEmpty())
00614                 continue;
00615             if (name != m_strName) {
00616                 kWarning() << "Got name" << name << "in file" << file << "expected" << m_strName;
00617             }
00618 
00619             while (xml.readNextStartElement()) {
00620                 const QStringRef tag = xml.name();
00621                 if (tag == "comment") {
00622                     if (!comment.isEmpty()) { // already found, skip this one
00623                         xml.skipCurrentElement();
00624                         continue;
00625                     }
00626                     QString lang = xml.attributes().value(QLatin1String("xml:lang")).toString();
00627                     const QString text = xml.readElementText();
00628                     if (lang.isEmpty()) {
00629                         lang = QLatin1String("en_US");
00630                     }
00631                     if (lang == preferredLanguage) {
00632                         comment = text;
00633                     } else {
00634                         commentsByLanguage.insert(lang, text);
00635                     }
00636                     continue; // we called readElementText, so we're at the EndElement already.
00637                 } else if (tag == "icon") { // as written out by shared-mime-info >= 0.40
00638                     m_iconName = xml.attributes().value(QLatin1String("name")).toString();
00639                 } else if (tag == "glob-deleteall") { // as written out by shared-mime-info >= 0.70
00640                     mainPattern.clear();
00641                     m_lstPatterns.clear();
00642                 } else if (tag == "glob") { // as written out by shared-mime-info >= 0.70
00643                     const QString pattern = xml.attributes().value(QLatin1String("pattern")).toString();
00644                     if (mainPattern.isEmpty() && pattern.startsWith(QLatin1Char('*'))) {
00645                         mainPattern = pattern;
00646                     }
00647                     if (!m_lstPatterns.contains(pattern))
00648                         m_lstPatterns.append(pattern);
00649                 }
00650                 xml.skipCurrentElement();
00651             }
00652             if (xml.name() != "mime-type") {
00653                 kFatal() << "Programming error in KMimeType XML loading, please create a bug report on http://bugs.kde.org and attach the file" << fullPath;
00654             }
00655         }
00656     }
00657 
00658     if (comment.isEmpty()) {
00659         Q_FOREACH(const QString& lang, languageList) {
00660             const QString comm = commentsByLanguage.value(lang);
00661             if (!comm.isEmpty()) {
00662                 comment = comm;
00663                 break;
00664             }
00665             const int pos = lang.indexOf(QLatin1Char('_'));
00666             if (pos != -1) {
00667                 // "pt_BR" not found? try just "pt"
00668                 const QString shortLang = lang.left(pos);
00669                 const QString comm = commentsByLanguage.value(shortLang);
00670                 if (!comm.isEmpty()) {
00671                     comment = comm;
00672                     break;
00673                 }
00674             }
00675         }
00676         if (comment.isEmpty()) {
00677             kWarning() << "Missing <comment> field in" << file;
00678         }
00679     }
00680     m_strComment = comment;
00681 
00682     const bool globsInXml = (KMimeType::sharedMimeInfoVersion() >= KDE_MAKE_VERSION(0, 70, 0));
00683     if (globsInXml) {
00684         if (!mainPattern.isEmpty() && m_lstPatterns.first() != mainPattern) {
00685             // ensure it's first in the list of patterns
00686             m_lstPatterns.removeAll(mainPattern);
00687             m_lstPatterns.prepend(mainPattern);
00688         }
00689     } else {
00690         // Fallback: get the patterns from the globs file
00691         m_lstPatterns = KMimeTypeRepository::self()->patternsForMimetype(m_strName);
00692     }
00693 }
00694 
00695 QString KMimeType::userSpecifiedIconName() const
00696 {
00697     Q_D(const KMimeType);
00698     d->ensureXmlDataLoaded();
00699     return d->m_iconName;
00700 }
00701 
00702 int KMimeType::sharedMimeInfoVersion()
00703 {
00704     return KMimeTypeRepository::self()->sharedMimeInfoVersion();
00705 }
00706 
00707 QString KMimeType::mainExtension() const
00708 {
00709     Q_D(const KMimeType);
00710 
00711 #if 1 // HACK START - can be removed once shared-mime-info >= 0.70 is used/required.
00712     // The idea was: first usable pattern from m_lstPatterns.
00713     // But update-mime-database makes a mess of the order of the patterns,
00714     // because it uses a hash internally.
00715     static const struct { const char* mime; const char* extension; } s_hardcodedMimes[] = {
00716         { "text/plain", ".txt" } };
00717     if (d->m_lstPatterns.count() > 1) {
00718         const QByteArray me = name().toLatin1();
00719         for (uint i = 0; i < sizeof(s_hardcodedMimes)/sizeof(*s_hardcodedMimes); ++i) {
00720             if (me == s_hardcodedMimes[i].mime)
00721                 return QString::fromLatin1(s_hardcodedMimes[i].extension);
00722         }
00723     }
00724 #endif // HACK END
00725 
00726      Q_FOREACH(const QString& pattern, patterns()) {
00727         // Skip if if looks like: README or *. or *.*
00728         // or *.JP*G or *.JP?
00729         if (pattern.startsWith(QLatin1String("*.")) &&
00730             pattern.length() > 2 &&
00731             pattern.indexOf(QLatin1Char('*'), 2) < 0 && pattern.indexOf(QLatin1Char('?'), 2) < 0) {
00732             return pattern.mid(1);
00733         }
00734     }
00735     // TODO we should also look into the parent mimetype's patterns, no?
00736     return QString();
00737 }
00738 
00739 int KMimeTypePrivate::serviceOffersOffset() const
00740 {
00741     return KMimeTypeFactory::self()->serviceOffersOffset(name());
00742 }

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