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
00036 KBuildMimeTypeFactory::KBuildMimeTypeFactory() :
00037 KMimeTypeFactory(), m_parser(this),
00038 m_oldOtherPatternOffset(0)
00039 {
00040 m_resourceList = new KSycocaResourceList;
00041
00042 m_resourceList->add( "xdgdata-mime", "*.xml" );
00043
00044 m_fastPatternDict = new KSycocaDict();
00045 }
00046
00047
00048
00049 QStringList KBuildMimeTypeFactory::resourceTypes()
00050 {
00051 return QStringList() << "xdgdata-mime";
00052 }
00053
00054 KBuildMimeTypeFactory::~KBuildMimeTypeFactory()
00055 {
00056 delete m_resourceList;
00057 }
00058
00059 KMimeType::Ptr KBuildMimeTypeFactory::findMimeTypeByName(const QString &_name, KMimeType::FindByNameOption options)
00060 {
00061 assert (KSycoca::self()->isBuilding());
00062
00063 QString name = _name;
00064 if (options & KMimeType::ResolveAliases) {
00065 AliasesMap::const_iterator it = aliases().constFind(_name);
00066 if (it != aliases().constEnd())
00067 name = *it;
00068 }
00069
00070
00071 KSycocaEntry::Ptr servType = m_entryDict->value( name );
00072 return KMimeType::Ptr::staticCast( servType );
00073 }
00074
00075 KSycocaEntry::List KBuildMimeTypeFactory::allEntries() const
00076 {
00077 assert (KSycoca::self()->isBuilding());
00078 KSycocaEntry::List lst;
00079 KSycocaEntryDict::Iterator itmime = m_entryDict->begin();
00080 const KSycocaEntryDict::Iterator endmime = m_entryDict->end();
00081 for( ; itmime != endmime ; ++itmime )
00082 lst.append( *itmime );
00083 return lst;
00084 }
00085
00086 KSycocaEntry* KBuildMimeTypeFactory::createEntry(const QString &file, const char *resource) const
00087 {
00088
00089 const int pos = file.lastIndexOf('/');
00090 if (pos == -1)
00091 return 0;
00092 const QString dirName = file.left(pos);
00093 if (dirName == "packages")
00094 return 0;
00095
00096 QString name;
00097 QString userIcon;
00098 QString comment;
00099 QString mainPattern;
00100 QMap<QString, QString> commentsByLanguage;
00101
00102 const QStringList mimeFiles = KGlobal::dirs()->findAllResources(resource, file);
00103 QListIterator<QString> mimeFilesIter(mimeFiles);
00104 mimeFilesIter.toBack();
00105 while (mimeFilesIter.hasPrevious()) {
00106 const QString fullPath = mimeFilesIter.previous();
00107 QFile qfile(fullPath);
00108 if (!qfile.open(QFile::ReadOnly))
00109 continue;
00110 QDomDocument doc;
00111 if (!doc.setContent(&qfile)) {
00112 kWarning() << "Parse error in " << fullPath;
00113 continue;
00114 }
00115 const QDomElement mimeTypeElement = doc.documentElement();
00116 if (mimeTypeElement.tagName() != "mime-type")
00117 continue;
00118 name = mimeTypeElement.attribute("type");
00119 if (name.isEmpty())
00120 continue;
00121
00122 for ( QDomElement e = mimeTypeElement.firstChildElement();
00123 !e.isNull();
00124 e = e.nextSiblingElement() ) {
00125 const QString tag = e.tagName();
00126 if (tag == "comment") {
00127 QString lang = e.attribute("xml:lang");
00128 if (lang.isEmpty()) {
00129 comment = e.text();
00130 lang = "en";
00131 }
00132 commentsByLanguage.insert(lang, e.text());
00133 } else if (tag == "icon") {
00134 userIcon = e.attribute("name");
00135 } else if (tag == "glob-deleteall") {
00136 mainPattern.clear();
00137 m_parsedMimeTypes[name] = QString();
00138 } else if (tag == "glob" && mainPattern.isEmpty()) {
00139 const QString pattern = e.attribute("pattern");
00140 if (pattern.startsWith('*')) {
00141 mainPattern = pattern;
00142 }
00143 }
00144 }
00145 }
00146 if (name.isEmpty()) {
00147 return 0;
00148 }
00149 Q_FOREACH(const QString& lang, KGlobal::locale()->languageList()) {
00150 const QString comm = commentsByLanguage.value(lang);
00151 if (!comm.isEmpty()) {
00152 comment = comm;
00153 break;
00154 }
00155 const int pos = lang.indexOf('_');
00156 if (pos != -1) {
00157
00158 const QString shortLang = lang.left(pos);
00159 const QString comm = commentsByLanguage.value(shortLang);
00160 if (!comm.isEmpty()) {
00161 comment = comm;
00162 break;
00163 }
00164 }
00165 }
00166 if (comment.isEmpty()) {
00167 kWarning() << "Missing <comment> field in" << file;
00168 }
00169
00170
00171
00172 KMimeType* e;
00173 if ( name == "inode/directory" )
00174 e = new KFolderMimeType( file, name, comment );
00175 else
00176 e = new KMimeType( file, name, comment );
00177
00178 if (e->isDeleted())
00179 {
00180 delete e;
00181 return 0;
00182 }
00183
00184 if ( !(e->isValid()) )
00185 {
00186 kWarning(7012) << "Invalid MimeType : " << file;
00187 delete e;
00188 return 0;
00189 }
00190
00191 if (!userIcon.isEmpty()) {
00192 e->setUserSpecifiedIcon(userIcon);
00193 }
00194
00195
00196 m_parsedMimeTypes[name] = mainPattern;
00197
00198 return e;
00199 }
00200
00201 void KBuildMimeTypeFactory::saveHeader(QDataStream &str)
00202 {
00203 KSycocaFactory::saveHeader(str);
00204
00205 str << (qint32) m_fastPatternOffset;
00206 str << (qint32) m_oldOtherPatternOffset;
00207 const AliasesMap& aliasMap = aliases();
00208 str << (qint32) aliasMap.count();
00209 for (AliasesMap::const_iterator it = aliasMap.begin(); it != aliasMap.end(); ++it) {
00210 str << it.key() << it.value();
00211 }
00212 str << (qint32) m_highWeightPatternOffset;
00213 str << (qint32) m_lowWeightPatternOffset;
00214 str << (qint32) m_parentsMapOffset;
00215 }
00216
00217 void KBuildMimeTypeFactory::parseSubclassFile(const QString& fileName)
00218 {
00219 ParentsMap& parentsMap = this->parentsMap();
00220 QFile qfile( fileName );
00221
00222 if (qfile.open(QIODevice::ReadOnly)) {
00223 QTextStream stream(&qfile);
00224 stream.setCodec("ISO 8859-1");
00225 while (!stream.atEnd()) {
00226 const QString line = stream.readLine();
00227 if (line.isEmpty() || line[0] == '#')
00228 continue;
00229 const int pos = line.indexOf(' ');
00230 if (pos == -1)
00231 continue;
00232 const QString derivedTypeName = line.left(pos);
00233 KMimeType::Ptr derivedType = findMimeTypeByName(derivedTypeName, KMimeType::ResolveAliases);
00234 if (!derivedType)
00235 kWarning(7012) << fileName << " refers to unknown mimetype " << derivedTypeName;
00236 else {
00237 const QString parentTypeName = line.mid(pos+1);
00238 Q_ASSERT(!parentTypeName.isEmpty());
00239
00240 parentsMap[derivedTypeName].append(parentTypeName);
00241 }
00242 }
00243 }
00244 }
00245
00246 void KBuildMimeTypeFactory::parseAliasFile(const QString& fileName)
00247 {
00248 AliasesMap& aliasMap = aliases();
00249 QFile qfile( fileName );
00250
00251 if (qfile.open(QIODevice::ReadOnly)) {
00252 QTextStream stream(&qfile);
00253 stream.setCodec("ISO 8859-1");
00254 while (!stream.atEnd()) {
00255 const QString line = stream.readLine();
00256 if (line.isEmpty() || line[0] == '#')
00257 continue;
00258 const int pos = line.indexOf(' ');
00259 if (pos == -1)
00260 continue;
00261 const QString aliasTypeName = line.left(pos);
00262 const QString parentTypeName = line.mid(pos+1);
00263 Q_ASSERT(!aliasTypeName.isEmpty());
00264 Q_ASSERT(!parentTypeName.isEmpty());
00265 aliasMap.insert(aliasTypeName, parentTypeName);
00266 }
00267 }
00268 }
00269
00270
00271 void KBuildMimeTypeFactory::parseSubclasses()
00272 {
00273
00274 aliases().clear();
00275
00276 #if 0
00277 KSycocaEntryDict::Iterator itmime = m_entryDict->begin();
00278 const KSycocaEntryDict::Iterator endmime = m_entryDict->end();
00279 for( ; itmime != endmime ; ++itmime ) {
00280 const KSycocaEntry::Ptr& entry = (*itmime);
00281 Q_ASSERT( entry->isType( KST_KMimeType ) );
00282 KMimeType::Ptr mimeType = KMimeType::Ptr::staticCast( entry );
00283 mimeType->internalClearData();
00284 }
00285 #endif
00286
00287 const QStringList subclassFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", "subclasses");
00288
00289 Q_FOREACH(const QString& file, subclassFiles) {
00290 parseSubclassFile(file);
00291 }
00292
00293 const QStringList aliasFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", "aliases");
00294
00295 Q_FOREACH(const QString& file, aliasFiles) {
00296 parseAliasFile(file);
00297 }
00298 }
00299
00300 void KBuildMimeTypeFactory::save(QDataStream &str)
00301 {
00302 m_parser.setParsedPatternMap(m_parsedMimeTypes);
00303 m_parser.parseGlobs();
00304
00305 KSycocaFactory::save(str);
00306
00307 savePatternLists(str);
00308
00309 m_parentsMapOffset = str.device()->pos();
00310 ParentsMap& parentsMap = this->parentsMap();
00311 str << (qint32) parentsMap.count();
00312 for (ParentsMap::const_iterator it = parentsMap.constBegin(); it != parentsMap.constEnd(); ++it) {
00313 str << it.key() << it.value().join("|");
00314 }
00315
00316 int endOfFactoryData = str.device()->pos();
00317
00318
00319 saveHeader(str);
00320
00321
00322 str.device()->seek(endOfFactoryData);
00323 }
00324
00325 static bool isFastPattern(const QString& pattern)
00326 {
00327
00328 return pattern.lastIndexOf('*') == 0
00329 && pattern.lastIndexOf('.') == 1
00330
00331 && !pattern.contains('?')
00332 && !pattern.contains('[')
00333 ;
00334 }
00335
00336
00337
00338 void KBuildMimeTypeFactory::savePatternLists(QDataStream &str)
00339 {
00340
00341
00342
00343
00344 OtherPatternList highWeightPatternOffset, lowWeightPatternOffset;
00345
00346
00347 const KMimeFileParser::AllGlobs& allGlobs = m_parser.mimeTypeGlobs();
00348 Q_FOREACH(const QString& mimeTypeName, m_parser.allMimeTypes()) {
00349 const KMimeType::Ptr mimeType = findMimeTypeByName(mimeTypeName, KMimeType::DontResolveAlias);
00350 const KMimeFileParser::GlobList globs = allGlobs.value(mimeTypeName);
00351 Q_FOREACH(const KMimeFileParser::Glob& glob, globs) {
00352 const QString &pattern = glob.pattern;
00353 Q_ASSERT(!pattern.isEmpty());
00354 if (glob.weight == 50 && isFastPattern(pattern)) {
00355
00356
00357 m_fastPatternDict->add(pattern.mid(2) , KSycocaEntry::Ptr::staticCast(mimeType));
00358 } else if (glob.weight > 50) {
00359 highWeightPatternOffset.append(OtherPattern(pattern, mimeType->offset(), glob.weight));
00360 } else {
00361 lowWeightPatternOffset.append(OtherPattern(pattern, mimeType->offset(), glob.weight));
00362 }
00363 }
00364 }
00365
00366 m_fastPatternOffset = str.device()->pos();
00367 m_fastPatternDict->save(str);
00368
00369
00370
00371
00372 m_highWeightPatternOffset = str.device()->pos();
00373 Q_FOREACH(const OtherPattern& op, highWeightPatternOffset) {
00374 str << op.pattern;
00375 str << (qint32)op.offset;
00376 str << (qint32)op.weight;
00377 }
00378 str << QString("");
00379
00380 m_lowWeightPatternOffset = str.device()->pos();
00381 Q_FOREACH(const OtherPattern& op, lowWeightPatternOffset) {
00382 str << op.pattern;
00383 str << (qint32)op.offset;
00384 str << (qint32)op.weight;
00385 }
00386 str << QString("");
00387
00388
00389 m_oldOtherPatternOffset = str.device()->pos();
00390 str << QString("");
00391 }