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

KDECore

kmimetypefactory.cpp

Go to the documentation of this file.
00001 /*  This file is part of the KDE libraries
00002  *  Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
00003  *  Copyright (C) 2006-2009 David Faure <faure@kde.org>
00004  *
00005  *  This library is free software; you can redistribute it and/or
00006  *  modify it under the terms of the GNU Library General Public
00007  *  License version 2 as published by the Free Software Foundation;
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 "kmimetypefactory.h"
00021 #include "kmimetype.h"
00022 #include "kfoldermimetype.h"
00023 #include <ksycoca.h>
00024 #include <ksycocadict.h>
00025 #include <kshell.h>
00026 #include <kdebug.h>
00027 
00028 K_GLOBAL_STATIC(KSycocaFactorySingleton<KMimeTypeFactory>, kMimeTypeFactoryInstance)
00029 
00030 KMimeTypeFactory::KMimeTypeFactory()
00031     : KSycocaFactory( KST_KMimeTypeFactory ),
00032       m_fastPatternOffset(0),
00033       m_highWeightPatternOffset(0),
00034       m_lowWeightPatternOffset(0),
00035       m_parentsMapOffset(0),
00036       m_highWeightPatternsLoaded(false),
00037       m_lowWeightPatternsLoaded(false),
00038       m_parentsMapLoaded(false),
00039       m_magicFilesParsed(false)
00040 {
00041     kMimeTypeFactoryInstance->instanceCreated(this);
00042     if (!KSycoca::self()->isBuilding()) {
00043         QDataStream* str = stream();
00044         Q_ASSERT(str);
00045         // Read Header
00046         qint32 i;
00047         (*str) >> i;
00048         m_fastPatternOffset = i;
00049         (*str) >> i;
00050         // that's the old m_otherPatternOffset, kept for compat but unused
00051 
00052         // alias map
00053         // TODO: to save time in apps that don't need this, we could
00054         // do like the parents hash (move it, store offset, and load it delayed).
00055         qint32 n;
00056         (*str) >> n;
00057         QString str1, str2;
00058         for(;n;n--) {
00059             KSycocaEntry::read(*str, str1);
00060             KSycocaEntry::read(*str, str2);
00061             m_aliases.insert(str1, str2);
00062         }
00063 
00064         (*str) >> i;
00065         m_highWeightPatternOffset = i;
00066         (*str) >> i;
00067         m_lowWeightPatternOffset = i;
00068         (*str) >> i;
00069         m_parentsMapOffset = i;
00070 
00071         const int saveOffset = str->device()->pos();
00072         // Init index tables
00073         m_fastPatternDict = new KSycocaDict(str, m_fastPatternOffset);
00074         str->device()->seek(saveOffset);
00075     } else {
00076         m_parentsMapLoaded = true;
00077     }
00078 }
00079 
00080 KMimeTypeFactory::~KMimeTypeFactory()
00081 {
00082     if (kMimeTypeFactoryInstance.exists())
00083         kMimeTypeFactoryInstance->instanceDestroyed(this);
00084     delete m_fastPatternDict;
00085 }
00086 
00087 KMimeTypeFactory * KMimeTypeFactory::self()
00088 {
00089     return kMimeTypeFactoryInstance->self();
00090 }
00091 
00092 KMimeType::Ptr KMimeTypeFactory::findMimeTypeByName(const QString &_name, KMimeType::FindByNameOption options)
00093 {
00094     if (!sycocaDict()) return KMimeType::Ptr(); // Error!
00095     assert (!KSycoca::self()->isBuilding());
00096 
00097     QString name = _name;
00098     if (options & KMimeType::ResolveAliases) {
00099         AliasesMap::const_iterator it = m_aliases.constFind(_name);
00100         if (it != m_aliases.constEnd())
00101             name = *it;
00102     }
00103 
00104     int offset = sycocaDict()->find_string( name );
00105     if (!offset) return KMimeType::Ptr(); // Not found
00106     KMimeType::Ptr newMimeType(createEntry(offset));
00107 
00108     // Check whether the dictionary was right.
00109     if (newMimeType && (newMimeType->name() != name))
00110     {
00111         // No it wasn't...
00112         newMimeType = 0; // Not found
00113     }
00114     return newMimeType;
00115 }
00116 
00117 bool KMimeTypeFactory::checkMimeTypes()
00118 {
00119    QDataStream *str = KSycoca::self()->findFactory( factoryId() );
00120    if (!str) return false;
00121 
00122    // check if there are mimetypes
00123    return !isEmpty();
00124 }
00125 
00126 KMimeType * KMimeTypeFactory::createEntry(int offset) const
00127 {
00128    KMimeType *newEntry = 0;
00129    KSycocaType type;
00130    QDataStream *str = KSycoca::self()->findEntry(offset, type);
00131    if (!str) return 0;
00132 
00133    switch(type)
00134    {
00135      case KST_KMimeType:
00136      case KST_KDEDesktopMimeType: // old, compat only
00137         newEntry = new KMimeType(*str, offset);
00138         break;
00139      case KST_KFolderMimeType:
00140         newEntry = new KFolderMimeType(*str, offset);
00141         break;
00142 
00143      default:
00144         kError(7011) << QString("KMimeTypeFactory: unexpected object entry in KSycoca database (type = %1)").arg((int)type) << endl;
00145         break;
00146    }
00147    if (newEntry && !newEntry->isValid())
00148    {
00149       kError(7011) << "KMimeTypeFactory: corrupt object in KSycoca database!\n" << endl;
00150       delete newEntry;
00151       newEntry = 0;
00152    }
00153    return newEntry;
00154 }
00155 
00156 
00157 QString KMimeTypeFactory::resolveAlias(const QString& mime) const
00158 {
00159     return m_aliases.value(mime);
00160 }
00161 
00162 QList<KMimeType::Ptr> KMimeTypeFactory::findFromFileName( const QString &filename, QString *matchingExtension )
00163 {
00164     // Assume we're NOT building a database
00165     if (!stream()) return QList<KMimeType::Ptr>();
00166 
00167     // "Applications MUST first try a case-sensitive match, then try again with
00168     // the filename converted to lower-case if that fails. This is so that
00169     // main.C will be seen as a C++ file, but IMAGE.GIF will still use the
00170     // *.gif pattern."
00171     QList<KMimeType::Ptr> mimeList = findFromFileNameHelper(filename, matchingExtension);
00172     if (mimeList.isEmpty()) {
00173         const QString lowerCase = filename.toLower();
00174         if (lowerCase != filename)
00175             mimeList = findFromFileNameHelper(lowerCase, matchingExtension);
00176     }
00177     return mimeList;
00178 }
00179 
00180 QList<KMimeType::Ptr> KMimeTypeFactory::findFromFastPatternDict(const QString &extension)
00181 {
00182     QList<KMimeType::Ptr> mimeList;
00183     if (!m_fastPatternDict) return mimeList; // Error!
00184 
00185     // Warning : this assumes we're NOT building a database
00186     const QList<int> offsetList = m_fastPatternDict->findMultiString(extension);
00187     if (offsetList.isEmpty()) return mimeList;
00188     const QString expectedPattern = "*."+extension;
00189     foreach(int offset, offsetList) {
00190         KMimeType::Ptr newMimeType(createEntry(offset));
00191         // Check whether the dictionary was right.
00192         if (newMimeType && newMimeType->patterns().contains(expectedPattern)) {
00193             mimeList.append(newMimeType);
00194         }
00195     }
00196     return mimeList;
00197 }
00198 
00199 bool KMimeTypeFactory::matchFileName( const QString &filename, const QString &pattern )
00200 {
00201     const int pattern_len = pattern.length();
00202     if (!pattern_len)
00203         return false;
00204     const int len = filename.length();
00205 
00206     const int starCount = pattern.count('*');
00207 
00208     // Patterns like "*~", "*.extension"
00209     if (pattern[0] == '*'  && pattern.indexOf('[') == -1 && starCount == 1)
00210     {
00211         if ( len + 1 < pattern_len ) return false;
00212 
00213         const QChar *c1 = pattern.unicode() + pattern_len - 1;
00214         const QChar *c2 = filename.unicode() + len - 1;
00215         int cnt = 1;
00216         while (cnt < pattern_len && *c1-- == *c2--)
00217             ++cnt;
00218         return cnt == pattern_len;
00219     }
00220 
00221     // Patterns like "README*" (well this is currently the only one like that...)
00222     if (starCount == 1 && pattern[pattern_len - 1] == '*') {
00223         if ( len + 1 < pattern_len ) return false;
00224         if (pattern[0] == '*')
00225             return filename.indexOf(pattern.mid(1, pattern_len - 2)) != -1;
00226 
00227         const QChar *c1 = pattern.unicode();
00228         const QChar *c2 = filename.unicode();
00229         int cnt = 1;
00230         while (cnt < pattern_len && *c1++ == *c2++)
00231            ++cnt;
00232         return cnt == pattern_len;
00233     }
00234 
00235     // Names without any wildcards like "README"
00236     if (pattern.indexOf('[') == -1 && starCount == 0 && pattern.indexOf('?'))
00237         return (pattern == filename);
00238 
00239     // Other (quite rare) patterns, like "*.anim[1-9j]": use slow but correct method
00240     QRegExp rx(pattern);
00241     rx.setPatternSyntax(QRegExp::Wildcard);
00242     return rx.exactMatch(filename);
00243 }
00244 
00245 void KMimeTypeFactory::findFromOtherPatternList(QList<KMimeType::Ptr>& matchingMimeTypes,
00246                                                 const QString &fileName,
00247                                                 QString& foundExt,
00248                                                 bool highWeight)
00249 {
00250     OtherPatternList& patternList = highWeight ? m_highWeightPatterns : m_lowWeightPatterns;
00251     bool& loaded = highWeight ? m_highWeightPatternsLoaded : m_lowWeightPatternsLoaded;
00252     if ( !loaded ) {
00253         loaded = true;
00254         // Load it only once
00255         QDataStream* str = stream();
00256         str->device()->seek( highWeight ? m_highWeightPatternOffset : m_lowWeightPatternOffset );
00257 
00258         QString pattern;
00259         qint32 mimetypeOffset;
00260         qint32 weight;
00261         Q_FOREVER {
00262             KSycocaEntry::read(*str, pattern);
00263             if (pattern.isEmpty()) // end of list
00264                 break;
00265             (*str) >> mimetypeOffset;
00266             (*str) >> weight;
00267             patternList.push_back(OtherPattern(pattern, mimetypeOffset, weight));
00268         }
00269     }
00270 
00271     int matchingPatternLength = 0;
00272     qint32 lastMatchedWeight = 0;
00273     if (!highWeight && !matchingMimeTypes.isEmpty()) {
00274         // We found matches in the fast pattern dict already:
00275         matchingPatternLength = foundExt.length() + 2; // *.foo -> length=5
00276         lastMatchedWeight = 50;
00277     }
00278     OtherPatternList::const_iterator it = patternList.constBegin();
00279     const OtherPatternList::const_iterator end = patternList.constEnd();
00280     for ( ; it != end; ++it ) {
00281         const OtherPattern op = *it;
00282         if ( matchFileName( fileName, op.pattern ) ) {
00283             // Is this a lower-weight pattern than the last match? Stop here then.
00284             if (op.weight < lastMatchedWeight)
00285                 break;
00286             if (lastMatchedWeight > 0 && op.weight > lastMatchedWeight) // can't happen
00287                 kWarning(7009) << "Assumption failed; globs2 weights not sorted correctly"
00288                                << op.weight << ">" << lastMatchedWeight;
00289             // Is this a shorter or a longer match than an existing one, or same length?
00290             if (op.pattern.length() < matchingPatternLength) {
00291                 continue; // too short, ignore
00292             } else if (op.pattern.length() > matchingPatternLength) {
00293                 // longer: clear any previous match (like *.bz2, when pattern is *.tar.bz2)
00294                 matchingMimeTypes.clear();
00295                 // remember the new "longer" length
00296                 matchingPatternLength = op.pattern.length();
00297             }
00298             KMimeType *newMimeType = createEntry( op.offset );
00299             assert (newMimeType && newMimeType->isType( KST_KMimeType ));
00300             matchingMimeTypes.push_back( KMimeType::Ptr( newMimeType ) );
00301             if (op.pattern.startsWith("*."))
00302                 foundExt = op.pattern.mid(2);
00303         }
00304     }
00305 }
00306 
00307 QList<KMimeType::Ptr> KMimeTypeFactory::findFromFileNameHelper(const QString &fileName, QString *pMatchingExtension)
00308 {
00309     // First try the high weight matches (>50), if any.
00310     QList<KMimeType::Ptr> matchingMimeTypes;
00311     QString foundExt;
00312     findFromOtherPatternList(matchingMimeTypes, fileName, foundExt, true);
00313     if (matchingMimeTypes.isEmpty()) {
00314 
00315         // Now use the "fast patterns" dict, for simple *.foo patterns with weight 50
00316         // (which is most of them, so this optimization is definitely worth it)
00317         const int lastDot = fileName.lastIndexOf('.');
00318         if (lastDot != -1) { // if no '.', skip the extension lookup
00319             const int ext_len = fileName.length() - lastDot - 1;
00320             const QString simpleExtension = fileName.right( ext_len );
00321 
00322             matchingMimeTypes = findFromFastPatternDict(simpleExtension);
00323             if (!matchingMimeTypes.isEmpty()) {
00324                 foundExt = simpleExtension;
00325                 // Can't return yet; *.tar.bz2 has to win over *.bz2, so we need the low-weight mimetypes anyway,
00326                 // at least those with weight 50.
00327             }
00328         }
00329 
00330         // Finally, try the low weight matches (<=50)
00331         findFromOtherPatternList(matchingMimeTypes, fileName, foundExt, false);
00332     }
00333     if (pMatchingExtension)
00334         *pMatchingExtension = foundExt;
00335     return matchingMimeTypes;
00336 }
00337 
00338 // TODO: remove unused whichPriority argument
00339 KMimeType::Ptr KMimeTypeFactory::findFromContent(QIODevice* device, WhichPriority whichPriority, int* accuracy, QByteArray& beginning)
00340 {
00341     Q_ASSERT(device->isOpen());
00342     if (device->size() == 0) {
00343         if (accuracy)
00344             *accuracy = 100;
00345         return findMimeTypeByName("application/x-zerosize");
00346     }
00347 
00348     if (!m_magicFilesParsed) {
00349         parseMagic();
00350         m_magicFilesParsed = true;
00351     }
00352 
00353     Q_FOREACH ( const KMimeMagicRule& rule, m_magicRules ) {
00354         // HighPriorityRules: select rules with priority >= 80
00355         // LowPriorityRules: select rules with priority < 80
00356         if ( ( whichPriority == AllRules ) ||
00357              ( (rule.priority() >= 80) == (whichPriority == HighPriorityRules) ) ) {
00358             if (rule.match(device, beginning)) {
00359                 if (accuracy)
00360                     *accuracy = rule.priority();
00361                 return findMimeTypeByName(rule.mimetype());
00362             }
00363         }
00364         // Rules are sorted by decreasing priority, so we can abort when we're past high-prio rules
00365         if (whichPriority == HighPriorityRules && rule.priority() < 80)
00366             break;
00367     }
00368 
00369     // Do fallback code so that we never return 0 - unless we were only looking for HighPriorityRules
00370     if (whichPriority != HighPriorityRules) {
00371         // Nothing worked, check if the file contents looks like binary or text
00372         if (!KMimeType::isBufferBinaryData(beginning)) {
00373             if (accuracy)
00374                 *accuracy = 5;
00375             return findMimeTypeByName("text/plain");
00376         }
00377         if (accuracy)
00378             *accuracy = 0;
00379         return KMimeType::defaultMimeTypePtr();
00380     }
00381 
00382     return KMimeType::Ptr();
00383 }
00384 
00385 KMimeType::List KMimeTypeFactory::allMimeTypes()
00386 {
00387     KMimeType::List result;
00388     const KSycocaEntry::List list = allEntries();
00389     for( KSycocaEntry::List::ConstIterator it = list.begin();
00390          it != list.end();
00391          ++it)
00392     {
00393         Q_ASSERT( (*it)->isType( KST_KMimeType ) );
00394         result.append( KMimeType::Ptr::staticCast( *it ) );
00395     }
00396     return result;
00397 }
00398 
00399 QStringList KMimeTypeFactory::parents(const QString& mime)
00400 {
00401     if (!m_parentsMapLoaded) {
00402         m_parentsMapLoaded = true;
00403         Q_ASSERT(m_parents.isEmpty());
00404         QDataStream* str = stream();
00405         str->device()->seek(m_parentsMapOffset);
00406         qint32 n;
00407         (*str) >> n;
00408         QString str1, str2;
00409         for(;n;n--) {
00410             KSycocaEntry::read(*str, str1);
00411             KSycocaEntry::read(*str, str2);
00412             m_parents.insert(str1, str2.split('|'));
00413         }
00414 
00415     }
00416     return m_parents.value(mime);
00417 }
00418 
00419 #include <arpa/inet.h> // for ntohs
00420 #include <kstandarddirs.h>
00421 #include <QFile>
00422 
00423 // Sort them in descending order of priority
00424 static bool mimeMagicRuleCompare(const KMimeMagicRule& lhs, const KMimeMagicRule& rhs) {
00425     return lhs.priority() > rhs.priority();
00426 }
00427 
00428 
00429 void KMimeTypeFactory::parseMagic()
00430 {
00431     const QStringList magicFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", "magic");
00432     //kDebug() << magicFiles;
00433     QListIterator<QString> magicIter( magicFiles );
00434     magicIter.toBack();
00435     while (magicIter.hasPrevious()) { // global first, then local. Turns out it doesn't matter though.
00436         const QString fileName = magicIter.previous();
00437         QFile magicFile(fileName);
00438         kDebug(7009) << "Now parsing " << fileName;
00439         if (magicFile.open(QIODevice::ReadOnly))
00440             m_magicRules += parseMagicFile(&magicFile, fileName);
00441     }
00442     qSort(m_magicRules.begin(), m_magicRules.end(), mimeMagicRuleCompare);
00443 }
00444 
00445 static char readNumber(qint64& value, QIODevice* file)
00446 {
00447     char ch;
00448     while (file->getChar(&ch)) {
00449         if (ch < '0' || ch > '9')
00450             return ch;
00451         value = 10 * value + ch - '0';
00452     }
00453     // eof
00454     return '\0';
00455 }
00456 
00457 
00458 #define MAKE_LITTLE_ENDIAN16(val) val = (quint16)(((quint16)(val) << 8)|((quint16)(val) >> 8))
00459 
00460 #define MAKE_LITTLE_ENDIAN32(val) \
00461    val = (((quint32)(val) & 0xFF000000U) >> 24) | \
00462          (((quint32)(val) & 0x00FF0000U) >> 8) | \
00463          (((quint32)(val) & 0x0000FF00U) << 8) | \
00464          (((quint32)(val) & 0x000000FFU) << 24)
00465 
00466 QList<KMimeMagicRule> KMimeTypeFactory::parseMagicFile(QIODevice* file, const QString& fileName) const
00467 {
00468     QList<KMimeMagicRule> rules;
00469     QByteArray header = file->read(12);
00470     if (header != QByteArray::fromRawData("MIME-Magic\0\n", 12)) {
00471         kWarning(7009) << "Invalid magic file " << fileName << " starts with " << header;
00472         return rules;
00473     }
00474     QList<KMimeMagicMatch> matches; // toplevel matches (indent==0)
00475     int priority = 0; // to avoid warning
00476     QString mimeTypeName;
00477 
00478     Q_FOREVER {
00479         char ch = '\0';
00480         bool chOk = file->getChar(&ch);
00481 
00482         if (!chOk || ch == '[') {
00483             // Finish previous section
00484             if (!mimeTypeName.isEmpty()) {
00485                 rules.append(KMimeMagicRule(mimeTypeName, priority, matches));
00486                 matches.clear();
00487                 mimeTypeName.clear();
00488             }
00489             if (file->atEnd())
00490                 break; // done
00491 
00492             // Parse new section
00493             const QString line = file->readLine();
00494             const int pos = line.indexOf(':');
00495             if (pos == -1) { // syntax error
00496                 kWarning(7009) << "Syntax error in " << mimeTypeName
00497                                << " ':' not present in section name" << endl;
00498                 break;
00499             }
00500             priority = line.left(pos).toInt();
00501             mimeTypeName = line.mid(pos+1);
00502             mimeTypeName = mimeTypeName.left(mimeTypeName.length()-2); // remove ']\n'
00503             //kDebug(7009) << "New rule for " << mimeTypeName
00504             //             << " with priority " << priority << endl;
00505         } else {
00506             // Parse line in the section
00507             // [ indent ] ">" start-offset "=" value
00508             //   [ "&" mask ] [ "~" word-size ] [ "+" range-length ] "\n"
00509             qint64 indent = 0;
00510             if (ch != '>') {
00511                 indent = ch - '0';
00512                 ch = readNumber(indent, file);
00513                 if (ch != '>') {
00514                     kWarning(7009) << "Invalid magic file " << fileName << " '>' not found, got " << ch << " at pos " << file->pos();
00515                     break;
00516                 }
00517             }
00518 
00519             KMimeMagicMatch match;
00520             match.m_rangeStart = 0;
00521             ch = readNumber(match.m_rangeStart, file);
00522             if (ch != '=') {
00523                 kWarning(7009) << "Invalid magic file " << fileName << " '=' not found";
00524                 break;
00525             }
00526 
00527             char lengthBuffer[2];
00528             if (file->read(lengthBuffer, 2) != 2)
00529                 break;
00530             const short valueLength = ntohs(*(short*)lengthBuffer);
00531             //kDebug() << "indent=" << indent << " rangeStart=" << match.m_rangeStart
00532             //         << " valueLength=" << valueLength << endl;
00533 
00534             match.m_data.resize(valueLength);
00535             if (file->read(match.m_data.data(), valueLength) != valueLength)
00536                 break;
00537 
00538             match.m_rangeLength = 1;
00539             bool invalidLine = false;
00540 
00541             if (!file->getChar(&ch))
00542                 break;
00543             qint64 wordSize = 1;
00544 
00545             Q_FOREVER {
00546                 // We get 'ch' before coming here, or as part of the parsing in each case below.
00547                 switch (ch) {
00548                 case '\n':
00549                     break;
00550                 case '&':
00551                     match.m_mask.resize(valueLength);
00552                     if (file->read(match.m_mask.data(), valueLength) != valueLength)
00553                         invalidLine = true;
00554                     if (!file->getChar(&ch))
00555                         invalidLine = true;
00556                     break;
00557                 case '~': {
00558                     wordSize = 0;
00559                     ch = readNumber(wordSize, file);
00560                     //kDebug() << "wordSize=" << wordSize;
00561                     break;
00562                 }
00563                 case '+':
00564                     // Parse range length
00565                     match.m_rangeLength = 0;
00566                     ch = readNumber(match.m_rangeLength, file);
00567                     if (ch == '\n')
00568                         break;
00569                     // fall-through intended
00570                 default:
00571                     // "If an unknown character is found where a newline is expected
00572                     // then the whole line should be ignored (there will be no binary
00573                     // data after the new character, so the next line starts after the
00574                     // next "\n" character). This is for future extensions.", says spec
00575                     while (ch != '\n' && !file->atEnd()) {
00576                         file->getChar(&ch);
00577                     }
00578                     invalidLine = true;
00579                     kDebug(7009) << "invalid line - garbage found - ch=" << ch;
00580                     break;
00581                 }
00582                 if (ch == '\n' || invalidLine)
00583                     break;
00584             }
00585             if (!invalidLine) {
00586                 // Finish match, doing byte-swapping on little endian hosts
00587 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
00588                 if (wordSize > 1) {
00589                     //kDebug() << "data before swapping: " << match.m_data;;
00590                     if ((wordSize != 2 && wordSize != 4) || (valueLength % wordSize != 0))
00591                         continue; // invalid word size
00592                     char* data = match.m_data.data();
00593                     char* mask = match.m_mask.data();
00594                     for (int i = 0; i < valueLength; i += wordSize) {
00595                         if (wordSize == 2)
00596                             MAKE_LITTLE_ENDIAN16( *((quint16 *) data + i) );
00597                         else if (wordSize == 4)
00598                             MAKE_LITTLE_ENDIAN32( *((quint32 *) data + i) );
00599                         if (!match.m_mask.isEmpty()) {
00600                             if (wordSize == 2)
00601                                 MAKE_LITTLE_ENDIAN16( *((quint16 *) mask + i) );
00602                             else if (wordSize == 4)
00603                                 MAKE_LITTLE_ENDIAN32( *((quint32 *) mask + i) );
00604                         }
00605                     }
00606                     //kDebug() << "data after swapping: " << match.m_data;
00607                 }
00608 #endif
00609                 // Append match at the right place depending on indent:
00610                 if (indent == 0) {
00611                     matches.append(match);
00612                 } else {
00613                     KMimeMagicMatch* m = &matches.last();
00614                     Q_ASSERT(m);
00615                     for (int i = 1 /* nothing to do for indent==1 */; i < indent; ++i) {
00616                         m = &m->m_subMatches.last();
00617                         Q_ASSERT(m);
00618                     }
00619                     m->m_subMatches.append(match);
00620                 }
00621             }
00622         }
00623     }
00624     return rules;
00625 }

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • 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
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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