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 #ifndef KIO_NO_STRIGI 00030 #include <strigi/bufferedstream.h> 00031 #include <strigi/analyzerconfiguration.h> 00032 #include <strigi/indexwriter.h> 00033 #include <strigi/analysisresult.h> 00034 #include <strigi/fieldtypes.h> 00035 #endif 00036 00037 #include <kurl.h> 00038 #include <kdebug.h> 00039 00040 #include <QFileInfo> 00041 #include <QDateTime> 00042 #include <QStringList> 00043 00044 class KFileMetaInfoGroupPrivate : public QSharedData { 00045 public: 00046 QString name; 00047 }; 00048 00049 KFileMetaInfoGroup::~KFileMetaInfoGroup() 00050 { 00051 } 00052 00053 KFileMetaInfoGroup::KFileMetaInfoGroup ( KFileMetaInfoGroup const& g ) 00054 { 00055 d = g.d; 00056 } 00057 00058 QDataStream& operator >> ( QDataStream& s, KFileMetaInfo& ) 00059 { 00060 return s; 00061 } 00062 00063 QDataStream& operator << ( QDataStream& s, const KFileMetaInfo& ) 00064 { 00065 return s; 00066 } 00067 #ifndef KIO_NO_STRIGI 00068 00071 class QIODeviceInputStream : public Strigi::BufferedInputStream { 00072 private: 00073 QIODevice& in; 00074 const qint64 m_maxRead; 00075 qint64 m_read; 00076 int32_t fillBuffer ( char* start, int32_t space ); 00077 public: 00078 QIODeviceInputStream ( QIODevice& i, qint64 max ); 00079 }; 00080 00081 int32_t 00082 QIODeviceInputStream::fillBuffer ( char* start, int32_t space ) 00083 { 00084 if ( !in.isOpen() || !in.isReadable() ) 00085 return -1; 00086 00087 // we force a max stream read length according to the config since some Strigi 00088 // plugins simply ignore the value which will lead to frozen client apps 00089 qint64 max = m_maxRead; 00090 if(max < 0) 00091 max = space; 00092 else 00093 max = qMin(qint64(space), qMax(max-m_read,qint64(0))); 00094 00095 // read into the buffer 00096 int32_t nwritten = in.read ( start, max ); 00097 00098 // check the file stream status 00099 if ( nwritten < 0 ) { 00100 m_error = "Could not read from QIODevice."; 00101 in.close(); 00102 return -1; 00103 } 00104 if ( nwritten == 0 || in.atEnd() ) { 00105 in.close(); 00106 } 00107 m_read += nwritten; 00108 return nwritten; 00109 } 00110 00111 QIODeviceInputStream::QIODeviceInputStream ( QIODevice& i, qint64 max ) 00112 : in ( i ), 00113 m_maxRead(max), 00114 m_read(0) 00115 { 00116 // determine if we have a character device, which will likely never eof and thereby 00117 // potentially cause an infinite loop. 00118 if ( i.isSequential() ) { 00119 in.close(); // cause fillBuffer to return -1 00120 } 00121 } 00122 00127 class KMetaInfoWriter : public Strigi::IndexWriter { 00128 public: 00129 // irrelevant for KFileMetaInfo 00130 void startAnalysis(const Strigi::AnalysisResult*) { 00131 } 00132 00133 // irrelevant for KFileMetaInfo 00134 // we do not store text as metainfo 00135 void addText(const Strigi::AnalysisResult*, const char* /*s*/, int32_t /*n*/) { 00136 } 00137 void addValue(const Strigi::AnalysisResult* idx, const Strigi::RegisteredField* field, 00138 const std::string& value) { 00139 if (idx->writerData()) { 00140 QString val = QString::fromUtf8(value.c_str(), value.size()); 00141 if( !val.startsWith(':') ) 00142 addValue(idx, field, val); 00143 } 00144 } 00145 void addValue(const Strigi::AnalysisResult* idx, const Strigi::RegisteredField* field, 00146 const unsigned char* data, uint32_t size) { 00147 if (idx->writerData()) { 00148 QByteArray d((const char*)data, size); 00149 addValue(idx, field, QVariant(d)); 00150 } 00151 } 00152 void addValue(const Strigi::AnalysisResult* idx, const Strigi::RegisteredField* field, 00153 uint32_t value) { 00154 if (idx->writerData()) { 00155 addValue(idx, field, QVariant((quint32)value)); 00156 } 00157 } 00158 void addValue(const Strigi::AnalysisResult* idx, const Strigi::RegisteredField* field, 00159 int32_t value) { 00160 if (idx->writerData()) { 00161 addValue(idx, field, QVariant((qint32)value)); 00162 } 00163 } 00164 void addValue(const Strigi::AnalysisResult* idx, const Strigi::RegisteredField* field, 00165 double value) { 00166 if (idx->writerData()) { 00167 addValue(idx, field, QVariant(value)); 00168 } 00169 } 00170 void addValue(const Strigi::AnalysisResult* idx, 00171 const Strigi::RegisteredField* field, const QVariant& value) { 00172 QHash<QString, KFileMetaInfoItem>* info 00173 = static_cast<QHash<QString, KFileMetaInfoItem>*>( 00174 idx->writerData()); 00175 if (info) { 00176 std::string name(field->key()); 00177 QString key = QString::fromUtf8(name.c_str(), name.size()); 00178 QHash<QString, KFileMetaInfoItem>::iterator i = info->find(key); 00179 if (i == info->end()) { 00180 info->insert(key, KFileMetaInfoItem(key, value, 0, true)); 00181 } else { 00182 i.value().addValue(value); 00183 } 00184 } 00185 } 00186 void addValue(const Strigi::AnalysisResult* ar, 00187 const Strigi::RegisteredField* field, const std::string& name, 00188 const std::string& value) { 00189 if (ar->writerData()) { 00190 QVariantMap m; 00191 m.insert ( name.c_str(), value.c_str() ); 00192 addValue ( ar, field, m ); 00193 } 00194 } 00195 00196 /* irrelevant for KFileMetaInfo: These triples does not convey information 00197 * about this file, so we ignore it 00198 */ 00199 void addTriplet ( const std::string& /*subject*/, 00200 const std::string& /*predicate*/, const std::string& /*object*/ ) { 00201 } 00202 00203 // irrelevant for KFileMetaInfo 00204 void finishAnalysis(const Strigi::AnalysisResult*) {} 00205 // irrelevant for KFileMetaInfo 00206 void deleteEntries(const std::vector<std::string>&) {} 00207 // irrelevant for KFileMetaInfo 00208 void deleteAllEntries() {} 00209 }; 00210 00211 00212 class KFileMetaInfoPrivate : public QSharedData 00213 { 00214 public: 00215 QHash<QString, KFileMetaInfoItem> items; 00216 KUrl m_url; 00217 00218 void init ( QIODevice& stream, const KUrl& url, time_t mtime, KFileMetaInfo::WhatFlags w = KFileMetaInfo::Everything ); 00219 void initWriters ( const KUrl& /*file*/ ); 00220 void operator= ( const KFileMetaInfoPrivate& k ) { 00221 items = k.items; 00222 } 00223 }; 00224 static const KFileMetaInfoItem nullitem; 00225 00226 class KFileMetaInfoAnalysisConfiguration : public Strigi::AnalyzerConfiguration 00227 { 00228 public: 00229 KFileMetaInfoAnalysisConfiguration( KFileMetaInfo::WhatFlags indexDetail ) 00230 : m_indexDetail(indexDetail) { 00231 } 00232 00233 int64_t maximalStreamReadLength ( const Strigi::AnalysisResult& ar ) { 00234 if(ar.depth() > 0) 00235 return 0; // ignore all data that has a depth > 0, i.e. files in archives 00236 else if(m_indexDetail == KFileMetaInfo::Everything) 00237 return -1; 00238 else 00239 return 65536; // do not read the whole file - this is used for on-the-fly analysis 00240 } 00241 00242 private: 00243 KFileMetaInfo::WhatFlags m_indexDetail; 00244 }; 00245 00246 void KFileMetaInfoPrivate::init ( QIODevice& stream, const KUrl& url, time_t mtime, KFileMetaInfo::WhatFlags w ) 00247 { 00248 m_url = url; 00249 00250 // get data from Strigi 00251 KFileMetaInfoAnalysisConfiguration c( w ); 00252 Strigi::StreamAnalyzer indexer ( c ); 00253 KMetaInfoWriter writer; 00254 kDebug ( 7033 ) << url; 00255 Strigi::AnalysisResult idx ( url.toLocalFile().toUtf8().constData(), mtime, writer, indexer ); 00256 idx.setWriterData ( &items ); 00257 00258 QIODeviceInputStream strigiStream ( stream, c.maximalStreamReadLength(idx) ); 00259 indexer.analyze ( idx, &strigiStream ); 00260 00261 // TODO: get data from Nepomuk 00262 } 00263 00264 void KFileMetaInfoPrivate::initWriters ( const KUrl& file ) 00265 { 00266 QStringList mimetypes; 00267 QHash<QString, KFileMetaInfoItem>::iterator i; 00268 for ( i = items.begin(); i != items.end(); ++i ) { 00269 KFileWritePlugin *w = 00270 KFileWriterProvider::self()->loadPlugin ( i.key() ); 00271 if ( w && w->canWrite ( file, i.key() ) ) { 00272 i.value().d->writer = w; 00273 } 00274 } 00275 } 00276 00277 KFileMetaInfo::KFileMetaInfo ( const QString& path, const QString& /*mimetype*/, 00278 KFileMetaInfo::WhatFlags w ) 00279 : d ( new KFileMetaInfoPrivate() ) 00280 { 00281 QFileInfo fileinfo ( path ); 00282 QFile file ( path ); 00283 // only open the file if it is a filetype Qt understands 00284 // if e.g. the path points to a pipe, it is not opened 00285 if ( ( fileinfo.isFile() || fileinfo.isDir() || fileinfo.isSymLink() ) 00286 && file.open ( QIODevice::ReadOnly ) ) { 00287 KUrl u ( path ); 00288 d->init ( file, u, fileinfo.lastModified().toTime_t(), w ); 00289 if ( fileinfo.isWritable() ) { 00290 d->initWriters ( u ); 00291 } 00292 } 00293 } 00294 00295 KFileMetaInfo::KFileMetaInfo ( const KUrl& url ) 00296 : d ( new KFileMetaInfoPrivate() ) 00297 { 00298 QFileInfo fileinfo ( url.toLocalFile() ); 00299 QFile file ( url.toLocalFile() ); 00300 if ( file.open ( QIODevice::ReadOnly ) ) { 00301 d->init ( file, url, fileinfo.lastModified().toTime_t() ); 00302 if ( fileinfo.isWritable() ) { 00303 d->initWriters ( url ); 00304 } 00305 } 00306 } 00307 00308 KFileMetaInfo::KFileMetaInfo() : d ( new KFileMetaInfoPrivate() ) 00309 { 00310 } 00311 00312 KFileMetaInfo::KFileMetaInfo ( const KFileMetaInfo& k ) : d ( k.d ) 00313 { 00314 } 00315 00316 const KFileMetaInfo& KFileMetaInfo::operator= ( KFileMetaInfo const & kfmi ) 00317 { 00318 d = kfmi.d; 00319 return kfmi; 00320 } 00321 00322 KFileMetaInfo::~KFileMetaInfo() 00323 { 00324 } 00325 00326 bool KFileMetaInfo::applyChanges() 00327 { 00328 // go through all editable fields and group them by writer 00329 QHash<KFileWritePlugin*, QVariantMap> data; 00330 QHash<QString, KFileMetaInfoItem>::const_iterator i; 00331 for ( i = d->items.constBegin(); i != d->items.constEnd(); ++i ) { 00332 if ( i.value().isModified() && i.value().d->writer ) { 00333 data[i.value().d->writer][i.key() ] = i.value().value(); 00334 } 00335 } 00336 00337 // call the writers on the data they can write 00338 bool ok = true; 00339 QHash<KFileWritePlugin*, QVariantMap>::const_iterator j; 00340 for ( j = data.constBegin(); j != data.constEnd(); ++j ) { 00341 ok &= j.key()->write ( d->m_url, j.value() ); 00342 } 00343 return ok; 00344 } 00345 00346 const KUrl& KFileMetaInfo::url() const 00347 { 00348 return d->m_url; 00349 } 00350 00351 const QHash<QString, KFileMetaInfoItem>& KFileMetaInfo::items() const 00352 { 00353 return d->items; 00354 } 00355 00356 const KFileMetaInfoItem& KFileMetaInfo::item ( const QString& key ) const 00357 { 00358 QHash<QString, KFileMetaInfoItem>::const_iterator i = d->items.constFind ( key ); 00359 return ( i == d->items.constEnd() ) ? nullitem : i.value(); 00360 } 00361 00362 QStringList KFileMetaInfo::keys() const 00363 { 00364 return d->items.keys(); 00365 } 00366 00367 KFileMetaInfoItem& KFileMetaInfo::item ( const QString& key ) 00368 { 00369 return d->items[key]; 00370 } 00371 00372 bool KFileMetaInfo::isValid() const 00373 { 00374 return !d->m_url.isEmpty(); 00375 } 00376 00377 QStringList KFileMetaInfo::preferredKeys() const 00378 { 00379 return QStringList(); 00380 } 00381 00382 QStringList KFileMetaInfo::supportedKeys() const 00383 { 00384 return QStringList(); 00385 } 00386 00387 #ifndef KDE_NO_DEPRECATED 00388 KFileMetaInfoGroupList KFileMetaInfo::preferredGroups() const 00389 { 00390 return KFileMetaInfoGroupList(); 00391 } 00392 #endif 00393 00394 #ifndef KDE_NO_DEPRECATED 00395 KFileMetaInfoGroupList KFileMetaInfo::supportedGroups() const 00396 { 00397 return KFileMetaInfoGroupList(); 00398 } 00399 #endif 00400 #else //KIO_NO_STRIGI 00401 00402 class KFileMetaInfoPrivate : public QSharedData 00403 { 00404 public: 00405 }; 00406 00407 KFileMetaInfo::KFileMetaInfo ( const QString& path, const QString& /*mimetype*/, 00408 KFileMetaInfo::WhatFlags w ) 00409 { 00410 } 00411 00412 KFileMetaInfo::KFileMetaInfo ( const KUrl& url ) 00413 { 00414 } 00415 00416 KFileMetaInfo::KFileMetaInfo() 00417 { 00418 } 00419 00420 KFileMetaInfo::KFileMetaInfo ( const KFileMetaInfo& k ) 00421 { 00422 } 00423 00424 const KFileMetaInfo& KFileMetaInfo::operator= ( KFileMetaInfo const & kfmi ) 00425 { 00426 return kfmi; 00427 } 00428 00429 KFileMetaInfo::~KFileMetaInfo() 00430 { 00431 } 00432 00433 bool KFileMetaInfo::applyChanges() 00434 { 00435 return false; 00436 } 00437 00438 const KUrl& KFileMetaInfo::url() const 00439 { 00440 static const KUrl item; 00441 return item; 00442 } 00443 00444 const QHash<QString, KFileMetaInfoItem>& KFileMetaInfo::items() const 00445 { 00446 static const QHash<QString, KFileMetaInfoItem> items; 00447 return items; 00448 } 00449 00450 const KFileMetaInfoItem& KFileMetaInfo::item ( const QString& key ) const 00451 { 00452 static const KFileMetaInfoItem item; 00453 return item; 00454 } 00455 00456 QStringList KFileMetaInfo::keys() const 00457 { 00458 return QStringList(); 00459 } 00460 00461 KFileMetaInfoItem& KFileMetaInfo::item ( const QString& key ) 00462 { 00463 static KFileMetaInfoItem item; 00464 return item; 00465 } 00466 00467 bool KFileMetaInfo::isValid() const 00468 { 00469 return false; 00470 } 00471 00472 QStringList KFileMetaInfo::preferredKeys() const 00473 { 00474 return QStringList(); 00475 } 00476 00477 QStringList KFileMetaInfo::supportedKeys() const 00478 { 00479 return QStringList(); 00480 } 00481 #endif 00482 00483 KFileMetaInfoItemList KFileMetaInfoGroup::items() const 00484 { 00485 return KFileMetaInfoItemList(); 00486 } 00487 00488 const QString& KFileMetaInfoGroup::name() const 00489 { 00490 return d->name; 00491 }
KDE 4.7 API Reference