Blob Blame History Raw
--- branches/KDE/4.4/kdelibs/kdeui/util/kpixmapcache.cpp	2010/01/24 02:37:20	1079318
+++ branches/KDE/4.4/kdelibs/kdeui/util/kpixmapcache.cpp	2010/03/25 02:24:54	1107210
@@ -40,6 +40,7 @@
 #include <kstandarddirs.h>
 #include <kdebug.h>
 #include <klockfile.h>
+#include <ksavefile.h>
 #include <ksvgrenderer.h>
 #include <kdefakes.h>
 
@@ -633,6 +634,10 @@
     qint32 leftchild, rightchild;
     stream >> fkey >> foffset >> timesused >> lastused >> leftchild >> rightchild;
 
+    if (fkey.isEmpty()) {
+        return start;
+    }
+
     if (key < fkey) {
         if (leftchild) {
             return binarySearchKey(stream, key, leftchild);
@@ -660,12 +665,23 @@
     //  exist yet and there are no entries. Otherwise, do a binary search
     //  starting from the root node.
     if (!stream.atEnd()) {
+        // One exception is that the root node may exist but be invalid,
+        // which can happen when the cache data is discarded. This is
+        // represented by an empty fkey
+        QString fkey;
+        stream >> fkey;
+
+        if (fkey.isEmpty()) {
+            delete device;
+            return -1;
+        }
+
         int nodeoffset = binarySearchKey(stream, key, mIndexRootOffset);
 
         // Load the found entry and check if it's the one we're looking for.
         device->seek(nodeoffset);
-        QString fkey;
         stream >> fkey;
+
         if (fkey == key) {
             // Read offset and statistics
             qint32 foffset;
@@ -814,7 +830,9 @@
         QString fkey;
         stream.device()->seek(parentoffset);
         stream >> fkey;
-        if (key == fkey) {
+
+        // The key would be empty if the cache had been discarded.
+        if (key == fkey || fkey.isEmpty()) {
             // We're overwriting an existing entry
             offset = parentoffset;
         }
@@ -1195,16 +1213,14 @@
         return false;
     }
 
-    d->invalidateMmapFiles();
-    d->unmmapFiles();
-
-    d->mEnabled = false;
-
     KPCLockFile lock(d->mLockFileName);
     // Hope we got the lock...
 
+    d->invalidateMmapFiles();
+    d->mEnabled = false;
+
     // Create index file
-    QFile indexfile(d->mIndexFile);
+    KSaveFile indexfile(d->mIndexFile);
     if (!indexfile.open(QIODevice::WriteOnly)) {
         kError() << "Couldn't create index file" << d->mIndexFile;
         return false;
@@ -1212,7 +1228,7 @@
 
     d->mCacheId = ::time(0);
     d->mTimestamp = ::time(0);
-    
+
     // We can't know the full size until custom headers written.
     // mmapFiles() will take care of correcting the size.
     KPixmapCacheIndexHeader indexHeader = { {0}, KPIXMAPCACHE_VERSION, 0, d->mCacheId, d->mTimestamp };
@@ -1221,7 +1237,7 @@
     indexfile.write(reinterpret_cast<char*>(&indexHeader), sizeof indexHeader);
 
     // Create data file
-    QFile datafile(d->mDataFile);
+    KSaveFile datafile(d->mDataFile);
     if (!datafile.open(QIODevice::WriteOnly)) {
         kError() << "Couldn't create data file" << d->mDataFile;
         return false;
@@ -1243,40 +1259,54 @@
     // Close the files and mmap them (if mmapping is used)
     indexfile.close();
     datafile.close();
+    indexfile.finalize();
+    datafile.finalize();
+
     d->mEnabled = true;
     d->mmapFiles();
+
     return true;
 }
 
 void KPixmapCache::deleteCache(const QString& name)
 {
-    foreach (KPixmapCache::Private *d, Private::mCaches) {
-        if (d->mName == name && d->mInited) {
-            d->q->discard();
-        }
-    }
+    QString indexFile = KGlobal::dirs()->locateLocal("cache", "kpc/" + name + ".index");
+    QString dataFile  = KGlobal::dirs()->locateLocal("cache", "kpc/" + name + ".data");
+
+    QFile::remove(indexFile);
+    QFile::remove(dataFile);
 }
 
 void KPixmapCache::discard()
 {
-    d->invalidateMmapFiles();
-    d->unmmapFiles();
-    d->mInited = false;
+    // To "discard" the cache we simply have to make sure that every that
+    // was in there before is no longer present when we search for them.
+    // Easiest way to do *that* is to simply delete the index.
+
+    KPCLockFile lock(d->mLockFileName);
+    if(!lock.isValid()) {
+        kError(264) << "Unable to lock pixmap cache when trying to discard it";
+        return;
+    }
+
+    QIODevice *device = d->indexDevice();
+    if (!device) {
+        kError(264) << "Unable to access index when trying to discard cache";
+        return;
+    }
+
+    device->seek(d->mIndexRootOffset);
+    QDataStream stream(device);
+
+    // Stream an empty QString as the hash key to signify that the cache
+    // has been discarded.
+    stream << QString();
 
     if (d->mUseQPixmapCache) {
         // TODO: This is broken, it removes every cached QPixmap in the whole
         // process, not just this KPixmapCache.
         QPixmapCache::clear();
     }
-
-    QString indexFile = KGlobal::dirs()->locateLocal("cache", "kpc/" + d->mName + ".index");
-    QString dataFile  = KGlobal::dirs()->locateLocal("cache", "kpc/" + d->mName + ".data");
-
-    QFile::remove(indexFile);
-    QFile::remove(dataFile);
-
-    // No need to remove the lockfile
-    d->init();
 }
 
 void KPixmapCache::removeEntries(int newsize)