From 0d8dceea4310fde5706b3ce1c70609d72a38efdf Mon Sep 17 00:00:00 2001 From: John Schoenick Date: Wed, 9 Sep 2015 18:35:41 -0700 Subject: Updated the SDK with the latest code from the TF and HL2 branches. --- mp/src/public/zip_utils.cpp | 439 ++++++++++++++++++++++++++++---------------- 1 file changed, 277 insertions(+), 162 deletions(-) (limited to 'mp/src/public/zip_utils.cpp') diff --git a/mp/src/public/zip_utils.cpp b/mp/src/public/zip_utils.cpp index 79f51c5c..848e7a79 100644 --- a/mp/src/public/zip_utils.cpp +++ b/mp/src/public/zip_utils.cpp @@ -23,6 +23,13 @@ #include "byteswap.h" #include "utlstring.h" +#include "tier1/lzmaDecoder.h" + +// Not every user of zip utils wants to link LZMA encoder +#ifdef ZIP_SUPPORT_LZMA_ENCODE +#include "lzma/lzma.h" +#endif + // Data descriptions for byte swapping - only needed // for structures that are written to file for use by the game. BEGIN_BYTESWAP_DATADESC( ZIP_EndOfCentralDirRecord ) @@ -248,7 +255,7 @@ public: CBufferStream( CUtlBuffer& buff ) : IWriteStream(), m_buff( &buff ) {} // Implementing IWriteStream method - virtual void Put( const void* pMem, int size ) { m_buff->Put( pMem, size ); } + virtual void Put( const void* pMem, int size ) {m_buff->Put( pMem, size );} // Implementing IWriteStream method virtual unsigned int Tell( void ) { return m_buff->TellPut(); } @@ -321,13 +328,13 @@ public: void Reset( void ); // Add file to zip under relative name - void AddFileToZip( const char *relativename, const char *fullpath ); + void AddFileToZip( const char *relativename, const char *fullpath, IZip::eCompressionType compressionType ); // Delete file from zip void RemoveFileFromZip( const char *relativename ); // Add buffer to zip as a file with given name - void AddBufferToZip( const char *relativename, void *data, int length, bool bTextMode ); + void AddBufferToZip( const char *relativename, void *data, int length, bool bTextMode, IZip::eCompressionType compressionType ); // Check if a file already exists in the zip. bool FileExistsInZip( const char *relativename ); @@ -373,9 +380,12 @@ private: typedef struct { - CUtlSymbol m_Name; - unsigned int filepos; - int filelen; + CUtlSymbol m_Name; + unsigned int filepos; + int filelen; + int uncompressedLen; + CRC32_t crc32; + IZip::eCompressionType compressionType; } TmpFileInfo_t; CByteswap m_Swap; @@ -405,18 +415,25 @@ private: CUtlSymbol m_Name; // Lenth of data element - int m_Length; + int m_nCompressedSize; + + // Original, uncompressed size + int m_nUncompressedSize; + // Raw data, could be null and data may be in disk write cache void *m_pData; // Offset in Zip ( set and valid during final write ) unsigned int m_ZipOffset; - // CRC of blob ( set and valid during final write ) + // CRC of blob CRC32_t m_ZipCRC; // Location of data in disk cache unsigned int m_DiskCacheOffset; unsigned int m_SourceDiskOffset; + + // The compression used on the data if any + IZip::eCompressionType m_eCompressionType; }; // For fast name lookup and sorting @@ -435,12 +452,14 @@ private: CZipFile::CZipEntry::CZipEntry( void ) { m_Name = ""; - m_Length = 0; + m_nCompressedSize = 0; + m_nUncompressedSize = 0; m_pData = NULL; m_ZipOffset = 0; m_ZipCRC = 0; m_DiskCacheOffset = 0; m_SourceDiskOffset = 0; + m_eCompressionType = IZip::eCompressionType_None; } //----------------------------------------------------------------------------- @@ -450,12 +469,14 @@ CZipFile::CZipEntry::CZipEntry( void ) CZipFile::CZipEntry::CZipEntry( const CZipFile::CZipEntry& src ) { m_Name = src.m_Name; - m_Length = src.m_Length; + m_nCompressedSize = src.m_nCompressedSize; + m_nUncompressedSize = src.m_nUncompressedSize; + m_eCompressionType = src.m_eCompressionType; - if ( src.m_Length > 0 && src.m_pData ) + if ( src.m_nCompressedSize > 0 && src.m_pData ) { - m_pData = malloc( src.m_Length ); - memcpy( m_pData, src.m_pData, src.m_Length ); + m_pData = malloc( src.m_nCompressedSize ); + memcpy( m_pData, src.m_pData, src.m_nCompressedSize ); } else { @@ -674,20 +695,27 @@ void CZipFile::ParseFromBuffer( void *buffer, int bufferlength ) ZIP_FileHeader zipFileHeader; buf.GetObjects( &zipFileHeader ); Assert( zipFileHeader.signature == PKID( 1, 2 ) ); - Assert( zipFileHeader.compressionMethod == 0 ); - - char tmpString[1024]; - buf.Get( tmpString, zipFileHeader.fileNameLength ); - tmpString[zipFileHeader.fileNameLength] = '\0'; + if ( zipFileHeader.compressionMethod != IZip::eCompressionType_None && + zipFileHeader.compressionMethod != IZip::eCompressionType_LZMA ) + { + Assert( false ); + Warning( "Opening ZIP file with unsupported compression type\n"); + } + + char tmpString[1024] = { 0 }; + buf.Get( tmpString, Min( (unsigned int)zipFileHeader.fileNameLength, (unsigned int)sizeof( tmpString ) ) ); Q_strlower( tmpString ); // can determine actual filepos, assuming a well formed zip newfiles[i].m_Name = tmpString; newfiles[i].filelen = zipFileHeader.compressedSize; + newfiles[i].uncompressedLen = zipFileHeader.uncompressedSize; + newfiles[i].crc32 = zipFileHeader.crc32; newfiles[i].filepos = zipFileHeader.relativeOffsetOfLocalHeader + - sizeof( ZIP_LocalFileHeader ) + - zipFileHeader.fileNameLength + - zipFileHeader.extraFieldLength; + sizeof( ZIP_LocalFileHeader ) + + zipFileHeader.fileNameLength + + zipFileHeader.extraFieldLength; + newfiles[i].compressionType = (IZip::eCompressionType)zipFileHeader.compressionMethod; int nextOffset; if ( m_bCompatibleFormat ) @@ -706,16 +734,19 @@ void CZipFile::ParseFromBuffer( void *buffer, int bufferlength ) { CZipEntry e; e.m_Name = newfiles[i].m_Name; - e.m_Length = newfiles[i].filelen; - + e.m_nCompressedSize = newfiles[i].filelen; + e.m_ZipCRC = newfiles[i].crc32; + e.m_nUncompressedSize = newfiles[i].uncompressedLen; + e.m_eCompressionType = newfiles[i].compressionType; + // Make sure length is reasonable - if ( e.m_Length > 0 ) + if ( e.m_nCompressedSize > 0 ) { - e.m_pData = malloc( e.m_Length ); + e.m_pData = malloc( e.m_nCompressedSize ); // Copy in data buf.SeekGet( CUtlBuffer::SEEK_HEAD, newfiles[i].filepos ); - buf.Get( e.m_pData, e.m_Length ); + buf.Get( e.m_pData, e.m_nCompressedSize ); } else { @@ -826,7 +857,9 @@ HANDLE CZipFile::ParseFromDisk( const char *pFilename ) ZIP_FileHeader zipFileHeader; zipDirBuff.GetObjects( &zipFileHeader ); - if ( zipFileHeader.signature != PKID( 1, 2 ) || zipFileHeader.compressionMethod != 0 ) + if ( zipFileHeader.signature != PKID( 1, 2 ) + || ( zipFileHeader.compressionMethod != IZip::eCompressionType_None + && zipFileHeader.compressionMethod != IZip::eCompressionType_LZMA ) ) { // bad contents #ifdef WIN32 @@ -836,7 +869,7 @@ HANDLE CZipFile::ParseFromDisk( const char *pFilename ) #endif return NULL; } - + char fileName[1024]; zipDirBuff.Get( fileName, zipFileHeader.fileNameLength ); fileName[zipFileHeader.fileNameLength] = '\0'; @@ -845,11 +878,15 @@ HANDLE CZipFile::ParseFromDisk( const char *pFilename ) // can determine actual filepos, assuming a well formed zip CZipEntry e; e.m_Name = fileName; - e.m_Length = zipFileHeader.compressedSize; + e.m_nCompressedSize = zipFileHeader.compressedSize; + e.m_nUncompressedSize = zipFileHeader.uncompressedSize; + e.m_ZipCRC = zipFileHeader.crc32; e.m_SourceDiskOffset = zipFileHeader.relativeOffsetOfLocalHeader + - sizeof( ZIP_LocalFileHeader ) + - zipFileHeader.fileNameLength + - zipFileHeader.extraFieldLength; + sizeof( ZIP_LocalFileHeader ) + + zipFileHeader.fileNameLength + + zipFileHeader.extraFieldLength; + e.m_eCompressionType = (IZip::eCompressionType)zipFileHeader.compressionMethod; + // Add to tree m_Files.Insert( e ); @@ -954,19 +991,85 @@ static void CopyTextData( char *pDst, const char *pSrc, int dstSize, int srcSize // *data - // length - //----------------------------------------------------------------------------- -void CZipFile::AddBufferToZip( const char *relativename, void *data, int length, bool bTextMode ) +void CZipFile::AddBufferToZip( const char *relativename, void *data, int length, bool bTextMode, IZip::eCompressionType compressionType ) { // Lower case only char name[512]; Q_strcpy( name, relativename ); Q_strlower( name ); - int dstLength = length; + int outLength = length; + int uncompressedLength = length; + void *outData = data; + CUtlBuffer textTransform; + CUtlBuffer compressionTransform; + if ( bTextMode ) { - dstLength = GetLengthOfBinStringAsText( ( const char * )data, length ); + int textLen = GetLengthOfBinStringAsText( ( const char * )outData, outLength ); + textTransform.EnsureCapacity( textLen ); + CopyTextData( (char *)textTransform.Base(), (char *)outData, textLen, outLength ); + + outData = (void *)textTransform.Base(); + outLength = textLen; + uncompressedLength = textLen; } - + + // uncompressed data final at this point (CRC is before compression) + CRC32_t zipCRC; + CRC32_Init( &zipCRC ); + CRC32_ProcessBuffer( &zipCRC, outData, outLength ); + CRC32_Final( &zipCRC ); + +#ifdef ZIP_SUPPORT_LZMA_ENCODE + if ( compressionType == IZip::eCompressionType_LZMA ) + { + unsigned int compressedSize = 0; + unsigned char *pCompressedOutput = LZMA_Compress( (unsigned char *)outData, outLength, &compressedSize ); + if ( !pCompressedOutput || compressedSize < sizeof( lzma_header_t ) ) + { + Warning( "ZipFile: LZMA compression failed\n" ); + return; + } + + // Fixup LZMA header for ZIP payload usage + // The output of LZMA_Compress uses lzma_header_t, defined alongside it. + // + // ZIP payload format, see ZIP spec 5.8.8: + // LZMA Version Information 2 bytes + // LZMA Properties Size 2 bytes + // LZMA Properties Data variable, defined by "LZMA Properties Size" + unsigned int nZIPHeader = 2 + 2 + sizeof( lzma_header_t().properties ); + unsigned int finalCompressedSize = compressedSize - sizeof( lzma_header_t ) + nZIPHeader; + compressionTransform.EnsureCapacity( finalCompressedSize ); + + // LZMA version + compressionTransform.PutUnsignedChar( LZMA_SDK_VERSION_MAJOR ); + compressionTransform.PutUnsignedChar( LZMA_SDK_VERSION_MINOR ); + // properties size + uint16 nSwappedPropertiesSize = LittleWord( sizeof( lzma_header_t().properties ) ); + compressionTransform.Put( &nSwappedPropertiesSize, sizeof( nSwappedPropertiesSize ) ); + // properties + compressionTransform.Put( &(((lzma_header_t *)pCompressedOutput)->properties), sizeof( lzma_header_t().properties ) ); + // payload + compressionTransform.Put( pCompressedOutput + sizeof( lzma_header_t ), compressedSize - sizeof( lzma_header_t ) ); + + // Free original + free( pCompressedOutput ); + pCompressedOutput = NULL; + + outData = (void *)compressionTransform.Base(); + outLength = finalCompressedSize; + // (Not updating uncompressedLength) + } + else +#endif + /* else from ifdef */ if ( compressionType != IZip::eCompressionType_None ) + { + Error( "Calling AddBufferToZip with unknown compression type\n" ); + return; + } + // See if entry is in list already CZipEntry e; e.m_Name = name; @@ -981,23 +1084,17 @@ void CZipFile::AddBufferToZip( const char *relativename, void *data, int length, free( update->m_pData ); } - if ( bTextMode ) - { - update->m_pData = malloc( dstLength ); - CopyTextData( ( char * )update->m_pData, ( char * )data, dstLength, length ); - update->m_Length = dstLength; - } - else - { - update->m_pData = malloc( length ); - memcpy( update->m_pData, data, length ); - update->m_Length = length; - } + update->m_eCompressionType = compressionType; + update->m_pData = malloc( outLength ); + memcpy( update->m_pData, outData, outLength ); + update->m_nCompressedSize = outLength; + update->m_nUncompressedSize = uncompressedLength; + update->m_ZipCRC = zipCRC; if ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE ) { update->m_DiskCacheOffset = CWin32File::FileTell( m_hDiskCacheWriteFile ); - CWin32File::FileWrite( m_hDiskCacheWriteFile, update->m_pData, update->m_Length ); + CWin32File::FileWrite( m_hDiskCacheWriteFile, update->m_pData, update->m_nCompressedSize ); free( update->m_pData ); update->m_pData = NULL; } @@ -1005,24 +1102,19 @@ void CZipFile::AddBufferToZip( const char *relativename, void *data, int length, else { // Create a new entry - e.m_Length = dstLength; - if ( dstLength > 0 ) + e.m_nCompressedSize = outLength; + e.m_nUncompressedSize = uncompressedLength; + e.m_eCompressionType = compressionType; + e.m_ZipCRC = zipCRC; + if ( outLength > 0 ) { - if ( bTextMode ) - { - e.m_pData = malloc( dstLength ); - CopyTextData( (char *)e.m_pData, ( char * )data, dstLength, length ); - } - else - { - e.m_pData = malloc( length ); - memcpy( e.m_pData, data, length ); - } - + e.m_pData = malloc( outLength ); + memcpy( e.m_pData, outData, outLength ); + if ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE ) { e.m_DiskCacheOffset = CWin32File::FileTell( m_hDiskCacheWriteFile ); - CWin32File::FileWrite( m_hDiskCacheWriteFile, e.m_pData, e.m_Length ); + CWin32File::FileWrite( m_hDiskCacheWriteFile, e.m_pData, e.m_nCompressedSize ); free( e.m_pData ); e.m_pData = NULL; } @@ -1042,38 +1134,11 @@ void CZipFile::AddBufferToZip( const char *relativename, void *data, int length, //----------------------------------------------------------------------------- bool CZipFile::ReadFileFromZip( const char *pRelativeName, bool bTextMode, CUtlBuffer &buf ) { - // Lower case only - char pName[512]; - Q_strncpy( pName, pRelativeName, 512 ); - Q_strlower( pName ); - - // See if entry is in list already - CZipEntry e; - e.m_Name = pName; - int nIndex = m_Files.Find( e ); - if ( nIndex == m_Files.InvalidIndex() ) - { - // not found - return false; - } - - CZipEntry *pEntry = &m_Files[ nIndex ]; - if ( bTextMode ) - { - buf.SetBufferType( true, false ); - ReadTextData( (char*)pEntry->m_pData, pEntry->m_Length, buf ); - } - else - { - buf.SetBufferType( false, false ); - buf.Put( pEntry->m_pData, pEntry->m_Length ); - } - - return true; + return ReadFileFromZip( 0, pRelativeName, bTextMode, buf ); } //----------------------------------------------------------------------------- -// Reads a file from the zip +// Reads a file from the zip. Requires the zip file handle if this zip was loaded via ParseFromDisk //----------------------------------------------------------------------------- bool CZipFile::ReadFileFromZip( HANDLE hZipFile, const char *pRelativeName, bool bTextMode, CUtlBuffer &buf ) { @@ -1094,27 +1159,63 @@ bool CZipFile::ReadFileFromZip( HANDLE hZipFile, const char *pRelativeName, bool CZipEntry *pEntry = &m_Files[nIndex]; - void *pData = malloc( pEntry->m_Length ); - CWin32File::FileSeek( hZipFile, pEntry->m_SourceDiskOffset, FILE_BEGIN ); - if ( !CWin32File::FileRead( hZipFile, pData, pEntry->m_Length ) ) + void *pData = pEntry->m_pData; + CUtlBuffer readBuffer; + if ( !pData && hZipFile ) { - free( pData ); - return false; + readBuffer.EnsureCapacity( pEntry->m_nCompressedSize ); + CWin32File::FileSeek( hZipFile, pEntry->m_SourceDiskOffset, FILE_BEGIN ); + if ( !CWin32File::FileRead( hZipFile, readBuffer.Base(), pEntry->m_nCompressedSize ) ) + { + return false; + } + + pData = readBuffer.Base(); + } + + CUtlBuffer decompressTransform; + if ( pEntry->m_eCompressionType != IZip::eCompressionType_None ) + { + if ( pEntry->m_eCompressionType == IZip::eCompressionType_LZMA ) + { + decompressTransform.EnsureCapacity( pEntry->m_nUncompressedSize ); + + CLZMAStream decompressStream; + decompressStream.InitZIPHeader( pEntry->m_nCompressedSize, pEntry->m_nUncompressedSize ); + + unsigned int nCompressedBytesRead = 0; + unsigned int nOutputBytesWritten = 0; + bool bSuccess = decompressStream.Read( (unsigned char *)pData, pEntry->m_nCompressedSize, + (unsigned char *)decompressTransform.Base(), decompressTransform.Size(), + nCompressedBytesRead, nOutputBytesWritten ); + if ( !bSuccess || + (int)nCompressedBytesRead != pEntry->m_nCompressedSize || + (int)nOutputBytesWritten != pEntry->m_nUncompressedSize ) + { + Error( "Zip: Failed decompressing LZMA data\n" ); + return false; + } + + pData = decompressTransform.Base(); + } + else + { + Error( "Unsupported compression type in Zip file: %u\n", pEntry->m_eCompressionType ); + return false; + } } if ( bTextMode ) { buf.SetBufferType( true, false ); - ReadTextData( (const char *)pData, pEntry->m_Length, buf ); + ReadTextData( (const char *)pData, pEntry->m_nUncompressedSize, buf ); } else { buf.SetBufferType( false, false ); - buf.Put( pData, pEntry->m_Length ); + buf.Put( pData, pEntry->m_nUncompressedSize ); } - free( pData ); - return true; } @@ -1142,7 +1243,7 @@ bool CZipFile::FileExistsInZip( const char *pRelativeName ) //----------------------------------------------------------------------------- // Purpose: Adds a new file to the zip. //----------------------------------------------------------------------------- -void CZipFile::AddFileToZip( const char *relativename, const char *fullpath ) +void CZipFile::AddFileToZip( const char *relativename, const char *fullpath, IZip::eCompressionType compressionType ) { FILE *temp = fopen( fullpath, "rb" ); if ( !temp ) @@ -1159,8 +1260,8 @@ void CZipFile::AddFileToZip( const char *relativename, const char *fullpath ) fclose( temp ); // Now add as a buffer - AddBufferToZip( relativename, buf, size, false ); - + AddBufferToZip( relativename, buf, size, false, compressionType ); + free( buf ); } @@ -1252,8 +1353,8 @@ unsigned int CZipFile::CalculateSize( void ) for ( int i = m_Files.FirstInorder(); i != m_Files.InvalidIndex(); i = m_Files.NextInorder( i ) ) { CZipEntry *e = &m_Files[ i ]; - - if ( e->m_Length == 0 ) + + if ( e->m_nCompressedSize == 0 ) continue; // local file header @@ -1268,7 +1369,7 @@ unsigned int CZipFile::CalculateSize( void ) { // round up to next boundary unsigned int nextBoundary = ( size + m_AlignmentSize ) & ~( m_AlignmentSize - 1 ); - + // the directory header also duplicates the padding dirHeaders += nextBoundary - size; @@ -1276,7 +1377,7 @@ unsigned int CZipFile::CalculateSize( void ) } // data size - size += e->m_Length; + size += e->m_nCompressedSize; } size += dirHeaders; @@ -1322,7 +1423,7 @@ int CZipFile::GetNextFilename( int id, char *pBuffer, int bufferSize, int &fileS CZipEntry *e = &m_Files[id]; Q_strncpy( pBuffer, e->m_Name.String(), bufferSize ); - fileSize = e->m_Length; + fileSize = e->m_nUncompressedSize; return id; } @@ -1373,6 +1474,9 @@ void CZipFile::SaveDirectory( IWriteStream& stream ) #endif } + // Might be writing a zip into a larger stream + unsigned int zipOffsetInStream = stream.Tell(); + int i; for ( i = m_Files.FirstInorder(); i != m_Files.InvalidIndex(); i = m_Files.NextInorder( i ) ) { @@ -1380,47 +1484,50 @@ void CZipFile::SaveDirectory( IWriteStream& stream ) Assert( e ); // Fix up the offset - e->m_ZipOffset = stream.Tell(); + e->m_ZipOffset = stream.Tell() - zipOffsetInStream; - if ( e->m_Length > 0 && ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE ) ) - { + if ( e->m_nCompressedSize > 0 && ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE ) ) + { // get the data back from the write cache - e->m_pData = malloc( e->m_Length ); + e->m_pData = malloc( e->m_nCompressedSize ); if ( e->m_pData ) { CWin32File::FileSeek( m_hDiskCacheWriteFile, e->m_DiskCacheOffset, FILE_BEGIN ); - CWin32File::FileRead( m_hDiskCacheWriteFile, e->m_pData, e->m_Length ); + CWin32File::FileRead( m_hDiskCacheWriteFile, e->m_pData, e->m_nCompressedSize ); } } - if ( e->m_Length > 0 && e->m_pData != NULL ) + if ( e->m_nCompressedSize > 0 && e->m_pData != NULL ) { ZIP_LocalFileHeader hdr = { 0 }; hdr.signature = PKID( 3, 4 ); - hdr.versionNeededToExtract = 10; // This is the version that the winzip that I have writes. + hdr.versionNeededToExtract = 10; // No special features or even compression here, set to 1.0 +#ifdef ZIP_SUPPORT_LZMA_ENCODE + if ( e->m_eCompressionType == IZip::eCompressionType_LZMA ) + { + // Per ZIP spec 5.8.8 + hdr.versionNeededToExtract = 63; + } +#endif hdr.flags = 0; - hdr.compressionMethod = 0; // NO COMPRESSION! + hdr.compressionMethod = e->m_eCompressionType; hdr.lastModifiedTime = 0; hdr.lastModifiedDate = 0; - - CRC32_Init( &e->m_ZipCRC ); - CRC32_ProcessBuffer( &e->m_ZipCRC, e->m_pData, e->m_Length ); - CRC32_Final( &e->m_ZipCRC ); hdr.crc32 = e->m_ZipCRC; - + const char *pFilename = e->m_Name.String(); - hdr.compressedSize = e->m_Length; - hdr.uncompressedSize = e->m_Length; + hdr.compressedSize = e->m_nCompressedSize; + hdr.uncompressedSize = e->m_nUncompressedSize; hdr.fileNameLength = strlen( pFilename ); hdr.extraFieldLength = CalculatePadding( hdr.fileNameLength, e->m_ZipOffset ); int extraFieldLength = hdr.extraFieldLength; - + // Swap header in place m_Swap.SwapFieldsToTargetEndian( &hdr ); stream.Put( &hdr, sizeof( hdr ) ); stream.Put( pFilename, strlen( pFilename ) ); stream.Put( pPaddingBuffer, extraFieldLength ); - stream.Put( e->m_pData, e->m_Length ); + stream.Put( e->m_pData, e->m_nCompressedSize ); if ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE ) { @@ -1437,7 +1544,7 @@ void CZipFile::SaveDirectory( IWriteStream& stream ) CWin32File::FileSeek( m_hDiskCacheWriteFile, 0, FILE_END ); } - unsigned int centralDirStart = stream.Tell(); + unsigned int centralDirStart = stream.Tell() - zipOffsetInStream; if ( m_AlignmentSize ) { // align the central directory starting position @@ -1455,21 +1562,28 @@ void CZipFile::SaveDirectory( IWriteStream& stream ) { CZipEntry *e = &m_Files[i]; Assert( e ); - - if ( e->m_Length > 0 && e->m_pData != NULL ) + + if ( e->m_nCompressedSize > 0 && e->m_pData != NULL ) { ZIP_FileHeader hdr = { 0 }; hdr.signature = PKID( 1, 2 ); hdr.versionMadeBy = 20; // This is the version that the winzip that I have writes. - hdr.versionNeededToExtract = 10; // This is the version that the winzip that I have writes. + hdr.versionNeededToExtract = 10; // No special features or even compression here, set to 1.0 +#ifdef ZIP_SUPPORT_LZMA_ENCODE + if ( e->m_eCompressionType == IZip::eCompressionType_LZMA ) + { + // Per ZIP spec 5.8.8 + hdr.versionNeededToExtract = 63; + } +#endif hdr.flags = 0; - hdr.compressionMethod = 0; + hdr.compressionMethod = e->m_eCompressionType; hdr.lastModifiedTime = 0; hdr.lastModifiedDate = 0; hdr.crc32 = e->m_ZipCRC; - hdr.compressedSize = e->m_Length; - hdr.uncompressedSize = e->m_Length; + hdr.compressedSize = e->m_nCompressedSize; + hdr.uncompressedSize = e->m_nUncompressedSize; hdr.fileNameLength = strlen( e->m_Name.String() ); hdr.extraFieldLength = CalculatePadding( hdr.fileNameLength, e->m_ZipOffset ); hdr.fileCommentLength = 0; @@ -1498,7 +1612,7 @@ void CZipFile::SaveDirectory( IWriteStream& stream ) } } - unsigned int centralDirEnd = stream.Tell(); + unsigned int centralDirEnd = stream.Tell() - zipOffsetInStream; if ( m_AlignmentSize ) { // align the central directory starting position @@ -1541,56 +1655,57 @@ public: CZip( const char *pDiskCacheWritePath, bool bSortByName ); virtual ~CZip(); - virtual void Reset(); + virtual void Reset() OVERRIDE; // Add a single file to a zip - maintains the zip's previous alignment state - virtual void AddFileToZip( const char *relativename, const char *fullpath ); + virtual void AddFileToZip( const char *relativename, const char *fullpath, eCompressionType compressionType ) OVERRIDE; // Whether a file is contained in a zip - maintains alignment - virtual bool FileExistsInZip( const char *pRelativeName ); + virtual bool FileExistsInZip( const char *pRelativeName ) OVERRIDE; // Reads a file from the zip - maintains alignement - virtual bool ReadFileFromZip( const char *pRelativeName, bool bTextMode, CUtlBuffer &buf ); - virtual bool ReadFileFromZip( HANDLE hZipFile, const char *relativename, bool bTextMode, CUtlBuffer &buf ); + virtual bool ReadFileFromZip( const char *pRelativeName, bool bTextMode, CUtlBuffer &buf ) OVERRIDE; + virtual bool ReadFileFromZip( HANDLE hZipFile, const char *relativename, bool bTextMode, CUtlBuffer &buf ) OVERRIDE; // Removes a single file from the zip - maintains alignment - virtual void RemoveFileFromZip( const char *relativename ); + virtual void RemoveFileFromZip( const char *relativename ) OVERRIDE; // Gets next filename in zip, for walking the directory - maintains alignment - virtual int GetNextFilename( int id, char *pBuffer, int bufferSize, int &fileSize ); + virtual int GetNextFilename( int id, char *pBuffer, int bufferSize, int &fileSize ) OVERRIDE; // Prints the zip's contents - maintains alignment - virtual void PrintDirectory( void ); + virtual void PrintDirectory( void ) OVERRIDE; // Estimate the size of the Zip (including header, padding, etc.) - virtual unsigned int EstimateSize( void ); + virtual unsigned int EstimateSize( void ) OVERRIDE; // Add buffer to zip as a file with given name - uses current alignment size, default 0 (no alignment) - virtual void AddBufferToZip( const char *relativename, void *data, int length, bool bTextMode ); + virtual void AddBufferToZip( const char *relativename, void *data, int length, + bool bTextMode, eCompressionType compressionType ) OVERRIDE; - // Writes out zip file to a buffer - uses current alignment size + // Writes out zip file to a buffer - uses current alignment size // (set by file's previous alignment, or a call to ForceAlignment) - virtual void SaveToBuffer( CUtlBuffer& outbuf ); + virtual void SaveToBuffer( CUtlBuffer& outbuf ) OVERRIDE; - // Writes out zip file to a filestream - uses current alignment size + // Writes out zip file to a filestream - uses current alignment size // (set by file's previous alignment, or a call to ForceAlignment) - virtual void SaveToDisk( FILE *fout ); - virtual void SaveToDisk( HANDLE hOutFile ); + virtual void SaveToDisk( FILE *fout ) OVERRIDE; + virtual void SaveToDisk( HANDLE hOutFile ) OVERRIDE; - // Reads a zip file from a buffer into memory - sets current alignment size to + // Reads a zip file from a buffer into memory - sets current alignment size to // the file's alignment size, unless overridden by a ForceAlignment call) - virtual void ParseFromBuffer( void *buffer, int bufferlength ); - virtual HANDLE ParseFromDisk( const char *pFilename ); + virtual void ParseFromBuffer( void *buffer, int bufferlength ) OVERRIDE; + virtual HANDLE ParseFromDisk( const char *pFilename ) OVERRIDE; // Forces a specific alignment size for all subsequent file operations, overriding files' previous alignment size. // Return to using files' individual alignment sizes by passing FALSE. - virtual void ForceAlignment( bool aligned, bool bCompatibleFormat, unsigned int alignmentSize ); + virtual void ForceAlignment( bool aligned, bool bCompatibleFormat, unsigned int alignmentSize ) OVERRIDE; // Sets the endianess of the zip - virtual void SetBigEndian( bool bigEndian ); - virtual void ActivateByteSwapping( bool bActivate ); + virtual void SetBigEndian( bool bigEndian ) OVERRIDE; + virtual void ActivateByteSwapping( bool bActivate ) OVERRIDE; - virtual unsigned int GetAlignment(); + virtual unsigned int GetAlignment() OVERRIDE; private: CZipFile m_ZipFile; @@ -1599,11 +1714,11 @@ private: static CUtlLinkedList< CZip* > g_ZipUtils; IZip *IZip::CreateZip( const char *pDiskCacheWritePath, bool bSortByName ) -{ +{ CZip *pZip = new CZip( pDiskCacheWritePath, bSortByName ); g_ZipUtils.AddToTail( pZip ); - return pZip; + return pZip; } void IZip::ReleaseZip( IZip *pZip ) @@ -1632,9 +1747,9 @@ void CZip::ActivateByteSwapping( bool bActivate ) m_ZipFile.ActivateByteSwapping( bActivate ); } -void CZip::AddFileToZip( const char *relativename, const char *fullpath ) +void CZip::AddFileToZip( const char *relativename, const char *fullpath, eCompressionType compressionType ) { - m_ZipFile.AddFileToZip( relativename, fullpath ); + m_ZipFile.AddFileToZip( relativename, fullpath, compressionType ); } bool CZip::FileExistsInZip( const char *pRelativeName ) @@ -1678,9 +1793,9 @@ unsigned int CZip::EstimateSize( void ) } // Add buffer to zip as a file with given name -void CZip::AddBufferToZip( const char *relativename, void *data, int length, bool bTextMode ) +void CZip::AddBufferToZip( const char *relativename, void *data, int length, bool bTextMode, eCompressionType compressionType ) { - m_ZipFile.AddBufferToZip( relativename, data, length, bTextMode ); + m_ZipFile.AddBufferToZip( relativename, data, length, bTextMode, compressionType ); } void CZip::SaveToBuffer( CUtlBuffer& outbuf ) -- cgit v1.2.3