-
Notifications
You must be signed in to change notification settings - Fork 270
/
Copy pathpackfile.h
277 lines (212 loc) · 8.79 KB
/
packfile.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
//========= 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