Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

ZIPFile.cpp

Go to the documentation of this file.
00001 //
00002 // ZIPFile.cpp
00003 //
00004 // Copyright (c) Shareaza Development Team, 2002-2005.
00005 // This file is part of SHAREAZA (www.shareaza.com)
00006 //
00007 // Shareaza is free software; you can redistribute it
00008 // and/or modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2 of
00010 // the License, or (at your option) any later version.
00011 //
00012 // Shareaza is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with Shareaza; if not, write to the Free Software
00019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 //
00021 
00022 #include "StdAfx.h"
00023 #include "ZIPFile.h"
00024 #include "Buffer.h"
00025 #include <zlib.h>
00026 
00027 
00029 // CZIPFile construction
00030 
00031 CZIPFile::CZIPFile(HANDLE hAttach)
00032 {
00033         m_bAttach       = FALSE;
00034         m_hFile         = INVALID_HANDLE_VALUE;
00035         m_pFile         = NULL;
00036         m_nFile         = 0;
00037 
00038         if ( hAttach != INVALID_HANDLE_VALUE ) Attach( hAttach );
00039 }
00040 
00041 CZIPFile::~CZIPFile()
00042 {
00043         Close();
00044 }
00045 
00047 // CZIPFile open
00048 
00049 BOOL CZIPFile::Open(LPCTSTR pszFile)
00050 {
00051         ASSERT( pszFile != NULL );
00052 
00053         Close();
00054 
00055         m_bAttach = FALSE;
00056         m_hFile = CreateFile( pszFile, GENERIC_READ, FILE_SHARE_READ, NULL,
00057                 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
00058         if ( m_hFile == INVALID_HANDLE_VALUE ) return FALSE;
00059 
00060         if ( LocateCentralDirectory() )
00061         {
00062                 return TRUE;
00063         }
00064         else
00065         {
00066                 Close();
00067                 return FALSE;
00068         }
00069 }
00070 
00072 // CZIPFile attach
00073 
00074 BOOL CZIPFile::Attach(HANDLE hFile)
00075 {
00076         ASSERT( hFile != INVALID_HANDLE_VALUE );
00077 
00078         Close();
00079 
00080         m_bAttach       = TRUE;
00081         m_hFile         = hFile;
00082 
00083         if ( LocateCentralDirectory() )
00084         {
00085                 return TRUE;
00086         }
00087         else
00088         {
00089                 Close();
00090                 return FALSE;
00091         }
00092 }
00093 
00095 // CZIPFile open test
00096 
00097 BOOL CZIPFile::IsOpen() const
00098 {
00099         return m_hFile != INVALID_HANDLE_VALUE;
00100 }
00101 
00103 // CZIPFile close
00104 
00105 void CZIPFile::Close()
00106 {
00107         if ( m_hFile != INVALID_HANDLE_VALUE )
00108         {
00109                 if ( ! m_bAttach ) CloseHandle( m_hFile );
00110                 m_hFile = INVALID_HANDLE_VALUE;
00111         }
00112 
00113         if ( m_pFile != NULL ) delete [] m_pFile;
00114         m_pFile = NULL;
00115         m_nFile = 0;
00116 }
00117 
00119 // CZIPFile get the file count
00120 
00121 int CZIPFile::GetCount() const
00122 {
00123         return m_nFile;
00124 }
00125 
00127 // CZIPFile get a particular file
00128 
00129 CZIPFile::File* CZIPFile::GetFile(int nFile) const
00130 {
00131         return ( nFile < 0 || nFile >= m_nFile ) ? NULL : m_pFile + nFile;
00132 }
00133 
00135 // CZIPFile lookup a file by name
00136 
00137 CZIPFile::File* CZIPFile::GetFile(LPCTSTR pszFile, BOOL bPartial) const
00138 {
00139         File* pFile = m_pFile;
00140 
00141         for ( int nFile = m_nFile ; nFile ; nFile--, pFile++ )
00142         {
00143                 if ( bPartial )
00144                 {
00145                         LPCTSTR pszName = _tcsrchr( pFile->m_sName, '/' );
00146                         pszName = pszName ? pszName + 1 : (LPCTSTR)pFile->m_sName;
00147                         if ( _tcsicoll( pszName, pszFile ) == 0 ) return pFile;
00148                 }
00149                 else
00150                 {
00151                         if ( _tcsicoll( pFile->m_sName, pszFile ) == 0 ) return pFile;
00152                 }
00153         }
00154 
00155         return NULL;
00156 }
00157 
00159 // CZIPFile locate the central directory
00160 
00161 #pragma pack(1)
00162 typedef struct
00163 {
00164         DWORD   nSignature;                     // 0x06054b50
00165         WORD    nThisDisk;
00166         WORD    nDirectoryDisk;
00167         WORD    nFilesThisDisk;
00168         WORD    nTotalFiles;
00169         DWORD   nDirectorySize;
00170         DWORD   nDirectoryOffset;
00171         WORD    nCommentLen;
00172 } ZIP_DIRECTORY_LOC;
00173 #pragma pack()
00174 
00175 BOOL CZIPFile::LocateCentralDirectory()
00176 {
00177         BYTE pBuffer[4096];
00178         DWORD nBuffer = 0;
00179 
00180         SetFilePointer( m_hFile, -4096, NULL, FILE_END );
00181         if ( ! ReadFile( m_hFile, pBuffer, 4096, &nBuffer, NULL ) ) return FALSE;
00182         if ( nBuffer < sizeof(ZIP_DIRECTORY_LOC) ) return FALSE;
00183 
00184         ZIP_DIRECTORY_LOC* pLoc = NULL;
00185 
00186         for ( DWORD nScan = 4 ; nScan < nBuffer ; nScan++ )
00187         {
00188                 DWORD* pnSignature = (DWORD*)( pBuffer + nBuffer - nScan  );
00189 
00190                 if ( *pnSignature == 0x06054b50 )
00191                 {
00192                         pLoc = (ZIP_DIRECTORY_LOC*)pnSignature;
00193                         break;
00194                 }
00195         }
00196 
00197         if ( pLoc == NULL ) return FALSE;
00198         ASSERT( pLoc->nSignature == 0x06054b50 );
00199 
00200         if ( GetFileSize( m_hFile, NULL ) < pLoc->nDirectorySize ) return FALSE;
00201 
00202         if ( SetFilePointer( m_hFile, pLoc->nDirectoryOffset, NULL, FILE_BEGIN )
00203                  != pLoc->nDirectoryOffset ) return FALSE;
00204 
00205         BYTE* pDirectory = new BYTE[ pLoc->nDirectorySize ];
00206         ReadFile( m_hFile, pDirectory, pLoc->nDirectorySize, &nBuffer, NULL );
00207 
00208         if ( nBuffer == pLoc->nDirectorySize )
00209         {
00210                 m_nFile = (int)pLoc->nTotalFiles;
00211                 m_pFile = new File[ m_nFile ];
00212 
00213                 if ( ! ParseCentralDirectory( pDirectory, pLoc->nDirectorySize ) )
00214                 {
00215                         delete [] m_pFile;
00216                         m_pFile = NULL;
00217                         m_nFile = 0;
00218                 }
00219         }
00220 
00221         delete [] pDirectory;
00222 
00223         return ( m_nFile > 0 );
00224 }
00225 
00227 // CZIPFile parse the central directory
00228 
00229 #pragma pack(1)
00230 typedef struct
00231 {
00232         DWORD   nSignature;             // 0x02014b50
00233         WORD    nWriteVersion;
00234         WORD    nReadVersion;
00235         WORD    nFlags;
00236         WORD    nCompression;
00237         WORD    nFileTime;
00238         WORD    nFileDate;
00239         DWORD   nCRC;
00240         DWORD   nCompressedSize;
00241         DWORD   nActualSize;
00242         WORD    nNameLen;
00243         WORD    nExtraLen;
00244         WORD    nCommentLen;
00245         WORD    nStartDisk;
00246         WORD    nInternalAttr;
00247         DWORD   nExternalAttr;
00248         DWORD   nLocalOffset;
00249 } ZIP_CENTRAL_FILE;
00250 #pragma pack()
00251 
00252 BOOL CZIPFile::ParseCentralDirectory(BYTE* pDirectory, DWORD nDirectory)
00253 {
00254         for ( int nFile = 0 ; nFile < m_nFile ; nFile++ )
00255         {
00256                 ZIP_CENTRAL_FILE* pRecord = (ZIP_CENTRAL_FILE*)pDirectory;
00257 
00258                 if ( nDirectory < sizeof(*pRecord) ) return FALSE;
00259                 if ( pRecord->nSignature != 0x02014b50 ) return FALSE;
00260 
00261                 pDirectory += sizeof(*pRecord);
00262                 nDirectory -= sizeof(*pRecord);
00263 
00264                 int nTailLen = (int)pRecord->nNameLen + (int)pRecord->nExtraLen + (int)pRecord->nCommentLen;
00265                 if ( nDirectory < (DWORD)nTailLen ) return FALSE;
00266 
00267                 m_pFile[ nFile ].m_pZIP                         = this;
00268                 m_pFile[ nFile ].m_nSize                        = pRecord->nActualSize;
00269                 m_pFile[ nFile ].m_nLocalOffset         = pRecord->nLocalOffset;
00270                 m_pFile[ nFile ].m_nCompressedSize      = pRecord->nCompressedSize;
00271                 m_pFile[ nFile ].m_nCompression         = pRecord->nCompression;
00272 
00273                 LPTSTR pszName = m_pFile[ nFile ].m_sName.GetBuffer( pRecord->nNameLen );
00274 
00275                 for ( WORD nChar = 0 ; nChar < pRecord->nNameLen ; nChar++ )
00276                 {
00277                         pszName[ nChar ] = (TCHAR)pDirectory[ nChar ];
00278                         if ( pszName[ nChar ] == '\\' ) pszName[ nChar ] = '/';
00279                 }
00280 
00281                 m_pFile[ nFile ].m_sName.ReleaseBuffer( pRecord->nNameLen );
00282 
00283                 pDirectory += (DWORD)nTailLen;
00284                 nDirectory -= (DWORD)nTailLen;
00285         }
00286 
00287         return TRUE;
00288 }
00289 
00291 // CZIPFile::File seek to a file
00292 
00293 #pragma pack(1)
00294 typedef struct
00295 {
00296         DWORD   nSignature;             // 0x04034b50
00297         WORD    nVersion;
00298         WORD    nFlags;
00299         WORD    nCompression;
00300         WORD    nFileTime;
00301         WORD    nFileDate;
00302         DWORD   nCRC;
00303         DWORD   nCompressedSize;
00304         DWORD   nActualSize;
00305         WORD    nNameLen;
00306         WORD    nExtraLen;
00307 } ZIP_LOCAL_FILE;
00308 #pragma pack()
00309 
00310 BOOL CZIPFile::SeekToFile(File* pFile)
00311 {
00312         ASSERT( this != NULL );
00313         ASSERT( pFile != NULL );
00314         ASSERT( pFile->m_pZIP == this );
00315 
00316         if ( m_hFile == INVALID_HANDLE_VALUE ) return FALSE;
00317 
00318         if ( SetFilePointer( m_hFile, (DWORD)pFile->m_nLocalOffset, NULL, FILE_BEGIN )
00319                  != pFile->m_nLocalOffset ) return FALSE;
00320 
00321         ZIP_LOCAL_FILE pLocal;
00322         DWORD nRead = 0;
00323 
00324         ReadFile( m_hFile, &pLocal, sizeof(pLocal), &nRead, NULL );
00325         if ( nRead != sizeof(pLocal) ) return FALSE;
00326 
00327         if ( pLocal.nSignature != 0x04034b50 ) return FALSE;
00328         if ( pLocal.nCompression != Z_DEFLATED && pLocal.nCompression != 0 ) return FALSE;
00329 
00330         SetFilePointer( m_hFile, pLocal.nNameLen + pLocal.nExtraLen, NULL, FILE_CURRENT );
00331 
00332         return TRUE;
00333 }
00334 
00336 // CZIPFile::File prepare to decompress
00337 
00338 BOOL CZIPFile::File::PrepareToDecompress(LPVOID pStream)
00339 {
00340         ZeroMemory( pStream, sizeof(z_stream) );
00341 
00342         if ( ! m_pZIP->SeekToFile( this ) ) return FALSE;
00343 
00344         if ( m_nCompression == 0 )
00345         {
00346                 return ( m_nSize == m_nCompressedSize );
00347         }
00348         else
00349         {
00350                 ASSERT( m_nCompression == Z_DEFLATED );
00351                 return Z_OK == inflateInit2( (z_stream*)pStream, -MAX_WBITS );
00352         }
00353 }
00354 
00356 // CZIPFile::File decompress to memory
00357 
00358 CBuffer* CZIPFile::File::Decompress()
00359 {
00360         z_stream pStream;
00361 
00362         if ( m_nSize > 32*1024*1024 ) return NULL;
00363         if ( ! PrepareToDecompress( &pStream ) ) return NULL;
00364 
00365         if ( m_nCompression == 0 )
00366         {
00367                 CBuffer* pTarget = new CBuffer();
00368                 pTarget->EnsureBuffer( (DWORD)m_nSize );
00369                 ReadFile( m_pZIP->m_hFile, pTarget->m_pBuffer, (DWORD)m_nSize, &pTarget->m_nLength, NULL );
00370                 if ( pTarget->m_nLength == (DWORD)m_nSize ) return pTarget;
00371                 delete pTarget;
00372                 return NULL;
00373         }
00374 
00375         DWORD nSource = (DWORD)m_nCompressedSize;
00376         BYTE* pSource = new BYTE[ nSource ];
00377         ReadFile( m_pZIP->m_hFile, pSource, nSource, &nSource, NULL );
00378 
00379         if ( nSource != (DWORD)m_nCompressedSize )
00380         {
00381                 inflateEnd( &pStream );
00382                 return NULL;
00383         }
00384 
00385         CBuffer* pTarget = new CBuffer();
00386         pTarget->EnsureBuffer( (DWORD)m_nSize );
00387         pTarget->m_nLength = (DWORD)m_nSize;
00388 
00389         pStream.next_in         = pSource;
00390         pStream.avail_in        = (DWORD)m_nCompressedSize;
00391         pStream.next_out        = pTarget->m_pBuffer;
00392         pStream.avail_out       = pTarget->m_nLength;
00393 
00394         inflate( &pStream, Z_FINISH );
00395 
00396         delete [] pSource;
00397 
00398         if ( pStream.avail_out != 0 )
00399         {
00400                 delete pTarget;
00401                 pTarget = NULL;
00402         }
00403 
00404         inflateEnd( &pStream );
00405 
00406         return pTarget;
00407 }
00408 
00410 // CZIPFile::File decompress to disk
00411 
00412 #define BUFFER_IN_SIZE          (64*1024)
00413 #define BUFFER_OUT_SIZE         (128*1024)
00414 
00415 BOOL CZIPFile::File::Extract(LPCTSTR pszFile)
00416 {
00417         z_stream pStream;
00418         HANDLE hFile;
00419 
00420         hFile = CreateFile( pszFile, GENERIC_WRITE, 0, NULL, CREATE_NEW,
00421                 FILE_ATTRIBUTE_NORMAL, NULL );
00422         if ( hFile == INVALID_HANDLE_VALUE ) return FALSE;
00423 
00424         if ( ! PrepareToDecompress( &pStream ) ) return NULL;
00425 
00426         QWORD nCompressed = 0, nUncompressed = 0;
00427 
00428         if ( m_nCompression == Z_DEFLATED )
00429         {
00430                 BYTE* pBufferIn         = new BYTE[BUFFER_IN_SIZE];
00431                 BYTE* pBufferOut        = new BYTE[BUFFER_OUT_SIZE];
00432 
00433                 while ( nCompressed < m_nCompressedSize || nUncompressed < m_nSize )
00434                 {
00435                         if ( pStream.avail_in == 0 )
00436                         {
00437                                 pStream.avail_in        = (DWORD)min( m_nCompressedSize - nCompressed, QWORD(BUFFER_IN_SIZE) );
00438                                 pStream.next_in         = pBufferIn;
00439 
00440                                 DWORD nRead = 0;
00441                                 ReadFile( m_pZIP->m_hFile, pBufferIn, pStream.avail_in, &nRead, NULL );
00442                                 if ( nRead != pStream.avail_in ) break;
00443                                 nCompressed += nRead;
00444                         }
00445 
00446                         pStream.avail_out       = BUFFER_OUT_SIZE;
00447                         pStream.next_out        = pBufferOut;
00448 
00449                         int nInflate = inflate( &pStream, Z_SYNC_FLUSH );
00450 
00451                         if ( pStream.avail_out < BUFFER_OUT_SIZE )
00452                         {
00453                                 DWORD nWrite = BUFFER_OUT_SIZE - pStream.avail_out;
00454                                 WriteFile( hFile, pBufferOut, nWrite, &nWrite, NULL );
00455                                 if ( nWrite != BUFFER_OUT_SIZE - pStream.avail_out ) break;
00456                                 nUncompressed += nWrite;
00457                         }
00458                 }
00459 
00460                 delete [] pBufferOut;
00461                 delete [] pBufferIn;
00462 
00463                 inflateEnd( &pStream );
00464         }
00465         else
00466         {
00467                 BYTE* pBufferOut = new BYTE[BUFFER_OUT_SIZE];
00468 
00469                 while ( nUncompressed < m_nSize )
00470                 {
00471                         DWORD nChunk = (DWORD)min( m_nSize - nUncompressed, QWORD(BUFFER_OUT_SIZE) );
00472                         DWORD nProcess = 0;
00473 
00474                         ReadFile( m_pZIP->m_hFile, pBufferOut, nChunk, &nProcess, NULL );
00475                         if ( nChunk != nProcess ) break;
00476                         WriteFile( hFile, pBufferOut, nChunk, &nProcess, NULL );
00477                         if ( nChunk != nProcess ) break;
00478 
00479                         nCompressed += nChunk;
00480                         nUncompressed += nChunk;
00481                 }
00482 
00483                 delete [] pBufferOut;
00484         }
00485 
00486         CloseHandle( hFile );
00487 
00488         if ( nUncompressed >= m_nSize ) return TRUE;
00489 
00490         DeleteFile( pszFile );
00491         return FALSE;
00492 }
00493 

Generated on Thu Dec 15 10:39:54 2005 for Shareaza 2.2.1.0 by  doxygen 1.4.2