summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Meeks <michael.meeks@collabora.com>2013-10-11 17:43:19 +0100
committerMichael Meeks <michael.meeks@collabora.com>2013-10-11 17:44:42 +0100
commit53138c9968e28a25a8cd6d2b5e3d31cbb3257852 (patch)
tree0d6078033f065dafd49e727db1dfbc550bab6083
parentd58d1719a49c5c25cce8ddfa7fef52b09d0f9957 (diff)
fdo#56007 - fast zip directory find to accelerate Windows Explorer thumbnail.
Change-Id: Id9436def56f40d2bb54dea35bea916bd99964653
-rw-r--r--shell/source/win32/zipfile/zipfile.cxx51
1 files changed, 40 insertions, 11 deletions
diff --git a/shell/source/win32/zipfile/zipfile.cxx b/shell/source/win32/zipfile/zipfile.cxx
index fb7dc88fc122..cf05a56882f5 100644
--- a/shell/source/win32/zipfile/zipfile.cxx
+++ b/shell/source/win32/zipfile/zipfile.cxx
@@ -102,6 +102,9 @@ struct CentralDirectoryEnd
#define LOC_FILE_HEADER_SIG 0x04034b50
#define CDIR_END_SIG 0x06054b50
+// This little lot performs in a truly appalling way without
+// buffering eg. on an IStream.
+
static unsigned char readByte(StreamInterface *stream)
{
if (!stream || stream->stell() == -1)
@@ -250,31 +253,57 @@ static bool areHeadersConsistent(const LocalFileHeader &header, const CentralDir
return true;
}
+#define BLOCK_SIZE 0x800
+
+static bool findSignatureAtOffset(StreamInterface *stream, unsigned long nOffset)
+{
+ // read in reasonably sized chunk, and read more, to get overlapping sigs
+ unsigned char aBuffer[ BLOCK_SIZE + 4 ];
+
+ stream->sseek(nOffset, SEEK_SET);
+
+ unsigned long nBytesRead = stream->sread(aBuffer, sizeof(aBuffer));
+ if (nBytesRead < 0)
+ return false;
+
+ for (long n = nBytesRead - 4; n >= 0; n--)
+ {
+ if (aBuffer[n ] == 0x50 && aBuffer[n+1] == 0x4b &&
+ aBuffer[n+2] == 0x05 && aBuffer[n+3] == 0x06)
+ { // a palpable hit ...
+ stream->sseek(nOffset + n, SEEK_SET);
+ return true;
+ }
+ }
+
+ return false;
+}
+
static bool findCentralDirectoryEnd(StreamInterface *stream)
{
if (!stream)
return false;
- stream->sseek(0, SEEK_SET);
- if (stream->sseek(-1024, SEEK_END)) stream->sseek(0, SEEK_SET);
+
+ stream->sseek(0,SEEK_END);
+
+ long nLength = stream->stell();
+ if (nLength == -1)
+ return false;
+
try
{
- while (stream->stell() != -1)
+ for (long nOffset = nLength - BLOCK_SIZE;
+ nOffset > 0; nOffset -= BLOCK_SIZE)
{
- unsigned signature = readInt(stream);
- if (signature == CDIR_END_SIG)
- {
- stream->sseek(-4, SEEK_CUR);
+ if (findSignatureAtOffset(stream, nOffset))
return true;
- }
- else
- stream->sseek(-3, SEEK_CUR);
}
+ return findSignatureAtOffset(stream, 0);
}
catch (...)
{
return false;
}
- return false;
}
static bool isZipStream(StreamInterface *stream)