• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDED

kbuildmimetypefactory.cpp

Go to the documentation of this file.
00001 /*  This file is part of the KDE libraries
00002  *  Copyright 1999-2007 David Faure <faure@kde.org>
00003  *
00004  *  This library is free software; you can redistribute it and/or
00005  *  modify it under the terms of the GNU Library General Public
00006  *  License as published by the Free Software Foundation; either
00007  *  version 2 of the License, or (at your option) any later version.
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 "kbuildmimetypefactory.h"
00021 #include "ksycoca.h"
00022 #include "kfoldermimetype.h"
00023 #include "ksycocadict.h"
00024 #include "kresourcelist.h"
00025 
00026 #include <kglobal.h>
00027 #include <kstandarddirs.h>
00028 #include <kdebug.h>
00029 #include <klocale.h>
00030 #include <assert.h>
00031 #include <kdesktopfile.h>
00032 #include <QtCore/QHash>
00033 #include <QtCore/QFile>
00034 #include <QtXml/QDomAttr>
00035 
00036 KBuildMimeTypeFactory::KBuildMimeTypeFactory() :
00037     KMimeTypeFactory(), m_parser(this),
00038     m_oldOtherPatternOffset(0)
00039 {
00040     m_resourceList = new KSycocaResourceList;
00041     // We want all xml files under xdgdata-mime - but not packages/*.xml
00042     m_resourceList->add( "xdgdata-mime", "*.xml" );
00043 }
00044 
00045 // return all resource types for this factory
00046 // i.e. first arguments to m_resourceList->add() above
00047 QStringList KBuildMimeTypeFactory::resourceTypes()
00048 {
00049     return QStringList() << "xdgdata-mime";
00050 }
00051 
00052 KBuildMimeTypeFactory::~KBuildMimeTypeFactory()
00053 {
00054     delete m_resourceList;
00055 }
00056 
00057 KMimeType::Ptr KBuildMimeTypeFactory::findMimeTypeByName(const QString &_name, KMimeType::FindByNameOption options)
00058 {
00059     assert (KSycoca::self()->isBuilding());
00060 
00061     QString name = _name;
00062     if (options & KMimeType::ResolveAliases) {
00063         QMap<QString, QString>::const_iterator it = aliases().constFind(_name);
00064         if (it != aliases().constEnd())
00065             name = *it;
00066     }
00067 
00068     // We're building a database - the mime type must be in memory
00069     KSycocaEntry::Ptr servType = m_entryDict->value( name );
00070     return KMimeType::Ptr::staticCast( servType );
00071 }
00072 
00073 KSycocaEntry::List KBuildMimeTypeFactory::allEntries() const
00074 {
00075     assert (KSycoca::self()->isBuilding());
00076     KSycocaEntry::List lst;
00077     KSycocaEntryDict::Iterator itmime = m_entryDict->begin();
00078     const KSycocaEntryDict::Iterator endmime = m_entryDict->end();
00079     for( ; itmime != endmime ; ++itmime )
00080         lst.append( *itmime );
00081     return lst;
00082 }
00083 
00084 KSycocaEntry* KBuildMimeTypeFactory::createEntry(const QString &file, const char *resource) const
00085 {
00086     // file=text/plain.xml  ->  name=plain.xml dirName=text
00087     const int pos = file.lastIndexOf('/');
00088     if (pos == -1) // huh?
00089         return 0;
00090     const QString dirName = file.left(pos);
00091     //pos = dirName.lastIndexOf('/');
00092     //dirName = dirName.mid(pos+1);
00093     if (dirName == "packages") // special subdir
00094         return 0;
00095 
00096     const QString fullPath = KGlobal::dirs()->locate( resource, file );
00097     if (fullPath.isEmpty()) // can't happen
00098         return 0;
00099     QFile qfile(fullPath);
00100     if (!qfile.open(QFile::ReadOnly))
00101         return 0;
00102     QDomDocument doc;
00103     if (!doc.setContent(&qfile)) {
00104         kWarning() << "Parse error in " << fullPath;
00105         return 0;
00106     }
00107     const QDomElement mimeTypeElement = doc.documentElement();
00108     if (mimeTypeElement.tagName() != "mime-type")
00109         return 0;
00110     const QString name = mimeTypeElement.attribute("type");
00111     if (name.isEmpty())
00112         return 0;
00113 
00114     QString comment;
00115     QMap<QString, QString> commentsByLanguage;
00116     for ( QDomElement e = mimeTypeElement.firstChildElement();
00117           !e.isNull();
00118           e = e.nextSiblingElement() ) {
00119         if(e.tagName() == "comment") {
00120             const QString lang = e.attribute("xml:lang");
00121             if (lang.isEmpty())
00122                 comment = e.text();
00123             else
00124                 commentsByLanguage.insert(lang, e.text());
00125         } // TODO handle "icon" and "generic-icon"
00126     }
00127     if (comment.isEmpty()) {
00128         kWarning() << "Missing <comment> field in " << fullPath;
00129     }
00130     foreach(const QString& lang, KGlobal::locale()->languageList()) {
00131         const QString comm = commentsByLanguage.value(lang);
00132         if (!comm.isEmpty()) {
00133             comment = comm;
00134             break;
00135         }
00136     }
00137 
00138     //kDebug() << "Creating mimetype" << name << "from file" << file << "path" << fullPath;
00139 
00140     KMimeType* e;
00141     if ( name == "inode/directory" )
00142         e = new KFolderMimeType( file, name, comment );
00143     else
00144         e = new KMimeType( file, name, comment );
00145 
00146     if (e->isDeleted())
00147     {
00148         delete e;
00149         return 0;
00150     }
00151 
00152     if ( !(e->isValid()) )
00153     {
00154         kWarning(7012) << "Invalid MimeType : " << file;
00155         delete e;
00156         return 0;
00157     }
00158 
00159     return e;
00160 }
00161 
00162 void KBuildMimeTypeFactory::saveHeader(QDataStream &str)
00163 {
00164     KSycocaFactory::saveHeader(str);
00165     // This header is read by KMimeTypeFactory's constructor
00166     str << (qint32) m_fastPatternOffset;
00167     str << (qint32) m_oldOtherPatternOffset;
00168     const QMap<QString, QString>& aliasMap = aliases();
00169     str << (qint32) aliasMap.count();
00170     for (QMap<QString, QString>::const_iterator it = aliasMap.begin(); it != aliasMap.end(); ++it) {
00171         str << it.key() << it.value();
00172     }
00173     str << (qint32) m_highWeightPatternOffset;
00174     str << (qint32) m_lowWeightPatternOffset;
00175 }
00176 
00177 void KBuildMimeTypeFactory::parseSubclassFile(const QString& fileName)
00178 {
00179     QFile qfile( fileName );
00180     kDebug(7021) << "Now parsing" << fileName;
00181     if (qfile.open(QIODevice::ReadOnly)) {
00182         QTextStream stream(&qfile);
00183         stream.setCodec("UTF-8");
00184         while (!stream.atEnd()) {
00185             const QString line = stream.readLine();
00186             if (line.isEmpty() || line[0] == '#')
00187                 continue;
00188             const int pos = line.indexOf(' ');
00189             if (pos == -1) // syntax error
00190                 continue;
00191             const QString derivedTypeName = line.left(pos);
00192             KMimeType::Ptr derivedType = findMimeTypeByName(derivedTypeName, KMimeType::ResolveAliases);
00193             if (!derivedType)
00194                 kWarning(7012) << fileName << " refers to unknown mimetype " << derivedTypeName;
00195             else {
00196                 const QString parentTypeName = line.mid(pos+1);
00197                 Q_ASSERT(!parentTypeName.isEmpty());
00198                 derivedType->setParentMimeType(parentTypeName);
00199             }
00200         }
00201     }
00202 }
00203 
00204 void KBuildMimeTypeFactory::parseAliasFile(const QString& fileName)
00205 {
00206     QFile qfile( fileName );
00207     kDebug(7021) << "Now parsing" << fileName;
00208     if (qfile.open(QIODevice::ReadOnly)) {
00209         QTextStream stream(&qfile);
00210         stream.setCodec("UTF-8");
00211         while (!stream.atEnd()) {
00212             const QString line = stream.readLine();
00213             if (line.isEmpty() || line[0] == '#')
00214                 continue;
00215             const int pos = line.indexOf(' ');
00216             if (pos == -1) // syntax error
00217                 continue;
00218             const QString aliasTypeName = line.left(pos);
00219             const QString parentTypeName = line.mid(pos+1);
00220             Q_ASSERT(!aliasTypeName.isEmpty());
00221             Q_ASSERT(!parentTypeName.isEmpty());
00222             aliases().insert(aliasTypeName, parentTypeName);
00223         }
00224     }
00225 }
00226 
00227 // Called by kbuildsycoca since it needs the subclasses and aliases for the trader index
00228 void KBuildMimeTypeFactory::parseSubclasses()
00229 {
00230     // First clear up any old data (loaded by the incremental mode) that we are going to reload anyway
00231     aliases().clear();
00232 
00233     KSycocaEntryDict::Iterator itmime = m_entryDict->begin();
00234     const KSycocaEntryDict::Iterator endmime = m_entryDict->end();
00235     for( ; itmime != endmime ; ++itmime ) {
00236         const KSycocaEntry::Ptr& entry = (*itmime);
00237         Q_ASSERT( entry->isType( KST_KMimeType ) );
00238         KMimeType::Ptr mimeType = KMimeType::Ptr::staticCast( entry );
00239         mimeType->internalClearData();
00240     }
00241 
00242 
00243     const QStringList subclassFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", "subclasses");
00244     //kDebug() << subclassFiles;
00245     Q_FOREACH(const QString& file, subclassFiles) {
00246         parseSubclassFile(file);
00247     }
00248 
00249     const QStringList aliasFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", "aliases");
00250     //kDebug() << aliasFiles;
00251     Q_FOREACH(const QString& file, aliasFiles) {
00252         parseAliasFile(file);
00253     }
00254 }
00255 
00256 void KBuildMimeTypeFactory::save(QDataStream &str)
00257 {
00258     m_parser.parseGlobs();
00259 
00260     KSycocaFactory::save(str);
00261 
00262     savePatternLists(str);
00263 
00264     int endOfFactoryData = str.device()->pos();
00265 
00266     // Update header (pass #3)
00267     saveHeader(str);
00268 
00269     // Seek to end.
00270     str.device()->seek(endOfFactoryData);
00271 }
00272 
00273 static bool isFastPattern(const QString& pattern)
00274 {
00275    // starts with "*.", has no other '*' and no other '.'
00276    return pattern.lastIndexOf('*') == 0
00277       && pattern.lastIndexOf('.') == 1
00278       // and contains no other special character
00279       && !pattern.contains('?')
00280       && !pattern.contains('[')
00281       ;
00282 }
00283 
00284 
00285 
00286 void KBuildMimeTypeFactory::savePatternLists(QDataStream &str)
00287 {
00288     // Store each patterns into either m_fastPatternDict (*.txt, *.html etc. with default weight 50)
00289     // or for the rest, like core.*, *.tar.bz2, *~, into highWeightPatternOffset (>50)
00290     // or lowWeightPatternOffset (<=50)
00291 
00292     OtherPatternList highWeightPatternOffset, lowWeightPatternOffset;
00293 
00294     // For each entry in the globs list
00295     const KMimeFileParser::AllGlobs& allGlobs = m_parser.mimeTypeGlobs();
00296     Q_FOREACH(const QString& mimeTypeName, m_parser.allMimeTypes()) {
00297         const KMimeType::Ptr mimeType = findMimeTypeByName(mimeTypeName, KMimeType::DontResolveAlias);
00298         const KMimeFileParser::GlobList globs = allGlobs.value(mimeTypeName);
00299         Q_FOREACH(const KMimeFileParser::Glob& glob, globs) {
00300             const QString &pattern = glob.pattern;
00301             Q_ASSERT(!pattern.isEmpty());
00302             if (glob.weight == 50 && isFastPattern(pattern)) {
00303                 // The bulk of the patterns is *.foo with weight 50 --> those go into the fast
00304                 // pattern dict.
00305                 m_fastPatternDict->add(pattern.mid(2) /* extension only*/, KSycocaEntry::Ptr::staticCast(mimeType));
00306             } else if (glob.weight > 50) {
00307                 highWeightPatternOffset.append(OtherPattern(pattern, mimeType->offset(), glob.weight));
00308             } else {
00309                 lowWeightPatternOffset.append(OtherPattern(pattern, mimeType->offset(), glob.weight));
00310             }
00311         }
00312     }
00313 
00314     m_fastPatternOffset = str.device()->pos();
00315     m_fastPatternDict->save(str);
00316 
00317     // The high and low weight pattern lists are already sorted by decreasing
00318     // weight, this is done by update-mime-database.
00319 
00320     m_highWeightPatternOffset = str.device()->pos();
00321     Q_FOREACH(const OtherPattern& op, highWeightPatternOffset) {
00322         str << op.pattern;
00323         str << (qint32)op.offset;
00324         str << (qint32)op.weight;
00325     }
00326     str << QString(""); // end of list marker (has to be a string !)
00327 
00328     m_lowWeightPatternOffset = str.device()->pos();
00329     Q_FOREACH(const OtherPattern& op, lowWeightPatternOffset) {
00330         str << op.pattern;
00331         str << (qint32)op.offset;
00332         str << (qint32)op.weight;
00333     }
00334     str << QString(""); // end of list marker (has to be a string !)
00335 
00336     // For compat with kde-4.1 kdecore: write the old "other patterns" thing
00337     m_oldOtherPatternOffset = str.device()->pos();
00338     // TODO: remove once 4.2 is released.
00339     Q_FOREACH(const OtherPattern& op, highWeightPatternOffset) {
00340         str << op.pattern;
00341         str << (qint32)op.offset;
00342     }
00343     Q_FOREACH(const OtherPattern& op, lowWeightPatternOffset) {
00344         str << op.pattern;
00345         str << (qint32)op.offset;
00346     }
00347     // END TODO
00348     str << QString(""); // end of list marker (has to be a string !)
00349 }
00350 
00351 void
00352 KBuildMimeTypeFactory::addEntry(const KSycocaEntry::Ptr& newEntry)
00353 {
00354    KMimeType::Ptr mimeType = KMimeType::Ptr::staticCast( newEntry );
00355    if ( m_entryDict->value( newEntry->name() ) )
00356    {
00357      // Already exists -> replace
00358      KSycocaFactory::removeEntry(newEntry->name());
00359    }
00360    KSycocaFactory::addEntry(newEntry);
00361 }

KDED

Skip menu "KDED"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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