diff options
author | Fridrich Štrba <fridrich.strba@bluewin.ch> | 2012-03-19 15:09:34 +0100 |
---|---|---|
committer | Fridrich Štrba <fridrich.strba@bluewin.ch> | 2012-03-19 15:22:55 +0100 |
commit | 04366df3bca16d4e0cbe254551e44427ae6338bb (patch) | |
tree | 92fcb6ed5e6f877aecd53777b07c389f643b710e /shell | |
parent | Workaround a strange wine / mingw crash. (diff) | |
download | core-04366df3bca16d4e0cbe254551e44427ae6338bb.tar.gz core-04366df3bca16d4e0cbe254551e44427ae6338bb.zip |
Simple Zip file-format implementation to avoid the need of minizip
Diffstat (limited to 'shell')
-rw-r--r-- | shell/inc/internal/basereader.hxx | 2 | ||||
-rw-r--r-- | shell/inc/internal/contentreader.hxx | 3 | ||||
-rw-r--r-- | shell/inc/internal/metainforeader.hxx | 2 | ||||
-rw-r--r-- | shell/inc/internal/stream_helper.hxx | 24 | ||||
-rw-r--r-- | shell/inc/internal/types.hxx | 17 | ||||
-rw-r--r-- | shell/inc/internal/zipfile.hxx | 29 | ||||
-rw-r--r-- | shell/source/win32/ooofilereader/basereader.cxx | 4 | ||||
-rw-r--r-- | shell/source/win32/ooofilereader/contentreader.cxx | 4 | ||||
-rw-r--r-- | shell/source/win32/ooofilereader/metainforeader.cxx | 4 | ||||
-rw-r--r-- | shell/source/win32/shlxthandler/makefile.mk | 2 | ||||
-rw-r--r-- | shell/source/win32/shlxthandler/ooofilt/ooofilt.cxx | 11 | ||||
-rw-r--r-- | shell/source/win32/shlxthandler/ooofilt/ooofilt.hxx | 2 | ||||
-rw-r--r-- | shell/source/win32/shlxthandler/ooofilt/stream_helper.cxx | 190 | ||||
-rw-r--r-- | shell/source/win32/shlxthandler/prophdl/propertyhdl.cxx | 5 | ||||
-rw-r--r-- | shell/source/win32/zipfile/zipfile.cxx | 473 |
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; } |