KIO
kfilemetainfo.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE libraries 00002 00003 Copyright (c) 2001,2002 Carsten Pfeiffer <pfeiffer@kde.org> 00004 2007 Jos van den Oever <jos@vandenoever.info> 00005 2010 Sebastian Trueg <trueg@kde.org> 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Library General Public 00009 License (LGPL) as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 Boston, MA 02110-1301, USA. 00021 */ 00022 00023 #include "kfilemetainfo.h" 00024 #include "kfilemetainfoitem.h" 00025 #include "kfilemetainfoitem_p.h" 00026 #include "kfilewriteplugin.h" 00027 #include "kfilewriteplugin_p.h" 00028 00029 #include <strigi/bufferedstream.h> 00030 #include <strigi/analyzerconfiguration.h> 00031 #include <strigi/indexwriter.h> 00032 #include <strigi/analysisresult.h> 00033 #include <strigi/fieldtypes.h> 00034 00035 #include <kurl.h> 00036 #include <kdebug.h> 00037 00038 #include <QFileInfo> 00039 #include <QDateTime> 00040 #include <QStringList> 00041 00042 class KFileMetaInfoGroupPrivate : public QSharedData { 00043 public: 00044 QString name; 00045 }; 00046 00047 KFileMetaInfoGroup::~KFileMetaInfoGroup() 00048 { 00049 } 00050 00051 KFileMetaInfoGroup::KFileMetaInfoGroup ( KFileMetaInfoGroup const& g ) 00052 { 00053 d = g.d; 00054 } 00055 00056 QDataStream& operator >> ( QDataStream& s, KFileMetaInfo& ) 00057 { 00058 return s; 00059 } 00060 00061 QDataStream& operator << ( QDataStream& s, const KFileMetaInfo& ) 00062 { 00063 return s; 00064 } 00065 00069 class QIODeviceInputStream : public Strigi::BufferedInputStream { 00070 private: 00071 QIODevice& in; 00072 const qint64 m_maxRead; 00073 qint64 m_read; 00074 int32_t fillBuffer ( char* start, int32_t space ); 00075 public: 00076 QIODeviceInputStream ( QIODevice& i, qint64 max ); 00077 }; 00078 00079 int32_t 00080 QIODeviceInputStream::fillBuffer ( char* start, int32_t space ) 00081 { 00082 if ( !in.isOpen() || !in.isReadable() ) 00083 return -1; 00084 00085 // we force a max stream read length according to the config since some Strigi 00086 // plugins simply ignore the value which will lead to frozen client apps 00087 qint64 max = m_maxRead; 00088 if(max < 0) 00089 max = space; 00090 else 00091 max = qMin(qint64(space), qMax(max-m_read,qint64(0))); 00092 00093 // read into the buffer 00094 int32_t nwritten = in.read ( start, max ); 00095 00096 // check the file stream status 00097 if ( nwritten < 0 ) { 00098 m_error = "Could not read from QIODevice."; 00099 in.close(); 00100 return -1; 00101 } 00102 if ( nwritten == 0 || in.atEnd() ) { 00103 in.close(); 00104 } 00105 m_read += nwritten; 00106 return nwritten; 00107 } 00108 00109 QIODeviceInputStream::QIODeviceInputStream ( QIODevice& i, qint64 max ) 00110 : in ( i ), 00111 m_maxRead(max), 00112 m_read(0) 00113 { 00114 // determine if we have a character device, which will likely never eof and thereby 00115 // potentially cause an infinite loop. 00116 if ( i.isSequential() ) { 00117 in.close(); // cause fillBuffer to return -1 00118 } 00119 } 00120 00125 class KMetaInfoWriter : public Strigi::IndexWriter { 00126 public: 00127 // irrelevant for KFileMetaInfo 00128 void startAnalysis(const Strigi::AnalysisResult*) { 00129 } 00130 00131 // irrelevant for KFileMetaInfo 00132 // we do not store text as metainfo 00133 void addText(const Strigi::AnalysisResult*, const char* /*s*/, int32_t /*n*/) { 00134 } 00135 void addValue(const Strigi::AnalysisResult* idx, const Strigi::RegisteredField* field, 00136 const std::string& value) { 00137 if (idx->writerData()) { 00138 QString val = QString::fromUtf8(value.c_str(), value.size()); 00139 if( !val.startsWith(':') ) 00140 addValue(idx, field, val); 00141 } 00142 } 00143 void addValue(const Strigi::AnalysisResult* idx, const Strigi::RegisteredField* field, 00144 const unsigned char* data, uint32_t size) { 00145 if (idx->writerData()) { 00146 QByteArray d((const char*)data, size); 00147 addValue(idx, field, QVariant(d)); 00148 } 00149 } 00150 void addValue(const Strigi::AnalysisResult* idx, const Strigi::RegisteredField* field, 00151 uint32_t value) { 00152 if (idx->writerData()) { 00153 addValue(idx, field, QVariant((quint32)value)); 00154 } 00155 } 00156 void addValue(const Strigi::AnalysisResult* idx, const Strigi::RegisteredField* field, 00157 int32_t value) { 00158 if (idx->writerData()) { 00159 addValue(idx, field, QVariant((qint32)value)); 00160 } 00161 } 00162 void addValue(const Strigi::AnalysisResult* idx, const Strigi::RegisteredField* field, 00163 double value) { 00164 if (idx->writerData()) { 00165 addValue(idx, field, QVariant(value)); 00166 } 00167 } 00168 void addValue(const Strigi::AnalysisResult* idx, 00169 const Strigi::RegisteredField* field, const QVariant& value) { 00170 QHash<QString, KFileMetaInfoItem>* info 00171 = static_cast<QHash<QString, KFileMetaInfoItem>*>( 00172 idx->writerData()); 00173 if (info) { 00174 std::string name(field->key()); 00175 QString key = QString::fromUtf8(name.c_str(), name.size()); 00176 QHash<QString, KFileMetaInfoItem>::iterator i = info->find(key); 00177 if (i == info->end()) { 00178 info->insert(key, KFileMetaInfoItem(key, value, 0, true)); 00179 } else { 00180 i.value().addValue(value); 00181 } 00182 } 00183 } 00184 void addValue(const Strigi::AnalysisResult* ar, 00185 const Strigi::RegisteredField* field, const std::string& name, 00186 const std::string& value) { 00187 if (ar->writerData()) { 00188 QVariantMap m; 00189 m.insert ( name.c_str(), value.c_str() ); 00190 addValue ( ar, field, m ); 00191 } 00192 } 00193 00194 /* irrelevant for KFileMetaInfo: These triples does not convey information 00195 * about this file, so we ignore it 00196 */ 00197 void addTriplet ( const std::string& /*subject*/, 00198 const std::string& /*predicate*/, const std::string& /*object*/ ) { 00199 } 00200 00201 // irrelevant for KFileMetaInfo 00202 void finishAnalysis(const Strigi::AnalysisResult*) {} 00203 // irrelevant for KFileMetaInfo 00204 void deleteEntries(const std::vector<std::string>&) {} 00205 // irrelevant for KFileMetaInfo 00206 void deleteAllEntries() {} 00207 }; 00208 00209 00210 class KFileMetaInfoPrivate : public QSharedData 00211 { 00212 public: 00213 QHash<QString, KFileMetaInfoItem> items; 00214 KUrl m_url; 00215 00216 void init ( QIODevice& stream, const KUrl& url, time_t mtime, KFileMetaInfo::WhatFlags w = KFileMetaInfo::Everything ); 00217 void initWriters ( const KUrl& /*file*/ ); 00218 void operator= ( const KFileMetaInfoPrivate& k ) { 00219 items = k.items; 00220 } 00221 }; 00222 static const KFileMetaInfoItem nullitem; 00223 00224 class KFileMetaInfoAnalysisConfiguration : public Strigi::AnalyzerConfiguration 00225 { 00226 public: 00227 KFileMetaInfoAnalysisConfiguration( KFileMetaInfo::WhatFlags indexDetail ) 00228 : m_indexDetail(indexDetail) { 00229 } 00230 00231 int64_t maximalStreamReadLength ( const Strigi::AnalysisResult& ar ) { 00232 if(ar.depth() > 0) 00233 return 0; // ignore all data that has a depth > 0, i.e. files in archives 00234 else if(m_indexDetail == KFileMetaInfo::Everything) 00235 return -1; 00236 else 00237 return 65536; // do not read the whole file - this is used for on-the-fly analysis 00238 } 00239 00240 private: 00241 KFileMetaInfo::WhatFlags m_indexDetail; 00242 }; 00243 00244 void KFileMetaInfoPrivate::init ( QIODevice& stream, const KUrl& url, time_t mtime, KFileMetaInfo::WhatFlags w ) 00245 { 00246 m_url = url; 00247 00248 // get data from Strigi 00249 KFileMetaInfoAnalysisConfiguration c( w ); 00250 Strigi::StreamAnalyzer indexer ( c ); 00251 KMetaInfoWriter writer; 00252 kDebug ( 7033 ) << url; 00253 Strigi::AnalysisResult idx ( url.toLocalFile().toUtf8().constData(), mtime, writer, indexer ); 00254 idx.setWriterData ( &items ); 00255 00256 QIODeviceInputStream strigiStream ( stream, c.maximalStreamReadLength(idx) ); 00257 indexer.analyze ( idx, &strigiStream ); 00258 00259 // TODO: get data from Nepomuk 00260 } 00261 00262 void KFileMetaInfoPrivate::initWriters ( const KUrl& file ) 00263 { 00264 QStringList mimetypes; 00265 QHash<QString, KFileMetaInfoItem>::iterator i; 00266 for ( i = items.begin(); i != items.end(); ++i ) { 00267 KFileWritePlugin *w = 00268 KFileWriterProvider::self()->loadPlugin ( i.key() ); 00269 if ( w && w->canWrite ( file, i.key() ) ) { 00270 i.value().d->writer = w; 00271 } 00272 } 00273 } 00274 00275 KFileMetaInfo::KFileMetaInfo ( const QString& path, const QString& /*mimetype*/, 00276 KFileMetaInfo::WhatFlags w ) 00277 : d ( new KFileMetaInfoPrivate() ) 00278 { 00279 QFileInfo fileinfo ( path ); 00280 QFile file ( path ); 00281 // only open the file if it is a filetype Qt understands 00282 // if e.g. the path points to a pipe, it is not opened 00283 if ( ( fileinfo.isFile() || fileinfo.isDir() || fileinfo.isSymLink() ) 00284 && file.open ( QIODevice::ReadOnly ) ) { 00285 KUrl u ( path ); 00286 d->init ( file, u, fileinfo.lastModified().toTime_t(), w ); 00287 if ( fileinfo.isWritable() ) { 00288 d->initWriters ( u ); 00289 } 00290 } 00291 } 00292 00293 KFileMetaInfo::KFileMetaInfo ( const KUrl& url ) 00294 : d ( new KFileMetaInfoPrivate() ) 00295 { 00296 QFileInfo fileinfo ( url.toLocalFile() ); 00297 QFile file ( url.toLocalFile() ); 00298 if ( file.open ( QIODevice::ReadOnly ) ) { 00299 d->init ( file, url, fileinfo.lastModified().toTime_t() ); 00300 if ( fileinfo.isWritable() ) { 00301 d->initWriters ( url ); 00302 } 00303 } 00304 } 00305 00306 KFileMetaInfo::KFileMetaInfo() : d ( new KFileMetaInfoPrivate() ) 00307 { 00308 } 00309 00310 KFileMetaInfo::KFileMetaInfo ( const KFileMetaInfo& k ) : d ( k.d ) 00311 { 00312 } 00313 00314 const KFileMetaInfo& KFileMetaInfo::operator= ( KFileMetaInfo const & kfmi ) 00315 { 00316 d = kfmi.d; 00317 return kfmi; 00318 } 00319 00320 KFileMetaInfo::~KFileMetaInfo() 00321 { 00322 } 00323 00324 bool KFileMetaInfo::applyChanges() 00325 { 00326 // go through all editable fields and group them by writer 00327 QHash<KFileWritePlugin*, QVariantMap> data; 00328 QHash<QString, KFileMetaInfoItem>::const_iterator i; 00329 for ( i = d->items.constBegin(); i != d->items.constEnd(); ++i ) { 00330 if ( i.value().isModified() && i.value().d->writer ) { 00331 data[i.value().d->writer][i.key() ] = i.value().value(); 00332 } 00333 } 00334 00335 // call the writers on the data they can write 00336 bool ok = true; 00337 QHash<KFileWritePlugin*, QVariantMap>::const_iterator j; 00338 for ( j = data.constBegin(); j != data.constEnd(); ++j ) { 00339 ok &= j.key()->write ( d->m_url, j.value() ); 00340 } 00341 return ok; 00342 } 00343 00344 const KUrl& KFileMetaInfo::url() const 00345 { 00346 return d->m_url; 00347 } 00348 00349 const QHash<QString, KFileMetaInfoItem>& KFileMetaInfo::items() const 00350 { 00351 return d->items; 00352 } 00353 00354 const KFileMetaInfoItem& KFileMetaInfo::item ( const QString& key ) const 00355 { 00356 QHash<QString, KFileMetaInfoItem>::const_iterator i = d->items.constFind ( key ); 00357 return ( i == d->items.constEnd() ) ? nullitem : i.value(); 00358 } 00359 00360 QStringList KFileMetaInfo::keys() const 00361 { 00362 return d->items.keys(); 00363 } 00364 00365 KFileMetaInfoItem& KFileMetaInfo::item ( const QString& key ) 00366 { 00367 return d->items[key]; 00368 } 00369 00370 bool KFileMetaInfo::isValid() const 00371 { 00372 return !d->m_url.isEmpty(); 00373 } 00374 00375 QStringList KFileMetaInfo::preferredKeys() const 00376 { 00377 return QStringList(); 00378 } 00379 00380 QStringList KFileMetaInfo::supportedKeys() const 00381 { 00382 return QStringList(); 00383 } 00384 00385 #ifndef KDE_NO_DEPRECATED 00386 KFileMetaInfoGroupList KFileMetaInfo::preferredGroups() const 00387 { 00388 return KFileMetaInfoGroupList(); 00389 } 00390 #endif 00391 00392 #ifndef KDE_NO_DEPRECATED 00393 KFileMetaInfoGroupList KFileMetaInfo::supportedGroups() const 00394 { 00395 return KFileMetaInfoGroupList(); 00396 } 00397 #endif 00398 00399 KFileMetaInfoItemList KFileMetaInfoGroup::items() const 00400 { 00401 return KFileMetaInfoItemList(); 00402 } 00403 00404 const QString& KFileMetaInfoGroup::name() const 00405 { 00406 return d->name; 00407 }
KDE 4.6 API Reference