summaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorFridrich Štrba <fridrich.strba@bluewin.ch>2012-03-19 15:09:34 +0100
committerFridrich Štrba <fridrich.strba@bluewin.ch>2012-03-19 15:22:55 +0100
commit04366df3bca16d4e0cbe254551e44427ae6338bb (patch)
tree92fcb6ed5e6f877aecd53777b07c389f643b710e /shell
parent43061897a69fbfc765170e87588f843fbd540e52 (diff)
Simple Zip file-format implementation to avoid the need of minizip
Diffstat (limited to 'shell')
-rw-r--r--shell/inc/internal/basereader.hxx2
-rw-r--r--shell/inc/internal/contentreader.hxx3
-rw-r--r--shell/inc/internal/metainforeader.hxx2
-rw-r--r--shell/inc/internal/stream_helper.hxx24
-rw-r--r--shell/inc/internal/types.hxx17
-rw-r--r--shell/inc/internal/zipfile.hxx29
-rw-r--r--shell/source/win32/ooofilereader/basereader.cxx4
-rw-r--r--shell/source/win32/ooofilereader/contentreader.cxx4
-rw-r--r--shell/source/win32/ooofilereader/metainforeader.cxx4
-rw-r--r--shell/source/win32/shlxthandler/makefile.mk2
-rw-r--r--shell/source/win32/shlxthandler/ooofilt/ooofilt.cxx11
-rw-r--r--shell/source/win32/shlxthandler/ooofilt/ooofilt.hxx2
-rw-r--r--shell/source/win32/shlxthandler/ooofilt/stream_helper.cxx190
-rw-r--r--shell/source/win32/shlxthandler/prophdl/propertyhdl.cxx5
-rw-r--r--shell/source/win32/zipfile/zipfile.cxx473
15 files changed, 547 insertions, 225 deletions
diff --git a/shell/inc/internal/basereader.hxx b/shell/inc/internal/basereader.hxx
index bb5c27645e2a..7a154103e44c 100644
--- a/shell/inc/internal/basereader.hxx
+++ b/shell/inc/internal/basereader.hxx
@@ -46,7 +46,7 @@ public:
protected: // protected because its only an implementation relevant class
CBaseReader( const std::string& DocumentName );
- CBaseReader( void* stream, zlib_filefunc_def* fa );
+ CBaseReader( StreamInterface *stream );
virtual void start_document();
diff --git a/shell/inc/internal/contentreader.hxx b/shell/inc/internal/contentreader.hxx
index 6a7dc594af60..e55a76035b90 100644
--- a/shell/inc/internal/contentreader.hxx
+++ b/shell/inc/internal/contentreader.hxx
@@ -32,6 +32,7 @@
#include "internal/basereader.hxx"
class ITag;
+class StreamInterface;
class CContentReader : public CBaseReader
{
@@ -40,7 +41,7 @@ public:
CContentReader( const std::string& DocumentName, LocaleSet_t const & DocumentLocale );
- CContentReader( void* stream, LocaleSet_t const & DocumentLocale, zlib_filefunc_def* fa );
+ CContentReader( StreamInterface* stream, LocaleSet_t const & DocumentLocale );
/** Get the chunkbuffer.
diff --git a/shell/inc/internal/metainforeader.hxx b/shell/inc/internal/metainforeader.hxx
index 516224571078..a0ed7d9584c1 100644
--- a/shell/inc/internal/metainforeader.hxx
+++ b/shell/inc/internal/metainforeader.hxx
@@ -44,7 +44,7 @@ public:
CMetaInfoReader( const std::string& DocumentName );
- CMetaInfoReader( void* stream, zlib_filefunc_def* fa);
+ CMetaInfoReader( StreamInterface* stream );
/** check if the Tag is in the target meta.xml file.
diff --git a/shell/inc/internal/stream_helper.hxx b/shell/inc/internal/stream_helper.hxx
index bd31ee111315..72eaf7355b2c 100644
--- a/shell/inc/internal/stream_helper.hxx
+++ b/shell/inc/internal/stream_helper.hxx
@@ -31,7 +31,29 @@
#include "internal/types.hxx"
-IStream* PrepareIStream( IStream* pStream, zlib_filefunc_def &zFileFunc );
+class BufferStream : public StreamInterface
+{
+public:
+ BufferStream(IStream *str);
+ ~BufferStream();
+ unsigned long sread (unsigned char *vuf, unsigned long size);
+ long stell ();
+ long sseek (unsigned long offset, int origin);
+private:
+ IStream *stream;
+};
+
+class FileStream : public StreamInterface
+{
+public:
+ FileStream(const char *filename);
+ ~FileStream();
+ unsigned long sread (unsigned char *buf, unsigned long size);
+ long stell ();
+ long sseek (unsigned long offset, int origin);
+private:
+ FILE *file;
+};
#endif
diff --git a/shell/inc/internal/types.hxx b/shell/inc/internal/types.hxx
index 0c6810aec0d0..c6fbfac5e50c 100644
--- a/shell/inc/internal/types.hxx
+++ b/shell/inc/internal/types.hxx
@@ -35,14 +35,6 @@
#include <vector>
#include <stack>
-#if defined SYSTEM_ZLIB
-#include <zlib.h>
-#include <minizip/ioapi.h>
-#else
-#include <external/zlib/zlib.h>
-#include <external/zlib/ioapi.h>
-#endif
-
typedef std::vector<std::wstring> StringList_t;
//+-------------------------------------------------------------------------
@@ -89,6 +81,15 @@ typedef ::std::map<StyleName_t, LocaleSet_t> StyleLocaleMap_t;
const StyleLocalePair_t EMPTY_STYLELOCALE_PAIR = ::std::make_pair(::std::wstring(), EMPTY_LOCALE );
+class StreamInterface
+{
+public:
+ virtual ~StreamInterface() {}
+ virtual unsigned long sread (unsigned char* vuf, unsigned long size) = 0;
+ virtual long stell () = 0;
+ virtual long sseek (unsigned long offset, int origin) = 0;
+};
+
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/shell/inc/internal/zipfile.hxx b/shell/inc/internal/zipfile.hxx
index 062ce38cf1af..24fba6542fcf 100644
--- a/shell/inc/internal/zipfile.hxx
+++ b/shell/inc/internal/zipfile.hxx
@@ -33,16 +33,19 @@
#define _WINDOWS
#endif
-#if defined SYSTEM_ZLIB
-#include <minizip/unzip.h>
+#ifdef SYSTEM_ZLIB
+#include <zlib.h>
#else
-#include <external/zlib/unzip.h>
+#include <external/zlib/zlib.h>
#endif
#include <string>
#include <vector>
#include <memory>
+class StreamInterface;
+class ZipFilePrivate;
+
/** A simple zip content provider based on the zlib
*/
@@ -69,9 +72,9 @@ public:
IOException if the specified file doesn't exist
AccessViolationException if read access to the file is denied
*/
- static bool IsZipFile(const std::string& FileName);
+ static bool IsZipFile(const std::string &FileName);
- static bool IsZipFile(void* stream);
+ static bool IsZipFile(void *stream);
/** Returns wheter the version of the specified zip file may be uncompressed with the
@@ -89,9 +92,9 @@ public:
IOException if the specified file doesn't exist or is no zip file
AccessViolationException if read access to the file is denied
*/
- static bool IsValidZipFileVersionNumber(const std::string& FileName);
+ static bool IsValidZipFileVersionNumber(const std::string &FileName);
- static bool IsValidZipFileVersionNumber(void* stream);
+ static bool IsValidZipFileVersionNumber(void *stream);
public:
@@ -107,9 +110,9 @@ public:
WrongZipVersionException if the zip file cannot be uncompressed
with the used zlib version
*/
- ZipFile(const std::string& FileName);
+ ZipFile(const std::string &FileName);
- ZipFile(void* stream, zlib_filefunc_def* fa);
+ ZipFile(StreamInterface *stream);
/** Destroys a zip file
@@ -134,7 +137,7 @@ public:
ZipContentMissException if the specified zip content
does not exist in this zip file
*/
- void GetUncompressedContent(const std::string& ContentName, /*inout*/ ZipContentBuffer_t& ContentBuffer);
+ void GetUncompressedContent(const std::string &ContentName, /*inout*/ ZipContentBuffer_t &ContentBuffer);
/** Returns a list with the content names contained within this file
@@ -146,7 +149,7 @@ public:
iterating over a ZipFileDirectory returned by
GetDirectory
*/
- bool HasContent(const std::string& ContentName) const;
+ bool HasContent(const std::string &ContentName) const;
private:
@@ -158,7 +161,9 @@ private:
long GetFileLongestFileNameLength() const;
private:
- unzFile m_uzFile;
+ StreamInterface *m_pStream;
+ bool m_bShouldFree;
+ long m_iStartOffset;
};
#endif
diff --git a/shell/source/win32/ooofilereader/basereader.cxx b/shell/source/win32/ooofilereader/basereader.cxx
index ed0c4a08e7e7..f4f694e6c683 100644
--- a/shell/source/win32/ooofilereader/basereader.cxx
+++ b/shell/source/win32/ooofilereader/basereader.cxx
@@ -47,8 +47,8 @@ m_ZipFile( DocumentName )
//------------------------------
-CBaseReader::CBaseReader(void * sw, zlib_filefunc_def* fa):
-m_ZipFile( sw , fa )
+CBaseReader::CBaseReader(StreamInterface * sw):
+m_ZipFile( sw )
{
}
diff --git a/shell/source/win32/ooofilereader/contentreader.cxx b/shell/source/win32/ooofilereader/contentreader.cxx
index f824dbc4121d..76cfc6cd3baa 100644
--- a/shell/source/win32/ooofilereader/contentreader.cxx
+++ b/shell/source/win32/ooofilereader/contentreader.cxx
@@ -62,8 +62,8 @@ CBaseReader( DocumentName )
}
}
-CContentReader::CContentReader( void* stream, LocaleSet_t const & DocumentLocale, zlib_filefunc_def* fa ) :
-CBaseReader( stream, fa )
+CContentReader::CContentReader( StreamInterface* stream, LocaleSet_t const & DocumentLocale ) :
+CBaseReader( stream )
{
try
{
diff --git a/shell/source/win32/ooofilereader/metainforeader.cxx b/shell/source/win32/ooofilereader/metainforeader.cxx
index 5abf72bd3144..4027b65cb150 100644
--- a/shell/source/win32/ooofilereader/metainforeader.cxx
+++ b/shell/source/win32/ooofilereader/metainforeader.cxx
@@ -81,8 +81,8 @@ CBaseReader( DocumentName )
}
}
-CMetaInfoReader::CMetaInfoReader( void* stream, zlib_filefunc_def* fa) :
-CBaseReader( stream, fa)
+CMetaInfoReader::CMetaInfoReader( StreamInterface* stream ) :
+CBaseReader( stream )
{
try
{
diff --git a/shell/source/win32/shlxthandler/makefile.mk b/shell/source/win32/shlxthandler/makefile.mk
index fa2a480dbff6..81c3515b20b7 100644
--- a/shell/source/win32/shlxthandler/makefile.mk
+++ b/shell/source/win32/shlxthandler/makefile.mk
@@ -73,6 +73,7 @@ SLOFILES=$(SLO)$/classfactory.obj\
$(SLO)$/listviewbuilder.obj\
$(SLO)$/document_statistic.obj\
$(SLO)$/thumbviewer.obj\
+ $(SLO)$/stream_helper.obj\
SHL1TARGET=$(TARGET)
@@ -128,6 +129,7 @@ SLOFILES_X64= \
$(SLO_X64)$/listviewbuilder.obj\
$(SLO_X64)$/document_statistic.obj\
$(SLO_X64)$/thumbviewer.obj\
+ $(SLO_X64)$/stream_helper.obj\
SHL1TARGET_X64=$(TARGET)
SHL1LIBS_X64=$(SOLARLIBDIR_X64)$/zlib.lib\
diff --git a/shell/source/win32/shlxthandler/ooofilt/ooofilt.cxx b/shell/source/win32/shlxthandler/ooofilt/ooofilt.cxx
index 8528d0cfa250..401ee6f79a71 100644
--- a/shell/source/win32/shlxthandler/ooofilt/ooofilt.cxx
+++ b/shell/source/win32/shlxthandler/ooofilt/ooofilt.cxx
@@ -120,6 +120,8 @@ COooFilter::~COooFilter()
delete m_pContentReader;
if (m_pMetaInfoReader)
delete m_pMetaInfoReader;
+ if (m_pStream)
+ delete m_pStream;
InterlockedDecrement( &g_lInstances );
}
@@ -640,19 +642,16 @@ SCODE STDMETHODCALLTYPE COooFilter::SaveCompleted(LPCWSTR /*pszFileName*/)
//--------------------------------------------------------------------------
SCODE STDMETHODCALLTYPE COooFilter::Load(IStream *pStm)
{
- zlib_filefunc_def z_filefunc;
-
- m_pStream = PrepareIStream( pStm, z_filefunc );
-
+ m_pStream = new BufferStream(pStm);
try
{
if (m_pMetaInfoReader)
delete m_pMetaInfoReader;
- m_pMetaInfoReader = new CMetaInfoReader((void*)m_pStream, &z_filefunc);
+ m_pMetaInfoReader = new CMetaInfoReader(m_pStream);
if (m_pContentReader)
delete m_pContentReader;
- m_pContentReader = new CContentReader((void*)m_pStream, m_pMetaInfoReader->getDefaultLocale(), &z_filefunc);
+ m_pContentReader = new CContentReader(m_pStream, m_pMetaInfoReader->getDefaultLocale());
}
catch (const std::exception&)
{
diff --git a/shell/source/win32/shlxthandler/ooofilt/ooofilt.hxx b/shell/source/win32/shlxthandler/ooofilt/ooofilt.hxx
index 030a3e5d99ca..5ecd91754429 100644
--- a/shell/source/win32/shlxthandler/ooofilt/ooofilt.hxx
+++ b/shell/source/win32/shlxthandler/ooofilt/ooofilt.hxx
@@ -165,7 +165,7 @@ private:
ULONG m_ChunkPosition; // Chunk pointer to specify the current Chunk;
ULONG m_cAttributes; // Count of attributes
CFullPropSpec * m_pAttributes; // Attributes to filter
- IStream * m_pStream;
+ StreamInterface * m_pStream;
};
diff --git a/shell/source/win32/shlxthandler/ooofilt/stream_helper.cxx b/shell/source/win32/shlxthandler/ooofilt/stream_helper.cxx
index 54409ebd631e..e4ace54674d8 100644
--- a/shell/source/win32/shlxthandler/ooofilt/stream_helper.cxx
+++ b/shell/source/win32/shlxthandler/ooofilt/stream_helper.cxx
@@ -39,20 +39,8 @@
#include <objidl.h>
#include "internal/stream_helper.hxx"
-extern "C" {
- voidpf ZCALLBACK cb_sopen OF((voidpf opaque, const char * filename, int mode));
- uLong ZCALLBACK cb_sread OF((voidpf opaque, voidpf stream, void* vuf, uLong size));
- uLong ZCALLBACK cb_swrite OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
- long ZCALLBACK cb_stell OF((voidpf opaque, voidpf stream));
- long ZCALLBACK cb_sseek OF((voidpf opaque, voidpf stream, uLong offset, int origin));
- int ZCALLBACK cb_sclose OF((voidpf opaque, voidpf stream));
- int ZCALLBACK cb_serror OF((voidpf opaque, voidpf stream));
-
- void fill_stream_filefunc (zlib_filefunc_def* pzlib_filefunc_def);
-}
-
-//-----------------------------
-IStream* PrepareIStream( IStream* pStream, zlib_filefunc_def &zFileFunc )
+BufferStream::BufferStream(IStream *str) :
+ stream(str)
{
// These next few lines work around the "Seek pointer" bug found on Vista.
char cBuf[20];
@@ -60,109 +48,101 @@ IStream* PrepareIStream( IStream* pStream, zlib_filefunc_def &zFileFunc )
ULARGE_INTEGER nNewPosition;
LARGE_INTEGER nMove;
nMove.QuadPart = 0;
- pStream->Seek( nMove, STREAM_SEEK_SET, &nNewPosition );
- pStream->Read( cBuf, 20, &nCount );
-
- fill_stream_filefunc( &zFileFunc );
- zFileFunc.opaque = (void*)pStream;
+ stream->Seek( nMove, STREAM_SEEK_SET, &nNewPosition );
+ stream->Read( cBuf, 20, &nCount );
+}
- return pStream;
+BufferStream::~BufferStream()
+{
}
-extern "C" {
+unsigned long BufferStream::sread (unsigned char *buf, unsigned long size)
+{
+ unsigned long newsize;
+ HRESULT hr;
+
+ hr = stream->Read (buf, size, &newsize);
+ if (hr == S_OK)
+ return (unsigned long)newsize;
+ else
+ return (unsigned long)0;
+}
- // IStream callback
- voidpf ZCALLBACK cb_sopen (voidpf opaque, const char* /*filename*/, int /*mode*/) {
- return opaque;
- }
+long BufferStream::stell ()
+{
+ HRESULT hr;
+ LARGE_INTEGER Move;
+ ULARGE_INTEGER NewPosition;
+ Move.QuadPart = 0;
+ NewPosition.QuadPart = 0;
+
+ hr = ((IStream *)stream)->Seek (Move, STREAM_SEEK_CUR, &NewPosition);
+ if (hr == S_OK)
+ return (long) NewPosition.QuadPart;
+ else
+ return -1;
+}
- uLong ZCALLBACK cb_sread (voidpf /*opaque*/, voidpf stream, void* buf, uLong size) {
- unsigned long newsize;
- HRESULT hr;
-
- hr = ((IStream *)stream)->Read (buf, size, &newsize);
- if (hr == S_OK){
- return (unsigned long)newsize;
- }
- else {
- return (uLong)0;
- }
+long BufferStream::sseek (unsigned long offset, int origin)
+{
+ HRESULT hr;
+ LARGE_INTEGER Move;
+ DWORD dwOrigin;
+ Move.QuadPart = (__int64)offset;
+
+ switch (origin)
+ {
+ case SEEK_CUR:
+ dwOrigin = STREAM_SEEK_CUR;
+ break;
+ case SEEK_END:
+ dwOrigin = STREAM_SEEK_END;
+ break;
+ case SEEK_SET:
+ dwOrigin = STREAM_SEEK_SET;
+ break;
+ default:
+ return -1;
}
- long ZCALLBACK cb_sseek (voidpf /*opaque*/, voidpf stream, uLong offset, int origin) {
- // IStream::Seek parameters
- HRESULT hr;
- LARGE_INTEGER Move;
- DWORD dwOrigin;
- Move.QuadPart = (__int64)offset;
-
- switch (origin) {
- case SEEK_CUR:
- dwOrigin = STREAM_SEEK_CUR;
- break;
- case SEEK_END:
- dwOrigin = STREAM_SEEK_END;
- break;
- case SEEK_SET:
- dwOrigin = STREAM_SEEK_SET;
- break;
- default:
- return -1;
- }
-
- hr = ((IStream*)stream)->Seek (Move, dwOrigin, NULL);
- if (hr == S_OK){
- return 0;
- }
- else {
- return -1;
- }
- }
+ hr = stream->Seek (Move, dwOrigin, NULL);
+ if (hr == S_OK)
+ return 0;
+ else
+ return -1;
+}
- long ZCALLBACK cb_stell (voidpf /*opaque*/, voidpf stream) {
- // IStream::Seek parameters
- HRESULT hr;
- LARGE_INTEGER Move;
- ULARGE_INTEGER NewPosition;
- Move.QuadPart = 0;
- NewPosition.QuadPart = 0;
-
- hr = ((IStream*)stream)->Seek (Move, STREAM_SEEK_CUR, &NewPosition);
- if (hr == S_OK){
- return (long) NewPosition.QuadPart;
- }
- else {
- return -1;
- }
- }
+FileStream::FileStream(const char *filename) :
+ file(0)
+{
+ file = fopen(filename, "rb");
+}
- int ZCALLBACK cb_sclose (voidpf /*opaque*/, voidpf /*stream*/) {
- return 0;
- }
+FileStream::~FileStream()
+{
+ if (file)
+ fclose(file);
+}
- int ZCALLBACK cb_serror (voidpf /*opaque*/, voidpf /*stream*/) {
- return 0; //RJK - for now
- }
+unsigned long FileStream::sread (unsigned char *buf, unsigned long size)
+{
+ if (file)
+ return fread(buf, 1, size, file);
+ return 0;
+}
- uLong ZCALLBACK cb_swrite (voidpf /*opaque*/, voidpf stream, const void* buf, uLong size) {
- HRESULT hr;
- unsigned long writecount;
- hr = ((IStream*)stream)->Write (buf, size, &writecount);
- if (hr == S_OK)
- return (unsigned int)writecount;
- else
- return (uLong)0;
- }
+long FileStream::stell ()
+{
+ if (file)
+ return ftell(file);
+ return -1L;
+}
- void fill_stream_filefunc (zlib_filefunc_def* pzlib_filefunc_def) {
- pzlib_filefunc_def->zopen_file = cb_sopen;
- pzlib_filefunc_def->zread_file = cb_sread;
- pzlib_filefunc_def->zwrite_file = cb_swrite;
- pzlib_filefunc_def->ztell_file = cb_stell;
- pzlib_filefunc_def->zseek_file = cb_sseek;
- pzlib_filefunc_def->zclose_file = cb_sclose;
- pzlib_filefunc_def->zerror_file = cb_serror;
- }
+long FileStream::sseek (unsigned long offset, int origin)
+{
+ if (file)
+ return fseek(file, offset, origin);
+ return -1L;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/shell/source/win32/shlxthandler/prophdl/propertyhdl.cxx b/shell/source/win32/shlxthandler/prophdl/propertyhdl.cxx
index d2d23ff7b159..7d21f3abc2b5 100644
--- a/shell/source/win32/shlxthandler/prophdl/propertyhdl.cxx
+++ b/shell/source/win32/shlxthandler/prophdl/propertyhdl.cxx
@@ -228,14 +228,13 @@ HRESULT STDMETHODCALLTYPE CPropertyHdl::Initialize( IStream *pStream, DWORD grfM
#endif
OutputDebugStringFormat( "CPropertyHdl::Initialize: PSCreateMemoryPropertyStore failed" );
- zlib_filefunc_def z_filefunc;
- pStream = PrepareIStream( pStream, z_filefunc );
+ BufferStream tmpStream(pStream);
CMetaInfoReader *pMetaInfoReader = NULL;
try
{
- pMetaInfoReader = new CMetaInfoReader( (void*)pStream, &z_filefunc );
+ pMetaInfoReader = new CMetaInfoReader( &tmpStream );
LoadProperties( pMetaInfoReader );
delete pMetaInfoReader;
}
diff --git a/shell/source/win32/zipfile/zipfile.cxx b/shell/source/win32/zipfile/zipfile.cxx
index 30c46b05df2b..de99aa671e62 100644
--- a/shell/source/win32/zipfile/zipfile.cxx
+++ b/shell/source/win32/zipfile/zipfile.cxx
@@ -29,6 +29,8 @@
#include "zipexcptn.hxx"
#include "internal/zipfile.hxx"
#include "internal/global.hxx"
+#include "internal/types.hxx"
+#include "internal/stream_helper.hxx"
#include <malloc.h>
#include <algorithm>
@@ -36,19 +38,289 @@
#include <string.h>
-namespace internal
+namespace
+{
+
+struct LocalFileHeader
+{
+ unsigned short min_version;
+ unsigned short general_flag;
+ unsigned short compression;
+ unsigned short lastmod_time;
+ unsigned short lastmod_date;
+ unsigned crc32;
+ unsigned compressed_size;
+ unsigned uncompressed_size;
+ unsigned short filename_size;
+ unsigned short extra_field_size;
+ std::string filename;
+ std::string extra_field;
+ LocalFileHeader()
+ : min_version(0), general_flag(0), compression(0), lastmod_time(0), lastmod_date(0),
+ crc32(0), compressed_size(0), uncompressed_size(0), filename_size(0), extra_field_size(0),
+ filename(), extra_field() {}
+ ~LocalFileHeader() {}
+};
+
+struct CentralDirectoryEntry
+{
+ unsigned short creator_version;
+ unsigned short min_version;
+ unsigned short general_flag;
+ unsigned short compression;
+ unsigned short lastmod_time;
+ unsigned short lastmod_date;
+ unsigned crc32;
+ unsigned compressed_size;
+ unsigned uncompressed_size;
+ unsigned short filename_size;
+ unsigned short extra_field_size;
+ unsigned short file_comment_size;
+ unsigned short disk_num;
+ unsigned short internal_attr;
+ unsigned external_attr;
+ unsigned offset;
+ std::string filename;
+ std::string extra_field;
+ std::string file_comment;
+ CentralDirectoryEntry()
+ : creator_version(0), min_version(0), general_flag(0), compression(0), lastmod_time(0),
+ lastmod_date(0), crc32(0), compressed_size(0), uncompressed_size(0), filename_size(0),
+ extra_field_size(0), file_comment_size(0), disk_num(0), internal_attr(0),
+ external_attr(0), offset(0), filename(), extra_field(), file_comment() {}
+ ~CentralDirectoryEntry() {}
+};
+
+struct CentralDirectoryEnd
+{
+ unsigned short disk_num;
+ unsigned short cdir_disk;
+ unsigned short disk_entries;
+ unsigned short cdir_entries;
+ unsigned cdir_size;
+ unsigned cdir_offset;
+ unsigned short comment_size;
+ std::string comment;
+ CentralDirectoryEnd()
+ : disk_num(0), cdir_disk(0), disk_entries(0), cdir_entries(0),
+ cdir_size(0), cdir_offset(0), comment_size(0), comment() {}
+ ~CentralDirectoryEnd() {}
+};
+
+#define CDIR_ENTRY_SIG 0x02014b50
+#define LOC_FILE_HEADER_SIG 0x04034b50
+#define CDIR_END_SIG 0x06054b50
+
+static unsigned char readByte(StreamInterface *stream)
+{
+ if (!stream || stream->stell() == -1)
+ throw IOException(-1);
+ unsigned char tmpBuf;
+ unsigned long numBytesRead = stream->sread(&tmpBuf, 1);
+ if (numBytesRead != 1)
+ throw IOException(-1);
+ return tmpBuf;
+}
+
+static unsigned short readShort(StreamInterface *stream)
+{
+ unsigned short p0 = (unsigned short)readByte(stream);
+ unsigned short p1 = (unsigned short)readByte(stream);
+ return (unsigned short)(p0|(p1<<8));
+}
+
+static unsigned readInt(StreamInterface *stream)
+{
+ unsigned p0 = (unsigned)readByte(stream);
+ unsigned p1 = (unsigned)readByte(stream);
+ unsigned p2 = (unsigned)readByte(stream);
+ unsigned p3 = (unsigned)readByte(stream);
+ return (unsigned)(p0|(p1<<8)|(p2<<16)|(p3<<24));
+}
+
+static bool readCentralDirectoryEnd(StreamInterface *stream, CentralDirectoryEnd &end)
+{
+ try
+ {
+ unsigned signature = readInt(stream);
+ if (signature != CDIR_END_SIG)
+ return false;
+
+ end.disk_num = readShort(stream);
+ end.cdir_disk = readShort(stream);
+ end.disk_entries = readShort(stream);
+ end.cdir_entries = readShort(stream);
+ end.cdir_size = readInt(stream);
+ end.cdir_offset = readInt(stream);
+ end.comment_size = readShort(stream);
+ end.comment.clear();
+ for (unsigned short i = 0; i < end.comment_size; i++)
+ end.comment.append(1,(char)readByte(stream));
+ }
+ catch (...)
+ {
+ return false;
+ }
+ return true;
+}
+
+static bool readCentralDirectoryEntry(StreamInterface *stream, CentralDirectoryEntry &entry)
+{
+ try
+ {
+ unsigned signature = readInt(stream);
+ if (signature != CDIR_ENTRY_SIG)
+ return false;
+
+ entry.creator_version = readShort(stream);
+ entry.min_version = readShort(stream);
+ entry.general_flag = readShort(stream);
+ entry.compression = readShort(stream);
+ entry.lastmod_time = readShort(stream);
+ entry.lastmod_date = readShort(stream);
+ entry.crc32 = readInt(stream);
+ entry.compressed_size = readInt(stream);
+ entry.uncompressed_size = readInt(stream);
+ entry.filename_size = readShort(stream);
+ entry.extra_field_size = readShort(stream);
+ entry.file_comment_size = readShort(stream);
+ entry.disk_num = readShort(stream);
+ entry.internal_attr = readShort(stream);
+ entry.external_attr = readInt(stream);
+ entry.offset = readInt(stream);
+ unsigned short i = 0;
+ entry.filename.clear();
+ for (i=0; i < entry.filename_size; i++)
+ entry.filename.append(1,(char)readByte(stream));
+ entry.extra_field.clear();
+ for (i=0; i < entry.extra_field_size; i++)
+ entry.extra_field.append(1,(char)readByte(stream));
+ entry.file_comment.clear();
+ for (i=0; i < entry.file_comment_size; i++)
+ entry.file_comment.append(1,(char)readByte(stream));
+ }
+ catch (...)
+ {
+ return false;
+ }
+ return true;
+}
+
+static bool readLocalFileHeader(StreamInterface *stream, LocalFileHeader &header)
+{
+ try
+ {
+ unsigned signature = readInt(stream);
+ if (signature != LOC_FILE_HEADER_SIG)
+ return false;
+
+ header.min_version = readShort(stream);
+ header.general_flag = readShort(stream);
+ header.compression = readShort(stream);
+ header.lastmod_time = readShort(stream);
+ header.lastmod_date = readShort(stream);
+ header.crc32 = readInt(stream);
+ header.compressed_size = readInt(stream);
+ header.uncompressed_size = readInt(stream);
+ header.filename_size = readShort(stream);
+ header.extra_field_size = readShort(stream);
+ unsigned short i = 0;
+ header.filename.clear();
+ for (i=0; i < header.filename_size; i++)
+ header.filename.append(1,(char)readByte(stream));
+ header.extra_field.clear();
+ for (i=0; i < header.extra_field_size; i++)
+ header.extra_field.append(1,(char)readByte(stream));
+ }
+ catch (...)
+ {
+ return false;
+ }
+ return true;
+}
+
+static bool areHeadersConsistent(const LocalFileHeader &header, const CentralDirectoryEntry &entry)
+{
+ if (header.min_version != entry.min_version)
+ return false;
+ if (header.general_flag != entry.general_flag)
+ return false;
+ if (header.compression != entry.compression)
+ return false;
+ if (!(header.general_flag & 0x08))
+ {
+ if (header.crc32 != entry.crc32)
+ return false;
+ if (header.compressed_size != entry.compressed_size)
+ return false;
+ if (header.uncompressed_size != entry.uncompressed_size)
+ return false;
+ }
+ return true;
+}
+
+static bool findCentralDirectoryEnd(StreamInterface *stream, long &startOffset)
{
- /* for case in-sensitive string comparison */
- struct stricmp : public std::unary_function<std::string, bool>
+ stream->sseek(startOffset, SEEK_SET);
+ try
{
- stricmp(const std::string& str) : str_(str)
- {}
+ while (stream->stell() != -1)
+ {
+ unsigned signature = readInt(stream);
+ if (signature == CDIR_END_SIG)
+ {
+ stream->sseek(-4, SEEK_CUR);
+ startOffset = stream->stell();
+ return true;
+ }
+ else
+ stream->sseek(-3, SEEK_CUR);
+ }
+ }
+ catch (...)
+ {
+ return false;
+ }
+ return false;
+}
+
+static bool isZipStream(StreamInterface *stream, long &startOffset)
+{
+ if (!findCentralDirectoryEnd(stream, startOffset))
+ return false;
+ CentralDirectoryEnd end;
+ if (!readCentralDirectoryEnd(stream, end))
+ return false;
+ stream->sseek(end.cdir_offset, SEEK_SET);
+ CentralDirectoryEntry entry;
+ if (!readCentralDirectoryEntry(stream, entry))
+ return false;
+ stream->sseek(entry.offset, SEEK_SET);
+ LocalFileHeader header;
+ if (!readLocalFileHeader(stream, header))
+ return false;
+ if (!areHeadersConsistent(header, entry))
+ return false;
+ return true;
+}
+
+} // anonymous namespace
+
+namespace internal
+{
+/* for case in-sensitive string comparison */
+struct stricmp : public std::unary_function<std::string, bool>
+{
+ stricmp(const std::string &str) : str_(str)
+ {}
- bool operator() (const std::string& other)
- { return (0 == _stricmp(str_.c_str(), other.c_str())); }
+ bool operator() (const std::string &other)
+ {
+ return (0 == _stricmp(str_.c_str(), other.c_str()));
+ }
- std::string str_;
- };
+ std::string str_;
+};
} // namespace internal
/** Checks whether a file is a zip file or not
@@ -113,21 +385,26 @@ bool ZipFile::IsValidZipFileVersionNumber(void* /* stream*/)
WrongZipVersionException if the zip file cannot be uncompressed
with the used zlib version
*/
-ZipFile::ZipFile(const std::string& FileName)
+ZipFile::ZipFile(const std::string &FileName) :
+ m_pStream(0),
+ m_bShouldFree(true),
+ m_iStartOffset(0)
{
- m_uzFile = unzOpen(FileName.c_str());
-
- if (0 == m_uzFile)
- throw IOException(-1);
+ m_pStream = new FileStream(FileName.c_str());
+ if (m_pStream && !isZipStream(m_pStream, m_iStartOffset))
+ {
+ delete m_pStream;
+ m_pStream = 0;
+ }
}
-ZipFile::ZipFile(void* stream, zlib_filefunc_def* fa)
+ZipFile::ZipFile(StreamInterface *stream) :
+ m_pStream(stream),
+ m_bShouldFree(false),
+ m_iStartOffset(0)
{
- fa->opaque = stream;
- m_uzFile = unzOpen2((const char *)NULL, fa);
-
- if (0 == m_uzFile)
- throw IOException(-1);
+ if (!isZipStream(stream, m_iStartOffset))
+ m_pStream = 0;
}
@@ -135,41 +412,84 @@ ZipFile::ZipFile(void* stream, zlib_filefunc_def* fa)
*/
ZipFile::~ZipFile()
{
- unzClose(m_uzFile);
+ if (m_pStream && m_bShouldFree)
+ delete m_pStream;
}
+#define CHUNK 16384
+
/** Provides an interface to read the uncompressed data of a content of the zip file
@precond The specified content must exist in this file
ppstm must not be NULL
*/
void ZipFile::GetUncompressedContent(
- const std::string& ContentName, /*inout*/ ZipContentBuffer_t& ContentBuffer)
+ const std::string &ContentName, /*inout*/ ZipContentBuffer_t &ContentBuffer)
{
- int rc = unzLocateFile(m_uzFile, ContentName.c_str(), 0);
-
- if (UNZ_END_OF_LIST_OF_FILE == rc)
- throw ZipContentMissException(rc);
-
- unz_file_info finfo;
- unzGetCurrentFileInfo(m_uzFile, &finfo, 0, 0, 0, 0, 0, 0);
-
- ContentBuffer.resize(finfo.uncompressed_size);
-
- rc = unzOpenCurrentFile(m_uzFile);
-
- if (UNZ_OK != rc)
- throw ZipException(rc);
-
- rc = unzReadCurrentFile(m_uzFile, &ContentBuffer[0], finfo.uncompressed_size);
-
- if (rc < 0)
- throw ZipException(rc);
-
- rc = unzCloseCurrentFile(m_uzFile);
-
- if (rc < 0)
- throw ZipException(rc);
+ long startOffset = m_iStartOffset;
+ if (!findCentralDirectoryEnd(m_pStream, startOffset))
+ return;
+ CentralDirectoryEnd end;
+ if (!readCentralDirectoryEnd(m_pStream, end))
+ return;
+ m_pStream->sseek(end.cdir_offset, SEEK_SET);
+ CentralDirectoryEntry entry;
+ while (m_pStream->stell() != -1 && m_pStream->stell() < startOffset && (unsigned long)m_pStream->stell() < end.cdir_offset + end.cdir_size)
+ {
+ if (!readCentralDirectoryEntry(m_pStream, entry))
+ return;
+ if (ContentName.length() == entry.filename_size && !_stricmp(entry.filename.c_str(), ContentName.c_str()))
+ break;
+ }
+ if (ContentName.length() != entry.filename_size)
+ return;
+ if (_stricmp(entry.filename.c_str(), ContentName.c_str()))
+ return;
+ m_pStream->sseek(entry.offset, SEEK_SET);
+ LocalFileHeader header;
+ if (!readLocalFileHeader(m_pStream, header))
+ return;
+ if (!areHeadersConsistent(header, entry))
+ return;
+ ContentBuffer.clear();
+ ContentBuffer = ZipContentBuffer_t(entry.uncompressed_size);
+ if (!entry.compression)
+ m_pStream->sread((unsigned char *)&ContentBuffer[0], entry.uncompressed_size);
+ else
+ {
+ int ret;
+ z_stream strm;
+
+ /* allocate inflate state */
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+ ret = inflateInit(&strm);
+ if (ret != Z_OK)
+ return;
+
+ std::vector<unsigned char> tmpBuffer(entry.compressed_size);
+ if (entry.compressed_size != m_pStream->sread(&tmpBuffer[0], entry.compressed_size))
+ return;
+
+ strm.avail_in = entry.compressed_size;
+ strm.next_in = reinterpret_cast<Bytef *>(&tmpBuffer[0]);
+
+ strm.avail_out = entry.uncompressed_size;
+ strm.next_out = reinterpret_cast<Bytef *>(&ContentBuffer[0]);
+ ret = inflate(&strm, Z_FINISH);
+ switch (ret)
+ {
+ case Z_NEED_DICT:
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ (void)inflateEnd(&strm);
+ ContentBuffer.clear();
+ return;
+ }
+ }
}
/** Returns a list with the content names contained within this file
@@ -178,36 +498,28 @@ void ZipFile::GetUncompressedContent(
ZipFile::DirectoryPtr_t ZipFile::GetDirectory() const
{
DirectoryPtr_t dir(new Directory_t());
-
- long lmax = GetFileLongestFileNameLength() + 1;
- char* szFileName = reinterpret_cast<char*>(_alloca(lmax));
-
- if (!szFileName)
- throw ZipException(ERROR_NOT_ENOUGH_MEMORY);
-
- int rc = unzGoToFirstFile(m_uzFile);
-
- while (UNZ_OK == rc && UNZ_END_OF_LIST_OF_FILE != rc)
+ long startOffset = m_iStartOffset;
+ if (!findCentralDirectoryEnd(m_pStream, startOffset))
+ return dir;
+ CentralDirectoryEnd end;
+ if (!readCentralDirectoryEnd(m_pStream, end))
+ return dir;
+ m_pStream->sseek(end.cdir_offset, SEEK_SET);
+ CentralDirectoryEntry entry;
+ while (m_pStream->stell() != -1 && m_pStream->stell() < startOffset && (unsigned long)m_pStream->stell() < end.cdir_offset + end.cdir_size)
{
- unz_file_info finfo;
- unzGetCurrentFileInfo(
- m_uzFile, &finfo, szFileName, lmax, 0, 0, 0, 0);
-
- dir->push_back(szFileName);
-
- rc = unzGoToNextFile(m_uzFile);
+ if (!readCentralDirectoryEntry(m_pStream, entry))
+ return dir;
+ if (entry.filename_size)
+ dir->push_back(entry.filename);
}
-
- if (UNZ_OK != rc && UNZ_END_OF_LIST_OF_FILE != rc)
- throw ZipException(rc);
-
return dir;
}
/** Convinience query function may even realized with
iterating over a ZipFileDirectory returned by
GetDirectory */
-bool ZipFile::HasContent(const std::string& ContentName) const
+bool ZipFile::HasContent(const std::string &ContentName) const
{
//#i34314# we need to compare package content names
//case in-sensitive as it is not defined that such
@@ -226,20 +538,21 @@ bool ZipFile::HasContent(const std::string& ContentName) const
long ZipFile::GetFileLongestFileNameLength() const
{
long lmax = 0;
- unz_file_info finfo;
-
- int rc = unzGoToFirstFile(m_uzFile);
-
- while (UNZ_OK == rc && UNZ_END_OF_LIST_OF_FILE != rc)
+ long startOffset = m_iStartOffset;
+ if (!findCentralDirectoryEnd(m_pStream, startOffset))
+ return lmax;
+ CentralDirectoryEnd end;
+ if (!readCentralDirectoryEnd(m_pStream, end))
+ return lmax;
+ m_pStream->sseek(end.cdir_offset, SEEK_SET);
+ CentralDirectoryEntry entry;
+ while (m_pStream->stell() != -1 && m_pStream->stell() < startOffset && (unsigned long)m_pStream->stell() < end.cdir_offset + end.cdir_size)
{
- unzGetCurrentFileInfo(m_uzFile, &finfo, 0, 0, 0, 0, 0, 0);
- lmax = std::max<long>(lmax, finfo.size_filename);
- rc = unzGoToNextFile(m_uzFile);
+ if (!readCentralDirectoryEntry(m_pStream, entry))
+ return lmax;
+ if (entry.filename_size > lmax)
+ lmax = entry.filename_size;
}
-
- if (UNZ_OK != rc && UNZ_END_OF_LIST_OF_FILE != rc)
- throw ZipException(rc);
-
return lmax;
}