summaryrefslogtreecommitdiff
path: root/kdecore/sycoca
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2012-06-25 18:42:22 (GMT)
committerChristian Mollekopf <chrigi_1@fastmail.fm>2012-06-25 18:42:22 (GMT)
commit43d35cfb36c924eede624f4a5c2fcb0dd7d698b6 (patch)
treeb7ac13bcf009d94cabb4c5afeee0825a4ce9da67 /kdecore/sycoca
parentbf385f44f99d73263b1787daac7423599e69f024 (diff)
downloadlibcalendaring-43d35cfb36c924eede624f4a5c2fcb0dd7d698b6.tar.gz
kdecore import
commit 557c1267cbb5e352e1487c3dd468cd4a4cb63254 Merge: aed99b0 387e3c3 Author: David Faure <faure@kde.org> Date: Thu Jun 14 17:56:59 2012 +0200 Merge remote-tracking branch 'origin/KDE/4.8'
Diffstat (limited to 'kdecore/sycoca')
-rw-r--r--kdecore/sycoca/.kprotocolinfofactory.cpp.kate-swpbin0 -> 63 bytes
-rw-r--r--kdecore/sycoca/kmemfile.cpp253
-rw-r--r--kdecore/sycoca/kmemfile.h100
-rw-r--r--kdecore/sycoca/kprotocolinfo.cpp462
-rw-r--r--kdecore/sycoca/kprotocolinfo.h378
-rw-r--r--kdecore/sycoca/kprotocolinfo_p.h65
-rw-r--r--kdecore/sycoca/kprotocolinfofactory.cpp122
-rw-r--r--kdecore/sycoca/kprotocolinfofactory.h99
-rw-r--r--kdecore/sycoca/ksycoca.cpp604
-rw-r--r--kdecore/sycoca/ksycoca.h235
-rw-r--r--kdecore/sycoca/ksycoca_p.h79
-rw-r--r--kdecore/sycoca/ksycocadevices_p.h125
-rw-r--r--kdecore/sycoca/ksycocadict.cpp562
-rw-r--r--kdecore/sycoca/ksycocadict_p.h135
-rw-r--r--kdecore/sycoca/ksycocaentry.cpp173
-rw-r--r--kdecore/sycoca/ksycocaentry.h157
-rw-r--r--kdecore/sycoca/ksycocaentry_p.h82
-rw-r--r--kdecore/sycoca/ksycocafactory.cpp248
-rw-r--r--kdecore/sycoca/ksycocafactory.h209
-rw-r--r--kdecore/sycoca/ksycocatype.h57
20 files changed, 4145 insertions, 0 deletions
diff --git a/kdecore/sycoca/.kprotocolinfofactory.cpp.kate-swp b/kdecore/sycoca/.kprotocolinfofactory.cpp.kate-swp
new file mode 100644
index 0000000..8867a67
--- /dev/null
+++ b/kdecore/sycoca/.kprotocolinfofactory.cpp.kate-swp
Binary files differ
diff --git a/kdecore/sycoca/kmemfile.cpp b/kdecore/sycoca/kmemfile.cpp
new file mode 100644
index 0000000..a786e92
--- /dev/null
+++ b/kdecore/sycoca/kmemfile.cpp
@@ -0,0 +1,253 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (C) 2008 Christian Ehrlicher <ch.ehrlicher@gmx.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kmemfile.h"
+
+#ifndef QT_NO_SHAREDMEMORY
+
+#include <QtCore/QSharedMemory>
+#include <QtCore/QCryptographicHash>
+#include <QtCore/QFile>
+#include <QtCore/QDir>
+
+#include "klocalizedstring.h"
+
+class KMemFile::Private
+{
+public:
+ struct sharedInfoData {
+ int shmCounter;
+ qint64 shmDataSize;
+
+ sharedInfoData() {
+ memset ( this, 0, sizeof ( *this ) );
+ }
+ };
+ Private ( KMemFile *_parent ) : readWritePos ( 0 ), shmDataSize ( 0 ), parent ( _parent ) {}
+
+ QString getShmKey ( int iCounter = -1 );
+ static QString getShmKey ( const QString &filename, int iCounter = -1 );
+ bool loadContentsFromFile();
+ void close();
+
+ QString filename;
+ QSharedMemory shmInfo;
+ QSharedMemory shmData;
+ qint64 readWritePos;
+ qint64 shmDataSize;
+
+ KMemFile *parent;
+};
+
+QString KMemFile::Private::getShmKey ( int iCounter )
+{
+ return getShmKey ( filename, iCounter );
+}
+
+QString KMemFile::Private::getShmKey ( const QString &filename, int iCounter )
+{
+ QByteArray tmp = QString ( QDir ( filename ).canonicalPath() + QString::number ( iCounter ) ).toUtf8();
+ return QString::fromAscii ( QCryptographicHash::hash ( tmp, QCryptographicHash::Sha1 ) );
+}
+
+bool KMemFile::Private::loadContentsFromFile()
+{
+ QFile f ( filename );
+ if ( !f.exists() ) {
+ close();
+ parent->setErrorString ( i18n ( "File %1 does not exist" , filename ) );
+ return false;
+ }
+ if ( !f.open ( QIODevice::ReadOnly ) ) {
+ close();
+ parent->setErrorString ( i18n ( "Cannot open %1 for reading" , filename ) );
+ return false;
+ }
+
+ sharedInfoData *infoPtr = static_cast<sharedInfoData*> ( shmInfo.data() );
+
+ infoPtr->shmDataSize = f.size();
+ shmData.setKey ( getShmKey ( infoPtr->shmCounter ) );
+ if ( !shmData.create ( infoPtr->shmDataSize ) ) {
+ close();
+ parent->setErrorString ( i18n ( "Cannot create memory segment for file %1" , filename ) );
+ return false;
+ }
+ shmData.lock();
+ qint64 size = 0;
+ qint64 bytesRead;
+ char *data = static_cast<char*> ( shmData.data() );
+ bytesRead = f.read ( data, infoPtr->shmDataSize );
+ if ( bytesRead != infoPtr->shmDataSize ) {
+ close();
+ parent->setErrorString ( i18n ( "Could not read data from %1 into shm" , filename ) );
+ return false;
+ }
+ shmDataSize = size;
+ shmData.unlock();
+ return true;
+}
+
+void KMemFile::Private::close()
+{
+ shmData.unlock();
+ shmData.detach();
+ shmInfo.unlock();
+ shmInfo.detach();
+ readWritePos = 0;
+ shmDataSize = 0;
+}
+
+KMemFile::KMemFile ( const QString &filename, QObject *parent )
+ : QIODevice ( parent ), d ( new Private ( this ) )
+{
+ d->filename = filename;
+}
+
+KMemFile::~KMemFile()
+{
+ close();
+ delete d;
+}
+
+void KMemFile::close ()
+{
+ QIODevice::close();
+ if ( !isOpen() )
+ return;
+ d->close();
+}
+
+bool KMemFile::isSequential () const
+{
+ return false;
+}
+
+bool KMemFile::open ( OpenMode mode )
+{
+ if ( isOpen() ) {
+ QIODevice::open ( mode );
+ return false;
+ }
+
+ if ( mode != QIODevice::ReadOnly ) {
+ setErrorString ( i18n ( "Only 'ReadOnly' allowed" ) );
+ return false;
+ }
+
+ if ( !QFile::exists ( d->filename ) ) {
+ setErrorString ( i18n ( "File %1 does not exist" , d->filename ) );
+ return false;
+ }
+
+ QSharedMemory lock ( QDir ( d->filename ).canonicalPath() );
+ lock.lock();
+
+ Private::sharedInfoData *infoPtr;
+ d->shmInfo.setKey ( d->getShmKey() );
+ // see if it's already in memory
+ if ( !d->shmInfo.attach ( QSharedMemory::ReadWrite ) ) {
+ if ( !d->shmInfo.create ( sizeof ( Private::sharedInfoData ) ) ) {
+ lock.unlock();
+ setErrorString ( i18n ( "Cannot create memory segment for file %1" , d->filename ) );
+ return false;
+ }
+ d->shmInfo.lock();
+ // no -> create it
+ infoPtr = static_cast<Private::sharedInfoData*> ( d->shmInfo.data() );
+ memset ( infoPtr, 0, sizeof ( Private::sharedInfoData ) );
+ infoPtr->shmCounter = 1;
+ if ( !d->loadContentsFromFile() ) {
+ d->shmInfo.unlock();
+ d->shmInfo.detach();
+ lock.unlock();
+ return false;
+ }
+ } else {
+ d->shmInfo.lock();
+ infoPtr = static_cast<Private::sharedInfoData*> ( d->shmInfo.data() );
+ d->shmData.setKey ( d->getShmKey ( infoPtr->shmCounter ) );
+ if ( !d->shmData.attach ( QSharedMemory::ReadOnly ) ) {
+ if ( !d->loadContentsFromFile() ) {
+ d->shmInfo.unlock();
+ d->shmInfo.detach();
+ lock.unlock();
+ return false;
+ }
+ }
+ }
+ d->shmDataSize = infoPtr->shmDataSize;
+ d->shmInfo.unlock();
+ lock.unlock();
+
+ setOpenMode ( mode );
+ return true;
+}
+
+bool KMemFile::seek ( qint64 pos )
+{
+ if ( d->shmDataSize < pos ) {
+ setErrorString ( i18n ( "Cannot seek past eof" ) );
+ return false;
+ }
+ d->readWritePos = pos;
+ QIODevice::seek ( pos );
+ return true;
+}
+
+qint64 KMemFile::size () const
+{
+ return d->shmDataSize;
+}
+
+qint64 KMemFile::readData ( char * data, qint64 maxSize )
+{
+ if ( ( openMode() & QIODevice::ReadOnly ) == 0 )
+ return -1;
+
+ qint64 maxRead = size() - d->readWritePos;
+ qint64 bytesToRead = qMin ( maxRead, maxSize );
+ const char *src = static_cast<const char*> ( d->shmData.data() );
+ memcpy ( data, &src[d->readWritePos], bytesToRead );
+ d->readWritePos += bytesToRead;
+ return bytesToRead;
+}
+
+qint64 KMemFile::writeData ( const char *, qint64 )
+{
+ return -1;
+}
+
+void KMemFile::fileContentsChanged ( const QString &filename )
+{
+ QSharedMemory lock ( QDir ( filename ).canonicalPath() );
+ lock.lock();
+
+ QSharedMemory shmData ( Private::getShmKey ( filename ) );
+ if ( !shmData.attach() )
+ return;
+ shmData.lock();
+ Private::sharedInfoData *infoPtr = static_cast<Private::sharedInfoData*> ( shmData.data() );
+ infoPtr->shmCounter++;
+ infoPtr->shmDataSize = 0;
+ shmData.unlock();
+}
+
+#endif //QT_NO_SHAREDMEMORY
diff --git a/kdecore/sycoca/kmemfile.h b/kdecore/sycoca/kmemfile.h
new file mode 100644
index 0000000..5a734a0
--- /dev/null
+++ b/kdecore/sycoca/kmemfile.h
@@ -0,0 +1,100 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (C) 2008 Christian Ehrlicher <ch.ehrlicher@gmx.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KMEMFILE_H
+#define KMEMFILE_H
+
+#ifndef QT_NO_SHAREDMEMORY
+
+#include <QtCore/QIODevice>
+#include <kdecore_export.h>
+
+/**
+ * @internal
+ * Simple QIODevice for QSharedMemory to keep ksycoca cache in memory only once
+ * The first call to open() loads the file into a shm segment. Every
+ * subsequent call only attaches to this segment. When the file content changed,
+ * you have to execute KMemFile::fileContentsChanged() to update the internal
+ * structures. The next call to open() creates a new shm segment. The old one
+ * is automatically destroyed when the last process closed KMemFile.
+ */
+
+class KDECORE_EXPORT KMemFile : public QIODevice
+{
+public:
+ /**
+ * ctor
+ *
+ * @param filename the file to load into memory
+ * @param parent our parent
+ */
+ explicit KMemFile ( const QString &filename, QObject *parent = 0 );
+ /**
+ * dtor
+ */
+ virtual ~KMemFile();
+ /**
+ * closes the KMemFile
+ *
+ * @reimp
+ */
+ virtual void close ();
+ /**
+ * As KMemFile is a random access device, it returns false
+ *
+ * @reimp
+ */
+ virtual bool isSequential () const;
+ /**
+ * @reimp
+ * @param mode only QIODevice::ReadOnly is accepted
+ */
+ virtual bool open ( OpenMode mode );
+ /**
+ * Sets the current read/write position to pos
+ * @reimp
+ * @param pos the new read/write position
+ */
+ virtual bool seek ( qint64 pos );
+ /**
+ * Returns the size of the file
+ * @reimp
+ */
+ virtual qint64 size () const;
+ /**
+ * This static function updates the internal information about the file
+ * loaded into shared memory. The next time the file is opened, the file is
+ * reread from the file system.
+ */
+ static void fileContentsChanged ( const QString &filename );
+protected:
+ /** @reimp */
+ virtual qint64 readData ( char * data, qint64 maxSize );
+ /** @reimp */
+ virtual qint64 writeData ( const char * data, qint64 maxSize );
+private:
+ class Private;
+ friend class Private;
+ Private * const d;
+};
+
+#endif //QT_NO_SHAREDMEMORY
+
+#endif // KMEMFILE_H
diff --git a/kdecore/sycoca/kprotocolinfo.cpp b/kdecore/sycoca/kprotocolinfo.cpp
new file mode 100644
index 0000000..7b98726
--- /dev/null
+++ b/kdecore/sycoca/kprotocolinfo.cpp
@@ -0,0 +1,462 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2003 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kprotocolinfo.h"
+#include "kprotocolinfo_p.h"
+#include "kprotocolinfofactory.h"
+
+#include <kmimetypetrader.h>
+#include <kstandarddirs.h>
+#include <kconfig.h>
+#include <kconfiggroup.h>
+
+//
+// Internal functions:
+//
+KProtocolInfo::KProtocolInfo(const QString &path)
+ : KSycocaEntry(*new KProtocolInfoPrivate(path, this))
+{
+ Q_D(KProtocolInfo);
+ QString fullPath = KStandardDirs::locate("services", path);
+
+ KConfig sconfig( fullPath );
+ KConfigGroup config(&sconfig, "Protocol" );
+
+ m_name = config.readEntry( "protocol" );
+ m_exec = config.readPathEntry( "exec", QString() );
+ m_isSourceProtocol = config.readEntry( "source", true );
+ m_isHelperProtocol = config.readEntry( "helper", false );
+ m_supportsReading = config.readEntry( "reading", false );
+ m_supportsWriting = config.readEntry( "writing", false );
+ m_supportsMakeDir = config.readEntry( "makedir", false );
+ m_supportsDeleting = config.readEntry( "deleting", false );
+ m_supportsLinking = config.readEntry( "linking", false );
+ m_supportsMoving = config.readEntry( "moving", false );
+ m_supportsOpening = config.readEntry( "opening", false );
+ m_canCopyFromFile = config.readEntry( "copyFromFile", false );
+ m_canCopyToFile = config.readEntry( "copyToFile", false );
+ d->canRenameFromFile = config.readEntry( "renameFromFile", false );
+ d->canRenameToFile = config.readEntry( "renameToFile", false );
+ d->canDeleteRecursive = config.readEntry( "deleteRecursive", false );
+ const QString fnu = config.readEntry( "fileNameUsedForCopying", "FromURL" );
+ d->fileNameUsedForCopying = FromUrl;
+ if (fnu == QLatin1String("Name"))
+ d->fileNameUsedForCopying = Name;
+ else if (fnu == QLatin1String("DisplayName"))
+ d->fileNameUsedForCopying = DisplayName;
+
+ m_listing = config.readEntry( "listing", QStringList() );
+ // Many .protocol files say "Listing=false" when they really mean "Listing=" (i.e. unsupported)
+ if ( m_listing.count() == 1 && m_listing.first() == QLatin1String("false") )
+ m_listing.clear();
+ m_supportsListing = ( m_listing.count() > 0 );
+ m_defaultMimetype = config.readEntry( "defaultMimetype" );
+ m_determineMimetypeFromExtension = config.readEntry( "determineMimetypeFromExtension", true );
+ d->archiveMimetype = config.readEntry("archiveMimetype", QStringList());
+ m_icon = config.readEntry( "Icon" );
+ m_config = config.readEntry( "config", m_name );
+ m_maxSlaves = config.readEntry( "maxInstances", 1);
+ d->maxSlavesPerHost = config.readEntry( "maxInstancesPerHost", 0);
+
+ QString tmp = config.readEntry( "input" );
+ if ( tmp == QLatin1String("filesystem") )
+ m_inputType = KProtocolInfo::T_FILESYSTEM;
+ else if ( tmp == QLatin1String("stream") )
+ m_inputType = KProtocolInfo::T_STREAM;
+ else
+ m_inputType = KProtocolInfo::T_NONE;
+
+ tmp = config.readEntry( "output" );
+ if ( tmp == QLatin1String("filesystem") )
+ m_outputType = KProtocolInfo::T_FILESYSTEM;
+ else if ( tmp == QLatin1String("stream") )
+ m_outputType = KProtocolInfo::T_STREAM;
+ else
+ m_outputType = KProtocolInfo::T_NONE;
+
+ d->docPath = config.readPathEntry( "X-DocPath", QString() );
+ if (d->docPath.isEmpty())
+ d->docPath = config.readPathEntry( "DocPath", QString() );
+ d->protClass = config.readEntry( "Class" ).toLower();
+ if (d->protClass[0] != QLatin1Char(':'))
+ d->protClass.prepend(QLatin1Char(':'));
+
+ const QStringList extraNames = config.readEntry( "ExtraNames", QStringList() );
+ const QStringList extraTypes = config.readEntry( "ExtraTypes", QStringList() );
+ QStringList::const_iterator it = extraNames.begin();
+ QStringList::const_iterator typeit = extraTypes.begin();
+ for( ; it != extraNames.end() && typeit != extraTypes.end(); ++it, ++typeit ) {
+ QVariant::Type type = QVariant::nameToType( (*typeit).toLatin1() );
+ // currently QVariant::Type and ExtraField::Type use the same subset of values, so we can just cast.
+ d->extraFields.append( ExtraField( *it, static_cast<ExtraField::Type>(type) ) );
+ }
+
+ d->showPreviews = config.readEntry( "ShowPreviews", d->protClass == QLatin1String(":local") );
+
+ d->capabilities = config.readEntry( "Capabilities", QStringList() );
+ d->proxyProtocol = config.readEntry( "ProxiedBy" );
+}
+
+KProtocolInfo::KProtocolInfo( QDataStream& _str, int offset) :
+ KSycocaEntry(*new KProtocolInfoPrivate( _str, offset, this) )
+{
+ load( _str );
+}
+
+KProtocolInfo::~KProtocolInfo()
+{
+}
+
+void
+KProtocolInfo::load( QDataStream& _str)
+{
+ Q_D(KProtocolInfo);
+ // You may add new fields at the end. Make sure to update the version
+ // number in ksycoca.h
+ qint32 i_inputType, i_outputType;
+ qint8 i_isSourceProtocol, i_isHelperProtocol,
+ i_supportsListing, i_supportsReading,
+ i_supportsWriting, i_supportsMakeDir,
+ i_supportsDeleting, i_supportsLinking,
+ i_supportsMoving, i_supportsOpening,
+ i_determineMimetypeFromExtension,
+ i_canCopyFromFile, i_canCopyToFile, i_showPreviews,
+ i_uriMode, i_canRenameFromFile, i_canRenameToFile,
+ i_canDeleteRecursive, i_fileNameUsedForCopying;
+
+ _str >> m_name >> m_exec >> m_listing >> m_defaultMimetype
+ >> i_determineMimetypeFromExtension
+ >> m_icon
+ >> i_inputType >> i_outputType
+ >> i_isSourceProtocol >> i_isHelperProtocol
+ >> i_supportsListing >> i_supportsReading
+ >> i_supportsWriting >> i_supportsMakeDir
+ >> i_supportsDeleting >> i_supportsLinking
+ >> i_supportsMoving >> i_supportsOpening
+ >> i_canCopyFromFile >> i_canCopyToFile
+ >> m_config >> m_maxSlaves >> d->docPath >> d->protClass
+ >> d->extraFields >> i_showPreviews >> i_uriMode
+ >> d->capabilities >> d->proxyProtocol
+ >> i_canRenameFromFile >> i_canRenameToFile
+ >> i_canDeleteRecursive >> i_fileNameUsedForCopying
+ >> d->archiveMimetype >> d->maxSlavesPerHost;
+
+ m_inputType = (Type) i_inputType;
+ m_outputType = (Type) i_outputType;
+ m_isSourceProtocol = (i_isSourceProtocol != 0);
+ m_isHelperProtocol = (i_isHelperProtocol != 0);
+ m_supportsListing = (i_supportsListing != 0);
+ m_supportsReading = (i_supportsReading != 0);
+ m_supportsWriting = (i_supportsWriting != 0);
+ m_supportsMakeDir = (i_supportsMakeDir != 0);
+ m_supportsDeleting = (i_supportsDeleting != 0);
+ m_supportsLinking = (i_supportsLinking != 0);
+ m_supportsMoving = (i_supportsMoving != 0);
+ m_supportsOpening = (i_supportsOpening != 0);
+ m_canCopyFromFile = (i_canCopyFromFile != 0);
+ m_canCopyToFile = (i_canCopyToFile != 0);
+ d->canRenameFromFile = (i_canRenameFromFile != 0);
+ d->canRenameToFile = (i_canRenameToFile != 0);
+ d->canDeleteRecursive = (i_canDeleteRecursive != 0);
+ d->fileNameUsedForCopying = FileNameUsedForCopying(i_fileNameUsedForCopying);
+ m_determineMimetypeFromExtension = (i_determineMimetypeFromExtension != 0);
+ d->showPreviews = (i_showPreviews != 0);
+}
+
+void
+KProtocolInfoPrivate::save( QDataStream& _str)
+{
+ KSycocaEntryPrivate::save( _str );
+
+ // You may add new fields at the end. Make sure to update the version
+ // number in ksycoca.h
+ qint32 i_inputType, i_outputType;
+ qint8 i_isSourceProtocol, i_isHelperProtocol,
+ i_supportsListing, i_supportsReading,
+ i_supportsWriting, i_supportsMakeDir,
+ i_supportsDeleting, i_supportsLinking,
+ i_supportsMoving, i_supportsOpening,
+ i_determineMimetypeFromExtension,
+ i_canCopyFromFile, i_canCopyToFile, i_showPreviews,
+ i_uriMode, i_canRenameFromFile, i_canRenameToFile,
+ i_canDeleteRecursive, i_fileNameUsedForCopying;
+
+ i_inputType = (qint32) q->m_inputType;
+ i_outputType = (qint32) q->m_outputType;
+ i_isSourceProtocol = q->m_isSourceProtocol ? 1 : 0;
+ i_isHelperProtocol = q->m_isHelperProtocol ? 1 : 0;
+ i_supportsListing = q->m_supportsListing ? 1 : 0;
+ i_supportsReading = q->m_supportsReading ? 1 : 0;
+ i_supportsWriting = q->m_supportsWriting ? 1 : 0;
+ i_supportsMakeDir = q->m_supportsMakeDir ? 1 : 0;
+ i_supportsDeleting = q->m_supportsDeleting ? 1 : 0;
+ i_supportsLinking = q->m_supportsLinking ? 1 : 0;
+ i_supportsMoving = q->m_supportsMoving ? 1 : 0;
+ i_supportsOpening = q->m_supportsOpening ? 1 : 0;
+ i_canCopyFromFile = q->m_canCopyFromFile ? 1 : 0;
+ i_canCopyToFile = q->m_canCopyToFile ? 1 : 0;
+ i_canRenameFromFile = canRenameFromFile ? 1 : 0;
+ i_canRenameToFile = canRenameToFile ? 1 : 0;
+ i_canDeleteRecursive = canDeleteRecursive ? 1 : 0;
+ i_fileNameUsedForCopying = int(fileNameUsedForCopying);
+ i_determineMimetypeFromExtension = q->m_determineMimetypeFromExtension ? 1 : 0;
+ i_showPreviews = showPreviews ? 1 : 0;
+ i_uriMode = 0;
+
+ _str << q->m_name << q->m_exec << q->m_listing << q->m_defaultMimetype
+ << i_determineMimetypeFromExtension
+ << q->m_icon
+ << i_inputType << i_outputType
+ << i_isSourceProtocol << i_isHelperProtocol
+ << i_supportsListing << i_supportsReading
+ << i_supportsWriting << i_supportsMakeDir
+ << i_supportsDeleting << i_supportsLinking
+ << i_supportsMoving << i_supportsOpening
+ << i_canCopyFromFile << i_canCopyToFile
+ << q->m_config << q->m_maxSlaves << docPath << protClass
+ << extraFields << i_showPreviews << i_uriMode
+ << capabilities << proxyProtocol
+ << i_canRenameFromFile << i_canRenameToFile
+ << i_canDeleteRecursive << i_fileNameUsedForCopying
+ << archiveMimetype << maxSlavesPerHost;
+}
+
+
+//
+// Static functions:
+//
+
+QStringList KProtocolInfo::protocols()
+{
+ return KProtocolInfoFactory::self()->protocols();
+}
+
+bool KProtocolInfo::isFilterProtocol( const QString& _protocol )
+{
+ // We call the findProtocol directly (not via KProtocolManager) to bypass any proxy settings.
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return false;
+
+ return !prot->m_isSourceProtocol;
+}
+
+QString KProtocolInfo::icon( const QString& _protocol )
+{
+ // We call the findProtocol directly (not via KProtocolManager) to bypass any proxy settings.
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return QString();
+
+ return prot->m_icon;
+}
+
+QString KProtocolInfo::config( const QString& _protocol )
+{
+ // We call the findProtocol directly (not via KProtocolManager) to bypass any proxy settings.
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return QString();
+
+ return QString::fromLatin1("kio_%1rc").arg(prot->m_config);
+}
+
+int KProtocolInfo::maxSlaves( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return 1;
+
+ return prot->m_maxSlaves;
+}
+
+int KProtocolInfo::maxSlavesPerHost( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return 0;
+
+ return prot->d_func()->maxSlavesPerHost;
+}
+
+bool KProtocolInfo::determineMimetypeFromExtension( const QString &_protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol( _protocol );
+ if ( !prot )
+ return true;
+
+ return prot->m_determineMimetypeFromExtension;
+}
+
+QString KProtocolInfo::exec(const QString& protocol)
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(protocol);
+ if ( prot ) {
+ return prot->m_exec;
+ }
+
+ // Maybe it's "helper protocol", i.e. launches an app?
+ const KService::Ptr service = KMimeTypeTrader::self()->preferredService(QString::fromLatin1("x-scheme-handler/") + protocol);
+ if (service)
+ return service->exec();
+
+ return QString();
+}
+
+KProtocolInfo::ExtraFieldList KProtocolInfo::extraFields( const KUrl &url )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(url.protocol());
+ if ( !prot )
+ return ExtraFieldList();
+
+ return prot->d_func()->extraFields;
+}
+
+QString KProtocolInfo::docPath( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return QString();
+
+ return prot->d_func()->docPath;
+}
+
+QString KProtocolInfo::protocolClass( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return QString();
+
+ return prot->d_func()->protClass;
+}
+
+bool KProtocolInfo::showFilePreview( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return false;
+
+ return prot->d_func()->showPreviews;
+}
+
+QStringList KProtocolInfo::capabilities( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return QStringList();
+
+ return prot->d_func()->capabilities;
+}
+
+QString KProtocolInfo::proxiedBy( const QString& _protocol )
+{
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(_protocol);
+ if ( !prot )
+ return QString();
+
+ return prot->d_func()->proxyProtocol;
+}
+
+QString KProtocolInfo::defaultMimeType() const
+{
+ return m_defaultMimetype;
+}
+
+
+QStringList KProtocolInfo::archiveMimeTypes() const
+{
+ Q_D(const KProtocolInfo);
+ return d->archiveMimetype;
+}
+
+bool KProtocolInfo::supportsListing() const
+{
+ return m_supportsListing;
+}
+
+bool KProtocolInfo::canRenameFromFile() const
+{
+ Q_D(const KProtocolInfo);
+ return d->canRenameFromFile;
+}
+
+bool KProtocolInfo::canRenameToFile() const
+{
+ Q_D(const KProtocolInfo);
+ return d->canRenameToFile;
+}
+
+bool KProtocolInfo::canDeleteRecursive() const
+{
+ Q_D(const KProtocolInfo);
+ return d->canDeleteRecursive;
+}
+
+KProtocolInfo::FileNameUsedForCopying KProtocolInfo::fileNameUsedForCopying() const
+{
+ Q_D(const KProtocolInfo);
+ return d->fileNameUsedForCopying;
+}
+
+bool KProtocolInfo::isFilterProtocol( const KUrl &url )
+{
+ return isFilterProtocol (url.protocol());
+}
+
+bool KProtocolInfo::isHelperProtocol( const KUrl &url )
+{
+ return isHelperProtocol (url.protocol());
+}
+
+bool KProtocolInfo::isHelperProtocol( const QString &protocol )
+{
+ // We call the findProtocol directly (not via KProtocolManager) to bypass any proxy settings.
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(protocol);
+ if ( prot )
+ return prot->m_isHelperProtocol;
+
+ const KService::Ptr service = KMimeTypeTrader::self()->preferredService(QString::fromLatin1("x-scheme-handler/") + protocol);
+ return !service.isNull();
+}
+
+bool KProtocolInfo::isKnownProtocol( const KUrl &url )
+{
+ return isKnownProtocol (url.protocol());
+}
+
+bool KProtocolInfo::isKnownProtocol( const QString &protocol )
+{
+ // We call the findProtocol (const QString&) to bypass any proxy settings.
+ KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol(protocol);
+ return prot || isHelperProtocol(protocol);
+}
+
+QDataStream& operator>>( QDataStream& s, KProtocolInfo::ExtraField& field ) {
+ s >> field.name;
+ int type;
+ s >> type;
+ field.type = static_cast<KProtocolInfo::ExtraField::Type>( type );
+ return s;
+}
+
+QDataStream& operator<<( QDataStream& s, const KProtocolInfo::ExtraField& field ) {
+ s << field.name;
+ s << static_cast<int>( field.type );
+ return s;
+}
diff --git a/kdecore/sycoca/kprotocolinfo.h b/kdecore/sycoca/kprotocolinfo.h
new file mode 100644
index 0000000..ec42745
--- /dev/null
+++ b/kdecore/sycoca/kprotocolinfo.h
@@ -0,0 +1,378 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2000-2001 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef KPROTOCOLINFO_H
+#define KPROTOCOLINFO_H
+
+#include <kglobal.h>
+
+#include <kurl.h>
+#include <ksycocaentry.h>
+#include <ksycocatype.h>
+#include <QtCore/QVariant>
+#include <QtCore/QStringList>
+
+class QDataStream;
+class KProtocolInfoPrivate;
+
+/**
+ * \class KProtocolInfo kprotocolinfo.h <KProtocolInfo>
+ *
+ * Information about I/O (Internet, etc.) protocols supported by KDE.
+
+ * This class is useful if you want to know which protocols
+ * KDE supports. In addition you can find out lots of information
+ * about a certain protocol. A KProtocolInfo instance represents a
+ * single protocol. Most of the functionality is provided by the static
+ * methods that scan the *.protocol files of all installed kioslaves to get
+ * this information.
+ *
+ * *.protocol files are installed in the "services" resource.
+ *
+ * @author Torben Weis <weis@kde.org>
+ */
+class KDECORE_EXPORT KProtocolInfo : public KSycocaEntry
+{
+ friend class KProtocolInfoFactory;
+ friend class KBuildProtocolInfoFactory;
+ friend class KProtocolManager;
+public:
+ typedef KSharedPtr<KProtocolInfo> Ptr;
+ typedef QList<Ptr> List;
+
+public:
+
+ //
+ // Static functions:
+ //
+
+ /**
+ * Returns list of all known protocols.
+ * @return a list of all known protocols
+ */
+ static QStringList protocols();
+
+ /**
+ * Returns whether a protocol is installed that is able to handle @p url.
+ *
+ * @param url the url to check
+ * @return true if the protocol is known
+ * @see name()
+ */
+ static bool isKnownProtocol( const KUrl &url );
+
+ /**
+ * Same as above except you can supply just the protocol instead of
+ * the whole URL.
+ */
+ static bool isKnownProtocol( const QString& protocol );
+
+ /**
+ * Returns the library / executable to open for the protocol @p protocol
+ * Example : "kio_ftp", meaning either the executable "kio_ftp" or
+ * the library "kio_ftp.la" (recommended), whichever is available.
+ *
+ * This corresponds to the "exec=" field in the protocol description file.
+ * @param protocol the protocol to check
+ * @return the executable of library to open, or QString() for
+ * unsupported protocols
+ * @see KUrl::protocol()
+ */
+ static QString exec( const QString& protocol );
+
+ /**
+ * Describes the type of a protocol.
+ * For instance ftp:// appears as a filesystem with folders and files,
+ * while bzip2:// appears as a single file (a stream of data),
+ * and telnet:// doesn't output anything.
+ * @see outputType
+ */
+ enum Type { T_STREAM, ///< stream of data (e.g. single file)
+ T_FILESYSTEM, ///< structured directory
+ T_NONE, ///< no information about the type available
+ T_ERROR ///< used to signal an error
+ };
+
+ /**
+ * Definition of an extra field in the UDS entries, returned by a listDir operation.
+ *
+ * The name is the name of the column, translated.
+ *
+ * The type name comes from QVariant::typeName()
+ * Currently supported types: "QString", "QDateTime" (ISO-8601 format)
+ */
+ struct ExtraField {
+
+ enum Type { String = QVariant::String, DateTime = QVariant::DateTime, Invalid = QVariant::Invalid };
+
+ ExtraField() : type(Invalid) {}
+ ExtraField(const QString& _name, Type _type )
+ : name(_name), type(_type) {
+ }
+ QString name;
+ Type type;
+ };
+ typedef QList<ExtraField> ExtraFieldList;
+ /**
+ * Definition of extra fields in the UDS entries, returned by a listDir operation.
+ *
+ * This corresponds to the "ExtraNames=" and "ExtraTypes=" fields in the protocol description file.
+ * Those two lists should be separated with ',' in the protocol description file.
+ * See ExtraField for details about names and types
+ */
+ static ExtraFieldList extraFields( const KUrl& url );
+
+ /**
+ * Returns whether the protocol can act as a helper protocol.
+ * A helper protocol invokes an external application and does not return
+ * a file or stream.
+ *
+ * This corresponds to the "helper=" field in the protocol description file.
+ * Valid values for this field are "true" or "false" (default).
+ *
+ * @param url the url to check
+ * @return true if the protocol is a helper protocol (e.g. vnc), false
+ * if not (e.g. http)
+ */
+ static bool isHelperProtocol( const KUrl &url );
+
+ /**
+ * Same as above except you can supply just the protocol instead of
+ * the whole URL.
+ */
+ static bool isHelperProtocol( const QString& protocol );
+
+ /**
+ * Returns whether the protocol can act as a filter protocol.
+ *
+ * A filter protocol can operate on data that is passed to it
+ * but does not retrieve/store data itself, like gzip.
+ * A filter protocol is the opposite of a source protocol.
+ *
+ * The "source=" field in the protocol description file determines
+ * whether a protocol is a source protocol or a filter protocol.
+ * Valid values for this field are "true" (default) for source protocol or
+ * "false" for filter protocol.
+ *
+ * @param url the url to check
+ * @return true if the protocol is a filter (e.g. gzip), false if the
+ * protocol is a helper or source
+ */
+ static bool isFilterProtocol( const KUrl &url );
+
+ /**
+ * Same as above except you can supply just the protocol instead of
+ * the whole URL.
+ */
+ static bool isFilterProtocol( const QString& protocol );
+
+ /**
+ * Returns the name of the icon, associated with the specified protocol.
+ *
+ * This corresponds to the "Icon=" field in the protocol description file.
+ *
+ * @param protocol the protocol to check
+ * @return the icon of the protocol, or an empty string if unknown
+ */
+ static QString icon( const QString& protocol );
+
+ /**
+ * Returns the name of the config file associated with the
+ * specified protocol. This is useful if two similar protocols
+ * need to share a single config file, e.g. http and https.
+ *
+ * This corresponds to the "config=" field in the protocol description file.
+ * The default is the protocol name, see name()
+ *
+ * @param protocol the protocol to check
+ * @return the config file, or an empty string if unknown
+ */
+ static QString config( const QString& protocol );
+
+ /**
+ * Returns the soft limit on the number of slaves for this protocol.
+ * This limits the number of slaves used for a single operation, note
+ * that multiple operations may result in a number of instances that
+ * exceeds this soft limit.
+ *
+ * This corresponds to the "maxInstances=" field in the protocol description file.
+ * The default is 1.
+ *
+ * @param protocol the protocol to check
+ * @return the maximum number of slaves, or 1 if unknown
+ */
+ static int maxSlaves( const QString& protocol );
+
+
+ /**
+ * Returns the limit on the number of slaves for this protocol per host.
+ *
+ * This corresponds to the "maxInstancesPerHost=" field in the protocol description file.
+ * The default is 0 which means there is no per host limit.
+ *
+ * @param protocol the protocol to check
+ * @return the maximum number of slaves, or 1 if unknown
+ *
+ * @since 4.4
+ */
+ static int maxSlavesPerHost( const QString& protocol );
+
+ /**
+ * Returns whether mimetypes can be determined based on extension for this
+ * protocol. For some protocols, e.g. http, the filename extension in the URL
+ * can not be trusted to truly reflect the file type.
+ *
+ * This corresponds to the "determineMimetypeFromExtension=" field in the protocol description file.
+ * Valid values for this field are "true" (default) or "false".
+ *
+ * @param protocol the protocol to check
+ * @return true if the mime types can be determined by extension
+ */
+ static bool determineMimetypeFromExtension( const QString &protocol );
+
+ /**
+ * Returns the documentation path for the specified protocol.
+ *
+ * This corresponds to the "X-DocPath=" or "DocPath=" field in the protocol description file.
+ *
+ * @param protocol the protocol to check
+ * @return the docpath of the protocol, or an empty string if unknown
+ */
+ static QString docPath( const QString& protocol );
+
+ /**
+ * Returns the protocol class for the specified protocol.
+ *
+ * This corresponds to the "Class=" field in the protocol description file.
+ *
+ * The following classes are defined:
+ * @li ":internet" for common internet protocols
+ * @li ":local" for protocols that access local resources
+ *
+ * Protocol classes always start with a ':' so that they can not be confused with
+ * the protocols themselves.
+ *
+ * @param protocol the protocol to check
+ * @return the class of the protocol, or an empty string if unknown
+ */
+ static QString protocolClass( const QString& protocol );
+
+ /**
+ * Returns whether file previews should be shown for the specified protocol.
+ *
+ * This corresponds to the "ShowPreviews=" field in the protocol description file.
+ *
+ * By default previews are shown if protocolClass is :local.
+ *
+ * @param protocol the protocol to check
+ * @return true if previews should be shown by default, false otherwise
+ */
+ static bool showFilePreview( const QString& protocol );
+
+ /**
+ * Returns the list of capabilities provided by the kioslave implementing
+ * this protocol.
+ *
+ * This corresponds to the "Capabilities=" field in the protocol description file.
+ *
+ * The capability names are not defined globally, they are up to each
+ * slave implementation. For example when adding support for a new
+ * special command for mounting, one would add the string "Mount" to the
+ * capabilities list, and applications could check for that string
+ * before sending a special() command that would otherwise do nothing
+ * on older kioslave implementations.
+ *
+ * @param protocol the protocol to check
+ * @return the list of capabilities.
+ */
+ static QStringList capabilities( const QString& protocol );
+
+ /**
+ * Returns the name of the protocol through which the request
+ * will be routed if proxy support is enabled.
+ *
+ * A good example of this is the ftp protocol for which proxy
+ * support is commonly handled by the http protocol.
+ *
+ * This corresponds to the "ProxiedBy=" in the protocol description file.
+ */
+ static QString proxiedBy( const QString& protocol );
+
+public:
+ // Internal functions:
+ /**
+ * @internal construct a KProtocolInfo from a stream
+ */
+ KProtocolInfo( QDataStream& _str, int offset);
+
+ virtual ~KProtocolInfo();
+
+ typedef enum { Name, FromUrl, DisplayName } FileNameUsedForCopying;
+
+ /// @internal. Use KProtocolManager instead.
+ bool supportsListing() const;
+ /// @internal. Use KProtocolManager instead.
+ QString defaultMimeType() const;
+ /// @internal. Use KProtocolManager instead.
+ QStringList archiveMimeTypes() const;
+
+protected:
+ QString m_name;
+ QString m_exec;
+ Type m_inputType;
+ Type m_outputType;
+ QStringList m_listing;
+ bool m_isSourceProtocol;
+ bool m_isHelperProtocol;
+ bool m_supportsListing;
+ bool m_supportsReading;
+ bool m_supportsWriting;
+ bool m_supportsMakeDir;
+ bool m_supportsDeleting;
+ bool m_supportsLinking;
+ bool m_supportsMoving;
+ bool m_supportsOpening;
+ QString m_defaultMimetype;
+ bool m_determineMimetypeFromExtension;
+ QString m_icon;
+ bool m_canCopyFromFile;
+ bool m_canCopyToFile;
+ QString m_config;
+ int m_maxSlaves;
+
+ bool canRenameFromFile() const;
+ bool canRenameToFile() const;
+ bool canDeleteRecursive() const;
+ FileNameUsedForCopying fileNameUsedForCopying() const;
+
+private:
+ /**
+ * Read a protocol description file
+ * @param path the path of the description file
+ */
+ KProtocolInfo( const QString & path);
+
+ Q_DECLARE_PRIVATE(KProtocolInfo)
+
+ void load(QDataStream &s);
+};
+
+KDECORE_EXPORT QDataStream& operator>>( QDataStream& s, KProtocolInfo::ExtraField& field );
+KDECORE_EXPORT QDataStream& operator<<( QDataStream& s, const KProtocolInfo::ExtraField& field );
+
+#endif
diff --git a/kdecore/sycoca/kprotocolinfo_p.h b/kdecore/sycoca/kprotocolinfo_p.h
new file mode 100644
index 0000000..e6ea150
--- /dev/null
+++ b/kdecore/sycoca/kprotocolinfo_p.h
@@ -0,0 +1,65 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2000-2001 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef KPROTOCOLINFOPRIVATE_H
+#define KPROTOCOLINFOPRIVATE_H
+
+#include "kprotocolinfo.h"
+
+#include <ksycocaentry_p.h>
+
+class KProtocolInfoPrivate : public KSycocaEntryPrivate
+{
+public:
+ K_SYCOCATYPE( KST_KProtocolInfo, KSycocaEntryPrivate )
+
+ KProtocolInfoPrivate(const QString &path, KProtocolInfo *q_)
+ : KSycocaEntryPrivate(path), q(q_)
+ {
+ }
+ KProtocolInfoPrivate(QDataStream& _str, int offset, KProtocolInfo *q_)
+ : KSycocaEntryPrivate(_str, offset), q(q_)
+ {
+ }
+
+ virtual void save(QDataStream &s);
+
+ virtual QString name() const
+ {
+ return q->m_name;
+ }
+
+
+ KProtocolInfo *q;
+ QString docPath;
+ QString protClass;
+ QStringList archiveMimetype;
+ KProtocolInfo::ExtraFieldList extraFields;
+ bool showPreviews : 1;
+ bool canRenameFromFile : 1;
+ bool canRenameToFile : 1;
+ bool canDeleteRecursive : 1;
+ KProtocolInfo::FileNameUsedForCopying fileNameUsedForCopying;
+ //KUrl::URIMode uriMode;
+ QStringList capabilities;
+ QString proxyProtocol;
+ int maxSlavesPerHost;
+};
+
+
+#endif
diff --git a/kdecore/sycoca/kprotocolinfofactory.cpp b/kdecore/sycoca/kprotocolinfofactory.cpp
new file mode 100644
index 0000000..a47af93
--- /dev/null
+++ b/kdecore/sycoca/kprotocolinfofactory.cpp
@@ -0,0 +1,122 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2003 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kprotocolinfofactory.h"
+
+#include <kstandarddirs.h>
+#include <kdebug.h>
+#include <ksycoca.h>
+#include <ksycocadict_p.h>
+
+K_GLOBAL_STATIC(KSycocaFactorySingleton<KProtocolInfoFactory>, kProtocolInfoFactoryInstance)
+
+KProtocolInfoFactory::KProtocolInfoFactory() : KSycocaFactory( KST_KProtocolInfoFactory )
+{
+ kProtocolInfoFactoryInstance->instanceCreated(this);
+}
+
+KProtocolInfoFactory::~KProtocolInfoFactory()
+{
+ if (kProtocolInfoFactoryInstance.exists())
+ kProtocolInfoFactoryInstance->instanceDestroyed(this);
+}
+
+KProtocolInfo*
+KProtocolInfoFactory::createEntry(int offset) const
+{
+ KProtocolInfo *info = 0;
+ KSycocaType type;
+ QDataStream *str = KSycoca::self()->findEntry(offset, type);
+ switch (type)
+ {
+ case KST_KProtocolInfo:
+ info = new KProtocolInfo(*str, offset);
+ break;
+ default:
+ return 0;
+ }
+ if (!info->isValid())
+ {
+ delete info;
+ info = 0;
+ }
+ return info;
+}
+
+
+QStringList KProtocolInfoFactory::protocols() const
+{
+ QStringList res;
+ const KSycocaEntry::List list = allEntries();
+ for( KSycocaEntry::List::const_iterator it = list.begin();
+ it != list.end();
+ ++it) {
+ const KSycocaEntry *entry = (*it).data();
+ const KProtocolInfo *info = static_cast<const KProtocolInfo *>(entry);
+ res.append( info->name() );
+ }
+ return res;
+}
+
+KProtocolInfo::List KProtocolInfoFactory::allProtocols() const
+{
+ KProtocolInfo::List result;
+ const KSycocaEntry::List list = allEntries();
+ for( KSycocaEntry::List::ConstIterator it = list.begin();
+ it != list.end();
+ ++it) {
+ if ((*it)->isType(KST_KProtocolInfo)) {
+ result.append(KProtocolInfo::Ptr::staticCast(*it));
+ }
+ }
+ return result;
+}
+
+KProtocolInfo::Ptr KProtocolInfoFactory::findProtocol(const QString &protocol)
+{
+ if (!sycocaDict()) return KProtocolInfo::Ptr(); // Error!
+
+ QMap<QString,KProtocolInfo::Ptr>::iterator it = m_cache.find(protocol);
+ if (it != m_cache.end())
+ return *it;
+
+ int offset;
+
+ offset = sycocaDict()->find_string( protocol );
+
+ if (!offset) return KProtocolInfo::Ptr(); // Not found;
+
+ KProtocolInfo::Ptr info(createEntry(offset));
+
+ if (info && (info->name() != protocol))
+ {
+ // No it wasn't...
+ return KProtocolInfo::Ptr(); // Not found
+ }
+ m_cache.insert(protocol,info);
+ return info;
+}
+
+void KProtocolInfoFactory::virtual_hook( int id, void* data )
+{ KSycocaFactory::virtual_hook( id, data ); }
+
+KProtocolInfoFactory* KProtocolInfoFactory::self()
+{
+ return kProtocolInfoFactoryInstance->self();
+}
diff --git a/kdecore/sycoca/kprotocolinfofactory.h b/kdecore/sycoca/kprotocolinfofactory.h
new file mode 100644
index 0000000..c0d5a2a
--- /dev/null
+++ b/kdecore/sycoca/kprotocolinfofactory.h
@@ -0,0 +1,99 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2000,2003 Waldo Bastian <bastian@kde.org>
+
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef kprotocolinfofactory_h
+#define kprotocolinfofactory_h
+
+#include "kprotocolinfo.h"
+
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <kurl.h>
+#include <ksycocafactory.h>
+
+
+/**
+ * @internal
+ *
+ * KProtocolInfoFactory is a factory for getting
+ * KProtocolInfo. The factory is a singleton
+ * (only one instance can exist).
+ *
+ * @short Factory for KProtocolInfo
+ *
+ * Exported for kbuildsycoca, but not installed.
+ */
+class KDECORE_EXPORT KProtocolInfoFactory : public KSycocaFactory
+{
+ K_SYCOCAFACTORY( KST_KProtocolInfoFactory )
+public:
+ /**
+ * The instance of the KProtocolInfoFactory.
+ * @return the factory instance
+ */
+ static KProtocolInfoFactory* self();
+
+ /** \internal */
+ KProtocolInfoFactory();
+ virtual ~KProtocolInfoFactory();
+
+ /*
+ * Returns protocol info for @p protocol.
+ *
+ * Does not take proxy settings into account.
+ * @param protocol the protocol to search for
+ * @return the pointer to the KProtocolInfo, or 0 if not found
+ */
+ KProtocolInfo::Ptr findProtocol(const QString &protocol);
+
+ /**
+ * @return all protocols
+ */
+ KProtocolInfo::List allProtocols() const;
+
+ /**
+ * Returns list of all known protocols.
+ * @return a list of all protocols
+ */
+ QStringList protocols() const;
+
+protected:
+ /**
+ * @internal Not used.
+ */
+ virtual KSycocaEntry *createEntry(const QString &, const char *) const
+ { return 0; }
+
+ /**
+ * @internal
+ */
+ virtual KProtocolInfo *createEntry(int offset) const;
+
+protected:
+ /** Virtual hook, used to add new "virtual" functions while maintaining
+ binary compatibility. Unused in this class.
+ */
+ virtual void virtual_hook( int id, void* data );
+private:
+ QMap<QString,KProtocolInfo::Ptr> m_cache;
+ class KProtocolInfoFactoryPrivate* d;
+};
+
+#endif
diff --git a/kdecore/sycoca/ksycoca.cpp b/kdecore/sycoca/ksycoca.cpp
new file mode 100644
index 0000000..bba13d8
--- /dev/null
+++ b/kdecore/sycoca/ksycoca.cpp
@@ -0,0 +1,604 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999-2000 Waldo Bastian <bastian@kde.org>
+ * Copyright (C) 2005-2009 David Faure <faure@kde.org>
+ * Copyright (C) 2008 Hamish Rodda <rodda@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation;
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "ksycoca.h"
+#include "ksycoca_p.h"
+#include "ksycocatype.h"
+#include "ksycocafactory.h"
+#include "ktoolinvocation.h"
+#include "kglobal.h"
+#include "kmemfile.h"
+#include "kde_file.h"
+#include "kconfiggroup.h"
+#include "ksharedconfig.h"
+
+#include "kdebug.h"
+#include "kstandarddirs.h"
+
+#include <QtCore/QDataStream>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QFile>
+#include <QtCore/QBuffer>
+#include <QProcess>
+#include <QtDBus/QtDBus>
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include "ksycocadevices_p.h"
+
+// TODO: remove mmap() from kdewin32 and use QFile::mmap() when needed
+#ifdef Q_WS_WIN
+#undef HAVE_MMAP
+#endif
+/**
+ * Sycoca file version number.
+ * If the existing file is outdated, it will not get read
+ * but instead we'll ask kded to regenerate a new one...
+ */
+#define KSYCOCA_VERSION 205
+
+/**
+ * Sycoca file name, used internally (by kbuildsycoca)
+ */
+#define KSYCOCA_FILENAME "ksycoca4"
+
+#if HAVE_MADVISE
+#include <sys/mman.h> // This #include was checked when looking for posix_madvise
+#endif
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *) -1)
+#endif
+
+static bool s_autoRebuild = true;
+
+// The following limitations are in place:
+// Maximum length of a single string: 8192 bytes
+// Maximum length of a string list: 1024 strings
+// Maximum number of entries: 8192
+//
+// The purpose of these limitations is to limit the impact
+// of database corruption.
+
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(KSycocaPrivate::BehaviorsIfNotFound)
+
+KSycocaPrivate::KSycocaPrivate()
+ : databaseStatus( DatabaseNotOpen ),
+ readError( false ),
+ timeStamp( 0 ),
+ m_databasePath(),
+ updateSig( 0 ),
+ sycoca_size(0),
+ sycoca_mmap(0),
+ m_mmapFile(0),
+ m_device(0)
+{
+#ifdef Q_OS_WIN
+ /*
+ on windows we use KMemFile (QSharedMemory) to avoid problems
+ with mmap (can't delete a mmap'd file)
+ */
+ m_sycocaStrategy = StrategyMemFile;
+#else
+ m_sycocaStrategy = StrategyMmap;
+#endif
+ KConfigGroup config(KGlobal::config(), "KSycoca");
+ setStrategyFromString(config.readEntry("strategy"));
+}
+
+void KSycocaPrivate::setStrategyFromString(const QString& strategy) {
+ if (strategy == QLatin1String("mmap"))
+ m_sycocaStrategy = StrategyMmap;
+ else if (strategy == QLatin1String("file"))
+ m_sycocaStrategy = StrategyFile;
+ else if (strategy == QLatin1String("sharedmem"))
+ m_sycocaStrategy = StrategyMemFile;
+ else if (!strategy.isEmpty())
+ kWarning(7011) << "Unknown sycoca strategy:" << strategy;
+}
+
+bool KSycocaPrivate::tryMmap()
+{
+#ifdef HAVE_MMAP
+ Q_ASSERT(!m_databasePath.isEmpty());
+ m_mmapFile = new QFile(m_databasePath);
+ const bool canRead = m_mmapFile->open(QIODevice::ReadOnly);
+ Q_ASSERT(canRead);
+ Q_UNUSED(canRead); // no compiler warning in release builds.
+ fcntl(m_mmapFile->handle(), F_SETFD, FD_CLOEXEC);
+ sycoca_size = m_mmapFile->size();
+ sycoca_mmap = (const char *) mmap(0, sycoca_size,
+ PROT_READ, MAP_SHARED,
+ m_mmapFile->handle(), 0);
+ /* POSIX mandates only MAP_FAILED, but we are paranoid so check for
+ null pointer too. */
+ if (sycoca_mmap == (const char*) MAP_FAILED || sycoca_mmap == 0) {
+ kDebug(7011) << "mmap failed. (length = " << sycoca_size << ")";
+ sycoca_mmap = 0;
+ return false;
+ } else {
+#ifdef HAVE_MADVISE
+ (void) posix_madvise((void*)sycoca_mmap, sycoca_size, POSIX_MADV_WILLNEED);
+#endif // HAVE_MADVISE
+ return true;
+ }
+#endif // HAVE_MMAP
+ return false;
+}
+
+int KSycoca::version()
+{
+ return KSYCOCA_VERSION;
+}
+
+class KSycocaSingleton
+{
+public:
+ KSycocaSingleton() { }
+ ~KSycocaSingleton() { }
+
+ bool hasSycoca() const {
+ return m_threadSycocas.hasLocalData();
+ }
+ KSycoca* sycoca() {
+ if (!m_threadSycocas.hasLocalData())
+ m_threadSycocas.setLocalData(new KSycoca);
+ return m_threadSycocas.localData();
+ }
+ void setSycoca(KSycoca* s) {
+ m_threadSycocas.setLocalData(s);
+ }
+
+private:
+ QThreadStorage<KSycoca*> m_threadSycocas;
+};
+
+K_GLOBAL_STATIC(KSycocaSingleton, ksycocaInstance)
+
+// Read-only constructor
+KSycoca::KSycoca()
+ : d(new KSycocaPrivate)
+{
+ QDBusConnection::sessionBus().connect(QString(), QString(),
+ QString::fromLatin1("org.kde.KSycoca"),
+ QString::fromLatin1("notifyDatabaseChanged"),
+ this, SLOT(notifyDatabaseChanged(QStringList)));
+}
+
+bool KSycocaPrivate::openDatabase(bool openDummyIfNotFound)
+{
+ Q_ASSERT(databaseStatus == DatabaseNotOpen);
+
+ delete m_device; m_device = 0;
+ QString path = KSycoca::absoluteFilePath();
+
+ bool canRead = KDE::access(path, R_OK) == 0;
+ kDebug(7011) << "Trying to open ksycoca from" << path;
+ if (!canRead) {
+ path = KSycoca::absoluteFilePath(KSycoca::GlobalDatabase);
+ if (!path.isEmpty()) {
+ kDebug(7011) << "Trying to open global ksycoca from " << path;
+ canRead = KDE::access(path, R_OK) == 0;
+ }
+ }
+
+ bool result = true;
+ if (canRead) {
+ m_databasePath = path;
+ checkVersion();
+ } else { // No database file
+ kDebug(7011) << "Could not open ksycoca";
+ m_databasePath.clear();
+ databaseStatus = NoDatabase;
+ if (openDummyIfNotFound) {
+ // We open a dummy database instead.
+ //kDebug(7011) << "No database, opening a dummy one.";
+
+ m_sycocaStrategy = StrategyDummyBuffer;
+ QDataStream* str = stream();
+ *str << qint32(KSYCOCA_VERSION);
+ *str << qint32(0);
+ } else {
+ result = false;
+ }
+ }
+ return result;
+}
+
+KSycocaAbstractDevice* KSycocaPrivate::device()
+{
+ if (m_device)
+ return m_device;
+
+ Q_ASSERT(!m_databasePath.isEmpty());
+
+ KSycocaAbstractDevice* device = m_device;
+ if (m_sycocaStrategy == StrategyDummyBuffer) {
+ device = new KSycocaBufferDevice;
+ device->device()->open(QIODevice::ReadOnly); // can't fail
+ } else {
+#ifdef HAVE_MMAP
+ if (m_sycocaStrategy == StrategyMmap && tryMmap()) {
+ device = new KSycocaMmapDevice(sycoca_mmap,
+ sycoca_size);
+ if (!device->device()->open(QIODevice::ReadOnly)) {
+ delete device; device = 0;
+ }
+ }
+#endif
+#ifndef QT_NO_SHAREDMEMORY
+ if (!device && m_sycocaStrategy == StrategyMemFile) {
+ device = new KSycocaMemFileDevice(m_databasePath);
+ if (!device->device()->open(QIODevice::ReadOnly)) {
+ delete device; device = 0;
+ }
+ }
+#endif
+ if (!device) {
+ device = new KSycocaFileDevice(m_databasePath);
+ if (!device->device()->open(QIODevice::ReadOnly)) {
+ kError(7011) << "Couldn't open" << m_databasePath << "even though it is readable? Impossible.";
+ //delete device; device = 0; // this would crash in the return statement...
+ }
+ }
+ }
+ if (device) {
+ m_device = device;
+ }
+ return m_device;
+}
+
+QDataStream*& KSycocaPrivate::stream()
+{
+ if (!m_device) {
+ if (databaseStatus == DatabaseNotOpen) {
+ checkDatabase(KSycocaPrivate::IfNotFoundRecreate | KSycocaPrivate::IfNotFoundOpenDummy);
+ }
+
+ device(); // create m_device
+ }
+
+ return m_device->stream();
+}
+
+// Read-write constructor - only for KBuildSycoca
+KSycoca::KSycoca( bool /* dummy */ )
+ : d(new KSycocaPrivate)
+{
+ // This instance was not created by the singleton, but by a direct call to new!
+ ksycocaInstance->setSycoca(this);
+}
+
+KSycoca * KSycoca::self()
+{
+ KSycoca* s = ksycocaInstance->sycoca();
+ Q_ASSERT(s);
+ return s;
+}
+
+KSycoca::~KSycoca()
+{
+ d->closeDatabase();
+ delete d;
+ //if (ksycocaInstance.exists()
+ // && ksycocaInstance->self == this)
+ // ksycocaInstance->self = 0;
+}
+
+bool KSycoca::isAvailable()
+{
+ return self()->d->checkDatabase(KSycocaPrivate::IfNotFoundDoNothing/* don't open dummy db if not found */);
+}
+
+void KSycocaPrivate::closeDatabase()
+{
+ delete m_device;
+ m_device = 0;
+
+ // It is very important to delete all factories here
+ // since they cache information about the database file
+ // But other threads might be using them, so this class is
+ // refcounted, and deleted when the last thread is done with them
+ qDeleteAll(m_factories);
+ m_factories.clear();
+#ifdef HAVE_MMAP
+ if (sycoca_mmap) {
+ //QBuffer *buf = static_cast<QBuffer*>(device);
+ //buf->buffer().clear();
+ // Solaris has munmap(char*, size_t) and everything else should
+ // be happy with a char* for munmap(void*, size_t)
+ munmap(const_cast<char*>(sycoca_mmap), sycoca_size);
+ sycoca_mmap = 0;
+ }
+ delete m_mmapFile; m_mmapFile = 0;
+#endif
+
+ databaseStatus = DatabaseNotOpen;
+ timeStamp = 0;
+}
+
+void KSycoca::addFactory( KSycocaFactory *factory )
+{
+ d->addFactory(factory);
+}
+
+#ifndef KDE_NO_DEPRECATED
+bool KSycoca::isChanged(const char *type)
+{
+ return self()->d->changeList.contains(QString::fromLatin1(type));
+}
+#endif
+
+void KSycoca::notifyDatabaseChanged(const QStringList &changeList)
+{
+ d->changeList = changeList;
+ //kDebug(7011) << QThread::currentThread() << "got a notifyDatabaseChanged signal" << changeList;
+ // kbuildsycoca tells us the database file changed
+ // Close the database and forget all about what we knew
+ // The next call to any public method will recreate
+ // everything that's needed.
+ d->closeDatabase();
+
+ // Now notify applications
+#ifndef KDE_NO_DEPRECATED
+ emit databaseChanged();
+#endif
+ emit databaseChanged(changeList);
+}
+
+QDataStream * KSycoca::findEntry(int offset, KSycocaType &type)
+{
+ QDataStream* str = stream();
+ Q_ASSERT(str);
+ //kDebug(7011) << QString("KSycoca::_findEntry(offset=%1)").arg(offset,8,16);
+ str->device()->seek(offset);
+ qint32 aType;
+ *str >> aType;
+ type = KSycocaType(aType);
+ //kDebug(7011) << QString("KSycoca::found type %1").arg(aType);
+ return str;
+}
+
+KSycocaFactoryList* KSycoca::factories()
+{
+ return d->factories();
+}
+
+// Warning, checkVersion rewinds to the beginning of stream().
+bool KSycocaPrivate::checkVersion()
+{
+ QDataStream *m_str = device()->stream();
+ Q_ASSERT(m_str);
+ m_str->device()->seek(0);
+ qint32 aVersion;
+ *m_str >> aVersion;
+ if ( aVersion < KSYCOCA_VERSION ) {
+ kWarning(7011) << "Found version" << aVersion << ", expecting version" << KSYCOCA_VERSION << "or higher.";
+ databaseStatus = BadVersion;
+ return false;
+ } else {
+ databaseStatus = DatabaseOK;
+ return true;
+ }
+}
+
+// If it returns true, we have a valid database and the stream has rewinded to the beginning
+// and past the version number.
+bool KSycocaPrivate::checkDatabase(BehaviorsIfNotFound ifNotFound)
+{
+ if (databaseStatus == DatabaseOK) {
+ if (checkVersion()) // we know the version is ok, but we must rewind the stream anyway
+ return true;
+ }
+
+ closeDatabase(); // close the dummy one
+
+ // We can only use the installed ksycoca file if kdeinit+klauncher+kded are running,
+ // since kded is what keeps the file uptodate.
+ const bool kdeinitRunning = QDBusConnection::sessionBus().interface()->isServiceRegistered(QString::fromLatin1("org.kde.klauncher"));
+
+ // Check if new database already available
+ if (kdeinitRunning && openDatabase(ifNotFound & IfNotFoundOpenDummy)) {
+ if (checkVersion()) {
+ // Database exists, and version is ok.
+ return true;
+ }
+ }
+
+ if (ifNotFound & IfNotFoundRecreate) {
+ // Well, if kdeinit is not running we need to launch it,
+ // but otherwise we simply need to run kbuildsycoca to recreate the sycoca file.
+ if (!kdeinitRunning) {
+ kDebug(7011) << "We have no database.... launching kdeinit";
+ KToolInvocation::klauncher(); // this calls startKdeinit, and blocks until it returns
+ // and since kdeinit4 only returns after kbuildsycoca4 is done, we can proceed.
+ } else {
+ kDebug(7011) << QThread::currentThread() << "We have no database.... launching" << KBUILDSYCOCA_EXENAME;
+ if (QProcess::execute(KStandardDirs::findExe(QString::fromLatin1(KBUILDSYCOCA_EXENAME))) != 0)
+ qWarning("ERROR: Running KSycoca failed.");
+ }
+
+ closeDatabase(); // close the dummy one
+
+ // Ok, the new database should be here now, open it.
+ if (!openDatabase(ifNotFound & IfNotFoundOpenDummy)) {
+ kDebug(7011) << "Still no database...";
+ return false; // Still no database - uh oh
+ }
+ if (!checkVersion()) {
+ kDebug(7011) << "Still outdated...";
+ return false; // Still outdated - uh oh
+ }
+ return true;
+ }
+
+ return false;
+}
+
+QDataStream * KSycoca::findFactory(KSycocaFactoryId id)
+{
+ // Ensure we have a valid database (right version, and rewinded to beginning)
+ if (!d->checkDatabase(KSycocaPrivate::IfNotFoundRecreate)) {
+ return 0;
+ }
+
+ QDataStream* str = stream();
+ Q_ASSERT(str);
+
+ qint32 aId;
+ qint32 aOffset;
+ while(true) {
+ *str >> aId;
+ if (aId == 0) {
+ kError(7011) << "Error, KSycocaFactory (id =" << int(id) << ") not found!";
+ break;
+ }
+ *str >> aOffset;
+ if (aId == id) {
+ //kDebug(7011) << "KSycoca::findFactory(" << id << ") offset " << aOffset;
+ str->device()->seek(aOffset);
+ return str;
+ }
+ }
+ return 0;
+}
+
+QString KSycoca::kfsstnd_prefixes()
+{
+ // do not try to launch kbuildsycoca from here; this code is also called by kbuildsycoca.
+ if (!d->checkDatabase(KSycocaPrivate::IfNotFoundDoNothing))
+ return QString();
+ QDataStream* str = stream();
+ Q_ASSERT(str);
+ qint32 aId;
+ qint32 aOffset;
+ // skip factories offsets
+ while(true)
+ {
+ *str >> aId;
+ if ( aId )
+ *str >> aOffset;
+ else
+ break; // just read 0
+ }
+ // We now point to the header
+ QString prefixes;
+ KSycocaEntry::read(*str, prefixes);
+ *str >> d->timeStamp;
+ KSycocaEntry::read(*str, d->language);
+ *str >> d->updateSig;
+ KSycocaEntry::read(*str, d->allResourceDirs);
+ return prefixes;
+}
+
+quint32 KSycoca::timeStamp()
+{
+ if (!d->timeStamp)
+ (void) kfsstnd_prefixes();
+ return d->timeStamp;
+}
+
+quint32 KSycoca::updateSignature()
+{
+ if (!d->timeStamp)
+ (void) kfsstnd_prefixes();
+ return d->updateSig;
+}
+
+QString KSycoca::absoluteFilePath(DatabaseType type)
+{
+ if (type == GlobalDatabase) {
+ QString path = KGlobal::dirs()->findResource("services", QString::fromLatin1(KSYCOCA_FILENAME));
+ if (path.isEmpty())
+ return KGlobal::dirs()->saveLocation("services") + QString::fromLatin1(KSYCOCA_FILENAME);
+ return path;
+ }
+
+ const QByteArray ksycoca_env = qgetenv("KDESYCOCA");
+ if (ksycoca_env.isEmpty())
+ return KGlobal::dirs()->saveLocation("cache") + QString::fromLatin1(KSYCOCA_FILENAME);
+ else
+ return QFile::decodeName(ksycoca_env);
+}
+
+QString KSycoca::language()
+{
+ if (d->language.isEmpty())
+ (void) kfsstnd_prefixes();
+ return d->language;
+}
+
+QStringList KSycoca::allResourceDirs()
+{
+ if (!d->timeStamp)
+ (void) kfsstnd_prefixes();
+ return d->allResourceDirs;
+}
+
+void KSycoca::flagError()
+{
+ kWarning(7011) << "ERROR: KSycoca database corruption!";
+ KSycocaPrivate* d = ksycocaInstance->sycoca()->d;
+ if (d->readError)
+ return;
+ d->readError = true;
+ if (s_autoRebuild) {
+ // Rebuild the damned thing.
+ if (QProcess::execute(KStandardDirs::findExe(QString::fromLatin1(KBUILDSYCOCA_EXENAME))) != 0)
+ qWarning("ERROR: Running %s failed", KBUILDSYCOCA_EXENAME);
+ // Old comment, maybe not true anymore:
+ // Do not wait until the DBUS signal from kbuildsycoca here.
+ // It deletes m_str which is a problem when flagError is called during the KSycocaFactory ctor...
+ }
+}
+
+#ifndef KDE_NO_DEPRECATED
+bool KSycoca::readError() // KDE5: remove
+{
+ return false;
+}
+#endif
+
+bool KSycoca::isBuilding()
+{
+ return false;
+}
+
+void KSycoca::disableAutoRebuild()
+{
+ s_autoRebuild = false;
+}
+
+QDataStream*& KSycoca::stream()
+{
+ return d->stream();
+}
+
+void KSycoca::clearCaches()
+{
+ if (ksycocaInstance.exists() && ksycocaInstance->hasSycoca())
+ ksycocaInstance->sycoca()->d->closeDatabase();
+}
+
+#include "ksycoca.moc"
diff --git a/kdecore/sycoca/ksycoca.h b/kdecore/sycoca/ksycoca.h
new file mode 100644
index 0000000..1067d70
--- /dev/null
+++ b/kdecore/sycoca/ksycoca.h
@@ -0,0 +1,235 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+ * Copyright (C) 2005-2008 David Faure <faure@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation;
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef KSYCOCA_H
+#define KSYCOCA_H
+
+#include <kdecore_export.h>
+#include <ksycocatype.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QStringList>
+
+class QDataStream;
+class KSycocaFactory;
+class KSycocaFactoryList;
+class KSycocaPrivate;
+
+/**
+ * Executable name of the kbuildsycoca program
+ */
+#define KBUILDSYCOCA_EXENAME "kbuildsycoca4"
+
+/**
+ * @internal
+ * Read-only SYstem COnfiguration CAche
+ */
+class KDECORE_EXPORT KSycoca : public QObject
+{
+ Q_OBJECT
+ //Q_CLASSINFO("D-Bus Interface", "org.kde.KSycoca")
+
+protected:
+ /**
+ * @internal
+ * Building database
+ */
+ explicit KSycoca( bool /* buildDatabase */ );
+
+public:
+ /**
+ * type of database
+ * @see absoluteFilePath()
+ */
+ typedef enum { LocalDatabase, GlobalDatabase } DatabaseType;
+
+ /**
+ * Read-only database
+ */
+ KSycoca();
+
+ /**
+ * Get or create the only instance of KSycoca (read-only)
+ */
+ static KSycoca *self();
+
+ virtual ~KSycoca();
+
+ /**
+ * @return the compiled-in version, i.e. the one used when writing a new ksycoca
+ */
+ static int version();
+
+ /**
+ * @return true if the ksycoca database is available
+ * This is usually the case, except if KDE isn't installed yet,
+ * or before kded is started.
+ */
+ static bool isAvailable();
+
+ /**
+ * @internal - called by factories in read-only mode
+ * This is how factories get a stream to an entry
+ */
+ QDataStream *findEntry(int offset, KSycocaType &type);
+ /**
+ * @internal - called by factories in read-only mode
+ * Returns stream(), but positioned for reading this factory, 0 on error.
+ */
+ QDataStream *findFactory(KSycocaFactoryId id);
+ /**
+ * @internal - returns kfsstnd stored inside database
+ */
+ QString kfsstnd_prefixes();
+ /**
+ * @internal - returns absolute file path of the database
+ *
+ * for global database type the database is searched under
+ * the 'services' install path.
+ * Otherwise, the value from the environment variable KDESYCOCA
+ * is returned if set. If not set the path is build based on
+ * KStandardDirs cache save location.
+ */
+ static QString absoluteFilePath(DatabaseType type=LocalDatabase);
+ /**
+ * @internal - returns language stored inside database
+ */
+ QString language();
+
+ /**
+ * @internal - returns timestamp of database
+ *
+ * The database contains all changes made _before_ this time and
+ * _might_ contain changes made after that.
+ */
+ quint32 timeStamp();
+
+ /**
+ * @internal - returns update signature of database
+ *
+ * Signature that keeps track of changes to
+ * $KDEDIR/share/services/update_ksycoca
+ *
+ * Touching this file causes the database to be recreated
+ * from scratch.
+ */
+ quint32 updateSignature();
+
+ /**
+ * @internal - returns all directories with information
+ * stored inside sycoca.
+ */
+ QStringList allResourceDirs();
+
+ /**
+ * @internal - add a factory
+ */
+ void addFactory( KSycocaFactory * );
+
+ /**
+ * @internal
+ * @return true if building (i.e. if a KBuildSycoca);
+ */
+ virtual bool isBuilding();
+
+ /**
+ * @internal - disables launching of kbuildsycoca
+ */
+ static void disableAutoRebuild();
+
+ /**
+ * When you receive a "databaseChanged" signal, you can query here if
+ * a change has occurred in a specific resource type.
+ * @see KStandardDirs for the various resource types.
+ *
+ * This method is meant to be called from the GUI thread only.
+ * @deprecated use the signal databaseChanged(QStringList) instead.
+ */
+#ifndef KDE_NO_DEPRECATED
+ static KDE_DEPRECATED bool isChanged(const char *type);
+#endif
+
+ /**
+ * A read error occurs.
+ * @internal
+ */
+ static void flagError();
+
+ /// @deprecated
+#ifndef KDE_NO_DEPRECATED
+ static KDE_DEPRECATED bool readError();
+#endif
+
+Q_SIGNALS:
+ /**
+ * Connect to this to get notified when the database changes
+ * @deprecated use the databaseChanged(QStringList) signal
+ */
+#ifndef KDE_NO_DEPRECATED
+ QT_MOC_COMPAT void databaseChanged(); // KDE5 TODO: remove
+#endif
+
+ /**
+ * Connect to this to get notified when the database changes
+ * Example: when mimetype definitions have changed, applications showing
+ * files as icons refresh icons to take into account the new mimetypes.
+ * Another example: after creating a .desktop file in KOpenWithDialog,
+ * it must wait until kbuildsycoca4 finishes until the KService::Ptr is available.
+ *
+ * @param changedResources List of resources where changes were detected.
+ * This can include the following resources (as defined in KStandardDirs) :
+ * apps, xdgdata-apps, services, servicetypes, xdgdata-mime.
+ */
+ void databaseChanged(const QStringList& changedResources);
+
+protected:
+ // @internal used by kbuildsycoca
+ KSycocaFactoryList* factories();
+
+ // @internal was for kbuildsycoca
+#ifndef KDE_NO_DEPRECATED
+ QDataStream *m_str_deprecated; // KDE5: REMOVE
+#endif
+ // @internal used by factories and kbuildsycoca
+ QDataStream*& stream();
+ friend class KSycocaFactory;
+ friend class KSycocaDict;
+
+private Q_SLOTS:
+ /**
+ * internal function for receiving kbuildsycoca's signal, when the sycoca file changes
+ */
+ void notifyDatabaseChanged(const QStringList &);
+
+private:
+ /**
+ * Clear all caches related to ksycoca contents.
+ * @internal only used by kded and kbuildsycoca.
+ */
+ static void clearCaches();
+ friend class KBuildSycoca;
+ friend class Kded;
+
+ Q_DISABLE_COPY(KSycoca)
+ friend class KSycocaPrivate;
+ KSycocaPrivate * const d;
+};
+
+#endif
+
diff --git a/kdecore/sycoca/ksycoca_p.h b/kdecore/sycoca/ksycoca_p.h
new file mode 100644
index 0000000..0d88f10
--- /dev/null
+++ b/kdecore/sycoca/ksycoca_p.h
@@ -0,0 +1,79 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999-2000 Waldo Bastian <bastian@kde.org>
+ * Copyright (C) 2005-2009 David Faure <faure@kde.org>
+ * Copyright (C) 2008 Hamish Rodda <rodda@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation;
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef KSYCOCA_P_H
+#define KSYCOCA_P_H
+
+#include "ksycocafactory.h"
+#include <QStringList>
+class QFile;
+class QDataStream;
+class KSycocaAbstractDevice;
+
+class KSycocaPrivate
+{
+public:
+ KSycocaPrivate();
+ bool checkVersion();
+ bool openDatabase(bool openDummyIfNotFound=true);
+ enum BehaviorIfNotFound {
+ IfNotFoundDoNothing = 0,
+ IfNotFoundOpenDummy = 1,
+ IfNotFoundRecreate = 2
+ };
+ Q_DECLARE_FLAGS(BehaviorsIfNotFound, BehaviorIfNotFound)
+ bool checkDatabase(BehaviorsIfNotFound ifNotFound);
+ void closeDatabase();
+ void setStrategyFromString(const QString& strategy);
+ bool tryMmap();
+
+ KSycocaAbstractDevice* device();
+ QDataStream*& stream();
+
+ enum {
+ DatabaseNotOpen, // openDatabase must be called
+ NoDatabase, // not found, so we opened a dummy one instead
+ BadVersion, // it's opened, but it's not useable
+ DatabaseOK } databaseStatus;
+ bool readError;
+
+ quint32 timeStamp;
+ enum { StrategyMmap, StrategyMemFile, StrategyFile, StrategyDummyBuffer } m_sycocaStrategy;
+ QString m_databasePath;
+ QStringList changeList;
+ QString language;
+ quint32 updateSig;
+ QStringList allResourceDirs;
+
+ void addFactory(KSycocaFactory* factory) {
+ m_factories.append(factory);
+ }
+ KSycocaFactoryList* factories() { return &m_factories; }
+
+private:
+ KSycocaFactoryList m_factories;
+ size_t sycoca_size;
+ const char *sycoca_mmap;
+ QFile* m_mmapFile;
+ KSycocaAbstractDevice* m_device;
+};
+
+#endif /* KSYCOCA_P_H */
+
diff --git a/kdecore/sycoca/ksycocadevices_p.h b/kdecore/sycoca/ksycocadevices_p.h
new file mode 100644
index 0000000..47e13cd
--- /dev/null
+++ b/kdecore/sycoca/ksycocadevices_p.h
@@ -0,0 +1,125 @@
+/* This file is part of the KDE project
+
+ Copyright 2009 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as published
+ by the Free Software Foundation; either version 2 of the License or
+ ( at your option ) version 3 or, at the discretion of KDE e.V.
+ ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSYCOCADEVICES_P_H
+#define KSYCOCADEVICES_P_H
+
+class KSycocaAbstractDevice
+{
+public:
+ KSycocaAbstractDevice() : m_stream(0)
+ {
+ }
+
+ virtual ~KSycocaAbstractDevice() { delete m_stream; }
+
+ virtual QIODevice* device() = 0;
+
+ QDataStream* & stream() {
+ if (!m_stream) {
+ m_stream = new QDataStream(device());
+ m_stream->setVersion(QDataStream::Qt_3_1);
+ }
+ return m_stream;
+ }
+
+private:
+ QDataStream* m_stream;
+};
+
+#ifdef HAVE_MMAP
+// Reading from a mmap'ed file
+class KSycocaMmapDevice : public KSycocaAbstractDevice
+{
+public:
+ KSycocaMmapDevice(const char* sycoca_mmap, size_t sycoca_size) {
+ m_buffer = new QBuffer;
+ m_buffer->setData(QByteArray::fromRawData(sycoca_mmap, sycoca_size));
+ }
+ ~KSycocaMmapDevice() {
+ delete m_buffer;
+ }
+ virtual QIODevice* device() {
+ return m_buffer;
+ }
+private:
+ QBuffer* m_buffer;
+};
+#endif
+
+// Reading from a QFile
+class KSycocaFileDevice : public KSycocaAbstractDevice
+{
+public:
+ KSycocaFileDevice(const QString& path) {
+ m_database = new QFile(path);
+#ifndef Q_OS_WIN
+ fcntl(m_database->handle(), F_SETFD, FD_CLOEXEC);
+#endif
+ }
+ ~KSycocaFileDevice() {
+ delete m_database;
+ }
+ virtual QIODevice* device() {
+ return m_database;
+ }
+private:
+ QFile* m_database;
+};
+
+#ifndef QT_NO_SHAREDMEMORY
+// Reading from a KMemFile
+class KSycocaMemFileDevice : public KSycocaAbstractDevice
+{
+public:
+ KSycocaMemFileDevice(const QString& path) {
+ m_database = new KMemFile(path);
+ }
+ ~KSycocaMemFileDevice() {
+ delete m_database;
+ }
+ virtual QIODevice* device() {
+ return m_database;
+ }
+private:
+ KMemFile* m_database;
+};
+#endif
+
+// Reading from a dummy memory buffer
+class KSycocaBufferDevice : public KSycocaAbstractDevice
+{
+public:
+ KSycocaBufferDevice() {
+ m_buffer = new QBuffer;
+ }
+ ~KSycocaBufferDevice() {
+ delete m_buffer;
+ }
+ virtual QIODevice* device() {
+ return m_buffer;
+ }
+private:
+ QBuffer* m_buffer;
+};
+
+#endif /* KSYCOCADEVICES_P_H */
+
diff --git a/kdecore/sycoca/ksycocadict.cpp b/kdecore/sycoca/ksycocadict.cpp
new file mode 100644
index 0000000..2f9a5b2
--- /dev/null
+++ b/kdecore/sycoca/ksycocadict.cpp
@@ -0,0 +1,562 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation;
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "ksycocadict_p.h"
+#include <kservice.h>
+#include "ksycocaentry.h"
+#include "ksycoca.h"
+#include "kdebug.h"
+
+#include <QtCore/QBitArray>
+
+namespace
+{
+struct string_entry {
+ string_entry(const QString& _key, const KSycocaEntry::Ptr& _payload)
+ : hash(0), length(_key.length()), keyStr(_key), key(keyStr.unicode()), payload(_payload)
+ {}
+ uint hash;
+ const int length;
+ const QString keyStr;
+ const QChar * const key; // always points to keyStr.unicode(); just an optimization
+ const KSycocaEntry::Ptr payload;
+};
+}
+
+class KSycocaDictStringList : public QList<string_entry*>
+{
+public:
+ ~KSycocaDictStringList() {
+ qDeleteAll(*this);
+ }
+};
+
+class KSycocaDict::Private
+{
+public:
+ Private()
+ : stringlist( 0 ),
+ stream( 0 ),
+ offset( 0 )
+ {
+ }
+
+ ~Private()
+ {
+ delete stringlist;
+ }
+
+ // Helper for find_string and findMultiString
+ qint32 offsetForKey(const QString& key) const;
+
+ // Calculate hash - can be used during loading and during saving.
+ quint32 hashKey(const QString & key) const;
+
+ KSycocaDictStringList *stringlist;
+ QDataStream *stream;
+ qint64 offset;
+ quint32 hashTableSize;
+ QList<qint32> hashList;
+};
+
+KSycocaDict::KSycocaDict()
+ : d( new Private )
+{
+}
+
+KSycocaDict::KSycocaDict(QDataStream *str, int offset)
+ : d( new Private )
+{
+ d->stream = str;
+ d->offset = offset;
+
+ quint32 test1, test2;
+ str->device()->seek(offset);
+ (*str) >> test1 >> test2;
+ if ((test1 > 0x000fffff) || (test2 > 1024))
+ {
+ KSycoca::flagError();
+ d->hashTableSize = 0;
+ d->offset = 0;
+ return;
+ }
+
+ str->device()->seek(offset);
+ (*str) >> d->hashTableSize;
+ (*str) >> d->hashList;
+ d->offset = str->device()->pos(); // Start of hashtable
+}
+
+KSycocaDict::~KSycocaDict()
+{
+ delete d;
+}
+
+void
+KSycocaDict::add(const QString &key, const KSycocaEntry::Ptr& payload)
+{
+ if (key.isEmpty()) return; // Not allowed (should never happen)
+ if (!payload) return; // Not allowed!
+ if (!d->stringlist)
+ {
+ d->stringlist = new KSycocaDictStringList;
+ }
+
+ string_entry *entry = new string_entry(key, payload);
+ d->stringlist->append(entry);
+}
+
+void
+KSycocaDict::remove(const QString &key)
+{
+ if (!d || !d->stringlist) {
+ return;
+ }
+
+ bool found = false;
+ for(KSycocaDictStringList::Iterator it = d->stringlist->begin(); it != d->stringlist->end(); ++it) {
+ string_entry* entry = *it;
+ if (entry->keyStr == key) {
+ d->stringlist->erase(it);
+ delete entry;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ kWarning(7011) << "key not found:" << key;
+ }
+}
+
+int KSycocaDict::find_string(const QString &key ) const
+{
+ Q_ASSERT(d);
+
+ //kDebug(7011) << QString("KSycocaDict::find_string(%1)").arg(key);
+ qint32 offset = d->offsetForKey(key);
+
+ //kDebug(7011) << QString("offset is %1").arg(offset,8,16);
+ if (offset == 0)
+ return 0;
+
+ if (offset > 0)
+ return offset; // Positive ID
+
+ // Lookup duplicate list.
+ offset = -offset;
+
+ d->stream->device()->seek(offset);
+ //kDebug(7011) << QString("Looking up duplicate list at %1").arg(offset,8,16);
+
+ while(true)
+ {
+ (*d->stream) >> offset;
+ if (offset == 0) break;
+ QString dupkey;
+ (*d->stream) >> dupkey;
+ //kDebug(7011) << QString(">> %1 %2").arg(offset,8,16).arg(dupkey);
+ if (dupkey == key) return offset;
+ }
+ //kWarning(7011) << "Not found!";
+
+ return 0;
+}
+
+
+QList<int> KSycocaDict::findMultiString(const QString &key ) const
+{
+ qint32 offset = d->offsetForKey(key);
+ QList<int> offsetList;
+ if (offset == 0)
+ return offsetList;
+
+ if (offset > 0) { // Positive ID: one entry found
+ offsetList.append(offset);
+ return offsetList;
+ }
+
+ // Lookup duplicate list.
+ offset = -offset;
+
+ d->stream->device()->seek(offset);
+ //kDebug(7011) << QString("Looking up duplicate list at %1").arg(offset,8,16);
+
+ while(true)
+ {
+ (*d->stream) >> offset;
+ if (offset == 0) break;
+ QString dupkey;
+ (*d->stream) >> dupkey;
+ //kDebug(7011) << QString(">> %1 %2").arg(offset,8,16).arg(dupkey);
+ if (dupkey == key)
+ offsetList.append(offset);
+ }
+ return offsetList;
+}
+
+uint KSycocaDict::count() const
+{
+ if ( !d || !d->stringlist ) return 0;
+
+ return d->stringlist->count();
+}
+
+void
+KSycocaDict::clear()
+{
+ delete d;
+ d = 0;
+}
+
+uint KSycocaDict::Private::hashKey( const QString &key) const
+{
+ int len = key.length();
+ uint h = 0;
+
+ for(int i = 0; i < hashList.count(); i++)
+ {
+ int pos = hashList[i];
+ if (pos == 0) {
+ continue;
+ } else if (pos < 0) {
+ pos = -pos;
+ if (pos < len)
+ h = ((h * 13) + (key[len-pos].cell() % 29)) & 0x3ffffff;
+ } else {
+ pos = pos-1;
+ if (pos < len)
+ h = ((h * 13) + (key[pos].cell() % 29)) & 0x3ffffff;
+ }
+ }
+ return h;
+}
+
+// If we have the strings
+// hello
+// world
+// kde
+// Then we end up with
+// ABCDE
+// where A = diversity of 'h' + 'w' + 'k' etc.
+// Also, diversity(-2) == 'l'+'l'+'d' (second character from the end)
+
+// The hasList is used for hashing:
+// hashList = (-2, 1, 3) means that the hash key comes from
+// the 2nd character from the right, then the 1st from the left, then the 3rd from the left.
+
+// Calculate the diversity of the strings at position 'pos'
+// NOTE: this code is slow, it takes 12% of the _overall_ `kbuildsycoca4 --noincremental` running time
+static int
+calcDiversity(KSycocaDictStringList *stringlist, int inPos, uint sz)
+{
+ if (inPos == 0) return 0;
+ QBitArray matrix(sz);
+ int pos;
+
+ //static const int s_maxItems = 50;
+ //int numItem = 0;
+
+ if (inPos < 0) {
+ pos = -inPos;
+ for(KSycocaDictStringList::const_iterator it = stringlist->constBegin(), end = stringlist->constEnd(); it != end; ++it)
+ {
+ string_entry* entry = *it;
+ int len = entry->length;
+ if (pos < len) {
+ uint hash = ((entry->hash * 13) + (entry->key[len-pos].cell() % 29)) & 0x3ffffff;
+ matrix.setBit( hash % sz, true );
+ }
+ //if (++numItem == s_maxItems)
+ // break;
+ }
+ } else {
+ pos = inPos-1;
+ for(KSycocaDictStringList::const_iterator it = stringlist->constBegin(), end = stringlist->constEnd(); it != end; ++it)
+ {
+ string_entry* entry = *it;
+ if (pos < entry->length) {
+ uint hash = ((entry->hash * 13) + (entry->key[pos].cell() % 29)) & 0x3ffffff;
+ matrix.setBit( hash % sz, true );
+ }
+ //if (++numItem == s_maxItems)
+ // break;
+ }
+ }
+ return matrix.count(true);
+}
+
+//
+// Add the diversity of the strings at position 'pos'
+static void
+addDiversity(KSycocaDictStringList *stringlist, int pos)
+{
+ if (pos == 0) return;
+ if (pos < 0) {
+ pos = -pos;
+ for(KSycocaDictStringList::const_iterator it = stringlist->constBegin(), end = stringlist->constEnd(); it != end; ++it)
+ {
+ string_entry* entry = *it;
+ int len = entry->length;
+ if (pos < len)
+ entry->hash = ((entry->hash * 13) + (entry->key[len-pos].cell() % 29)) & 0x3fffffff;
+ }
+ } else {
+ pos = pos - 1;
+ for(KSycocaDictStringList::const_iterator it = stringlist->constBegin(), end = stringlist->constEnd(); it != end; ++it)
+ {
+ string_entry* entry = *it;
+ if (pos < entry->length)
+ entry->hash = ((entry->hash * 13) + (entry->key[pos].cell() % 29)) & 0x3fffffff;
+ }
+ }
+}
+
+
+void
+KSycocaDict::save(QDataStream &str)
+{
+ if (count() == 0)
+ {
+ d->hashTableSize = 0;
+ d->hashList.clear();
+ str << d->hashTableSize;
+ str << d->hashList;
+ return;
+ }
+
+ d->offset = str.device()->pos();
+
+ //kDebug(7011) << "KSycocaDict:" << count() << "entries.";
+
+ //kDebug(7011) << "Calculating hash keys..";
+
+ int maxLength = 0;
+ //kDebug(7011) << "Finding maximum string length";
+ for(KSycocaDictStringList::const_iterator it = d->stringlist->constBegin(); it != d->stringlist->constEnd(); ++it)
+ {
+ string_entry* entry = *it;
+ entry->hash = 0;
+ if (entry->length > maxLength)
+ maxLength = entry->length;
+ }
+
+ //kDebug(7011) << "Max string length=" << maxLength << "existing hashList=" << d->hashList;
+
+ // use "almost prime" number for sz (to calculate diversity) and later
+ // for the table size of big tables
+ // int sz = d->stringlist->count()*5-1;
+ register unsigned int sz = count()*4 + 1;
+ while(!(((sz % 3) && (sz % 5) && (sz % 7) && (sz % 11) && (sz % 13))))
+ sz+=2;
+
+ d->hashList.clear();
+
+ // Times (with warm caches, i.e. after multiple runs)
+ // kbuildsycoca4 --noincremental 2.83s user 0.20s system 95% cpu 3.187 total
+ // kbuildsycoca4 --noincremental 2.74s user 0.25s system 93% cpu 3.205 total
+ // unittest: 0.50-60 msec per iteration / 0.40-50 msec per iteration
+
+ // Now that MimeTypes are not parsed anymore:
+ // kbuildsycoca4 --noincremental 2.18s user 0.30s system 91% cpu 2.719 total
+ // kbuildsycoca4 --noincremental 2.07s user 0.34s system 89% cpu 2.681 total
+
+ // If I enabled s_maxItems = 50, it goes down to
+ // but I don't know if that's a good idea.
+ // kbuildsycoca4 --noincremental 1.73s user 0.31s system 85% cpu 2.397 total
+ // kbuildsycoca4 --noincremental 1.84s user 0.29s system 95% cpu 2.230 total
+
+ // try to limit diversity scan by "predicting" positions
+ // with high diversity
+ QVector<int> oldvec(maxLength*2+1);
+ oldvec.fill(0);
+ int mindiv=0;
+ int lastDiv = 0;
+
+ while(true)
+ {
+ int divsum=0,divnum=0;
+
+ int maxDiv = 0;
+ int maxPos = 0;
+ for (int pos = -maxLength; pos <= maxLength; ++pos) {
+ // cut off
+ if (oldvec[pos+maxLength] < mindiv) { oldvec[pos+maxLength]=0; continue; }
+
+ const int diversity = calcDiversity(d->stringlist, pos, sz);
+ if (diversity > maxDiv) {
+ maxDiv = diversity;
+ maxPos = pos;
+ }
+ oldvec[pos + maxLength] = diversity;
+ divsum += diversity;
+ ++divnum;
+ }
+ // arbitrary cut-off value 3/4 of average seems to work
+ if (divnum)
+ mindiv=(3*divsum)/(4*divnum);
+
+ if (maxDiv <= lastDiv)
+ break;
+ //kDebug() << "Max Div=" << maxDiv << "at pos" << maxPos;
+ lastDiv = maxDiv;
+ addDiversity(d->stringlist, maxPos);
+ d->hashList.append(maxPos);
+ }
+
+
+ for(KSycocaDictStringList::Iterator it = d->stringlist->begin(); it != d->stringlist->end(); ++it) {
+ (*it)->hash = d->hashKey((*it)->keyStr);
+ }
+// fprintf(stderr, "Calculating minimum table size..\n");
+
+ d->hashTableSize = sz;
+
+ //kDebug() << "hashTableSize=" << sz << "hashList=" << d->hashList << "oldvec=" << oldvec;
+
+ struct hashtable_entry {
+ string_entry *entry;
+ QList<string_entry*>* duplicates;
+ qint64 duplicate_offset;
+ };
+
+ hashtable_entry *hashTable = new hashtable_entry[ sz ];
+
+ //kDebug(7011) << "Clearing hashtable...";
+ for (unsigned int i=0; i < sz; i++)
+ {
+ hashTable[i].entry = 0;
+ hashTable[i].duplicates = 0;
+ }
+
+ //kDebug(7011) << "Filling hashtable...";
+ for(KSycocaDictStringList::const_iterator it = d->stringlist->constBegin(); it != d->stringlist->constEnd(); ++it)
+ {
+ string_entry* entry = *it;
+ //kDebug(7011) << "entry keyStr=" << entry->keyStr << entry->payload.data() << entry->payload->entryPath();
+ int hash = entry->hash % sz;
+ if (!hashTable[hash].entry)
+ { // First entry
+ hashTable[hash].entry = entry;
+ }
+ else
+ {
+ if (!hashTable[hash].duplicates)
+ { // Second entry, build duplicate list.
+ hashTable[hash].duplicates = new QList<string_entry*>;
+ hashTable[hash].duplicates->append(hashTable[hash].entry);
+ hashTable[hash].duplicate_offset = 0;
+ }
+ hashTable[hash].duplicates->append(entry);
+ }
+ }
+
+ str << d->hashTableSize;
+ str << d->hashList;
+
+ d->offset = str.device()->pos(); // d->offset points to start of hashTable
+ //kDebug(7011) << QString("Start of Hash Table, offset = %1").arg(d->offset,8,16);
+
+ // Write the hashtable + the duplicates twice.
+ // The duplicates are after the normal hashtable, but the offset of each
+ // duplicate entry is written into the normal hashtable.
+ for(int pass = 1; pass <= 2; pass++)
+ {
+ str.device()->seek(d->offset);
+ //kDebug(7011) << QString("Writing hash table (pass #%1)").arg(pass);
+ for(uint i=0; i < d->hashTableSize; i++)
+ {
+ qint32 tmpid;
+ if (!hashTable[i].entry)
+ tmpid = (qint32) 0;
+ else if (!hashTable[i].duplicates)
+ tmpid = (qint32) hashTable[i].entry->payload->offset(); // Positive ID
+ else
+ tmpid = (qint32) -hashTable[i].duplicate_offset; // Negative ID
+ str << tmpid;
+ //kDebug(7011) << QString("Hash table : %1").arg(tmpid,8,16);
+ }
+ //kDebug(7011) << QString("End of Hash Table, offset = %1").arg(str.device()->at(),8,16);
+
+ //kDebug(7011) << QString("Writing duplicate lists (pass #%1)").arg(pass);
+ for(uint i=0; i < d->hashTableSize; i++)
+ {
+ const QList<string_entry*> *dups = hashTable[i].duplicates;
+ if (dups)
+ {
+ hashTable[i].duplicate_offset = str.device()->pos();
+
+ /*kDebug(7011) << QString("Duplicate lists: Offset = %1 list_size = %2") .arg(hashTable[i].duplicate_offset,8,16).arg(dups->count());
+*/
+ for(QList<string_entry*>::ConstIterator dup = dups->begin(); dup != dups->end(); ++dup)
+ {
+ const qint32 offset = (*dup)->payload->offset();
+ if (!offset) {
+ const QString storageId = (*dup)->payload->storageId();
+ kDebug() << "about to assert! dict=" << this << "storageId=" << storageId << (*dup)->payload.data();
+ if ((*dup)->payload->isType(KST_KService)) {
+ KService::Ptr service = KService::Ptr::staticCast((*dup)->payload);
+ kDebug() << service->storageId() << service->entryPath();
+ }
+ // save() must have been called on the entry
+ Q_ASSERT_X( offset, "KSycocaDict::save",
+ QByteArray("entry offset is 0, save() was not called on "
+ + (*dup)->payload->storageId().toLatin1()
+ + " entryPath="
+ + (*dup)->payload->entryPath().toLatin1())
+ );
+ }
+ str << offset ; // Positive ID
+ str << (*dup)->keyStr; // Key (QString)
+ }
+ str << (qint32) 0; // End of list marker (0)
+ }
+ }
+ //kDebug(7011) << QString("End of Dict, offset = %1").arg(str.device()->at(),8,16);
+ }
+
+ //kDebug(7011) << "Cleaning up hash table.";
+ for(uint i=0; i < d->hashTableSize; i++)
+ {
+ delete hashTable[i].duplicates;
+ }
+ delete [] hashTable;
+}
+
+qint32 KSycocaDict::Private::offsetForKey(const QString& key) const
+{
+ if ( !stream || !offset )
+ {
+ kError() << "No ksycoca4 database available!" << endl;
+ return 0;
+ }
+
+ if (hashTableSize == 0)
+ return 0; // Unlikely to find anything :-]
+
+ // Read hash-table data
+ const uint hash = hashKey(key) % hashTableSize;
+ //kDebug(7011) << "hash is" << hash;
+
+ const qint32 off = offset+sizeof(qint32)*hash;
+ //kDebug(7011) << QString("off is %1").arg(off,8,16);
+ stream->device()->seek( off );
+
+ qint32 retOffset;
+ (*stream) >> retOffset;
+ return retOffset;
+}
diff --git a/kdecore/sycoca/ksycocadict_p.h b/kdecore/sycoca/ksycocadict_p.h
new file mode 100644
index 0000000..43b0072
--- /dev/null
+++ b/kdecore/sycoca/ksycocadict_p.h
@@ -0,0 +1,135 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation;
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef KSYCOCADICT_H
+#define KSYCOCADICT_H
+
+#include <kdecore_export.h>
+#include "ksycocaentry.h"
+
+#include <QList>
+
+class QString;
+class QDataStream;
+
+/**
+ * @internal
+ * Hash table implementation for the sycoca database file
+ *
+ * Only exported for the unit test
+ */
+class KDECORE_EXPORT KSycocaDict //krazy:exclude=dpointer (not const because it gets deleted by clear())
+{
+public:
+ /**
+ * Create an empty dict, for building the database
+ */
+ KSycocaDict();
+ /**
+ * Create a dict from an existing database
+ */
+ KSycocaDict(QDataStream *str, int offset);
+
+ ~KSycocaDict();
+
+ /**
+ * Adds a 'payload' to the dictionary with key 'key'.
+ *
+ * 'payload' should have a valid offset by the time
+ * the dictionary gets saved.
+ **/
+ void add(const QString &key, const KSycocaEntry::Ptr& payload);
+
+ /**
+ * Removes the 'payload' from the dictionary with key 'key'.
+ *
+ * Not very fast, use with care O(N)
+ **/
+ void remove(const QString &key);
+
+ /**
+ * Looks up an entry identified by 'key'.
+ *
+ * If 0 is returned, no matching entry exists.
+ * Otherwise, the offset of the entry is returned.
+ *
+ * NOTE: It is not guaranteed that this entry is
+ * indeed the one you were looking for.
+ * After loading the entry you should check that it
+ * indeed matches the search key. If it doesn't
+ * then no matching entry exists.
+ */
+ int find_string(const QString &key ) const;
+
+ /**
+ * Looks up all entries identified by 'key'.
+ * This is useful when the dict is used as a multi-hash.
+ *
+ * If an empty list is returned, no matching entry exists.
+ * Otherwise, the offset of the matching entries are returned.
+ *
+ * NOTE: It is not guaranteed that each entry is
+ * indeed among the ones you were looking for.
+ * After loading each entry you should check that it
+ * indeed matches the search key.
+ */
+ QList<int> findMultiString(const QString &key ) const;
+
+ /**
+ * The number of entries in the dictionary.
+ *
+ * Only valid when building the database.
+ */
+ uint count() const;
+
+ /**
+ * Reset the dictionary.
+ *
+ * Only valid when building the database.
+ */
+ void clear();
+
+ /**
+ * Save the dictionary to the stream
+ * A reasonable fast hash algorithm will be created.
+ *
+ * Typically this will find 90% of the entries directly.
+ * Average hash table size: nrOfItems * 20 bytes.
+ * Average duplicate list size: nrOfItms * avgKeyLength / 5.
+ *
+ * Unknown keys have an average 20% chance to give a false hit.
+ * (That's why your program should check the result)
+ *
+ * Example:
+ * Assume 1000 items with an average key length of 60 bytes.
+ *
+ * Approx. 900 items will hash directly to the right entry.
+ * Approx. 100 items require a lookup in the duplicate list.
+ *
+ * The hash table size will be approx. 20Kb.
+ * The duplicate list size will be approx. 12Kb.
+ **/
+ void save(QDataStream &str);
+
+private:
+ Q_DISABLE_COPY(KSycocaDict)
+ class Private;
+ Private* d;
+};
+
+#endif
diff --git a/kdecore/sycoca/ksycocaentry.cpp b/kdecore/sycoca/ksycocaentry.cpp
new file mode 100644
index 0000000..194f9c1
--- /dev/null
+++ b/kdecore/sycoca/ksycocaentry.cpp
@@ -0,0 +1,173 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation;
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "ksycocaentry.h"
+#include "ksycocaentry_p.h"
+#include <kdebug.h>
+
+#include <ksycoca.h>
+
+KSycocaEntryPrivate::KSycocaEntryPrivate(QDataStream &_str, int iOffset)
+ : offset(iOffset), deleted(false)
+{
+ KSycocaEntry::read( _str, path );
+}
+
+KSycocaEntry::KSycocaEntry()
+ : d_ptr(0)
+{
+}
+
+KSycocaEntry::KSycocaEntry(KSycocaEntryPrivate &d)
+ : d_ptr(&d)
+{
+}
+
+KSycocaEntry::~KSycocaEntry()
+{
+ delete d_ptr;
+}
+
+void KSycocaEntry::read( QDataStream &s, QString &str )
+{
+ quint32 bytes;
+ s >> bytes; // read size of string
+ if ( bytes > 8192 ) { // null string or too big
+ if (bytes != 0xffffffff)
+ KSycoca::flagError();
+ str.clear();
+ }
+ else if ( bytes > 0 ) { // not empty
+ int bt = bytes/2;
+ str.resize( bt );
+ QChar* ch = (QChar *) str.unicode();
+ char t[8192];
+ char *b = t;
+ s.readRawData( b, bytes );
+ while ( bt-- ) {
+ *ch++ = (ushort) (((ushort)b[0])<<8) | (uchar)b[1];
+ b += 2;
+ }
+ } else {
+ str.clear();
+ }
+}
+
+void KSycocaEntry::read( QDataStream &s, QStringList &list )
+{
+ list.clear();
+ quint32 count;
+ s >> count; // read size of list
+ if (count >= 1024)
+ {
+ KSycoca::flagError();
+ return;
+ }
+ for(quint32 i = 0; i < count; i++)
+ {
+ QString str;
+ read(s, str);
+ list.append( str );
+ if (s.atEnd())
+ {
+ KSycoca::flagError();
+ return;
+ }
+ }
+}
+
+bool KSycocaEntry::isType(KSycocaType t) const
+{
+ return d_ptr->isType(t);
+}
+
+KSycocaType KSycocaEntry::sycocaType() const
+{
+ return d_ptr->sycocaType();
+}
+
+QString KSycocaEntry::entryPath() const
+{
+ Q_D(const KSycocaEntry);
+ return d->path;
+}
+
+QString KSycocaEntry::storageId() const
+{
+ Q_D(const KSycocaEntry);
+ return d->storageId();
+}
+
+bool KSycocaEntry::isDeleted() const
+{
+ Q_D(const KSycocaEntry);
+ return d->deleted;
+}
+
+void KSycocaEntry::setDeleted( bool deleted )
+{
+ Q_D(KSycocaEntry);
+ d->deleted = deleted;
+}
+
+bool KSycocaEntry::isSeparator() const
+{
+ return d_ptr == 0 || isType(KST_KServiceSeparator);
+}
+
+int KSycocaEntry::offset() const
+{
+ Q_D(const KSycocaEntry);
+ return d->offset;
+}
+
+void KSycocaEntryPrivate::save(QDataStream &s)
+{
+ offset = s.device()->pos(); // store position in member variable
+ s << qint32(sycocaType()) << path;
+}
+
+void KSycocaEntry::save(QDataStream &s)
+{
+ Q_D(KSycocaEntry);
+ d->save(s);
+}
+
+bool KSycocaEntry::isValid() const
+{
+ Q_D(const KSycocaEntry);
+ return d && d->isValid();
+}
+
+QString KSycocaEntry::name() const
+{
+ Q_D(const KSycocaEntry);
+ return d->name();
+}
+
+QStringList KSycocaEntry::propertyNames() const
+{
+ Q_D(const KSycocaEntry);
+ return d->propertyNames();
+}
+
+QVariant KSycocaEntry::property(const QString &name) const
+{
+ Q_D(const KSycocaEntry);
+ return d->property(name);
+}
diff --git a/kdecore/sycoca/ksycocaentry.h b/kdecore/sycoca/ksycocaentry.h
new file mode 100644
index 0000000..32f587a
--- /dev/null
+++ b/kdecore/sycoca/ksycocaentry.h
@@ -0,0 +1,157 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation;
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef KSYCOCAENTRY_H
+#define KSYCOCAENTRY_H
+
+#include <kglobal.h>
+#include <ksycocatype.h>
+#include <ksharedptr.h>
+
+#include <QtCore/QDataStream>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+
+class KSycocaEntryPrivate;
+
+/**
+ * Base class for all Sycoca entries.
+ *
+ * You can't create an instance of KSycocaEntry, but it provides
+ * the common functionality for servicetypes and services.
+ *
+ * @internal
+ * @see http://techbase.kde.org/Development/Architecture/KDE3/System_Configuration_Cache
+ */
+class KDECORE_EXPORT KSycocaEntry : public KShared
+{
+
+public:
+ /*
+ * constructs a invalid KSycocaEntry object
+ */
+ KSycocaEntry();
+
+ virtual ~KSycocaEntry();
+
+ /**
+ * internal
+ */
+ bool isType(KSycocaType t) const;
+ /**
+ * internal
+ */
+ KSycocaType sycocaType() const;
+
+ typedef KSharedPtr<KSycocaEntry> Ptr;
+ typedef QList<Ptr> List;
+
+ /**
+ * Default constructor
+ */
+// explicit KSycocaEntry(const QString &path);
+
+ /**
+ * Safe demarshalling functions.
+ */
+ static void read( QDataStream &s, QString &str );
+ static void read( QDataStream &s, QStringList &list );
+
+
+ /**
+ * @return the name of this entry
+ */
+ QString name() const;
+
+ /**
+ * @return the path of this entry
+ * The path can be absolute or relative.
+ * The corresponding factory should know relative to what.
+ */
+ QString entryPath() const;
+
+ /**
+ * @return the unique ID for this entry
+ * In practice, this is storageId() for KService and name() for everything else.
+ * \since 4.2.1
+ */
+ QString storageId() const;
+
+ /**
+ * @return true if valid
+ */
+ bool isValid() const;
+
+ /**
+ * @return true if deleted
+ */
+ bool isDeleted() const;
+
+ /**
+ * Returns the requested property. Some often used properties
+ * have convenience access functions like exec(),
+ * serviceTypes etc.
+ *
+ * @param name the name of the property
+ * @return the property, or invalid if not found
+ */
+ QVariant property(const QString &name) const;
+
+ /**
+ * Returns the list of all properties that this service can have.
+ * That means, that some of these properties may be empty.
+ * @return the list of supported properties
+ */
+ QStringList propertyNames() const;
+
+ /**
+ * Sets whether or not this service is deleted
+ */
+ void setDeleted( bool deleted );
+
+
+ /*
+ * @returns true, if this is a separator
+ */
+ bool isSeparator() const;
+
+ /**
+ * @internal
+ * @return the position of the entry in the sycoca file
+ */
+ int offset() const;
+
+ /**
+ * @internal
+ * Save ourselves to the database.
+ */
+ void save(QDataStream &s);
+
+// KSycocaEntry(const KSycocaEntry &copy);
+// KSycocaEntry &operator=(const KSycocaEntry &right);
+protected:
+ KSycocaEntry(KSycocaEntryPrivate &d);
+ KSycocaEntryPrivate *d_ptr;
+
+private:
+ Q_DISABLE_COPY(KSycocaEntry)
+
+ Q_DECLARE_PRIVATE(KSycocaEntry)
+};
+
+#endif
diff --git a/kdecore/sycoca/ksycocaentry_p.h b/kdecore/sycoca/ksycocaentry_p.h
new file mode 100644
index 0000000..496c2cc
--- /dev/null
+++ b/kdecore/sycoca/ksycocaentry_p.h
@@ -0,0 +1,82 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation;
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef KSYCOCAENTRYPRIVATE_H
+#define KSYCOCAENTRYPRIVATE_H
+
+#include "ksycocaentry.h"
+
+#define K_SYCOCATYPE( type, baseclass ) \
+ virtual bool isType(KSycocaType t) const { if (t == type) return true; return baseclass::isType(t);} \
+ virtual KSycocaType sycocaType() const { return type; }
+
+
+class KSycocaEntryPrivate
+{
+public:
+ KSycocaEntryPrivate(const QString &path_)
+ : offset( 0 ),
+ deleted( false ), path(path_)
+ {}
+
+ KSycocaEntryPrivate(QDataStream &_str, int iOffset);
+
+ virtual ~KSycocaEntryPrivate() {}
+
+ // Don't forget to call the parent class
+ // first if you override this function.
+ virtual void save(QDataStream &s);
+
+ virtual bool isType(KSycocaType t) const
+ {
+ return (t == KST_KSycocaEntry);
+ }
+
+ virtual KSycocaType sycocaType() const
+ {
+ return KST_KSycocaEntry;
+ }
+
+ virtual bool isValid() const
+ {
+ return !name().isEmpty();
+ }
+
+ virtual QVariant property(const QString &name) const
+ {
+ Q_UNUSED(name)
+ return QVariant();
+ }
+
+ virtual QStringList propertyNames() const
+ {
+ return QStringList();
+ }
+
+ virtual QString name() const = 0;
+
+ virtual QString storageId() const { return name(); }
+
+ int offset;
+ bool deleted;
+ QString path;
+};
+
+
+
+#endif
diff --git a/kdecore/sycoca/ksycocafactory.cpp b/kdecore/sycoca/ksycocafactory.cpp
new file mode 100644
index 0000000..24ceca5
--- /dev/null
+++ b/kdecore/sycoca/ksycocafactory.cpp
@@ -0,0 +1,248 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 David Faure <faure@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation;
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "ksycocafactory.h"
+#include "ksycoca.h"
+#include "ksycocatype.h"
+#include "ksycocaentry.h"
+#include "ksycocadict_p.h"
+
+#include <config.h>
+#include <kdebug.h>
+
+#include <QThread>
+#include <QtCore/QHash>
+
+class KSycocaFactory::Private
+{
+public:
+ Private() : mOffset(0),
+ m_sycocaDictOffset(0),
+ m_beginEntryOffset(0),
+ m_endEntryOffset(0) {}
+ ~Private()
+ {
+ delete m_sycocaDict;
+ }
+
+ int mOffset;
+ int m_sycocaDictOffset;
+ int m_beginEntryOffset;
+ int m_endEntryOffset;
+ KSycocaDict *m_sycocaDict;
+};
+
+KSycocaFactory::KSycocaFactory(KSycocaFactoryId factory_id)
+ : m_resourceList(0), m_entryDict(0), m_str(0), d(new Private)
+{
+ if (!KSycoca::self()->isBuilding() && (m_str = KSycoca::self()->findFactory(factory_id))) {
+ // Read position of index tables....
+ qint32 i;
+ (*m_str) >> i;
+ d->m_sycocaDictOffset = i;
+ (*m_str) >> i;
+ d->m_beginEntryOffset = i;
+ (*m_str) >> i;
+ d->m_endEntryOffset = i;
+
+ QDataStream* str = stream();
+ int saveOffset = str->device()->pos();
+ // Init index tables
+ d->m_sycocaDict = new KSycocaDict(str, d->m_sycocaDictOffset);
+ saveOffset = str->device()->seek(saveOffset);
+ } else {
+ // We are in kbuildsycoca4 -- build new database!
+ m_entryDict = new KSycocaEntryDict;
+ d->m_sycocaDict = new KSycocaDict;
+ d->m_beginEntryOffset = 0;
+ d->m_endEntryOffset = 0;
+
+ // m_resourceList will be filled in by inherited constructors
+ }
+ KSycoca::self()->addFactory(this);
+}
+
+KSycocaFactory::~KSycocaFactory()
+{
+ delete m_entryDict;
+ delete d;
+}
+
+void
+KSycocaFactory::saveHeader(QDataStream &str)
+{
+ // Write header
+ str.device()->seek(d->mOffset);
+ str << (qint32) d->m_sycocaDictOffset;
+ str << (qint32) d->m_beginEntryOffset;
+ str << (qint32) d->m_endEntryOffset;
+}
+
+void
+KSycocaFactory::save(QDataStream &str)
+{
+ if (!m_entryDict) return; // Error! Function should only be called when
+ // building database
+ if (!d->m_sycocaDict) return; // Error!
+
+ d->mOffset = str.device()->pos(); // store position in member variable
+ d->m_sycocaDictOffset = 0;
+
+ // Write header (pass #1)
+ saveHeader(str);
+
+ d->m_beginEntryOffset = str.device()->pos();
+
+ // Write all entries.
+ int entryCount = 0;
+ for(KSycocaEntryDict::Iterator it = m_entryDict->begin();
+ it != m_entryDict->end(); ++it)
+ {
+ KSycocaEntry::Ptr entry = *it;
+ entry->save(str);
+ entryCount++;
+ }
+
+ d->m_endEntryOffset = str.device()->pos();
+
+ // Write indices...
+ // Linear index
+ str << (qint32) entryCount;
+ for(KSycocaEntryDict::Iterator it = m_entryDict->begin();
+ it != m_entryDict->end(); ++it)
+ {
+ str << qint32(it->data()->offset());
+ }
+
+ // Dictionary index
+ d->m_sycocaDictOffset = str.device()->pos();
+ d->m_sycocaDict->save(str);
+
+ int endOfFactoryData = str.device()->pos();
+
+ // Update header (pass #2)
+ saveHeader(str);
+
+ // Seek to end.
+ str.device()->seek(endOfFactoryData);
+}
+
+void
+KSycocaFactory::addEntry(const KSycocaEntry::Ptr& newEntry)
+{
+ if (!m_entryDict) return; // Error! Function should only be called when
+ // building database
+
+ if (!d->m_sycocaDict) return; // Error!
+
+ KSycocaEntry::Ptr oldEntry = m_entryDict->value(newEntry->storageId());
+ if (oldEntry) {
+ // Already exists -> replace
+ // We found a more-local override, e.g. ~/.local/share/applications/kde4/foo.desktop
+ // So forget about the more global file.
+ //
+ // This can also happen with two .protocol files using the same protocol= entry.
+ // If we didn't remove one here, we would end up asserting because save()
+ // wasn't called on one of the entries.
+ //kDebug(7021) << "removing" << oldEntry.data() << oldEntry->entryPath() << "because of" << newEntry->entryPath() << "they have the same storageId" << newEntry->storageId();
+ removeEntry(newEntry->storageId());
+ }
+
+ const QString name = newEntry->storageId();
+ m_entryDict->insert( name, newEntry );
+ d->m_sycocaDict->add( name, newEntry );
+}
+
+void
+KSycocaFactory::removeEntry(const QString& entryName)
+{
+ if (!m_entryDict) return; // Error! Function should only be called when
+ // building database
+
+ if (!d->m_sycocaDict) return; // Error!
+
+ m_entryDict->remove( entryName );
+ d->m_sycocaDict->remove( entryName ); // O(N)
+}
+
+KSycocaEntry::List KSycocaFactory::allEntries() const
+{
+ KSycocaEntry::List list;
+
+ // Assume we're NOT building a database
+
+ QDataStream* str = stream();
+ if (!str) return list;
+ str->device()->seek(d->m_endEntryOffset);
+ qint32 entryCount;
+ (*str) >> entryCount;
+
+ if (entryCount > 8192)
+ {
+ kDebug(7021) << QThread::currentThread() << "error detected in factory" << this;
+ KSycoca::flagError();
+ return list;
+ }
+
+ // offsetList is needed because createEntry() modifies the stream position
+ qint32 *offsetList = new qint32[entryCount];
+ for(int i = 0; i < entryCount; i++)
+ {
+ (*str) >> offsetList[i];
+ }
+
+ for(int i = 0; i < entryCount; i++)
+ {
+ KSycocaEntry *newEntry = createEntry(offsetList[i]);
+ if (newEntry)
+ {
+ list.append( KSycocaEntry::Ptr( newEntry ) );
+ }
+ }
+ delete [] offsetList;
+ return list;
+}
+
+int KSycocaFactory::offset() const
+{
+ return d->mOffset;
+}
+
+const KSycocaResourceList * KSycocaFactory::resourceList() const
+{
+ return m_resourceList;
+}
+
+const KSycocaDict * KSycocaFactory::sycocaDict() const
+{
+ return d->m_sycocaDict;
+}
+
+bool KSycocaFactory::isEmpty() const
+{
+ return d->m_beginEntryOffset == d->m_endEntryOffset;
+}
+
+QDataStream* KSycocaFactory::stream() const
+{
+ return m_str;
+}
+
+void KSycocaFactory::virtual_hook( int /*id*/, void* /*data*/)
+{ /*BASE::virtual_hook( id, data );*/ }
+
diff --git a/kdecore/sycoca/ksycocafactory.h b/kdecore/sycoca/ksycocafactory.h
new file mode 100644
index 0000000..8ebcf95
--- /dev/null
+++ b/kdecore/sycoca/ksycocafactory.h
@@ -0,0 +1,209 @@
+/* This file is part of the KDE libraries
+ * Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation;
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef KSYCOCAFACTORY_H
+#define KSYCOCAFACTORY_H
+
+#include <ksycocaentry.h>
+
+class QString;
+class KSycocaDict;
+class KSycocaResourceList;
+template <typename T> class QList;
+template <typename KT, typename VT> class QHash;
+
+typedef QHash<QString, KSycocaEntry::Ptr> KSycocaEntryDict;
+
+/**
+ * @internal
+ * Base class for sycoca factories
+ */
+class KDECORE_EXPORT KSycocaFactory
+{
+public:
+ virtual KSycocaFactoryId factoryId() const = 0;
+
+protected: // virtual class
+ /**
+ * Create a factory which can be used to lookup from/create a database
+ * (depending on KSycoca::isBuilding())
+ */
+ explicit KSycocaFactory( KSycocaFactoryId factory_id );
+
+public:
+ virtual ~KSycocaFactory();
+
+ /**
+ * @return the position of the factory in the sycoca file
+ */
+ int offset() const;
+
+ /**
+ * @return the dict, for special use by KBuildSycoca
+ */
+ KSycocaEntryDict * entryDict() { return m_entryDict; }
+
+ /**
+ * Construct an entry from a config file.
+ * To be implemented in the real factories.
+ */
+ virtual KSycocaEntry *createEntry(const QString &file, const char *resource) const = 0;
+
+ /**
+ * Add an entry
+ */
+ virtual void addEntry(const KSycocaEntry::Ptr& newEntry);
+
+ /**
+ * Remove all entries with the given name.
+ * Not very fast (O(N)), use with care.
+ */
+ void removeEntry(const QString& entryName);
+
+ /**
+ * Read an entry from the database
+ */
+ virtual KSycocaEntry *createEntry(int offset) const = 0;
+
+ /**
+ * Get a list of all entries from the database.
+ */
+ virtual KSycocaEntry::List allEntries() const;
+
+ /**
+ * Saves all entries it maintains as well as index files
+ * for these entries to the stream 'str'.
+ *
+ * Also sets mOffset to the starting position.
+ *
+ * The stream is positioned at the end of the last index.
+ *
+ * Don't forget to call the parent first when you override
+ * this function.
+ */
+ virtual void save(QDataStream &str);
+
+ /**
+ * Writes out a header to the stream 'str'.
+ * The baseclass positions the stream correctly.
+ *
+ * Don't forget to call the parent first when you override
+ * this function.
+ */
+ virtual void saveHeader(QDataStream &str);
+
+ /**
+ * @return the resources for which this factory is responsible.
+ * @internal to kbuildsycoca
+ */
+ const KSycocaResourceList * resourceList() const;
+
+ /**
+ * @return the sycoca dict, for factories to find entries by name.
+ */
+ const KSycocaDict *sycocaDict() const;
+
+ /**
+ * @return true if the factory is completely empty - no entries defined
+ */
+ bool isEmpty() const;
+
+protected:
+ QDataStream* stream() const;
+
+ KSycocaResourceList *m_resourceList;
+ KSycocaEntryDict *m_entryDict;
+
+private:
+ QDataStream *m_str;
+ class Private;
+ Private* const d;
+
+protected:
+ /** Virtual hook, used to add new "virtual" functions while maintaining
+ binary compatibility. Unused in this class.
+ */
+ virtual void virtual_hook( int id, void* data );
+};
+
+/**
+ * This, instead of a typedef, allows to declare "class ..." in header files.
+ * @internal
+ */
+class KDECORE_EXPORT KSycocaFactoryList : public QList<KSycocaFactory*> //krazy:exclude=dpointer (acts as a typedef)
+{
+public:
+ KSycocaFactoryList() { }
+};
+
+#include <QThreadStorage>
+/**
+ * Workaround for the lack of QThreadStorage::setAutoDelete(false).
+ * Container for KSycocaFactory that doesn't delete it when it is deleted.
+ */
+template <typename F> class KSycocaFactoryContainer
+{
+public:
+ KSycocaFactoryContainer(F* factory) : m_factory(factory) {}
+ F* factory() { return m_factory; }
+private:
+ F* m_factory;
+};
+
+/**
+ * Template for making it easier to define a threadsafe singleton
+ * for each factory, with support for kbuildsycoca providing a
+ * subclass of the factory.
+ *
+ * @since 4.3
+ * @internal
+ */
+template <typename F> class KSycocaFactorySingleton
+{
+public:
+ typedef KSycocaFactoryContainer<F> C;
+ KSycocaFactorySingleton() {
+ }
+ ~KSycocaFactorySingleton() {
+ // Do not delete the factory here.
+ // All factories are owned by KSycoca, and deleted by it.
+ }
+ void instanceCreated(F* newFactory) {
+ // This can also register a subclass created by kbuildsycoca
+ Q_ASSERT(!m_factories.hasLocalData());
+ Q_ASSERT(newFactory);
+ m_factories.setLocalData(new C(newFactory));
+ }
+ void instanceDestroyed(F* factory) {
+ if (m_factories.hasLocalData()) { // could be false on thread exit
+ Q_ASSERT(m_factories.localData()->factory() == factory); Q_UNUSED(factory)
+ m_factories.setLocalData(0);
+ }
+ }
+ F* self() {
+ if (!m_factories.hasLocalData()) {
+ new F; // calls instanceCreated, which calls setLocalData
+ Q_ASSERT(m_factories.hasLocalData());
+ }
+ return m_factories.localData()->factory();
+ }
+private:
+ QThreadStorage<C*> m_factories;
+};
+
+#endif
diff --git a/kdecore/sycoca/ksycocatype.h b/kdecore/sycoca/ksycocatype.h
new file mode 100644
index 0000000..9f9ab44
--- /dev/null
+++ b/kdecore/sycoca/ksycocatype.h
@@ -0,0 +1,57 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSYCOCATYPE_H
+#define KSYCOCATYPE_H
+
+/**
+ * \relates KSycocaEntry
+ * A KSycocaType is a code (out of the KSycocaType enum) assigned to each
+ * class type derived from KSycocaEntry .
+ * To use it, call the macro K_SYCOCATYPE( your_typecode, parent_class )
+ * at the top of your class definition.
+ */
+enum KSycocaType { KST_KSycocaEntry = 0, KST_KService = 1, KST_KServiceType = 2, KST_KMimeType = 3,
+ KST_KFolderMimeType = 4, KST_KDEDesktopMimeType = 5 /*compat*/, KST_KMimeTypeEntry = 6 /*internal*/,
+ KST_KServiceGroup = 7, KST_KImageIOFormat = 8, KST_KProtocolInfo = 9,
+ KST_KServiceSeparator = 10,
+ KST_KCustom = 1000 };
+
+/**
+ * \relates KSycocaFactory
+ * A KSycocaFactoryId is a code (out of the KSycocaFactoryId enum)
+ * assigned to each class type derived from KSycocaFactory.
+ * To use it, call the macro K_SYCOCAFACTORY( your_factory_id )
+ * at the top of your class definition.
+ */
+enum KSycocaFactoryId { KST_KServiceFactory = 1,
+ KST_KServiceTypeFactory = 2,
+ KST_KServiceGroupFactory = 3,
+ KST_KImageIO = 4, // unused, KDE5: remove
+ KST_KProtocolInfoFactory = 5,
+ KST_KMimeTypeFactory = 6,
+ KST_CTimeInfo = 100 };
+
+#define K_SYCOCAFACTORY( factory_id ) \
+public: \
+ virtual KSycocaFactoryId factoryId() const { return factory_id; } \
+private:
+
+#endif