2009-05-08 13:28:41 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2013-12-17 20:01:09 +00:00
* Copyright ( c ) 1998 - 2000 , Matthes Bender
* Copyright ( c ) 2001 - 2009 , RedWolf Design GmbH , http : //www.clonk.de/
2016-04-03 18:18:29 +00:00
* Copyright ( c ) 2009 - 2016 , The OpenClonk Team and contributors
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* To redistribute this file separately , substitute the full license texts
* for the above references .
2009-05-08 13:28:41 +00:00
*/
/* Handles group files */
# ifndef INC_C4Group
# define INC_C4Group
# ifdef HAVE_IO_H
# include <io.h>
# endif
2016-04-03 18:07:56 +00:00
# include "c4group/CStdFile.h"
2009-05-08 13:28:41 +00:00
// C4Group-Rewind-warning:
// The current C4Group-implementation cannot handle random file access very well,
// because all files are written within a single zlib-stream.
// For every out-of-order-file accessed a group-rewind must be performed, and every
// single file up to the accessed file unpacked. As a workaround, all C4Groups are
// packed in a file order matching the reading order of the engine.
// If the reading order doesn't match the packing order, and a rewind has to be performed,
// a warning is issued in Debug-builds of the engine. But since some components require
// random access because they are loaded on-demand at runtime (e.g. global sounds), the
// warning may be temp disabled for those files using C4GRP_DISABLE_REWINDWARN and
// C4GRP_ENABLE_REWINDWARN. A ref counter keeps track of nested calls to those functions.
//
// If you add any new components to scenario or definition files, remember to adjust the
// sort order lists in C4Components.h accordingly, and enforce a reading order for that
// component.
//
// Maybe some day, someone will write a C4Group-implementation that is probably capable of
// random access...
# ifdef _DEBUG
extern int iC4GroupRewindFilePtrNoWarn ;
# define C4GRP_DISABLE_REWINDWARN ++iC4GroupRewindFilePtrNoWarn;
# define C4GRP_ENABLE_REWINDWARN --iC4GroupRewindFilePtrNoWarn;
# else
# define C4GRP_DISABLE_REWINDWARN ;
# define C4GRP_ENABLE_REWINDWARN ;
# endif
const int C4GroupFileVer1 = 1 , C4GroupFileVer2 = 2 ;
2011-05-01 11:37:36 +00:00
const int C4GroupMaxError = 100 ;
2009-05-08 13:28:41 +00:00
const int32_t C4GroupSwapThreshold = 10 * 1024 * 1024 ;
# define C4GroupFileID "RedWolf Design GrpFolder"
2010-04-15 20:24:34 +00:00
bool C4Group_TestIgnore ( const char * szFilename ) ;
2009-05-08 13:28:41 +00:00
void C4Group_SetTempPath ( const char * szPath ) ;
const char * C4Group_GetTempPath ( ) ;
void C4Group_SetSortList ( const char * * ppSortList ) ;
2009-08-15 18:50:32 +00:00
void C4Group_SetProcessCallback ( bool ( * fnCallback ) ( const char * , int ) ) ;
bool C4Group_IsGroup ( const char * szFilename ) ;
bool C4Group_CopyItem ( const char * szSource , const char * szTarget , bool fNoSort = false , bool fResetAttributes = false ) ;
bool C4Group_MoveItem ( const char * szSource , const char * szTarget , bool fNoSort = false ) ;
bool C4Group_DeleteItem ( const char * szItem , bool fRecycle = false ) ;
2009-05-08 13:28:41 +00:00
bool C4Group_PackDirectoryTo ( const char * szFilename , const char * szFilenameTo ) ;
bool C4Group_PackDirectory ( const char * szFilename ) ;
2009-08-15 18:50:32 +00:00
bool C4Group_UnpackDirectory ( const char * szFilename ) ;
2009-05-08 13:28:41 +00:00
bool C4Group_ExplodeDirectory ( const char * szFilename ) ;
bool C4Group_ReadFile ( const char * szFilename , char * * pData , size_t * iSize ) ;
extern const char * C4CFN_FLS [ ] ;
# pragma pack (push, 1)
2015-11-14 15:17:00 +00:00
struct C4GroupHeader
2010-03-28 17:58:21 +00:00
{
2015-11-14 15:17:00 +00:00
char id [ 24 + 4 ] = C4GroupFileID ;
int Ver1 = C4GroupFileVer1 ;
int Ver2 = C4GroupFileVer2 ;
int Entries = 0 ;
char reserved [ 164 ] = { 0 } ;
2010-03-28 17:58:21 +00:00
} ;
2009-05-08 13:28:41 +00:00
2015-11-14 15:17:00 +00:00
struct C4GroupEntryCore
2010-03-28 17:58:21 +00:00
{
2015-11-14 15:17:00 +00:00
char FileName [ 260 ] = { 0 } ;
int32_t Packed = 0 , ChildGroup = 0 ;
int32_t Size = 0 , reserved1 = 0 , Offset = 0 ;
int32_t reserved2 = 0 ;
char reserved3 = ' \0 ' ;
unsigned int reserved4 = 0 ;
char Executable = ' \0 ' ;
BYTE fbuf [ 26 ] = { 0 } ;
2010-03-28 17:58:21 +00:00
} ;
2009-05-08 13:28:41 +00:00
# pragma pack (pop)
class C4GroupEntry : public C4GroupEntryCore
2010-03-28 17:58:21 +00:00
{
public :
~ C4GroupEntry ( ) ;
2015-02-13 17:49:23 +00:00
enum EntryStatus
{
C4GRES_InGroup ,
C4GRES_OnDisk ,
C4GRES_InMemory ,
C4GRES_Deleted
} ;
2010-03-28 17:58:21 +00:00
public :
2015-11-14 15:17:00 +00:00
char DiskPath [ _MAX_PATH + 1 ] = { 0 } ;
EntryStatus Status = C4GRES_InGroup ;
bool DeleteOnDisk = false ;
bool HoldBuffer = false ;
bool BufferIsStdbuf = false ;
bool NoSort = false ;
2017-05-07 11:50:00 +00:00
BYTE * bpMemBuf = nullptr ;
C4GroupEntry * Next = nullptr ;
2010-03-28 17:58:21 +00:00
public :
void Set ( const DirectoryIterator & iter , const char * szPath ) ;
} ;
2009-05-08 13:28:41 +00:00
2015-02-13 17:49:23 +00:00
class C4Group : public CStdStream
2010-03-28 17:58:21 +00:00
{
2017-01-07 19:27:14 +00:00
struct P ;
std : : unique_ptr < P > p ;
2010-03-28 17:58:21 +00:00
public :
C4Group ( ) ;
2017-05-07 11:50:00 +00:00
~ C4Group ( ) override ;
2017-01-07 19:27:14 +00:00
C4Group ( C4Group & & ) = default ;
C4Group & operator = ( C4Group & & ) = default ;
2009-05-08 13:28:41 +00:00
2017-01-07 12:35:39 +00:00
protected :
// C4Update requires these to be available by a subclass (C4GroupEx)
C4GroupHeader Head ;
C4GroupEntry * GetEntry ( const char * szName ) ;
void Clear ( ) ;
2010-03-28 17:58:21 +00:00
public :
bool Open ( const char * szGroupName , bool fCreate = false ) ;
bool Close ( ) ;
bool Save ( bool fReOpen ) ;
bool OpenAsChild ( C4Group * pMother , const char * szEntryName , bool fExclusive = false , bool fCreate = false ) ;
bool OpenChild ( const char * strEntry ) ;
bool OpenMother ( ) ;
bool Add ( const char * szFile , const char * szAddAs ) ;
2011-05-01 11:37:36 +00:00
bool Add ( const char * szName , void * pBuffer , int iSize , bool fChild = false , bool fHoldBuffer = false , bool fExecutable = false ) ;
bool Add ( const char * szName , StdBuf & pBuffer , bool fChild = false , bool fHoldBuffer = false , bool fExecutable = false ) ;
bool Add ( const char * szName , StdStrBuf & pBuffer , bool fChild = false , bool fHoldBuffer = false , bool fExecutable = false ) ;
2010-03-28 17:58:21 +00:00
bool Merge ( const char * szFolders ) ;
bool Move ( const char * szFile , const char * szAddAs ) ;
2016-11-02 23:58:02 +00:00
bool Extract ( const char * szFiles , const char * szExtractTo = nullptr , const char * szExclude = nullptr ) ;
bool ExtractEntry ( const char * szFilename , const char * szExtractTo = nullptr ) ;
2010-03-28 17:58:21 +00:00
bool Delete ( const char * szFiles , bool fRecursive = false ) ;
bool DeleteEntry ( const char * szFilename , bool fRecycle = false ) ;
bool Rename ( const char * szFile , const char * szNewName ) ;
bool Sort ( const char * szSortList ) ;
2016-11-02 23:58:02 +00:00
bool SortByList ( const char * * ppSortList , const char * szFilename = nullptr ) ;
2010-03-28 17:58:21 +00:00
bool AccessEntry ( const char * szWildCard ,
2016-11-02 23:58:02 +00:00
size_t * iSize = nullptr , char * sFileName = nullptr ,
2011-03-05 01:45:27 +00:00
bool NeedsToBeAGroup = false ) ;
2010-03-28 17:58:21 +00:00
bool AccessNextEntry ( const char * szWildCard ,
2016-11-02 23:58:02 +00:00
size_t * iSize = nullptr , char * sFileName = nullptr ,
2011-05-22 22:02:10 +00:00
bool fStartAtFilename = false ) ;
2010-03-28 17:58:21 +00:00
bool LoadEntry ( const char * szEntryName , char * * lpbpBuf ,
2016-11-02 23:58:02 +00:00
size_t * ipSize = nullptr , int iAppendZeros = 0 ) ;
2011-03-05 01:44:26 +00:00
bool LoadEntry ( const char * szEntryName , StdBuf * Buf ) ;
bool LoadEntry ( const StdStrBuf & name , StdBuf * Buf ) { return LoadEntry ( name . getData ( ) , Buf ) ; }
bool LoadEntryString ( const char * szEntryName , StdStrBuf * Buf ) ;
bool LoadEntryString ( const StdStrBuf & name , StdStrBuf * Buf ) { return LoadEntryString ( name . getData ( ) , Buf ) ; }
2010-03-28 17:58:21 +00:00
bool FindEntry ( const char * szWildCard ,
2016-11-02 23:58:02 +00:00
StdStrBuf * sFileName = nullptr ,
size_t * iSize = nullptr ) ;
2011-03-05 01:45:27 +00:00
bool FindEntry ( const char * szWildCard ,
char * sFileName )
{
StdStrBuf name ;
bool r = FindEntry ( szWildCard , & name ) ;
if ( sFileName ) SCopy ( name . getData ( ) , sFileName ) ;
return r ;
}
2010-03-28 17:58:21 +00:00
bool FindNextEntry ( const char * szWildCard ,
2016-11-02 23:58:02 +00:00
StdStrBuf * sFileName = nullptr ,
size_t * iSize = nullptr ,
2010-03-28 17:58:21 +00:00
bool fStartAtFilename = false ) ;
2011-03-05 01:45:27 +00:00
bool FindNextEntry ( const char * szWildCard ,
char * sFileName ,
2016-11-02 23:58:02 +00:00
size_t * iSize = nullptr ,
2011-03-05 01:45:27 +00:00
bool fStartAtFilename = false )
{
2011-07-18 00:12:37 +00:00
StdStrBuf name ( fStartAtFilename ? sFileName : " " ) ;
2011-03-05 01:45:27 +00:00
bool r = FindNextEntry ( szWildCard , & name , iSize , fStartAtFilename ) ;
2011-08-05 20:07:44 +00:00
if ( r & & sFileName ) SCopy ( name . getData ( ) , sFileName ) ;
2011-03-05 01:45:27 +00:00
return r ;
}
2017-01-07 19:27:14 +00:00
bool Read ( void * pBuffer , size_t iSize ) override ;
bool Advance ( int iOffset ) override ;
2010-03-28 17:58:21 +00:00
void SetStdOutput ( bool fStatus ) ;
2012-11-17 18:44:04 +00:00
void ResetSearch ( bool reload_contents = false ) ; // reset search pointer so calls to FindNextEntry find first entry again. if reload_contents is set, the file list for directories is also refreshed.
2010-03-28 17:58:21 +00:00
const char * GetError ( ) ;
2017-01-07 19:27:14 +00:00
const char * GetName ( ) const ;
2010-03-28 17:58:21 +00:00
StdStrBuf GetFullName ( ) const ;
2016-11-02 23:58:02 +00:00
int EntryCount ( const char * szWildCard = nullptr ) ;
size_t EntrySize ( const char * szWildCard = nullptr ) ;
2017-01-07 19:29:46 +00:00
size_t AccessedEntrySize ( ) const override ; // retrieve size of last accessed entry
2016-11-02 23:58:02 +00:00
unsigned int EntryCRC32 ( const char * szWildCard = nullptr ) ;
2017-01-07 19:27:14 +00:00
bool IsOpen ( ) const ;
2010-03-28 17:58:21 +00:00
C4Group * GetMother ( ) ;
2017-01-07 19:27:14 +00:00
bool IsPacked ( ) const ;
bool HasPackedMother ( ) const ;
bool SetNoSort ( bool fNoSort ) ;
2015-09-11 02:32:51 +00:00
int PreCacheEntries ( const char * szSearchPattern , bool cache_previous = false ) ; // pre-load entries to memory. return number of loaded entries.
2009-05-08 13:28:41 +00:00
2017-01-07 19:27:14 +00:00
const C4GroupHeader & GetHeader ( ) const ;
const C4GroupEntry * GetFirstEntry ( ) const ;
2015-02-13 16:12:10 +00:00
2017-01-07 12:35:39 +00:00
private :
2010-03-28 17:58:21 +00:00
void Init ( ) ;
bool EnsureChildFilePtr ( C4Group * pChild ) ;
bool CloseExclusiveMother ( ) ;
bool Error ( const char * szStatus ) ;
bool OpenReal ( const char * szGroupName ) ;
bool OpenRealGrpFile ( ) ;
bool SetFilePtr ( int iOffset ) ;
bool RewindFilePtr ( ) ;
2017-01-07 12:32:25 +00:00
bool AdvanceFilePtr ( int iOffset ) ;
2015-02-13 17:49:23 +00:00
bool AddEntry ( C4GroupEntry : : EntryStatus status ,
2010-03-28 17:58:21 +00:00
bool childgroup ,
const char * fname ,
long size ,
2016-11-02 23:58:02 +00:00
const char * entryname = nullptr ,
BYTE * membuf = nullptr ,
2010-03-28 17:58:21 +00:00
bool fDeleteOnDisk = false ,
bool fHoldBuffer = false ,
bool fExecutable = false ,
bool fBufferIsStdbuf = false ) ;
2016-11-02 23:58:02 +00:00
bool AddEntryOnDisk ( const char * szFilename , const char * szAddAs = nullptr , bool fMove = false ) ;
2011-03-28 17:31:28 +00:00
bool SetFilePtr2Entry ( const char * szName , bool NeedsToBeAGroup = false ) ;
2010-03-28 17:58:21 +00:00
bool AppendEntry2StdFile ( C4GroupEntry * centry , CStdFile & stdfile ) ;
C4GroupEntry * SearchNextEntry ( const char * szName ) ;
C4GroupEntry * GetNextFolderEntry ( ) ;
2012-02-07 23:12:44 +00:00
uint32_t CalcCRC32 ( C4GroupEntry * pEntry ) ;
2015-09-11 02:32:51 +00:00
void PreCacheEntry ( C4GroupEntry * p ) ;
2010-03-28 17:58:21 +00:00
} ;
2009-05-08 13:28:41 +00:00
# endif