KDED
kbuildmimetypefactory.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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 #include "kmimefileparser.h"
00036
00037 KBuildMimeTypeFactory::KBuildMimeTypeFactory() :
00038 KMimeTypeFactory()
00039 {
00040 m_resourceList = new KSycocaResourceList;
00041
00042 m_resourceList->add( "xdgdata-mime", "*.xml" );
00043 }
00044
00045
00046
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().find(_name);
00064 if (it != aliases().end())
00065 name = *it;
00066 }
00067
00068
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
00087 const int pos = file.lastIndexOf('/');
00088 if (pos == -1)
00089 return 0;
00090 const QString dirName = file.left(pos);
00091
00092
00093 if (dirName == "packages")
00094 return 0;
00095
00096 const QString fullPath = KGlobal::dirs()->locate( resource, file );
00097 if (fullPath.isEmpty())
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 }
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
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
00166 str << (qint32) m_fastPatternOffset;
00167 str << (qint32) m_otherPatternOffset;
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 }
00174
00175 void KBuildMimeTypeFactory::parseSubclassFile(const QString& fileName)
00176 {
00177 QFile qfile( fileName );
00178 kDebug(7021) << "Now parsing" << fileName;
00179 if (qfile.open(QIODevice::ReadOnly)) {
00180 QTextStream stream(&qfile);
00181 stream.setCodec("UTF-8");
00182 while (!stream.atEnd()) {
00183 const QString line = stream.readLine();
00184 if (line.isEmpty() || line[0] == '#')
00185 continue;
00186 const int pos = line.indexOf(' ');
00187 if (pos == -1)
00188 continue;
00189 const QString derivedTypeName = line.left(pos);
00190 KMimeType::Ptr derivedType = findMimeTypeByName(derivedTypeName);
00191 if (!derivedType)
00192 kWarning(7012) << fileName << " refers to unknown mimetype " << derivedTypeName;
00193 else {
00194 const QString parentTypeName = line.mid(pos+1);
00195 Q_ASSERT(!parentTypeName.isEmpty());
00196 derivedType->setParentMimeType(parentTypeName);
00197 }
00198 }
00199 }
00200 }
00201
00202 void KBuildMimeTypeFactory::parseAliasFile(const QString& fileName)
00203 {
00204 QFile qfile( fileName );
00205 kDebug(7021) << "Now parsing" << fileName;
00206 if (qfile.open(QIODevice::ReadOnly)) {
00207 QTextStream stream(&qfile);
00208 stream.setCodec("UTF-8");
00209 while (!stream.atEnd()) {
00210 const QString line = stream.readLine();
00211 if (line.isEmpty() || line[0] == '#')
00212 continue;
00213 const int pos = line.indexOf(' ');
00214 if (pos == -1)
00215 continue;
00216 const QString aliasTypeName = line.left(pos);
00217 const QString parentTypeName = line.mid(pos+1);
00218 Q_ASSERT(!aliasTypeName.isEmpty());
00219 Q_ASSERT(!parentTypeName.isEmpty());
00220 aliases().insert(aliasTypeName, parentTypeName);
00221 }
00222 }
00223 }
00224
00225
00226 void KBuildMimeTypeFactory::parseSubclasses()
00227 {
00228
00229 aliases().clear();
00230
00231 KSycocaEntryDict::Iterator itmime = m_entryDict->begin();
00232 const KSycocaEntryDict::Iterator endmime = m_entryDict->end();
00233 for( ; itmime != endmime ; ++itmime ) {
00234 const KSycocaEntry::Ptr& entry = (*itmime);
00235 Q_ASSERT( entry->isType( KST_KMimeType ) );
00236 KMimeType::Ptr mimeType = KMimeType::Ptr::staticCast( entry );
00237 mimeType->internalClearData();
00238 }
00239
00240
00241 const QStringList subclassFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", "subclasses");
00242
00243 Q_FOREACH(const QString& file, subclassFiles) {
00244 parseSubclassFile(file);
00245 }
00246
00247 const QStringList aliasFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", "aliases");
00248
00249 Q_FOREACH(const QString& file, aliasFiles) {
00250 parseAliasFile(file);
00251 }
00252 }
00253
00254 void KBuildMimeTypeFactory::save(QDataStream &str)
00255 {
00256 KMimeFileParser parser(this);
00257 parser.parseGlobs();
00258
00259 KSycocaFactory::save(str);
00260
00261 savePatternLists(str);
00262
00263 int endOfFactoryData = str.device()->pos();
00264
00265
00266 saveHeader(str);
00267
00268
00269 str.device()->seek(endOfFactoryData);
00270 }
00271
00272 static bool isFastPattern(const QString& pattern)
00273 {
00274
00275 return pattern.lastIndexOf('*') == 0
00276 && pattern.lastIndexOf('.') == 1
00277
00278 && !pattern.contains('?')
00279 && !pattern.contains('[')
00280 ;
00281 }
00282
00283 void
00284 KBuildMimeTypeFactory::savePatternLists(QDataStream &str)
00285 {
00286
00287
00288
00289
00290 typedef QMultiMap<QString, const KMimeType*> PatternMap;
00291 PatternMap otherPatterns;
00292
00293
00294 for(KSycocaEntryDict::Iterator it = m_entryDict->begin();
00295 it != m_entryDict->end();
00296 ++it)
00297 {
00298 const KSycocaEntry::Ptr& entry = (*it);
00299 Q_ASSERT( entry->isType( KST_KMimeType ) );
00300
00301 const KMimeType::Ptr mimeType = KMimeType::Ptr::staticCast( entry );
00302 const QStringList pat = mimeType->patterns();
00303 QStringList::ConstIterator patit = pat.begin();
00304 for ( ; patit != pat.end() ; ++patit )
00305 {
00306 const QString &pattern = *patit;
00307 Q_ASSERT(!pattern.isEmpty());
00308 if (isFastPattern(pattern))
00309 m_fastPatternDict->add(pattern.mid(2) , entry);
00310 else
00311 otherPatterns.insert(pattern, mimeType.constData());
00312 }
00313 }
00314
00315 m_fastPatternOffset = str.device()->pos();
00316 m_fastPatternDict->save(str);
00317
00318
00319 m_otherPatternOffset = str.device()->pos();
00320 str.device()->seek(m_otherPatternOffset);
00321
00322 for ( PatternMap::ConstIterator it = otherPatterns.begin(); it != otherPatterns.end() ; ++it )
00323 {
00324
00325 str << it.key();
00326 str << it.value()->offset();
00327 }
00328
00329 str << QString("");
00330 }
00331
00332 void
00333 KBuildMimeTypeFactory::addEntry(const KSycocaEntry::Ptr& newEntry)
00334 {
00335 KMimeType::Ptr mimeType = KMimeType::Ptr::staticCast( newEntry );
00336 if ( m_entryDict->value( newEntry->name() ) )
00337 {
00338
00339 KSycocaFactory::removeEntry(newEntry->name());
00340 }
00341 KSycocaFactory::addEntry(newEntry);
00342 }