Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1872 lines
54 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. // If we are going to include windows.h then we need to disable protected_things.h
  7. // or else we get many warnings.
  8. #undef PROTECTED_THINGS_ENABLE
  9. #include <tier0/platform.h>
  10. #ifdef IS_WINDOWS_PC
  11. #include <windows.h>
  12. #else
  13. #define INVALID_HANDLE_VALUE (void *)0
  14. #define FILE_BEGIN SEEK_SET
  15. #define FILE_END SEEK_END
  16. #endif
  17. #include "utlbuffer.h"
  18. #include "utllinkedlist.h"
  19. #include "zip_utils.h"
  20. #include "zip_uncompressed.h"
  21. #include "checksum_crc.h"
  22. #include "byteswap.h"
  23. #include "utlstring.h"
  24. #include "tier1/lzmaDecoder.h"
  25. // Not every user of zip utils wants to link LZMA encoder
  26. #ifdef ZIP_SUPPORT_LZMA_ENCODE
  27. #include "lzma/lzma.h"
  28. #endif
  29. #include "tier0/memdbgon.h"
  30. // Data descriptions for byte swapping - only needed
  31. // for structures that are written to file for use by the game.
  32. BEGIN_BYTESWAP_DATADESC( ZIP_EndOfCentralDirRecord )
  33. DEFINE_FIELD( signature, FIELD_INTEGER ),
  34. DEFINE_FIELD( numberOfThisDisk, FIELD_SHORT ),
  35. DEFINE_FIELD( numberOfTheDiskWithStartOfCentralDirectory, FIELD_SHORT ),
  36. DEFINE_FIELD( nCentralDirectoryEntries_ThisDisk, FIELD_SHORT ),
  37. DEFINE_FIELD( nCentralDirectoryEntries_Total, FIELD_SHORT ),
  38. DEFINE_FIELD( centralDirectorySize, FIELD_INTEGER ),
  39. DEFINE_FIELD( startOfCentralDirOffset, FIELD_INTEGER ),
  40. DEFINE_FIELD( commentLength, FIELD_SHORT ),
  41. END_BYTESWAP_DATADESC()
  42. BEGIN_BYTESWAP_DATADESC( ZIP_FileHeader )
  43. DEFINE_FIELD( signature, FIELD_INTEGER ),
  44. DEFINE_FIELD( versionMadeBy, FIELD_SHORT ),
  45. DEFINE_FIELD( versionNeededToExtract, FIELD_SHORT ),
  46. DEFINE_FIELD( flags, FIELD_SHORT ),
  47. DEFINE_FIELD( compressionMethod, FIELD_SHORT ),
  48. DEFINE_FIELD( lastModifiedTime, FIELD_SHORT ),
  49. DEFINE_FIELD( lastModifiedDate, FIELD_SHORT ),
  50. DEFINE_FIELD( crc32, FIELD_INTEGER ),
  51. DEFINE_FIELD( compressedSize, FIELD_INTEGER ),
  52. DEFINE_FIELD( uncompressedSize, FIELD_INTEGER ),
  53. DEFINE_FIELD( fileNameLength, FIELD_SHORT ),
  54. DEFINE_FIELD( extraFieldLength, FIELD_SHORT ),
  55. DEFINE_FIELD( fileCommentLength, FIELD_SHORT ),
  56. DEFINE_FIELD( diskNumberStart, FIELD_SHORT ),
  57. DEFINE_FIELD( internalFileAttribs, FIELD_SHORT ),
  58. DEFINE_FIELD( externalFileAttribs, FIELD_INTEGER ),
  59. DEFINE_FIELD( relativeOffsetOfLocalHeader, FIELD_INTEGER ),
  60. END_BYTESWAP_DATADESC()
  61. BEGIN_BYTESWAP_DATADESC( ZIP_LocalFileHeader )
  62. DEFINE_FIELD( signature, FIELD_INTEGER ),
  63. DEFINE_FIELD( versionNeededToExtract, FIELD_SHORT ),
  64. DEFINE_FIELD( flags, FIELD_SHORT ),
  65. DEFINE_FIELD( compressionMethod, FIELD_SHORT ),
  66. DEFINE_FIELD( lastModifiedTime, FIELD_SHORT ),
  67. DEFINE_FIELD( lastModifiedDate, FIELD_SHORT ),
  68. DEFINE_FIELD( crc32, FIELD_INTEGER ),
  69. DEFINE_FIELD( compressedSize, FIELD_INTEGER ),
  70. DEFINE_FIELD( uncompressedSize, FIELD_INTEGER ),
  71. DEFINE_FIELD( fileNameLength, FIELD_SHORT ),
  72. DEFINE_FIELD( extraFieldLength, FIELD_SHORT ),
  73. END_BYTESWAP_DATADESC()
  74. BEGIN_BYTESWAP_DATADESC( ZIP_PreloadHeader )
  75. DEFINE_FIELD( Version, FIELD_INTEGER ),
  76. DEFINE_FIELD( DirectoryEntries, FIELD_INTEGER ),
  77. DEFINE_FIELD( PreloadDirectoryEntries, FIELD_INTEGER ),
  78. DEFINE_FIELD( Alignment, FIELD_INTEGER ),
  79. END_BYTESWAP_DATADESC()
  80. BEGIN_BYTESWAP_DATADESC( ZIP_PreloadDirectoryEntry )
  81. DEFINE_FIELD( Length, FIELD_INTEGER ),
  82. DEFINE_FIELD( DataOffset, FIELD_INTEGER ),
  83. END_BYTESWAP_DATADESC()
  84. #ifdef WIN32
  85. //-----------------------------------------------------------------------------
  86. // For >2 GB File Support
  87. //-----------------------------------------------------------------------------
  88. class CWin32File
  89. {
  90. public:
  91. static HANDLE CreateTempFile( CUtlString &WritePath, CUtlString &FileName )
  92. {
  93. char tempFileName[MAX_PATH];
  94. if ( WritePath.IsEmpty() )
  95. {
  96. // use a safe name in the cwd
  97. char *pBuffer = tmpnam( NULL );
  98. if ( !pBuffer )
  99. {
  100. return INVALID_HANDLE_VALUE;
  101. }
  102. if ( pBuffer[0] == '\\' )
  103. {
  104. pBuffer++;
  105. }
  106. if ( pBuffer[strlen( pBuffer )-1] == '.' )
  107. {
  108. pBuffer[strlen( pBuffer )-1] = '\0';
  109. }
  110. V_snprintf( tempFileName, sizeof( tempFileName ), "_%s.tmp", pBuffer );
  111. }
  112. else
  113. {
  114. // generate safe name at the desired prefix
  115. char uniqueFilename[MAX_PATH];
  116. SYSTEMTIME sysTime; \
  117. GetLocalTime( &sysTime );
  118. sprintf( uniqueFilename, "%d_%d_%d_%d_%d.tmp", sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond, sysTime.wMilliseconds ); \
  119. V_ComposeFileName( WritePath.String(), uniqueFilename, tempFileName, sizeof( tempFileName ) );
  120. }
  121. FileName = tempFileName;
  122. HANDLE hFile = CreateFile( tempFileName, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  123. return hFile;
  124. }
  125. static unsigned int FileSeek( HANDLE hFile, unsigned int distance, DWORD MoveMethod )
  126. {
  127. LARGE_INTEGER li;
  128. li.QuadPart = distance;
  129. li.LowPart = SetFilePointer( hFile, li.LowPart, &li.HighPart, MoveMethod);
  130. if ( li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR )
  131. {
  132. li.QuadPart = -1;
  133. }
  134. return ( unsigned int )li.QuadPart;
  135. }
  136. static unsigned int FileTell( HANDLE hFile )
  137. {
  138. return FileSeek( hFile, 0, FILE_CURRENT );
  139. }
  140. static bool FileRead( HANDLE hFile, void *pBuffer, unsigned int size )
  141. {
  142. DWORD numBytesRead;
  143. BOOL bSuccess = ::ReadFile( hFile, pBuffer, size, &numBytesRead, NULL );
  144. return bSuccess && ( numBytesRead == size );
  145. }
  146. static bool FileWrite( HANDLE hFile, void *pBuffer, unsigned int size )
  147. {
  148. DWORD numBytesWritten;
  149. BOOL bSuccess = WriteFile( hFile, pBuffer, size, &numBytesWritten, NULL );
  150. return bSuccess && ( numBytesWritten == size );
  151. }
  152. };
  153. #else
  154. class CWin32File
  155. {
  156. public:
  157. static HANDLE CreateTempFile( CUtlString &WritePath, CUtlString &FileName )
  158. {
  159. char tempFileName[MAX_PATH];
  160. if ( WritePath.IsEmpty() )
  161. {
  162. // use a safe name in the cwd
  163. char *pBuffer = tmpnam( NULL );
  164. if ( !pBuffer )
  165. {
  166. return INVALID_HANDLE_VALUE;
  167. }
  168. if ( pBuffer[0] == '\\' )
  169. {
  170. pBuffer++;
  171. }
  172. if ( pBuffer[strlen( pBuffer )-1] == '.' )
  173. {
  174. pBuffer[strlen( pBuffer )-1] = '\0';
  175. }
  176. V_snprintf( tempFileName, sizeof( tempFileName ), "_%s.tmp", pBuffer );
  177. }
  178. else
  179. {
  180. char uniqueFilename[MAX_PATH];
  181. static int counter = 0;
  182. time_t now = time( NULL );
  183. struct tm *tm = localtime( &now );
  184. sprintf( uniqueFilename, "%d_%d_%d_%d_%d.tmp", tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec, ++counter ); \
  185. V_ComposeFileName( WritePath.String(), uniqueFilename, tempFileName, sizeof( tempFileName ) );
  186. }
  187. FileName = tempFileName;
  188. FILE *hFile = fopen( tempFileName, "rw+" );
  189. return (HANDLE)hFile;
  190. }
  191. static unsigned int FileSeek( HANDLE hFile, unsigned int distance, DWORD MoveMethod )
  192. {
  193. if ( fseeko( (FILE *)hFile, distance, MoveMethod ) == 0 )
  194. {
  195. return FileTell( hFile );
  196. }
  197. return 0;
  198. }
  199. static unsigned int FileTell( HANDLE hFile )
  200. {
  201. return ftello( (FILE *)hFile );
  202. }
  203. static bool FileRead( HANDLE hFile, void *pBuffer, unsigned int size )
  204. {
  205. size_t bytesRead = fread( pBuffer, 1, size, (FILE *)hFile );
  206. return bytesRead == size;
  207. }
  208. static bool FileWrite( HANDLE hFile, void *pBuffer, unsigned int size )
  209. {
  210. size_t bytesWrtitten = fwrite( pBuffer, 1, size, (FILE *)hFile );
  211. return bytesWrtitten == size;
  212. }
  213. };
  214. #endif
  215. //-----------------------------------------------------------------------------
  216. // Purpose: Interface to allow abstraction of zip file output methods, and
  217. // avoid duplication of code. Files may be written to a CUtlBuffer or a filestream
  218. //-----------------------------------------------------------------------------
  219. abstract_class IWriteStream
  220. {
  221. public:
  222. virtual void Put( const void* pMem, int size ) = 0;
  223. virtual unsigned int Tell( void ) = 0;
  224. };
  225. //-----------------------------------------------------------------------------
  226. // Purpose: Wrapper for CUtlBuffer methods
  227. //-----------------------------------------------------------------------------
  228. class CBufferStream : public IWriteStream
  229. {
  230. public:
  231. CBufferStream( CUtlBuffer& buff ) : IWriteStream(), m_buff( &buff ) {}
  232. // Implementing IWriteStream method
  233. virtual void Put( const void* pMem, int size ) {m_buff->Put( pMem, size );}
  234. // Implementing IWriteStream method
  235. virtual unsigned int Tell( void ) { return m_buff->TellPut(); }
  236. private:
  237. CUtlBuffer *m_buff;
  238. };
  239. //-----------------------------------------------------------------------------
  240. // Purpose: Wrapper for file I/O methods
  241. //-----------------------------------------------------------------------------
  242. class CFileStream : public IWriteStream
  243. {
  244. public:
  245. CFileStream( FILE *fout ) : IWriteStream(), m_file( fout ), m_hFile( INVALID_HANDLE_VALUE ) {}
  246. CFileStream( HANDLE hOutFile ) : IWriteStream(), m_file( NULL ), m_hFile( hOutFile ) {}
  247. // Implementing IWriteStream method
  248. virtual void Put( const void* pMem, int size )
  249. {
  250. if ( m_file )
  251. {
  252. fwrite( pMem, size, 1, m_file );
  253. }
  254. #ifdef WIN32
  255. else
  256. {
  257. DWORD numBytesWritten;
  258. WriteFile( m_hFile, pMem, size, &numBytesWritten, NULL );
  259. }
  260. #endif
  261. }
  262. // Implementing IWriteStream method
  263. virtual unsigned int Tell( void )
  264. {
  265. if ( m_file )
  266. {
  267. return ftell( m_file );
  268. }
  269. else
  270. {
  271. #ifdef WIN32
  272. return CWin32File::FileTell( m_hFile );
  273. #else
  274. return 0;
  275. #endif
  276. }
  277. }
  278. private:
  279. FILE *m_file;
  280. HANDLE m_hFile;
  281. };
  282. //-----------------------------------------------------------------------------
  283. // Purpose: Container for modifiable pak file which is embedded inside the .bsp file
  284. // itself. It's used to allow one-off files to be stored local to the map and it is
  285. // hooked into the file system as an override for searching for named files.
  286. //-----------------------------------------------------------------------------
  287. class CZipFile
  288. {
  289. public:
  290. // Construction
  291. CZipFile( const char *pDiskCacheWritePath, bool bSortByName );
  292. ~CZipFile( void );
  293. // Public API
  294. // Clear all existing data
  295. void Reset( void );
  296. // Add file to zip under relative name
  297. void AddFileToZip( const char *relativename, const char *fullpath, IZip::eCompressionType compressionType );
  298. // Delete file from zip
  299. void RemoveFileFromZip( const char *relativename );
  300. // Add buffer to zip as a file with given name
  301. void AddBufferToZip( const char *relativename, void *data, int length, bool bTextMode, IZip::eCompressionType compressionType );
  302. // Check if a file already exists in the zip.
  303. bool FileExistsInZip( const char *relativename );
  304. // Reads a file from a zip file
  305. bool ReadFileFromZip( const char *relativename, bool bTextMode, CUtlBuffer &buf );
  306. bool ReadFileFromZip( HANDLE hZipFile, const char *relativename, bool bTextMode, CUtlBuffer &buf );
  307. // Initialize the zip file from a buffer
  308. void ParseFromBuffer( void *buffer, int bufferlength );
  309. HANDLE ParseFromDisk( const char *pFilename );
  310. // Estimate the size of the zip file (including header, padding, etc.)
  311. unsigned int EstimateSize();
  312. // Print out a directory of files in the zip.
  313. void PrintDirectory( void );
  314. // Use to iterate directory, pass 0 for first element
  315. // returns nonzero element id with filled buffer, or -1 at list conclusion
  316. int GetNextFilename( int id, char *pBuffer, int bufferSize, int &fileSize );
  317. // Write the zip to a buffer
  318. void SaveToBuffer( CUtlBuffer& buffer );
  319. // Write the zip to a filestream
  320. void SaveToDisk( FILE *fout );
  321. void SaveToDisk( HANDLE hOutFile );
  322. unsigned int CalculateSize( void );
  323. void ForceAlignment( bool aligned, bool bCompatibleFormat, unsigned int alignmentSize );
  324. unsigned int GetAlignment();
  325. void SetBigEndian( bool bigEndian );
  326. void ActivateByteSwapping( bool bActivate );
  327. private:
  328. enum
  329. {
  330. MAX_FILES_IN_ZIP = 32768,
  331. };
  332. typedef struct
  333. {
  334. CUtlSymbol m_Name;
  335. unsigned int filepos;
  336. int filelen;
  337. int uncompressedLen;
  338. CRC32_t crc32;
  339. IZip::eCompressionType compressionType;
  340. } TmpFileInfo_t;
  341. CByteswap m_Swap;
  342. unsigned int m_AlignmentSize;
  343. bool m_bForceAlignment;
  344. bool m_bCompatibleFormat;
  345. unsigned short CalculatePadding( unsigned int filenameLen, unsigned int pos );
  346. void SaveDirectory( IWriteStream& stream );
  347. int MakeXZipCommentString( char *pComment );
  348. void ParseXZipCommentString( const char *pComment );
  349. // Internal entry for faster searching, etc.
  350. class CZipEntry
  351. {
  352. public:
  353. CZipEntry( void );
  354. ~CZipEntry( void );
  355. CZipEntry( const CZipEntry& src );
  356. // RB tree compare function
  357. static bool ZipFileLessFunc( CZipEntry const& src1, CZipEntry const& src2 );
  358. static bool ZipFileLessFunc_CaselessSort( CZipEntry const& src1, CZipEntry const& src2 );
  359. // Name of entry
  360. CUtlSymbol m_Name;
  361. // Lenth of data element
  362. int m_nCompressedSize;
  363. // Original, uncompressed size
  364. int m_nUncompressedSize;
  365. // Raw data, could be null and data may be in disk write cache
  366. void *m_pData;
  367. // Offset in Zip ( set and valid during final write )
  368. unsigned int m_ZipOffset;
  369. // CRC of blob
  370. CRC32_t m_ZipCRC;
  371. // Location of data in disk cache
  372. unsigned int m_DiskCacheOffset;
  373. unsigned int m_SourceDiskOffset;
  374. // The compression used on the data if any
  375. IZip::eCompressionType m_eCompressionType;
  376. };
  377. // For fast name lookup and sorting
  378. CUtlRBTree< CZipEntry, int > m_Files;
  379. // Used to buffer zip data, instead of ram
  380. bool m_bUseDiskCacheForWrites;
  381. HANDLE m_hDiskCacheWriteFile;
  382. CUtlString m_DiskCacheName;
  383. CUtlString m_DiskCacheWritePath;
  384. };
  385. //-----------------------------------------------------------------------------
  386. // Purpose:
  387. //-----------------------------------------------------------------------------
  388. CZipFile::CZipEntry::CZipEntry( void )
  389. {
  390. m_Name = "";
  391. m_nCompressedSize = 0;
  392. m_nUncompressedSize = 0;
  393. m_pData = NULL;
  394. m_ZipOffset = 0;
  395. m_ZipCRC = 0;
  396. m_DiskCacheOffset = 0;
  397. m_SourceDiskOffset = 0;
  398. m_eCompressionType = IZip::eCompressionType_None;
  399. }
  400. //-----------------------------------------------------------------------------
  401. // Purpose:
  402. // Input : src -
  403. //-----------------------------------------------------------------------------
  404. CZipFile::CZipEntry::CZipEntry( const CZipFile::CZipEntry& src )
  405. {
  406. m_Name = src.m_Name;
  407. m_nCompressedSize = src.m_nCompressedSize;
  408. m_nUncompressedSize = src.m_nUncompressedSize;
  409. m_eCompressionType = src.m_eCompressionType;
  410. if ( src.m_nCompressedSize > 0 && src.m_pData )
  411. {
  412. m_pData = malloc( src.m_nCompressedSize );
  413. memcpy( m_pData, src.m_pData, src.m_nCompressedSize );
  414. }
  415. else
  416. {
  417. m_pData = NULL;
  418. }
  419. m_ZipOffset = src.m_ZipOffset;
  420. m_ZipCRC = src.m_ZipCRC;
  421. m_DiskCacheOffset = src.m_DiskCacheOffset;
  422. m_SourceDiskOffset = src.m_SourceDiskOffset;
  423. }
  424. //-----------------------------------------------------------------------------
  425. // Purpose: Clear any leftover data
  426. //-----------------------------------------------------------------------------
  427. CZipFile::CZipEntry::~CZipEntry( void )
  428. {
  429. if ( m_pData )
  430. {
  431. free( m_pData );
  432. }
  433. }
  434. //-----------------------------------------------------------------------------
  435. // Purpose: Construction
  436. //-----------------------------------------------------------------------------
  437. CZipFile::CZipFile( const char *pDiskCacheWritePath, bool bSortByName )
  438. : m_Files( 0, 32 )
  439. {
  440. m_AlignmentSize = 0;
  441. m_bForceAlignment = false;
  442. m_bCompatibleFormat = true;
  443. m_bUseDiskCacheForWrites = ( pDiskCacheWritePath != NULL );
  444. m_DiskCacheWritePath = pDiskCacheWritePath;
  445. m_hDiskCacheWriteFile = INVALID_HANDLE_VALUE;
  446. if ( bSortByName )
  447. {
  448. m_Files.SetLessFunc( CZipEntry::ZipFileLessFunc_CaselessSort );
  449. }
  450. else
  451. {
  452. m_Files.SetLessFunc( CZipEntry::ZipFileLessFunc );
  453. }
  454. }
  455. //-----------------------------------------------------------------------------
  456. // Purpose: Destroy zip data
  457. //-----------------------------------------------------------------------------
  458. CZipFile::~CZipFile( void )
  459. {
  460. m_bUseDiskCacheForWrites = false;
  461. Reset();
  462. }
  463. //-----------------------------------------------------------------------------
  464. // Purpose: Delete all current data
  465. //-----------------------------------------------------------------------------
  466. void CZipFile::Reset( void )
  467. {
  468. m_Files.RemoveAll();
  469. if ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE )
  470. {
  471. #ifdef WIN32
  472. CloseHandle( m_hDiskCacheWriteFile );
  473. DeleteFile( m_DiskCacheName.String() );
  474. #else
  475. fclose( (FILE *)m_hDiskCacheWriteFile );
  476. unlink( m_DiskCacheName.String() );
  477. #endif
  478. m_hDiskCacheWriteFile = INVALID_HANDLE_VALUE;
  479. }
  480. if ( m_bUseDiskCacheForWrites )
  481. {
  482. m_hDiskCacheWriteFile = CWin32File::CreateTempFile( m_DiskCacheWritePath, m_DiskCacheName );
  483. }
  484. }
  485. //-----------------------------------------------------------------------------
  486. // Purpose: Comparison for sorting entries
  487. // Input : src1 -
  488. // src2 -
  489. // Output : Returns true on success, false on failure.
  490. //-----------------------------------------------------------------------------
  491. bool CZipFile::CZipEntry::ZipFileLessFunc( CZipEntry const& src1, CZipEntry const& src2 )
  492. {
  493. return ( src1.m_Name < src2.m_Name );
  494. }
  495. bool CZipFile::CZipEntry::ZipFileLessFunc_CaselessSort( CZipEntry const& src1, CZipEntry const& src2 )
  496. {
  497. return ( V_stricmp( src1.m_Name.String(), src2.m_Name.String() ) < 0 );
  498. }
  499. void CZipFile::ForceAlignment( bool bAligned, bool bCompatibleFormat, unsigned int alignment )
  500. {
  501. m_bForceAlignment = bAligned;
  502. m_AlignmentSize = alignment;
  503. m_bCompatibleFormat = bCompatibleFormat;
  504. if ( !bAligned )
  505. {
  506. m_AlignmentSize = 0;
  507. }
  508. else if ( !IsPowerOfTwo( m_AlignmentSize ) )
  509. {
  510. m_AlignmentSize = 0;
  511. }
  512. }
  513. unsigned int CZipFile::GetAlignment()
  514. {
  515. if ( !m_bForceAlignment || !m_AlignmentSize )
  516. {
  517. return 0;
  518. }
  519. return m_AlignmentSize;
  520. }
  521. void CZipFile::SetBigEndian( bool bigEndian )
  522. {
  523. m_Swap.SetTargetBigEndian( bigEndian );
  524. }
  525. void CZipFile::ActivateByteSwapping( bool bActivate )
  526. {
  527. m_Swap.ActivateByteSwapping( bActivate );
  528. }
  529. //-----------------------------------------------------------------------------
  530. // Purpose: Load pak file from raw buffer
  531. // Input : *buffer -
  532. // bufferlength -
  533. //-----------------------------------------------------------------------------
  534. void CZipFile::ParseFromBuffer( void *buffer, int bufferlength )
  535. {
  536. // Throw away old data
  537. Reset();
  538. // Initialize a buffer
  539. CUtlBuffer buf( 0, bufferlength +1 ); // +1 for null termination
  540. // need to swap bytes, so set the buffer opposite the machine's endian
  541. buf.ActivateByteSwapping( m_Swap.IsSwappingBytes() );
  542. buf.Put( buffer, bufferlength );
  543. buf.SeekGet( CUtlBuffer::SEEK_TAIL, 0 );
  544. unsigned int fileLen = buf.TellGet();
  545. // Start from beginning
  546. buf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
  547. ZIP_EndOfCentralDirRecord rec = { 0 };
  548. #ifdef DBGFLAG_ASSERT
  549. bool bFoundEndOfCentralDirRecord = false;
  550. #endif
  551. unsigned int offset = fileLen - sizeof( ZIP_EndOfCentralDirRecord );
  552. // If offset is ever greater than startOffset then it means that it has
  553. // wrapped. This used to be a tautological >= 0 test.
  554. ANALYZE_SUPPRESS( 6293 ); // warning C6293: Ill-defined for-loop: counts down from minimum
  555. for ( unsigned int startOffset = offset; offset <= startOffset; offset-- )
  556. {
  557. buf.SeekGet( CUtlBuffer::SEEK_HEAD, offset );
  558. buf.GetObjects( &rec );
  559. if ( rec.signature == PKID( 5, 6 ) )
  560. {
  561. #ifdef DBGFLAG_ASSERT
  562. bFoundEndOfCentralDirRecord = true;
  563. #endif
  564. // Set any xzip configuration
  565. if ( rec.commentLength )
  566. {
  567. char commentString[128] = { 0 };
  568. int commentLength = min( (int)rec.commentLength, (int)sizeof( commentString ) );
  569. buf.Get( commentString, commentLength );
  570. if ( commentLength == sizeof( commentString ) )
  571. --commentLength;
  572. commentString[commentLength] = '\0';
  573. ParseXZipCommentString( commentString );
  574. }
  575. break;
  576. }
  577. else
  578. {
  579. // wrong record
  580. rec.nCentralDirectoryEntries_Total = 0;
  581. }
  582. }
  583. Assert( bFoundEndOfCentralDirRecord );
  584. // Make sure there are some files to parse
  585. int numzipfiles = rec.nCentralDirectoryEntries_Total;
  586. if ( numzipfiles <= 0 )
  587. {
  588. // No files
  589. return;
  590. }
  591. buf.SeekGet( CUtlBuffer::SEEK_HEAD, rec.startOfCentralDirOffset );
  592. // Allocate space for directory
  593. TmpFileInfo_t *newfiles = new TmpFileInfo_t[numzipfiles];
  594. Assert( newfiles );
  595. // build directory
  596. int i;
  597. for ( i = 0; i < rec.nCentralDirectoryEntries_Total; i++ )
  598. {
  599. ZIP_FileHeader zipFileHeader;
  600. buf.GetObjects( &zipFileHeader );
  601. Assert( zipFileHeader.signature == PKID( 1, 2 ) );
  602. if ( zipFileHeader.compressionMethod != IZip::eCompressionType_None &&
  603. zipFileHeader.compressionMethod != IZip::eCompressionType_LZMA )
  604. {
  605. Assert( false );
  606. Warning( "Opening ZIP file with unsupported compression type\n");
  607. }
  608. char tmpString[MAX_PATH] = { 0 };
  609. buf.Get( tmpString, Min( (unsigned int)zipFileHeader.fileNameLength, (unsigned int)sizeof( tmpString ) ) );
  610. Q_strlower( tmpString );
  611. // can determine actual filepos, assuming a well formed zip
  612. newfiles[i].m_Name = tmpString;
  613. newfiles[i].filelen = zipFileHeader.compressedSize;
  614. newfiles[i].uncompressedLen = zipFileHeader.uncompressedSize;
  615. newfiles[i].crc32 = zipFileHeader.crc32;
  616. newfiles[i].filepos = zipFileHeader.relativeOffsetOfLocalHeader +
  617. sizeof( ZIP_LocalFileHeader ) +
  618. zipFileHeader.fileNameLength +
  619. zipFileHeader.extraFieldLength;
  620. newfiles[i].compressionType = (IZip::eCompressionType)zipFileHeader.compressionMethod;
  621. int nextOffset;
  622. if ( m_bCompatibleFormat )
  623. {
  624. nextOffset = zipFileHeader.extraFieldLength + zipFileHeader.fileCommentLength;
  625. }
  626. else
  627. {
  628. nextOffset = 0;
  629. }
  630. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, nextOffset );
  631. }
  632. // Insert current data into rb tree
  633. for ( i=0; i<numzipfiles; i++ )
  634. {
  635. CZipEntry e;
  636. e.m_Name = newfiles[i].m_Name;
  637. e.m_nCompressedSize = newfiles[i].filelen;
  638. e.m_ZipCRC = newfiles[i].crc32;
  639. e.m_nUncompressedSize = newfiles[i].uncompressedLen;
  640. e.m_eCompressionType = newfiles[i].compressionType;
  641. // Make sure length is reasonable
  642. if ( e.m_nCompressedSize > 0 )
  643. {
  644. e.m_pData = malloc( e.m_nCompressedSize );
  645. // Copy in data
  646. buf.SeekGet( CUtlBuffer::SEEK_HEAD, newfiles[i].filepos );
  647. buf.Get( e.m_pData, e.m_nCompressedSize );
  648. }
  649. else
  650. {
  651. e.m_pData = NULL;
  652. }
  653. // Add to tree
  654. m_Files.Insert( e );
  655. }
  656. // Through away directory
  657. delete[] newfiles;
  658. }
  659. //-----------------------------------------------------------------------------
  660. // Purpose: Mount pak file from disk
  661. //-----------------------------------------------------------------------------
  662. HANDLE CZipFile::ParseFromDisk( const char *pFilename )
  663. {
  664. #ifdef WIN32
  665. HANDLE hFile = CreateFile( pFilename, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  666. if ( hFile == INVALID_HANDLE_VALUE )
  667. {
  668. // not found
  669. return NULL;
  670. }
  671. #else
  672. HANDLE hFile = fopen( pFilename, "rw+" );
  673. if ( !hFile )
  674. {
  675. // not found
  676. return NULL;
  677. }
  678. #endif
  679. unsigned int fileLen = CWin32File::FileSeek( hFile, 0, FILE_END );
  680. CWin32File::FileSeek( hFile, 0, FILE_BEGIN );
  681. if ( fileLen < sizeof( ZIP_EndOfCentralDirRecord ) )
  682. {
  683. // bad format
  684. #ifdef WIN32
  685. CloseHandle( hFile );
  686. #else
  687. fclose( (FILE *)hFile );
  688. #endif
  689. return NULL;
  690. }
  691. // need to get the central dir
  692. ZIP_EndOfCentralDirRecord rec = { 0 };
  693. unsigned int offset = fileLen - sizeof( ZIP_EndOfCentralDirRecord );
  694. // If offset is ever greater than startOffset then it means that it has
  695. // wrapped. This used to be a tautological >= 0 test.
  696. ANALYZE_SUPPRESS( 6293 ); // warning C6293: Ill-defined for-loop: counts down from minimum
  697. for ( unsigned int startOffset = offset; offset <= startOffset; offset-- )
  698. {
  699. CWin32File::FileSeek( hFile, offset, FILE_BEGIN );
  700. CWin32File::FileRead( hFile, &rec, sizeof( rec ) );
  701. m_Swap.SwapFieldsToTargetEndian( &rec );
  702. if ( rec.signature == PKID( 5, 6 ) )
  703. {
  704. // Set any xzip configuration
  705. if ( rec.commentLength )
  706. {
  707. char commentString[128] = { 0 };
  708. int commentLength = min( (int)rec.commentLength, (int)sizeof( commentString ) );
  709. CWin32File::FileRead( hFile, commentString, commentLength );
  710. if ( commentLength == sizeof( commentString ) )
  711. --commentLength;
  712. commentString[commentLength] = '\0';
  713. ParseXZipCommentString( commentString );
  714. }
  715. break;
  716. }
  717. else
  718. {
  719. // wrong record
  720. rec.nCentralDirectoryEntries_Total = 0;
  721. }
  722. }
  723. // Make sure there are some files to parse
  724. int numZipFiles = rec.nCentralDirectoryEntries_Total;
  725. if ( numZipFiles <= 0 )
  726. {
  727. // No files
  728. #ifdef WIN32
  729. CloseHandle( hFile );
  730. #else
  731. fclose( (FILE *)hFile );
  732. #endif
  733. return NULL;
  734. }
  735. CWin32File::FileSeek( hFile, rec.startOfCentralDirOffset, FILE_BEGIN );
  736. // read entire central dir into memory
  737. CUtlBuffer zipDirBuff( 0, rec.centralDirectorySize, 0 );
  738. zipDirBuff.ActivateByteSwapping( m_Swap.IsSwappingBytes() );
  739. CWin32File::FileRead( hFile, zipDirBuff.Base(), rec.centralDirectorySize );
  740. zipDirBuff.SeekPut( CUtlBuffer::SEEK_HEAD, rec.centralDirectorySize );
  741. // build directory
  742. for ( int i = 0; i < numZipFiles; i++ )
  743. {
  744. ZIP_FileHeader zipFileHeader;
  745. zipDirBuff.GetObjects( &zipFileHeader );
  746. if ( zipFileHeader.signature != PKID( 1, 2 )
  747. || ( zipFileHeader.compressionMethod != IZip::eCompressionType_None
  748. && zipFileHeader.compressionMethod != IZip::eCompressionType_LZMA ) )
  749. {
  750. // bad contents
  751. #ifdef WIN32
  752. CloseHandle( hFile );
  753. #else
  754. fclose( (FILE *)hFile );
  755. #endif
  756. return NULL;
  757. }
  758. char fileName[MAX_PATH] = { 0 };
  759. zipDirBuff.Get( fileName, Min( (size_t)zipFileHeader.fileNameLength, sizeof( fileName ) - 1 ) );
  760. Q_strlower( fileName );
  761. // can determine actual filepos, assuming a well formed zip
  762. CZipEntry e;
  763. e.m_Name = fileName;
  764. e.m_nCompressedSize = zipFileHeader.compressedSize;
  765. e.m_nUncompressedSize = zipFileHeader.uncompressedSize;
  766. e.m_ZipCRC = zipFileHeader.crc32;
  767. e.m_SourceDiskOffset = zipFileHeader.relativeOffsetOfLocalHeader +
  768. sizeof( ZIP_LocalFileHeader ) +
  769. zipFileHeader.fileNameLength +
  770. zipFileHeader.extraFieldLength;
  771. e.m_eCompressionType = (IZip::eCompressionType)zipFileHeader.compressionMethod;
  772. // Add to tree
  773. m_Files.Insert( e );
  774. int nextOffset;
  775. if ( m_bCompatibleFormat )
  776. {
  777. nextOffset = zipFileHeader.extraFieldLength + zipFileHeader.fileCommentLength;
  778. }
  779. else
  780. {
  781. nextOffset = 0;
  782. }
  783. zipDirBuff.SeekGet( CUtlBuffer::SEEK_CURRENT, nextOffset );
  784. }
  785. return hFile;
  786. }
  787. static int GetLengthOfBinStringAsText( const char *pSrc, int srcSize )
  788. {
  789. const char *pSrcScan = pSrc;
  790. const char *pSrcEnd = pSrc + srcSize;
  791. int numChars = 0;
  792. for( ; pSrcScan < pSrcEnd; pSrcScan++ )
  793. {
  794. if( *pSrcScan == '\n' )
  795. {
  796. numChars += 2;
  797. }
  798. else
  799. {
  800. numChars++;
  801. }
  802. }
  803. return numChars;
  804. }
  805. //-----------------------------------------------------------------------------
  806. // Copies text data from a form appropriate for disk to a normal string
  807. //-----------------------------------------------------------------------------
  808. static void ReadTextData( const char *pSrc, int nSrcSize, CUtlBuffer &buf )
  809. {
  810. buf.EnsureCapacity( nSrcSize + 1 );
  811. const char *pSrcEnd = pSrc + nSrcSize;
  812. for ( const char *pSrcScan = pSrc; pSrcScan < pSrcEnd; ++pSrcScan )
  813. {
  814. if ( *pSrcScan == '\r' )
  815. {
  816. if ( pSrcScan[1] == '\n' )
  817. {
  818. buf.PutChar( '\n' );
  819. ++pSrcScan;
  820. continue;
  821. }
  822. }
  823. buf.PutChar( *pSrcScan );
  824. }
  825. // Null terminate
  826. buf.PutChar( '\0' );
  827. }
  828. //-----------------------------------------------------------------------------
  829. // Copies text data into a form appropriate for disk
  830. //-----------------------------------------------------------------------------
  831. static void CopyTextData( char *pDst, const char *pSrc, int dstSize, int srcSize )
  832. {
  833. const char *pSrcScan = pSrc;
  834. const char *pSrcEnd = pSrc + srcSize;
  835. char *pDstScan = pDst;
  836. #ifdef DBGFLAG_ASSERT
  837. char *pDstEnd = pDst + dstSize;
  838. #endif
  839. for ( ; pSrcScan < pSrcEnd; pSrcScan++ )
  840. {
  841. if ( *pSrcScan == '\n' )
  842. {
  843. *pDstScan = '\r';
  844. pDstScan++;
  845. *pDstScan = '\n';
  846. pDstScan++;
  847. }
  848. else
  849. {
  850. *pDstScan = *pSrcScan;
  851. pDstScan++;
  852. }
  853. }
  854. Assert( pSrcScan == pSrcEnd );
  855. Assert( pDstScan == pDstEnd );
  856. }
  857. //-----------------------------------------------------------------------------
  858. // Purpose: Adds a new lump, or overwrites existing one
  859. // Input : *relativename -
  860. // *data -
  861. // length -
  862. //-----------------------------------------------------------------------------
  863. void CZipFile::AddBufferToZip( const char *relativename, void *data, int length, bool bTextMode, IZip::eCompressionType compressionType )
  864. {
  865. // Lower case only
  866. char name[512];
  867. Q_strcpy( name, relativename );
  868. Q_strlower( name );
  869. int outLength = length;
  870. int uncompressedLength = length;
  871. void *outData = data;
  872. CUtlBuffer textTransform;
  873. CUtlBuffer compressionTransform;
  874. if ( bTextMode )
  875. {
  876. int textLen = GetLengthOfBinStringAsText( ( const char * )outData, outLength );
  877. textTransform.EnsureCapacity( textLen );
  878. CopyTextData( (char *)textTransform.Base(), (char *)outData, textLen, outLength );
  879. outData = (void *)textTransform.Base();
  880. outLength = textLen;
  881. uncompressedLength = textLen;
  882. }
  883. // uncompressed data final at this point (CRC is before compression)
  884. CRC32_t zipCRC;
  885. CRC32_Init( &zipCRC );
  886. CRC32_ProcessBuffer( &zipCRC, outData, outLength );
  887. CRC32_Final( &zipCRC );
  888. #ifdef ZIP_SUPPORT_LZMA_ENCODE
  889. if ( compressionType == IZip::eCompressionType_LZMA )
  890. {
  891. unsigned int compressedSize = 0;
  892. unsigned char *pCompressedOutput = LZMA_Compress( (unsigned char *)outData, outLength, &compressedSize );
  893. if ( !pCompressedOutput || compressedSize < sizeof( lzma_header_t ) )
  894. {
  895. Warning( "ZipFile: LZMA compression failed\n" );
  896. return;
  897. }
  898. // Fixup LZMA header for ZIP payload usage
  899. // The output of LZMA_Compress uses lzma_header_t, defined alongside it.
  900. //
  901. // ZIP payload format, see ZIP spec 5.8.8:
  902. // LZMA Version Information 2 bytes
  903. // LZMA Properties Size 2 bytes
  904. // LZMA Properties Data variable, defined by "LZMA Properties Size"
  905. unsigned int nZIPHeader = 2 + 2 + sizeof( lzma_header_t().properties );
  906. unsigned int finalCompressedSize = compressedSize - sizeof( lzma_header_t ) + nZIPHeader;
  907. compressionTransform.EnsureCapacity( finalCompressedSize );
  908. // LZMA version
  909. compressionTransform.PutUnsignedChar( LZMA_SDK_VERSION_MAJOR );
  910. compressionTransform.PutUnsignedChar( LZMA_SDK_VERSION_MINOR );
  911. // properties size
  912. uint16 nSwappedPropertiesSize = LittleWord( sizeof( lzma_header_t().properties ) );
  913. compressionTransform.Put( &nSwappedPropertiesSize, sizeof( nSwappedPropertiesSize ) );
  914. // properties
  915. compressionTransform.Put( &(((lzma_header_t *)pCompressedOutput)->properties), sizeof( lzma_header_t().properties ) );
  916. // payload
  917. compressionTransform.Put( pCompressedOutput + sizeof( lzma_header_t ), compressedSize - sizeof( lzma_header_t ) );
  918. // Free original
  919. free( pCompressedOutput );
  920. pCompressedOutput = NULL;
  921. outData = (void *)compressionTransform.Base();
  922. outLength = finalCompressedSize;
  923. // (Not updating uncompressedLength)
  924. }
  925. else
  926. #endif
  927. /* else from ifdef */ if ( compressionType != IZip::eCompressionType_None )
  928. {
  929. Error( "Calling AddBufferToZip with unknown compression type\n" );
  930. return;
  931. }
  932. // See if entry is in list already
  933. CZipEntry e;
  934. e.m_Name = name;
  935. int index = m_Files.Find( e );
  936. // If already existing, throw away old data and update data and length
  937. if ( index != m_Files.InvalidIndex() )
  938. {
  939. CZipEntry *update = &m_Files[ index ];
  940. if ( update->m_pData )
  941. {
  942. free( update->m_pData );
  943. }
  944. update->m_eCompressionType = compressionType;
  945. update->m_pData = malloc( outLength );
  946. memcpy( update->m_pData, outData, outLength );
  947. update->m_nCompressedSize = outLength;
  948. update->m_nUncompressedSize = uncompressedLength;
  949. update->m_ZipCRC = zipCRC;
  950. if ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE )
  951. {
  952. update->m_DiskCacheOffset = CWin32File::FileTell( m_hDiskCacheWriteFile );
  953. CWin32File::FileWrite( m_hDiskCacheWriteFile, update->m_pData, update->m_nCompressedSize );
  954. free( update->m_pData );
  955. update->m_pData = NULL;
  956. }
  957. }
  958. else
  959. {
  960. // Create a new entry
  961. e.m_nCompressedSize = outLength;
  962. e.m_nUncompressedSize = uncompressedLength;
  963. e.m_eCompressionType = compressionType;
  964. e.m_ZipCRC = zipCRC;
  965. if ( outLength > 0 )
  966. {
  967. e.m_pData = malloc( outLength );
  968. memcpy( e.m_pData, outData, outLength );
  969. if ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE )
  970. {
  971. e.m_DiskCacheOffset = CWin32File::FileTell( m_hDiskCacheWriteFile );
  972. CWin32File::FileWrite( m_hDiskCacheWriteFile, e.m_pData, e.m_nCompressedSize );
  973. free( e.m_pData );
  974. e.m_pData = NULL;
  975. }
  976. }
  977. else
  978. {
  979. e.m_pData = NULL;
  980. }
  981. m_Files.Insert( e );
  982. }
  983. }
  984. //-----------------------------------------------------------------------------
  985. // Reads a file from the zip
  986. //-----------------------------------------------------------------------------
  987. bool CZipFile::ReadFileFromZip( const char *pRelativeName, bool bTextMode, CUtlBuffer &buf )
  988. {
  989. return ReadFileFromZip( 0, pRelativeName, bTextMode, buf );
  990. }
  991. //-----------------------------------------------------------------------------
  992. // Reads a file from the zip. Requires the zip file handle if this zip was loaded via ParseFromDisk
  993. //-----------------------------------------------------------------------------
  994. bool CZipFile::ReadFileFromZip( HANDLE hZipFile, const char *pRelativeName, bool bTextMode, CUtlBuffer &buf )
  995. {
  996. // Lower case only
  997. char pName[512];
  998. Q_strncpy( pName, pRelativeName, 512 );
  999. Q_strlower( pName );
  1000. // See if entry is in list already
  1001. CZipEntry e;
  1002. e.m_Name = pName;
  1003. int nIndex = m_Files.Find( e );
  1004. if ( nIndex == m_Files.InvalidIndex() )
  1005. {
  1006. // not found
  1007. return false;
  1008. }
  1009. CZipEntry *pEntry = &m_Files[nIndex];
  1010. void *pData = pEntry->m_pData;
  1011. CUtlBuffer readBuffer;
  1012. if ( !pData && hZipFile )
  1013. {
  1014. readBuffer.EnsureCapacity( pEntry->m_nCompressedSize );
  1015. CWin32File::FileSeek( hZipFile, pEntry->m_SourceDiskOffset, FILE_BEGIN );
  1016. if ( !CWin32File::FileRead( hZipFile, readBuffer.Base(), pEntry->m_nCompressedSize ) )
  1017. {
  1018. return false;
  1019. }
  1020. pData = readBuffer.Base();
  1021. }
  1022. CUtlBuffer decompressTransform;
  1023. if ( pEntry->m_eCompressionType != IZip::eCompressionType_None )
  1024. {
  1025. if ( pEntry->m_eCompressionType == IZip::eCompressionType_LZMA )
  1026. {
  1027. decompressTransform.EnsureCapacity( pEntry->m_nUncompressedSize );
  1028. CLZMAStream decompressStream;
  1029. decompressStream.InitZIPHeader( pEntry->m_nCompressedSize, pEntry->m_nUncompressedSize );
  1030. unsigned int nCompressedBytesRead = 0;
  1031. unsigned int nOutputBytesWritten = 0;
  1032. bool bSuccess = decompressStream.Read( (unsigned char *)pData, pEntry->m_nCompressedSize,
  1033. (unsigned char *)decompressTransform.Base(), decompressTransform.Size(),
  1034. nCompressedBytesRead, nOutputBytesWritten );
  1035. if ( !bSuccess ||
  1036. (int)nCompressedBytesRead != pEntry->m_nCompressedSize ||
  1037. (int)nOutputBytesWritten != pEntry->m_nUncompressedSize )
  1038. {
  1039. Error( "Zip: Failed decompressing LZMA data\n" );
  1040. return false;
  1041. }
  1042. pData = decompressTransform.Base();
  1043. }
  1044. else
  1045. {
  1046. Error( "Unsupported compression type in Zip file: %u\n", pEntry->m_eCompressionType );
  1047. return false;
  1048. }
  1049. }
  1050. if ( bTextMode )
  1051. {
  1052. buf.SetBufferType( true, false );
  1053. ReadTextData( (const char *)pData, pEntry->m_nUncompressedSize, buf );
  1054. }
  1055. else
  1056. {
  1057. buf.SetBufferType( false, false );
  1058. buf.Put( pData, pEntry->m_nUncompressedSize );
  1059. }
  1060. return true;
  1061. }
  1062. //-----------------------------------------------------------------------------
  1063. // Purpose: Check if a file already exists in the zip.
  1064. // Input : *relativename -
  1065. //-----------------------------------------------------------------------------
  1066. bool CZipFile::FileExistsInZip( const char *pRelativeName )
  1067. {
  1068. // Lower case only
  1069. char pName[512];
  1070. Q_strncpy( pName, pRelativeName, 512 );
  1071. Q_strlower( pName );
  1072. // See if entry is in list already
  1073. CZipEntry e;
  1074. e.m_Name = pName;
  1075. int nIndex = m_Files.Find( e );
  1076. // If it is, then it exists in the pack!
  1077. return nIndex != m_Files.InvalidIndex();
  1078. }
  1079. //-----------------------------------------------------------------------------
  1080. // Purpose: Adds a new file to the zip.
  1081. //-----------------------------------------------------------------------------
  1082. void CZipFile::AddFileToZip( const char *relativename, const char *fullpath, IZip::eCompressionType compressionType )
  1083. {
  1084. FILE *temp = fopen( fullpath, "rb" );
  1085. if ( !temp )
  1086. return;
  1087. // Determine length
  1088. fseek( temp, 0, SEEK_END );
  1089. int size = ftell( temp );
  1090. fseek( temp, 0, SEEK_SET );
  1091. byte *buf = (byte *)malloc( size + 1 );
  1092. // Read data
  1093. fread( buf, size, 1, temp );
  1094. fclose( temp );
  1095. // Now add as a buffer
  1096. AddBufferToZip( relativename, buf, size, false, compressionType );
  1097. free( buf );
  1098. }
  1099. //-----------------------------------------------------------------------------
  1100. // Purpose: Removes a file from the zip.
  1101. //-----------------------------------------------------------------------------
  1102. void CZipFile::RemoveFileFromZip( const char *relativename )
  1103. {
  1104. CZipEntry e;
  1105. e.m_Name = relativename;
  1106. int index = m_Files.Find( e );
  1107. if ( index != m_Files.InvalidIndex() )
  1108. {
  1109. CZipEntry update = m_Files[index];
  1110. m_Files.Remove( update );
  1111. }
  1112. }
  1113. //---------------------------------------------------------------
  1114. // Purpose: Calculates how many bytes should be added to the extra field
  1115. // to push the start of the file data to the next aligned boundary
  1116. // Output: Required padding size
  1117. //---------------------------------------------------------------
  1118. unsigned short CZipFile::CalculatePadding( unsigned int filenameLen, unsigned int pos )
  1119. {
  1120. if ( m_AlignmentSize == 0 )
  1121. {
  1122. return 0;
  1123. }
  1124. unsigned int headerSize = sizeof( ZIP_LocalFileHeader ) + filenameLen;
  1125. return (unsigned short)( m_AlignmentSize - ( ( pos + headerSize ) % m_AlignmentSize ) );
  1126. }
  1127. //-----------------------------------------------------------------------------
  1128. // Purpose: Create the XZIP identifying comment string
  1129. // Output : Length
  1130. //-----------------------------------------------------------------------------
  1131. int CZipFile::MakeXZipCommentString( char *pCommentString )
  1132. {
  1133. char tempString[XZIP_COMMENT_LENGTH];
  1134. memset( tempString, 0, sizeof( tempString ) );
  1135. V_snprintf( tempString, sizeof( tempString ), "XZP%c %d", m_bCompatibleFormat ? '1' : '2', m_AlignmentSize );
  1136. if ( pCommentString )
  1137. {
  1138. memcpy( pCommentString, tempString, sizeof( tempString ) );
  1139. }
  1140. // expected fixed length
  1141. return XZIP_COMMENT_LENGTH;
  1142. }
  1143. //-----------------------------------------------------------------------------
  1144. // Purpose: An XZIP has its configuration in the ascii comment
  1145. //-----------------------------------------------------------------------------
  1146. void CZipFile::ParseXZipCommentString( const char *pCommentString )
  1147. {
  1148. if ( !V_strnicmp( pCommentString, "XZP", 3 ) )
  1149. {
  1150. m_bCompatibleFormat = true;
  1151. if ( pCommentString[3] == '2' )
  1152. {
  1153. m_bCompatibleFormat = false;
  1154. }
  1155. // parse out the alignement configuration
  1156. if ( !m_bForceAlignment )
  1157. {
  1158. m_AlignmentSize = 0;
  1159. sscanf( pCommentString + 4, "%d", &m_AlignmentSize );
  1160. if ( !IsPowerOfTwo( m_AlignmentSize ) )
  1161. {
  1162. m_AlignmentSize = 0;
  1163. }
  1164. }
  1165. }
  1166. }
  1167. //-----------------------------------------------------------------------------
  1168. // Purpose: Calculate the exact size of zip file, with headers and padding
  1169. // Output : int
  1170. //-----------------------------------------------------------------------------
  1171. unsigned int CZipFile::CalculateSize( void )
  1172. {
  1173. unsigned int size = 0;
  1174. unsigned int dirHeaders = 0;
  1175. for ( int i = m_Files.FirstInorder(); i != m_Files.InvalidIndex(); i = m_Files.NextInorder( i ) )
  1176. {
  1177. CZipEntry *e = &m_Files[ i ];
  1178. if ( e->m_nCompressedSize == 0 )
  1179. continue;
  1180. // local file header
  1181. size += sizeof( ZIP_LocalFileHeader );
  1182. size += strlen( e->m_Name.String() );
  1183. // every file has a directory header that duplicates the filename
  1184. dirHeaders += sizeof( ZIP_FileHeader ) + strlen( e->m_Name.String() );
  1185. // calculate padding
  1186. if ( m_AlignmentSize != 0 )
  1187. {
  1188. // round up to next boundary
  1189. unsigned int nextBoundary = ( size + m_AlignmentSize ) & ~( m_AlignmentSize - 1 );
  1190. // the directory header also duplicates the padding
  1191. dirHeaders += nextBoundary - size;
  1192. size = nextBoundary;
  1193. }
  1194. // data size
  1195. size += e->m_nCompressedSize;
  1196. }
  1197. size += dirHeaders;
  1198. // All processed zip files will have a comment string
  1199. size += sizeof( ZIP_EndOfCentralDirRecord ) + MakeXZipCommentString( NULL );
  1200. return size;
  1201. }
  1202. //-----------------------------------------------------------------------------
  1203. // Purpose: Print a directory of files in the zip
  1204. //-----------------------------------------------------------------------------
  1205. void CZipFile::PrintDirectory( void )
  1206. {
  1207. for ( int i = m_Files.FirstInorder(); i != m_Files.InvalidIndex(); i = m_Files.NextInorder( i ) )
  1208. {
  1209. CZipEntry *e = &m_Files[ i ];
  1210. Msg( "%s\n", e->m_Name.String() );
  1211. }
  1212. }
  1213. //-----------------------------------------------------------------------------
  1214. // Purpose: Iterate through directory
  1215. //-----------------------------------------------------------------------------
  1216. int CZipFile::GetNextFilename( int id, char *pBuffer, int bufferSize, int &fileSize )
  1217. {
  1218. if ( id == -1 )
  1219. {
  1220. id = m_Files.FirstInorder();
  1221. }
  1222. else
  1223. {
  1224. id = m_Files.NextInorder( id );
  1225. }
  1226. if ( id == m_Files.InvalidIndex() )
  1227. {
  1228. // list is empty
  1229. return -1;
  1230. }
  1231. CZipEntry *e = &m_Files[id];
  1232. Q_strncpy( pBuffer, e->m_Name.String(), bufferSize );
  1233. fileSize = e->m_nUncompressedSize;
  1234. return id;
  1235. }
  1236. //-----------------------------------------------------------------------------
  1237. // Purpose: Store data out to disk
  1238. //-----------------------------------------------------------------------------
  1239. void CZipFile::SaveToDisk( FILE *fout )
  1240. {
  1241. CFileStream stream( fout );
  1242. SaveDirectory( stream );
  1243. }
  1244. void CZipFile::SaveToDisk( HANDLE hOutFile )
  1245. {
  1246. CFileStream stream( hOutFile );
  1247. SaveDirectory( stream );
  1248. }
  1249. //-----------------------------------------------------------------------------
  1250. // Purpose: Store data out to a CUtlBuffer
  1251. //-----------------------------------------------------------------------------
  1252. void CZipFile::SaveToBuffer( CUtlBuffer& buf )
  1253. {
  1254. // Estimate size for buffer, since the linear growth of CUtlBuffer is a virtual memory steamroller. This is
  1255. // best-effort. Ideally CUtlBuffer's growth strategy would be sane and this would be unnecessary.
  1256. int sizeEstimate = 0;
  1257. for ( int i = m_Files.FirstInorder(); i != m_Files.InvalidIndex(); i = m_Files.NextInorder( i ) )
  1258. {
  1259. CZipEntry *e = &m_Files[i];
  1260. Assert( e );
  1261. int nameLen = V_strlen( e->m_Name.String() );
  1262. // Both the per-file header and central directory have these
  1263. sizeEstimate += 2 * sizeof( ZIP_LocalFileHeader );
  1264. sizeEstimate += 2 * nameLen;
  1265. sizeEstimate += 2 * CalculatePadding( nameLen, e->m_ZipOffset );
  1266. sizeEstimate += sizeof( ZIP_EndOfCentralDirRecord );
  1267. sizeEstimate += e->m_nCompressedSize;
  1268. // XZip comment string, max 128
  1269. sizeEstimate += 128;
  1270. // We align things to m_AlignmentSize at two points
  1271. sizeEstimate += m_AlignmentSize * 2;
  1272. }
  1273. int start = buf.TellPut();
  1274. buf.EnsureCapacity( start + sizeEstimate );
  1275. CBufferStream stream( buf );
  1276. SaveDirectory( stream );
  1277. int end = buf.TellPut();
  1278. if ( start + sizeEstimate < end )
  1279. {
  1280. Warning( "ZIP Output overshot buffer estimate: Estimated %i, actual %i\n", sizeEstimate, end - start );
  1281. }
  1282. else
  1283. {
  1284. DevMsg( "Wrote ZIP buffer, estimated size %i, actual size %i\n", sizeEstimate, end - start );
  1285. }
  1286. }
  1287. //-----------------------------------------------------------------------------
  1288. // Purpose: Store data back out to a stream (could be CUtlBuffer or filestream)
  1289. //-----------------------------------------------------------------------------
  1290. void CZipFile::SaveDirectory( IWriteStream& stream )
  1291. {
  1292. void *pPaddingBuffer = NULL;
  1293. if ( m_AlignmentSize )
  1294. {
  1295. // get a temp buffer for all padding work
  1296. pPaddingBuffer = malloc( m_AlignmentSize );
  1297. memset( pPaddingBuffer, 0x00, m_AlignmentSize );
  1298. }
  1299. if ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE )
  1300. {
  1301. #ifdef WIN32
  1302. FlushFileBuffers( m_hDiskCacheWriteFile );
  1303. #else
  1304. fflush( (FILE *)m_hDiskCacheWriteFile );
  1305. #endif
  1306. }
  1307. // Might be writing a zip into a larger stream
  1308. unsigned int zipOffsetInStream = stream.Tell();
  1309. int i;
  1310. for ( i = m_Files.FirstInorder(); i != m_Files.InvalidIndex(); i = m_Files.NextInorder( i ) )
  1311. {
  1312. CZipEntry *e = &m_Files[i];
  1313. Assert( e );
  1314. // Fix up the offset
  1315. e->m_ZipOffset = stream.Tell() - zipOffsetInStream;
  1316. if ( e->m_nCompressedSize > 0 && ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE ) )
  1317. {
  1318. // get the data back from the write cache
  1319. e->m_pData = malloc( e->m_nCompressedSize );
  1320. if ( e->m_pData )
  1321. {
  1322. CWin32File::FileSeek( m_hDiskCacheWriteFile, e->m_DiskCacheOffset, FILE_BEGIN );
  1323. CWin32File::FileRead( m_hDiskCacheWriteFile, e->m_pData, e->m_nCompressedSize );
  1324. }
  1325. }
  1326. if ( e->m_nCompressedSize > 0 && e->m_pData != NULL )
  1327. {
  1328. ZIP_LocalFileHeader hdr = { 0 };
  1329. hdr.signature = PKID( 3, 4 );
  1330. hdr.versionNeededToExtract = 10; // No special features or even compression here, set to 1.0
  1331. #ifdef ZIP_SUPPORT_LZMA_ENCODE
  1332. if ( e->m_eCompressionType == IZip::eCompressionType_LZMA )
  1333. {
  1334. // Per ZIP spec 5.8.8
  1335. hdr.versionNeededToExtract = 63;
  1336. }
  1337. #endif
  1338. hdr.flags = 0;
  1339. hdr.compressionMethod = e->m_eCompressionType;
  1340. hdr.lastModifiedTime = 0;
  1341. hdr.lastModifiedDate = 0;
  1342. hdr.crc32 = e->m_ZipCRC;
  1343. const char *pFilename = e->m_Name.String();
  1344. hdr.compressedSize = e->m_nCompressedSize;
  1345. hdr.uncompressedSize = e->m_nUncompressedSize;
  1346. hdr.fileNameLength = strlen( pFilename );
  1347. hdr.extraFieldLength = CalculatePadding( hdr.fileNameLength, e->m_ZipOffset );
  1348. int extraFieldLength = hdr.extraFieldLength;
  1349. // Swap header in place
  1350. m_Swap.SwapFieldsToTargetEndian( &hdr );
  1351. stream.Put( &hdr, sizeof( hdr ) );
  1352. stream.Put( pFilename, strlen( pFilename ) );
  1353. stream.Put( pPaddingBuffer, extraFieldLength );
  1354. stream.Put( e->m_pData, e->m_nCompressedSize );
  1355. if ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE )
  1356. {
  1357. free( e->m_pData );
  1358. // temp hackery for the logic below to succeed
  1359. e->m_pData = (void*)0xFFFFFFFF;
  1360. }
  1361. }
  1362. }
  1363. if ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE )
  1364. {
  1365. CWin32File::FileSeek( m_hDiskCacheWriteFile, 0, FILE_END );
  1366. }
  1367. unsigned int centralDirStart = stream.Tell() - zipOffsetInStream;
  1368. if ( m_AlignmentSize )
  1369. {
  1370. // align the central directory starting position
  1371. unsigned int newDirStart = AlignValue( centralDirStart, m_AlignmentSize );
  1372. int padLength = newDirStart - centralDirStart;
  1373. if ( padLength )
  1374. {
  1375. stream.Put( pPaddingBuffer, padLength );
  1376. centralDirStart = newDirStart;
  1377. }
  1378. }
  1379. int realNumFiles = 0;
  1380. for ( i = m_Files.FirstInorder(); i != m_Files.InvalidIndex(); i = m_Files.NextInorder( i ) )
  1381. {
  1382. CZipEntry *e = &m_Files[i];
  1383. Assert( e );
  1384. if ( e->m_nCompressedSize > 0 && e->m_pData != NULL )
  1385. {
  1386. ZIP_FileHeader hdr = { 0 };
  1387. hdr.signature = PKID( 1, 2 );
  1388. hdr.versionMadeBy = 20; // This is the version that the winzip that I have writes.
  1389. hdr.versionNeededToExtract = 10; // No special features or even compression here, set to 1.0
  1390. #ifdef ZIP_SUPPORT_LZMA_ENCODE
  1391. if ( e->m_eCompressionType == IZip::eCompressionType_LZMA )
  1392. {
  1393. // Per ZIP spec 5.8.8
  1394. hdr.versionNeededToExtract = 63;
  1395. }
  1396. #endif
  1397. hdr.flags = 0;
  1398. hdr.compressionMethod = e->m_eCompressionType;
  1399. hdr.lastModifiedTime = 0;
  1400. hdr.lastModifiedDate = 0;
  1401. hdr.crc32 = e->m_ZipCRC;
  1402. hdr.compressedSize = e->m_nCompressedSize;
  1403. hdr.uncompressedSize = e->m_nUncompressedSize;
  1404. hdr.fileNameLength = strlen( e->m_Name.String() );
  1405. hdr.extraFieldLength = CalculatePadding( hdr.fileNameLength, e->m_ZipOffset );
  1406. hdr.fileCommentLength = 0;
  1407. hdr.diskNumberStart = 0;
  1408. hdr.internalFileAttribs = 0;
  1409. hdr.externalFileAttribs = 0; // This is usually something, but zero is OK as if the input came from stdin
  1410. hdr.relativeOffsetOfLocalHeader = e->m_ZipOffset;
  1411. int extraFieldLength = hdr.extraFieldLength;
  1412. // Swap the header in place
  1413. m_Swap.SwapFieldsToTargetEndian( &hdr );
  1414. stream.Put( &hdr, sizeof( hdr ) );
  1415. stream.Put( e->m_Name.String(), strlen( e->m_Name.String() ) );
  1416. if ( m_bCompatibleFormat )
  1417. {
  1418. stream.Put( pPaddingBuffer, extraFieldLength );
  1419. }
  1420. realNumFiles++;
  1421. if ( m_hDiskCacheWriteFile != INVALID_HANDLE_VALUE )
  1422. {
  1423. // clear out temp hackery
  1424. e->m_pData = NULL;
  1425. }
  1426. }
  1427. }
  1428. unsigned int centralDirEnd = stream.Tell() - zipOffsetInStream;
  1429. if ( m_AlignmentSize )
  1430. {
  1431. // align the central directory starting position
  1432. unsigned int newDirEnd = AlignValue( centralDirEnd, m_AlignmentSize );
  1433. int padLength = newDirEnd - centralDirEnd;
  1434. if ( padLength )
  1435. {
  1436. stream.Put( pPaddingBuffer, padLength );
  1437. centralDirEnd = newDirEnd;
  1438. }
  1439. }
  1440. ZIP_EndOfCentralDirRecord rec = { 0 };
  1441. rec.signature = PKID( 5, 6 );
  1442. rec.numberOfThisDisk = 0;
  1443. rec.numberOfTheDiskWithStartOfCentralDirectory = 0;
  1444. rec.nCentralDirectoryEntries_ThisDisk = realNumFiles;
  1445. rec.nCentralDirectoryEntries_Total = realNumFiles;
  1446. rec.centralDirectorySize = centralDirEnd - centralDirStart;
  1447. rec.startOfCentralDirOffset = centralDirStart;
  1448. char commentString[128];
  1449. int commentLength = MakeXZipCommentString( commentString );
  1450. rec.commentLength = commentLength;
  1451. // Swap the header in place
  1452. m_Swap.SwapFieldsToTargetEndian( &rec );
  1453. stream.Put( &rec, sizeof( rec ) );
  1454. stream.Put( commentString, commentLength );
  1455. if ( pPaddingBuffer )
  1456. {
  1457. free( pPaddingBuffer );
  1458. }
  1459. }
  1460. class CZip : public IZip
  1461. {
  1462. public:
  1463. CZip( const char *pDiskCacheWritePath, bool bSortByName );
  1464. virtual ~CZip();
  1465. virtual void Reset() OVERRIDE;
  1466. // Add a single file to a zip - maintains the zip's previous alignment state
  1467. virtual void AddFileToZip( const char *relativename, const char *fullpath, eCompressionType compressionType ) OVERRIDE;
  1468. // Whether a file is contained in a zip - maintains alignment
  1469. virtual bool FileExistsInZip( const char *pRelativeName ) OVERRIDE;
  1470. // Reads a file from the zip - maintains alignement
  1471. virtual bool ReadFileFromZip( const char *pRelativeName, bool bTextMode, CUtlBuffer &buf ) OVERRIDE;
  1472. virtual bool ReadFileFromZip( HANDLE hZipFile, const char *relativename, bool bTextMode, CUtlBuffer &buf ) OVERRIDE;
  1473. // Removes a single file from the zip - maintains alignment
  1474. virtual void RemoveFileFromZip( const char *relativename ) OVERRIDE;
  1475. // Gets next filename in zip, for walking the directory - maintains alignment
  1476. virtual int GetNextFilename( int id, char *pBuffer, int bufferSize, int &fileSize ) OVERRIDE;
  1477. // Prints the zip's contents - maintains alignment
  1478. virtual void PrintDirectory( void ) OVERRIDE;
  1479. // Estimate the size of the Zip (including header, padding, etc.)
  1480. virtual unsigned int EstimateSize( void ) OVERRIDE;
  1481. // Add buffer to zip as a file with given name - uses current alignment size, default 0 (no alignment)
  1482. virtual void AddBufferToZip( const char *relativename, void *data, int length,
  1483. bool bTextMode, eCompressionType compressionType ) OVERRIDE;
  1484. // Writes out zip file to a buffer - uses current alignment size
  1485. // (set by file's previous alignment, or a call to ForceAlignment)
  1486. virtual void SaveToBuffer( CUtlBuffer& outbuf ) OVERRIDE;
  1487. // Writes out zip file to a filestream - uses current alignment size
  1488. // (set by file's previous alignment, or a call to ForceAlignment)
  1489. virtual void SaveToDisk( FILE *fout ) OVERRIDE;
  1490. virtual void SaveToDisk( HANDLE hOutFile ) OVERRIDE;
  1491. // Reads a zip file from a buffer into memory - sets current alignment size to
  1492. // the file's alignment size, unless overridden by a ForceAlignment call)
  1493. virtual void ParseFromBuffer( void *buffer, int bufferlength ) OVERRIDE;
  1494. virtual HANDLE ParseFromDisk( const char *pFilename ) OVERRIDE;
  1495. // Forces a specific alignment size for all subsequent file operations, overriding files' previous alignment size.
  1496. // Return to using files' individual alignment sizes by passing FALSE.
  1497. virtual void ForceAlignment( bool aligned, bool bCompatibleFormat, unsigned int alignmentSize ) OVERRIDE;
  1498. // Sets the endianess of the zip
  1499. virtual void SetBigEndian( bool bigEndian ) OVERRIDE;
  1500. virtual void ActivateByteSwapping( bool bActivate ) OVERRIDE;
  1501. virtual unsigned int GetAlignment() OVERRIDE;
  1502. private:
  1503. CZipFile m_ZipFile;
  1504. };
  1505. static CUtlLinkedList< CZip* > g_ZipUtils;
  1506. IZip *IZip::CreateZip( const char *pDiskCacheWritePath, bool bSortByName )
  1507. {
  1508. CZip *pZip = new CZip( pDiskCacheWritePath, bSortByName );
  1509. g_ZipUtils.AddToTail( pZip );
  1510. return pZip;
  1511. }
  1512. void IZip::ReleaseZip( IZip *pZip )
  1513. {
  1514. g_ZipUtils.FindAndRemove( (CZip *)pZip );
  1515. delete ((CZip *)pZip);
  1516. }
  1517. CZip::CZip( const char *pDiskCacheWritePath, bool bSortByName ) : m_ZipFile( pDiskCacheWritePath, bSortByName )
  1518. {
  1519. m_ZipFile.Reset();
  1520. }
  1521. CZip::~CZip()
  1522. {
  1523. }
  1524. void CZip::SetBigEndian( bool bigEndian )
  1525. {
  1526. m_ZipFile.SetBigEndian( bigEndian );
  1527. }
  1528. void CZip::ActivateByteSwapping( bool bActivate )
  1529. {
  1530. m_ZipFile.ActivateByteSwapping( bActivate );
  1531. }
  1532. void CZip::AddFileToZip( const char *relativename, const char *fullpath, eCompressionType compressionType )
  1533. {
  1534. m_ZipFile.AddFileToZip( relativename, fullpath, compressionType );
  1535. }
  1536. bool CZip::FileExistsInZip( const char *pRelativeName )
  1537. {
  1538. return m_ZipFile.FileExistsInZip( pRelativeName );
  1539. }
  1540. bool CZip::ReadFileFromZip( const char *pRelativeName, bool bTextMode, CUtlBuffer &buf )
  1541. {
  1542. return m_ZipFile.ReadFileFromZip( pRelativeName, bTextMode, buf );
  1543. }
  1544. bool CZip::ReadFileFromZip( HANDLE hZipFile, const char *pRelativeName, bool bTextMode, CUtlBuffer &buf )
  1545. {
  1546. return m_ZipFile.ReadFileFromZip( hZipFile, pRelativeName, bTextMode, buf );
  1547. }
  1548. void CZip::RemoveFileFromZip( const char *relativename )
  1549. {
  1550. m_ZipFile.RemoveFileFromZip( relativename );
  1551. }
  1552. int CZip::GetNextFilename( int id, char *pBuffer, int bufferSize, int &fileSize )
  1553. {
  1554. return m_ZipFile.GetNextFilename( id, pBuffer, bufferSize, fileSize );
  1555. }
  1556. void CZip::PrintDirectory( void )
  1557. {
  1558. m_ZipFile.PrintDirectory();
  1559. }
  1560. void CZip::Reset()
  1561. {
  1562. m_ZipFile.Reset();
  1563. }
  1564. unsigned int CZip::EstimateSize( void )
  1565. {
  1566. return m_ZipFile.CalculateSize();
  1567. }
  1568. // Add buffer to zip as a file with given name
  1569. void CZip::AddBufferToZip( const char *relativename, void *data, int length, bool bTextMode, eCompressionType compressionType )
  1570. {
  1571. m_ZipFile.AddBufferToZip( relativename, data, length, bTextMode, compressionType );
  1572. }
  1573. void CZip::SaveToBuffer( CUtlBuffer& outbuf )
  1574. {
  1575. m_ZipFile.SaveToBuffer( outbuf );
  1576. }
  1577. void CZip::SaveToDisk( FILE *fout )
  1578. {
  1579. m_ZipFile.SaveToDisk( fout );
  1580. }
  1581. void CZip::SaveToDisk( HANDLE hOutFile )
  1582. {
  1583. m_ZipFile.SaveToDisk( hOutFile );
  1584. }
  1585. void CZip::ParseFromBuffer( void *buffer, int bufferlength )
  1586. {
  1587. m_ZipFile.Reset();
  1588. m_ZipFile.ParseFromBuffer( buffer, bufferlength );
  1589. }
  1590. HANDLE CZip::ParseFromDisk( const char *pFilename )
  1591. {
  1592. m_ZipFile.Reset();
  1593. return m_ZipFile.ParseFromDisk( pFilename );
  1594. }
  1595. void CZip::ForceAlignment( bool aligned, bool bCompatibleFormat, unsigned int alignmentSize )
  1596. {
  1597. m_ZipFile.ForceAlignment( aligned, bCompatibleFormat, alignmentSize );
  1598. }
  1599. unsigned int CZip::GetAlignment()
  1600. {
  1601. return m_ZipFile.GetAlignment();
  1602. }