kservicetypefactory.cpp

00001 /*  This file is part of the KDE libraries
00002  *  Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
00003  *
00004  *  This library is free software; you can redistribute it and/or
00005  *  modify it under the terms of the GNU Library General Public
00006  *  License version 2 as published by the Free Software Foundation;
00007  *
00008  *  This library is distributed in the hope that it will be useful,
00009  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011  *  Library General Public License for more details.
00012  *
00013  *  You should have received a copy of the GNU Library General Public License
00014  *  along with this library; see the file COPYING.LIB.  If not, write to
00015  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016  *  Boston, MA 02110-1301, USA.
00017  **/
00018 
00019 #include "kservicetypefactory.h"
00020 #include "ksycoca.h"
00021 #include "ksycocatype.h"
00022 #include "ksycocadict.h"
00023 #include "kservicetype.h"
00024 #include "kmimetype.h"
00025 #include "kuserprofile.h"
00026 
00027 #include <kapplication.h>
00028 #include <kdebug.h>
00029 #include <assert.h>
00030 #include <kstringhandler.h>
00031 #include <qfile.h>
00032 
00033 KServiceTypeFactory::KServiceTypeFactory()
00034  : KSycocaFactory( KST_KServiceTypeFactory )
00035 {
00036    _self = this;
00037    m_fastPatternOffset = 0;
00038    m_otherPatternOffset = 0;
00039    if (m_str)
00040    {
00041       // Read Header
00042       Q_INT32 i,n;
00043       (*m_str) >> i;
00044       m_fastPatternOffset = i;
00045       (*m_str) >> i;
00046       m_otherPatternOffset = i;
00047       (*m_str) >> n;
00048 
00049       if (n > 1024)
00050       {
00051          KSycoca::flagError();
00052       }
00053       else
00054       {
00055          QString str;
00056          for(;n;n--)
00057          {
00058             KSycocaEntry::read(*m_str, str);
00059             (*m_str) >> i;
00060             m_propertyTypeDict.insert(str, i);
00061          }
00062       }
00063    }
00064 }
00065 
00066 
00067 KServiceTypeFactory::~KServiceTypeFactory()
00068 {
00069   _self = 0L;
00070   KServiceTypeProfile::clear();
00071 }
00072 
00073 KServiceTypeFactory * KServiceTypeFactory::self()
00074 {
00075   if (!_self)
00076     _self = new KServiceTypeFactory();
00077   return _self;
00078 }
00079 
00080 KServiceType * KServiceTypeFactory::findServiceTypeByName(const QString &_name)
00081 {
00082    if (!m_sycocaDict) return 0L; // Error!
00083    assert (!KSycoca::self()->isBuilding());
00084    int offset = m_sycocaDict->find_string( _name );
00085    if (!offset) return 0; // Not found
00086    KServiceType * newServiceType = createEntry(offset);
00087 
00088    // Check whether the dictionary was right.
00089    if (newServiceType && (newServiceType->name() != _name))
00090    {
00091      // No it wasn't...
00092      delete newServiceType;
00093      newServiceType = 0; // Not found
00094    }
00095    return newServiceType;
00096 }
00097 
00098 QVariant::Type KServiceTypeFactory::findPropertyTypeByName(const QString &_name)
00099 {
00100    if (!m_sycocaDict)
00101       return QVariant::Invalid; // Error!
00102 
00103    assert (!KSycoca::self()->isBuilding());
00104 
00105    QMapConstIterator<QString,int> it = m_propertyTypeDict.find(_name);
00106    if (it != m_propertyTypeDict.end()) {
00107      return (QVariant::Type)it.data();
00108    }
00109 
00110    return QVariant::Invalid;
00111 }
00112 
00113 KMimeType * KServiceTypeFactory::findFromPattern(const QString &_filename, QString *match)
00114 {
00115    // Assume we're NOT building a database
00116    if (!m_str) return 0;
00117 
00118    // Get stream to the header
00119    QDataStream *str = m_str;
00120 
00121    str->device()->at( m_fastPatternOffset );
00122 
00123    Q_INT32 nrOfEntries;
00124    (*str) >> nrOfEntries;
00125    Q_INT32 entrySize;
00126    (*str) >> entrySize;
00127 
00128    Q_INT32 fastOffset =  str->device()->at( );
00129 
00130    Q_INT32 matchingOffset = 0;
00131 
00132    // Let's go for a binary search in the "fast" pattern index
00133    Q_INT32 left = 0;
00134    Q_INT32 right = nrOfEntries - 1;
00135    Q_INT32 middle;
00136    // Extract extension
00137    int lastDot = _filename.findRev('.');
00138    int ext_len = _filename.length() - lastDot - 1;
00139    if (lastDot != -1 && ext_len <= 4) // if no '.', skip the extension lookup
00140    {
00141       QString extension = _filename.right( ext_len );
00142       extension = extension.leftJustify(4);
00143 
00144       QString pattern;
00145       while (left <= right) {
00146          middle = (left + right) / 2;
00147          // read pattern at position "middle"
00148          str->device()->at( middle * entrySize + fastOffset );
00149          KSycocaEntry::read(*str, pattern);
00150          int cmp = pattern.compare( extension );
00151          if (cmp < 0)
00152             left = middle + 1;
00153          else if (cmp == 0) // found
00154          {
00155             (*str) >> matchingOffset;
00156             // don't return newServiceType - there may be an "other" pattern that
00157             // matches best this file, like *.tar.bz
00158             if (match)
00159                 *match = "*."+pattern;
00160             break; // but get out of the fast patterns
00161          }
00162          else
00163             right = middle - 1;
00164       }
00165    }
00166 
00167    // Now try the "other" Pattern table
00168    if ( m_patterns.isEmpty() ) {
00169       str->device()->at( m_otherPatternOffset );
00170 
00171       QString pattern;
00172       Q_INT32 mimetypeOffset;
00173 
00174       while (true)
00175       {
00176          KSycocaEntry::read(*str, pattern);
00177          if (pattern.isEmpty()) // end of list
00178             break;
00179          (*str) >> mimetypeOffset;
00180          m_patterns.push_back( pattern );
00181          m_pattern_offsets.push_back( mimetypeOffset );
00182       }
00183    }
00184 
00185    assert( m_patterns.size() == m_pattern_offsets.size() );
00186 
00187    QStringList::const_iterator it = m_patterns.begin();
00188    QStringList::const_iterator end = m_patterns.end();
00189    QValueVector<Q_INT32>::const_iterator it_offset = m_pattern_offsets.begin();
00190 
00191   for ( ; it != end; ++it, ++it_offset )
00192    {
00193       if ( KStringHandler::matchFileName( _filename, *it ) )
00194       {
00195          if ( !matchingOffset || !(*it).endsWith( "*" ) ) // *.html wins over Makefile.*
00196          {
00197              matchingOffset = *it_offset;
00198              if (match)
00199                 *match = *it;
00200              break;
00201          }
00202       }
00203    }
00204 
00205    if ( matchingOffset ) {
00206       KServiceType *newServiceType = createEntry( matchingOffset );
00207       assert (newServiceType && newServiceType->isType( KST_KMimeType ));
00208       return (KMimeType *) newServiceType;
00209    }
00210    else
00211       return 0;
00212 }
00213 
00214 KMimeType::List KServiceTypeFactory::allMimeTypes()
00215 {
00216    KMimeType::List result;
00217    KSycocaEntry::List list = allEntries();
00218    for( KSycocaEntry::List::Iterator it = list.begin();
00219         it != list.end();
00220         ++it)
00221    {
00222       KMimeType *newMimeType = dynamic_cast<KMimeType *>((*it).data());
00223       if (newMimeType)
00224          result.append( KMimeType::Ptr( newMimeType ) );
00225    }
00226    return result;
00227 }
00228 
00229 KServiceType::List KServiceTypeFactory::allServiceTypes()
00230 {
00231    KServiceType::List result;
00232    KSycocaEntry::List list = allEntries();
00233    for( KSycocaEntry::List::Iterator it = list.begin();
00234         it != list.end();
00235         ++it)
00236    {
00237 #ifndef Q_WS_QWS
00238       KServiceType *newServiceType = dynamic_cast<KServiceType *>((*it).data());
00239 #else //FIXME
00240       KServiceType *newServiceType = (KServiceType*)(*it).data();
00241 #endif
00242       if (newServiceType)
00243          result.append( KServiceType::Ptr( newServiceType ) );
00244    }
00245    return result;
00246 }
00247 
00248 bool KServiceTypeFactory::checkMimeTypes()
00249 {
00250    QDataStream *str = KSycoca::self()->findFactory( factoryId() );
00251    if (!str) return false;
00252 
00253    // check if there are mimetypes/servicetypes
00254    return (m_beginEntryOffset != m_endEntryOffset);
00255 }
00256 
00257 KServiceType * KServiceTypeFactory::createEntry(int offset)
00258 {
00259    KServiceType *newEntry = 0;
00260    KSycocaType type;
00261    QDataStream *str = KSycoca::self()->findEntry(offset, type);
00262    if (!str) return 0;
00263 
00264    switch(type)
00265    {
00266      case KST_KServiceType:
00267         newEntry = new KServiceType(*str, offset);
00268         break;
00269      case KST_KMimeType:
00270         newEntry = new KMimeType(*str, offset);
00271         break;
00272      case KST_KFolderType:
00273         newEntry = new KFolderType(*str, offset);
00274         break;
00275      case KST_KDEDesktopMimeType:
00276         newEntry = new KDEDesktopMimeType(*str, offset);
00277         break;
00278      case KST_KExecMimeType:
00279         newEntry = new KExecMimeType(*str, offset);
00280         break;
00281 
00282      default:
00283         kdError(7011) << QString("KServiceTypeFactory: unexpected object entry in KSycoca database (type = %1)").arg((int)type) << endl;
00284         break;
00285    }
00286    if (newEntry && !newEntry->isValid())
00287    {
00288       kdError(7011) << "KServiceTypeFactory: corrupt object in KSycoca database!\n" << endl;
00289       delete newEntry;
00290       newEntry = 0;
00291    }
00292    return newEntry;
00293 }
00294 
00295 KServiceTypeFactory *KServiceTypeFactory::_self = 0;
00296 
00297 void KServiceTypeFactory::virtual_hook( int id, void* data )
00298 { KSycocaFactory::virtual_hook( id, data ); }
00299 
00300 // vim: ts=3 sw=3 et
KDE Home | KDE Accessibility Home | Description of Access Keys