00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "StdAfx.h"
00023 #include "ZIPFile.h"
00024 #include "Buffer.h"
00025 #include <zlib.h>
00026
00027
00029
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
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
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
00096
00097 BOOL CZIPFile::IsOpen() const
00098 {
00099 return m_hFile != INVALID_HANDLE_VALUE;
00100 }
00101
00103
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
00120
00121 int CZIPFile::GetCount() const
00122 {
00123 return m_nFile;
00124 }
00125
00127
00128
00129 CZIPFile::File* CZIPFile::GetFile(int nFile) const
00130 {
00131 return ( nFile < 0 || nFile >= m_nFile ) ? NULL : m_pFile + nFile;
00132 }
00133
00135
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
00160
00161 #pragma pack(1)
00162 typedef struct
00163 {
00164 DWORD nSignature;
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
00228
00229 #pragma pack(1)
00230 typedef struct
00231 {
00232 DWORD nSignature;
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
00292
00293 #pragma pack(1)
00294 typedef struct
00295 {
00296 DWORD nSignature;
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
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
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
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