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.
277 lines
8.8 KiB
277 lines
8.8 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//===========================================================================// |
|
|
|
#ifndef PACKFILE_H |
|
#define PACKFILE_H |
|
|
|
#ifdef _WIN32 |
|
#pragma once |
|
#endif |
|
|
|
// How many bytes compressed filehandles should hold for seeking backwards. Seeks beyond this limit will require |
|
// rewinding and restarting the compression, at significant performance penalty. (Warnings emitted when this occurs) |
|
#define PACKFILE_COMPRESSED_FILEHANDLE_SEEK_BUFFER 4096 |
|
|
|
// How many bytes compressed filehandles should attempt to read (and cache) at a time from the underlying compressed data. |
|
#define PACKFILE_COMPRESSED_FILEHANDLE_READ_BUFFER 4096 |
|
|
|
// Emit warnings in debug builds if we hold more than this many compressed file handles alive to alert to the poor |
|
// memory characteristics. |
|
#define PACKFILE_COMPRESSED_FILE_HANDLES_WARNING 20 |
|
|
|
#include "basefilesystem.h" |
|
#include "tier1/refcount.h" |
|
#include "tier1/utlbuffer.h" |
|
#include "tier1/lzmaDecoder.h" |
|
|
|
class CPackFile; |
|
class CZipPackFile; |
|
|
|
// A pack file handle - essentially represents a file inside the pack file. |
|
class CPackFileHandle |
|
{ |
|
public: |
|
virtual ~CPackFileHandle() {}; |
|
|
|
virtual int Read( void* pBuffer, int nDestSize, int nBytes ) = 0; |
|
virtual int Seek( int nOffset, int nWhence ) = 0; |
|
virtual int Tell() = 0; |
|
virtual int Size() = 0; |
|
|
|
virtual void SetBufferSize( int nBytes ) = 0; |
|
virtual int GetSectorSize() = 0; |
|
virtual int64 AbsoluteBaseOffset() = 0; |
|
}; |
|
|
|
class CZipPackFileHandle : public CPackFileHandle |
|
{ |
|
public: |
|
CZipPackFileHandle( CZipPackFile* pOwner, int64 nBase, unsigned int nLength, unsigned int nIndex = -1, unsigned int nFilePointer = 0 ); |
|
virtual ~CZipPackFileHandle(); |
|
|
|
virtual int Read( void* pBuffer, int nDestSize, int nBytes ) OVERRIDE; |
|
virtual int Seek( int nOffset, int nWhence ) OVERRIDE; |
|
|
|
virtual int Tell() OVERRIDE { return m_nFilePointer; }; |
|
virtual int Size() OVERRIDE { return m_nLength; }; |
|
|
|
virtual void SetBufferSize( int nBytes ) OVERRIDE; |
|
virtual int GetSectorSize() OVERRIDE; |
|
virtual int64 AbsoluteBaseOffset() OVERRIDE; |
|
|
|
protected: |
|
int64 m_nBase; // Base offset of the file inside the pack file. |
|
unsigned int m_nFilePointer; // Current seek pointer (0 based from the beginning of the file). |
|
CZipPackFile* m_pOwner; // Pack file that owns this handle |
|
unsigned int m_nLength; // Length of this file. |
|
unsigned int m_nIndex; // Index into the pack's directory table |
|
}; |
|
|
|
class CLZMAZipPackFileHandle : public CZipPackFileHandle |
|
{ |
|
public: |
|
CLZMAZipPackFileHandle( CZipPackFile* pOwner, int64 nBase, unsigned int nOriginalSize, unsigned int nCompressedSize, |
|
unsigned int nIndex = -1, unsigned int nFilePointer = 0 ); |
|
~CLZMAZipPackFileHandle(); |
|
|
|
virtual int Read( void* pBuffer, int nDestSize, int nBytes ) OVERRIDE; |
|
virtual int Seek( int nOffset, int nWhence ) OVERRIDE; |
|
|
|
virtual int Tell() OVERRIDE; |
|
virtual int Size() OVERRIDE; |
|
|
|
private: |
|
// Ensure there are bytes in the read buffer, assuming we're not at the end of the underlying data |
|
int FillReadBuffer(); |
|
|
|
// Reset buffers and underlying seek position to 0 |
|
void Reset(); |
|
|
|
// Contains the last PACKFILE_COMPRESSED_FILEHANDLE_SEEK_BUFFER decompressed bytes. The Put and Get locations mimic our |
|
// filehandle -- TellPut() == TelGet() when we are not back seeking. |
|
CUtlBuffer m_BackSeekBuffer; |
|
|
|
// The read buffer from the underlying compressed stream. We read PACKFILE_COMPRESSED_FILEHANDLE_READ_BUFFER bytes |
|
// into this buffer, then consume it via the buffer get position. |
|
CUtlBuffer m_ReadBuffer; |
|
|
|
// The decompress stream we feed our base filehandle into |
|
CLZMAStream *m_pLZMAStream; |
|
|
|
// Current seek position in uncompressed data |
|
int m_nSeekPosition; |
|
|
|
// Size of the decompressed data |
|
unsigned int m_nOriginalSize; |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
// An abstract pack file |
|
class CPackFile : public CRefCounted<CRefCountServiceMT> |
|
{ |
|
public: |
|
CPackFile(); |
|
virtual ~CPackFile(); |
|
|
|
// The means by which you open files: |
|
virtual CFileHandle *OpenFile( const char *pFileName, const char *pOptions = "rb" ) = 0; |
|
|
|
// Check for existance in pack |
|
virtual bool ContainsFile( const char *pFileName ) = 0; |
|
|
|
// The two functions a pack file must provide |
|
virtual bool Prepare( int64 fileLen = -1, int64 nFileOfs = 0 ) = 0; |
|
|
|
// Returns the filename for a given file in the pack. Returns true if a filename is found, otherwise buffer is filled with "unknown" |
|
virtual bool IndexToFilename( int nIndex, char* buffer, int nBufferSize ) = 0; |
|
|
|
inline int GetSectorSize(); |
|
|
|
virtual void SetupPreloadData() {} |
|
virtual void DiscardPreloadData() {} |
|
virtual int64 GetPackFileBaseOffset() = 0; |
|
|
|
CBaseFileSystem *FileSystem() { return m_fs; } |
|
|
|
// Helper for the filesystem's FindFirst/FindNext() API which mimics the old windows equivalent. pWildcard is the |
|
// same pattern that you would pass to FindFirst, not a true wildcard. |
|
// Mirrors the VPK code's similar call. |
|
virtual void GetFileAndDirLists( const char *pFindWildCard, CUtlStringList &outDirnames, CUtlStringList &outFilenames, bool bSortedOutput ) = 0; |
|
|
|
// Note: threading model for pack files assumes that data |
|
// is segmented into pack files that aggregate files |
|
// meant to be read in one thread. Performance characteristics |
|
// tuned for that case |
|
CThreadFastMutex m_mutex; |
|
|
|
// Path management: |
|
void SetPath( const CUtlSymbol &path ) { m_Path = path; } |
|
const CUtlSymbol& GetPath() const { Assert( m_Path != UTL_INVAL_SYMBOL ); return m_Path; } |
|
CUtlSymbol m_Path; |
|
|
|
// possibly embedded pack |
|
int64 m_nBaseOffset; |
|
|
|
CUtlString m_ZipName; |
|
|
|
bool m_bIsMapPath; |
|
long m_lPackFileTime; |
|
|
|
int m_refCount; |
|
int m_nOpenFiles; |
|
|
|
FILE *m_hPackFileHandleFS; |
|
#if defined( SUPPORT_PACKED_STORE ) |
|
CPackedStoreFileHandle m_hPackFileHandleVPK; |
|
#endif |
|
bool m_bIsExcluded; |
|
|
|
int m_PackFileID; |
|
protected: |
|
// This is the core IO routine for reading anything from a pack file, everything should go through here at some point |
|
virtual int ReadFromPack( int nIndex, void* buffer, int nDestBytes, int nBytes, int64 nOffset ) = 0; |
|
|
|
int64 m_FileLength; |
|
CBaseFileSystem *m_fs; |
|
|
|
friend class CPackFileHandle; |
|
}; |
|
|
|
class CZipPackFile : public CPackFile |
|
{ |
|
friend class CZipPackFileHandle; |
|
public: |
|
CZipPackFile( CBaseFileSystem* fs, void *pSection = NULL ); |
|
virtual ~CZipPackFile(); |
|
|
|
// Loads the pack file |
|
virtual bool Prepare( int64 fileLen = -1, int64 nFileOfs = 0 ) OVERRIDE; |
|
virtual bool ContainsFile( const char *pFileName ) OVERRIDE; |
|
virtual CFileHandle *OpenFile( const char *pFileName, const char *pOptions = "rb" ) OVERRIDE; |
|
|
|
virtual void GetFileAndDirLists( const char *pFindWildCard, CUtlStringList &outDirnames, CUtlStringList &outFilenames, bool bSortedOutput ) OVERRIDE; |
|
|
|
virtual int64 GetPackFileBaseOffset() OVERRIDE { return m_nBaseOffset; } |
|
|
|
virtual bool IndexToFilename( int nIndex, char *pBuffer, int nBufferSize ) OVERRIDE; |
|
|
|
protected: |
|
virtual int ReadFromPack( int nIndex, void* buffer, int nDestBytes, int nBytes, int64 nOffset ) OVERRIDE; |
|
|
|
#pragma pack(1) |
|
|
|
typedef struct |
|
{ |
|
char name[ 112 ]; |
|
int64 filepos; |
|
int64 filelen; |
|
} packfile64_t; |
|
|
|
typedef struct |
|
{ |
|
char id[ 4 ]; |
|
int64 dirofs; |
|
int64 dirlen; |
|
} packheader64_t; |
|
|
|
typedef struct |
|
{ |
|
char id[ 8 ]; |
|
int64 packheaderpos; |
|
int64 originalfilesize; |
|
} packappenededheader_t; |
|
|
|
#pragma pack() |
|
|
|
// A Pack file directory entry: |
|
class CPackFileEntry |
|
{ |
|
public: |
|
unsigned int m_nPosition; |
|
unsigned int m_nOriginalSize; |
|
unsigned int m_nCompressedSize; |
|
unsigned int m_HashName; |
|
unsigned short m_nPreloadIdx; |
|
unsigned short pad; |
|
unsigned short m_nCompressionMethod; |
|
FileNameHandle_t m_hFileName; |
|
}; |
|
|
|
class CPackFileLessFunc |
|
{ |
|
public: |
|
bool Less( CPackFileEntry const& src1, CPackFileEntry const& src2, void *pCtx ); |
|
}; |
|
|
|
// Find a file inside a pack file: |
|
const CPackFileEntry* FindFile( const char* pFileName ); |
|
|
|
// Entries to the individual files stored inside the pack file. |
|
CUtlSortVector< CPackFileEntry, CPackFileLessFunc > m_PackFiles; |
|
|
|
bool GetFileInfo( const char *pFileName, int &nBaseIndex, int64 &nFileOffset, int &nOriginalSize, int &nCompressedSize, unsigned short &nCompressionMethod ); |
|
|
|
// Preload Support |
|
void SetupPreloadData() OVERRIDE; |
|
void DiscardPreloadData() OVERRIDE; |
|
ZIP_PreloadDirectoryEntry* GetPreloadEntry( int nEntryIndex ); |
|
|
|
int64 m_nPreloadSectionOffset; |
|
unsigned int m_nPreloadSectionSize; |
|
ZIP_PreloadHeader *m_pPreloadHeader; |
|
unsigned short* m_pPreloadRemapTable; |
|
ZIP_PreloadDirectoryEntry *m_pPreloadDirectory; |
|
void* m_pPreloadData; |
|
CByteswap m_swap; |
|
|
|
#if defined ( _X360 ) |
|
void *m_pSection; |
|
#endif |
|
}; |
|
|
|
#endif // PACKFILE_H
|
|
|