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