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
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().constFind(_name);
00064 if (it != aliases().constEnd())
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_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)
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)
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
00228 void KBuildMimeTypeFactory::parseSubclasses()
00229 {
00230
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
00245 Q_FOREACH(const QString& file, subclassFiles) {
00246 parseSubclassFile(file);
00247 }
00248
00249 const QStringList aliasFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", "aliases");
00250
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
00267 saveHeader(str);
00268
00269
00270 str.device()->seek(endOfFactoryData);
00271 }
00272
00273 static bool isFastPattern(const QString& pattern)
00274 {
00275
00276 return pattern.lastIndexOf('*') == 0
00277 && pattern.lastIndexOf('.') == 1
00278
00279 && !pattern.contains('?')
00280 && !pattern.contains('[')
00281 ;
00282 }
00283
00284
00285
00286 void KBuildMimeTypeFactory::savePatternLists(QDataStream &str)
00287 {
00288
00289
00290
00291
00292 OtherPatternList highWeightPatternOffset, lowWeightPatternOffset;
00293
00294
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
00304
00305 m_fastPatternDict->add(pattern.mid(2) , 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
00318
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("");
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("");
00335
00336
00337 m_oldOtherPatternOffset = str.device()->pos();
00338
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
00348 str << QString("");
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
00358 KSycocaFactory::removeEntry(newEntry->name());
00359 }
00360 KSycocaFactory::addEntry(newEntry);
00361 }