KDECore
kmemfile.cpp
Go to the documentation of this file.
00001 /* 00002 This file is part of the KDE libraries 00003 Copyright (C) 2008 Christian Ehrlicher <ch.ehrlicher@gmx.de> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "kmemfile.h" 00022 00023 #ifndef QT_NO_SHAREDMEMORY 00024 00025 #include <QtCore/QSharedMemory> 00026 #include <QtCore/QCryptographicHash> 00027 #include <QtCore/QFile> 00028 #include <QtCore/QDir> 00029 00030 #include "klocalizedstring.h" 00031 00032 class KMemFile::Private 00033 { 00034 public: 00035 struct sharedInfoData { 00036 int shmCounter; 00037 qint64 shmDataSize; 00038 00039 sharedInfoData() { 00040 memset ( this, 0, sizeof ( this ) ); 00041 } 00042 }; 00043 Private ( KMemFile *_parent ) : readWritePos ( 0 ), shmDataSize ( 0 ), parent ( _parent ) {} 00044 00045 QString getShmKey ( int iCounter = -1 ); 00046 static QString getShmKey ( const QString &filename, int iCounter = -1 ); 00047 bool loadContentsFromFile(); 00048 void close(); 00049 00050 QString filename; 00051 QSharedMemory shmInfo; 00052 QSharedMemory shmData; 00053 qint64 readWritePos; 00054 qint64 shmDataSize; 00055 00056 KMemFile *parent; 00057 }; 00058 00059 QString KMemFile::Private::getShmKey ( int iCounter ) 00060 { 00061 return getShmKey ( filename, iCounter ); 00062 } 00063 00064 QString KMemFile::Private::getShmKey ( const QString &filename, int iCounter ) 00065 { 00066 QByteArray tmp = QString ( QDir ( filename ).canonicalPath() + QString::number ( iCounter ) ).toUtf8(); 00067 return QString::fromAscii ( QCryptographicHash::hash ( tmp, QCryptographicHash::Sha1 ) ); 00068 } 00069 00070 bool KMemFile::Private::loadContentsFromFile() 00071 { 00072 QFile f ( filename ); 00073 if ( !f.exists() ) { 00074 close(); 00075 parent->setErrorString ( i18n ( "File %1 does not exist" , filename ) ); 00076 return false; 00077 } 00078 if ( !f.open ( QIODevice::ReadOnly ) ) { 00079 close(); 00080 parent->setErrorString ( i18n ( "Cannot open %1 for reading" , filename ) ); 00081 return false; 00082 } 00083 00084 sharedInfoData *infoPtr = static_cast<sharedInfoData*> ( shmInfo.data() ); 00085 00086 infoPtr->shmDataSize = f.size(); 00087 shmData.setKey ( getShmKey ( infoPtr->shmCounter ) ); 00088 if ( !shmData.create ( infoPtr->shmDataSize ) ) { 00089 close(); 00090 parent->setErrorString ( i18n ( "Cannot create memory segment for file %1" , filename ) ); 00091 return false; 00092 } 00093 shmData.lock(); 00094 qint64 size = 0; 00095 qint64 bytesRead; 00096 char *data = static_cast<char*> ( shmData.data() ); 00097 bytesRead = f.read ( data, infoPtr->shmDataSize ); 00098 if ( bytesRead != infoPtr->shmDataSize ) { 00099 close(); 00100 parent->setErrorString ( i18n ( "Could not read data from %1 into shm" , filename ) ); 00101 return false; 00102 } 00103 shmDataSize = size; 00104 shmData.unlock(); 00105 return true; 00106 } 00107 00108 void KMemFile::Private::close() 00109 { 00110 shmData.unlock(); 00111 shmData.detach(); 00112 shmInfo.unlock(); 00113 shmInfo.detach(); 00114 readWritePos = 0; 00115 shmDataSize = 0; 00116 } 00117 00118 KMemFile::KMemFile ( const QString &filename, QObject *parent ) 00119 : QIODevice ( parent ), d ( new Private ( this ) ) 00120 { 00121 d->filename = filename; 00122 } 00123 00124 KMemFile::~KMemFile() 00125 { 00126 close(); 00127 delete d; 00128 } 00129 00130 void KMemFile::close () 00131 { 00132 QIODevice::close(); 00133 if ( !isOpen() ) 00134 return; 00135 d->close(); 00136 } 00137 00138 bool KMemFile::isSequential () const 00139 { 00140 return false; 00141 } 00142 00143 bool KMemFile::open ( OpenMode mode ) 00144 { 00145 if ( isOpen() ) { 00146 QIODevice::open ( mode ); 00147 return false; 00148 } 00149 00150 if ( mode != QIODevice::ReadOnly ) { 00151 setErrorString ( i18n ( "Only 'ReadOnly' allowed" ) ); 00152 return false; 00153 } 00154 00155 if ( !QFile::exists ( d->filename ) ) { 00156 setErrorString ( i18n ( "File %1 does not exist" , d->filename ) ); 00157 return false; 00158 } 00159 00160 QSharedMemory lock ( QDir ( d->filename ).canonicalPath() ); 00161 lock.lock(); 00162 00163 Private::sharedInfoData *infoPtr; 00164 d->shmInfo.setKey ( d->getShmKey() ); 00165 // see if it's already in memory 00166 if ( !d->shmInfo.attach ( QSharedMemory::ReadWrite ) ) { 00167 if ( !d->shmInfo.create ( sizeof ( Private::sharedInfoData ) ) ) { 00168 lock.unlock(); 00169 setErrorString ( i18n ( "Cannot create memory segment for file %1" , d->filename ) ); 00170 return false; 00171 } 00172 d->shmInfo.lock(); 00173 // no -> create it 00174 infoPtr = static_cast<Private::sharedInfoData*> ( d->shmInfo.data() ); 00175 memset ( infoPtr, 0, sizeof ( Private::sharedInfoData ) ); 00176 infoPtr->shmCounter = 1; 00177 if ( !d->loadContentsFromFile() ) { 00178 d->shmInfo.unlock(); 00179 d->shmInfo.detach(); 00180 lock.unlock(); 00181 return false; 00182 } 00183 } else { 00184 d->shmInfo.lock(); 00185 infoPtr = static_cast<Private::sharedInfoData*> ( d->shmInfo.data() ); 00186 d->shmData.setKey ( d->getShmKey ( infoPtr->shmCounter ) ); 00187 if ( !d->shmData.attach ( QSharedMemory::ReadOnly ) ) { 00188 if ( !d->loadContentsFromFile() ) { 00189 d->shmInfo.unlock(); 00190 d->shmInfo.detach(); 00191 lock.unlock(); 00192 return false; 00193 } 00194 } 00195 } 00196 d->shmDataSize = infoPtr->shmDataSize; 00197 d->shmInfo.unlock(); 00198 lock.unlock(); 00199 00200 setOpenMode ( mode ); 00201 return true; 00202 } 00203 00204 bool KMemFile::seek ( qint64 pos ) 00205 { 00206 if ( d->shmDataSize < pos ) { 00207 setErrorString ( i18n ( "Cannot seek past eof" ) ); 00208 return false; 00209 } 00210 d->readWritePos = pos; 00211 QIODevice::seek ( pos ); 00212 return true; 00213 } 00214 00215 qint64 KMemFile::size () const 00216 { 00217 return d->shmDataSize; 00218 } 00219 00220 qint64 KMemFile::readData ( char * data, qint64 maxSize ) 00221 { 00222 if ( ( openMode() & QIODevice::ReadOnly ) == 0 ) 00223 return -1; 00224 00225 qint64 maxRead = size() - d->readWritePos; 00226 qint64 bytesToRead = qMin ( maxRead, maxSize ); 00227 const char *src = static_cast<const char*> ( d->shmData.data() ); 00228 memcpy ( data, &src[d->readWritePos], bytesToRead ); 00229 d->readWritePos += bytesToRead; 00230 return bytesToRead; 00231 } 00232 00233 qint64 KMemFile::writeData ( const char *, qint64 ) 00234 { 00235 return -1; 00236 } 00237 00238 void KMemFile::fileContentsChanged ( const QString &filename ) 00239 { 00240 QSharedMemory lock ( QDir ( filename ).canonicalPath() ); 00241 lock.lock(); 00242 00243 QSharedMemory shmData ( Private::getShmKey ( filename ) ); 00244 if ( !shmData.attach() ) 00245 return; 00246 shmData.lock(); 00247 Private::sharedInfoData *infoPtr = static_cast<Private::sharedInfoData*> ( shmData.data() ); 00248 infoPtr->shmCounter++; 00249 infoPtr->shmDataSize = 0; 00250 shmData.unlock(); 00251 } 00252 00253 #endif //QT_NO_SHAREDMEMORY
KDE 4.6 API Reference