1 /* 2 * OpenClonk, http://www.openclonk.org 3 * 4 * Copyright (c) 1998-2000, Matthes Bender 5 * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/ 6 * Copyright (c) 2009-2016, The OpenClonk Team and contributors 7 * 8 * Distributed under the terms of the ISC license; see accompanying file 9 * "COPYING" for details. 10 * 11 * "Clonk" is a registered trademark of Matthes Bender, used with permission. 12 * See accompanying file "TRADEMARK" for details. 13 * 14 * To redistribute this file separately, substitute the full license texts 15 * for the above references. 16 */ 17 18 /* Handles group files */ 19 20 #ifndef INC_C4Group 21 #define INC_C4Group 22 23 #ifdef HAVE_IO_H 24 #include <io.h> 25 #endif 26 #include "c4group/CStdFile.h" 27 28 // C4Group-Rewind-warning: 29 // The current C4Group-implementation cannot handle random file access very well, 30 // because all files are written within a single zlib-stream. 31 // For every out-of-order-file accessed a group-rewind must be performed, and every 32 // single file up to the accessed file unpacked. As a workaround, all C4Groups are 33 // packed in a file order matching the reading order of the engine. 34 // If the reading order doesn't match the packing order, and a rewind has to be performed, 35 // a warning is issued in Debug-builds of the engine. But since some components require 36 // random access because they are loaded on-demand at runtime (e.g. global sounds), the 37 // warning may be temp disabled for those files using C4GRP_DISABLE_REWINDWARN and 38 // C4GRP_ENABLE_REWINDWARN. A ref counter keeps track of nested calls to those functions. 39 // 40 // If you add any new components to scenario or definition files, remember to adjust the 41 // sort order lists in C4Components.h accordingly, and enforce a reading order for that 42 // component. 43 // 44 // Maybe some day, someone will write a C4Group-implementation that is probably capable of 45 // random access... 46 #ifdef _DEBUG 47 extern int iC4GroupRewindFilePtrNoWarn; 48 #define C4GRP_DISABLE_REWINDWARN ++iC4GroupRewindFilePtrNoWarn; 49 #define C4GRP_ENABLE_REWINDWARN --iC4GroupRewindFilePtrNoWarn; 50 #else 51 #define C4GRP_DISABLE_REWINDWARN ; 52 #define C4GRP_ENABLE_REWINDWARN ; 53 #endif 54 55 const int C4GroupFileVer1=1, C4GroupFileVer2=2; 56 57 const int C4GroupMaxError = 100; 58 59 const int32_t C4GroupSwapThreshold = 10 * 1024 * 1024; 60 61 #define C4GroupFileID "RedWolf Design GrpFolder" 62 63 bool C4Group_TestIgnore(const char *szFilename); 64 void C4Group_SetTempPath(const char *szPath); 65 const char* C4Group_GetTempPath(); 66 void C4Group_SetSortList(const char **ppSortList); 67 void C4Group_SetProcessCallback(bool (*fnCallback)(const char *, int)); 68 bool C4Group_IsGroup(const char *szFilename); 69 bool C4Group_CopyItem(const char *szSource, const char *szTarget, bool fNoSort=false, bool fResetAttributes=false); 70 bool C4Group_MoveItem(const char *szSource, const char *szTarget, bool fNoSort=false); 71 bool C4Group_DeleteItem(const char *szItem, bool fRecycle=false); 72 bool C4Group_PackDirectoryTo(const char *szFilename, const char *szFilenameTo); 73 bool C4Group_PackDirectory(const char *szFilename); 74 bool C4Group_UnpackDirectory(const char *szFilename); 75 bool C4Group_ExplodeDirectory(const char *szFilename); 76 bool C4Group_ReadFile(const char *szFilename, char **pData, size_t *iSize); 77 78 extern const char *C4CFN_FLS[]; 79 80 #pragma pack (push, 1) 81 82 struct C4GroupHeader 83 { 84 char id[24+4] = C4GroupFileID; 85 int Ver1 = C4GroupFileVer1; 86 int Ver2 = C4GroupFileVer2; 87 int Entries = 0; 88 char reserved[164] = { 0 }; 89 }; 90 91 struct C4GroupEntryCore 92 { 93 char FileName[260] = { 0 }; 94 int32_t Packed = 0, ChildGroup = 0; 95 int32_t Size = 0, reserved1 = 0, Offset = 0; 96 int32_t reserved2 = 0; 97 char reserved3 = '\0'; 98 unsigned int reserved4 = 0; 99 char Executable = '\0'; 100 BYTE fbuf[26] = { 0 }; 101 }; 102 103 #pragma pack (pop) 104 105 class C4GroupEntry: public C4GroupEntryCore 106 { 107 public: 108 ~C4GroupEntry(); 109 110 enum EntryStatus 111 { 112 C4GRES_InGroup, 113 C4GRES_OnDisk, 114 C4GRES_InMemory, 115 C4GRES_Deleted 116 }; 117 118 public: 119 char DiskPath[_MAX_PATH + 1] = { 0 }; 120 EntryStatus Status = C4GRES_InGroup; 121 bool DeleteOnDisk = false; 122 bool HoldBuffer = false; 123 bool BufferIsStdbuf = false; 124 bool NoSort = false; 125 BYTE *bpMemBuf = nullptr; 126 C4GroupEntry *Next = nullptr; 127 public: 128 void Set(const DirectoryIterator & iter, const char * szPath); 129 }; 130 131 class C4Group : public CStdStream 132 { 133 struct P; 134 std::unique_ptr<P> p; 135 public: 136 C4Group(); 137 ~C4Group() override; 138 C4Group(C4Group &&) = default; 139 C4Group &operator=(C4Group &&) = default; 140 141 protected: 142 // C4Update requires these to be available by a subclass (C4GroupEx) 143 C4GroupHeader Head; 144 C4GroupEntry *GetEntry(const char *szName); 145 void Clear(); 146 147 public: 148 bool Open(const char *szGroupName, bool fCreate=false); 149 bool Close(); 150 bool Save(bool fReOpen); 151 bool OpenAsChild(C4Group *pMother, const char *szEntryName, bool fExclusive=false, bool fCreate=false); 152 bool OpenChild(const char* strEntry); 153 bool OpenMother(); 154 bool Add(const char *szFile, const char *szAddAs); 155 bool Add(const char *szName, void *pBuffer, int iSize, bool fChild = false, bool fHoldBuffer = false, bool fExecutable = false); 156 bool Add(const char *szName, StdBuf &pBuffer, bool fChild = false, bool fHoldBuffer = false, bool fExecutable = false); 157 bool Add(const char *szName, StdStrBuf &pBuffer, bool fChild = false, bool fHoldBuffer = false, bool fExecutable = false); 158 bool Merge(const char *szFolders); 159 bool Move(const char *szFile, const char *szAddAs); 160 bool Extract(const char *szFiles, const char *szExtractTo=nullptr, const char *szExclude=nullptr); 161 bool ExtractEntry(const char *szFilename, const char *szExtractTo=nullptr); 162 bool Delete(const char *szFiles, bool fRecursive = false); 163 bool DeleteEntry(const char *szFilename, bool fRecycle=false); 164 bool Rename(const char *szFile, const char *szNewName); 165 bool Sort(const char *szSortList); 166 bool SortByList(const char **ppSortList, const char *szFilename=nullptr); 167 bool AccessEntry(const char *szWildCard, 168 size_t *iSize=nullptr, char *sFileName=nullptr, 169 bool NeedsToBeAGroup = false); 170 bool AccessNextEntry(const char *szWildCard, 171 size_t *iSize=nullptr, char *sFileName=nullptr, 172 bool fStartAtFilename=false); 173 bool LoadEntry(const char *szEntryName, char **lpbpBuf, 174 size_t *ipSize=nullptr, int iAppendZeros=0); 175 bool LoadEntry(const char *szEntryName, StdBuf * Buf); LoadEntry(const StdStrBuf & name,StdBuf * Buf)176 bool LoadEntry(const StdStrBuf & name, StdBuf * Buf) { return LoadEntry(name.getData(), Buf); } 177 bool LoadEntryString(const char *szEntryName, StdStrBuf * Buf); LoadEntryString(const StdStrBuf & name,StdStrBuf * Buf)178 bool LoadEntryString(const StdStrBuf & name, StdStrBuf * Buf) { return LoadEntryString(name.getData(), Buf); } 179 bool FindEntry(const char *szWildCard, 180 StdStrBuf *sFileName=nullptr, 181 size_t *iSize=nullptr); FindEntry(const char * szWildCard,char * sFileName)182 bool FindEntry(const char *szWildCard, 183 char *sFileName) 184 { 185 StdStrBuf name; 186 bool r = FindEntry(szWildCard, &name); 187 if(sFileName) SCopy(name.getData(),sFileName); 188 return r; 189 } 190 bool FindNextEntry(const char *szWildCard, 191 StdStrBuf *sFileName=nullptr, 192 size_t *iSize=nullptr, 193 bool fStartAtFilename=false); 194 bool FindNextEntry(const char *szWildCard, 195 char *sFileName, 196 size_t *iSize=nullptr, 197 bool fStartAtFilename=false) 198 { 199 StdStrBuf name(fStartAtFilename ? sFileName : ""); 200 bool r = FindNextEntry(szWildCard, &name, iSize, fStartAtFilename); 201 if (r && sFileName) SCopy(name.getData(),sFileName); 202 return r; 203 } 204 bool Read(void *pBuffer, size_t iSize) override; 205 bool Advance(int iOffset) override; 206 void SetStdOutput(bool fStatus); 207 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. 208 const char *GetError(); 209 const char *GetName() const; 210 StdStrBuf GetFullName() const; 211 int EntryCount(const char *szWildCard=nullptr); 212 size_t EntrySize(const char *szWildCard=nullptr); 213 size_t AccessedEntrySize() const override; // retrieve size of last accessed entry 214 unsigned int EntryCRC32(const char *szWildCard=nullptr); 215 bool IsOpen() const; 216 C4Group *GetMother(); 217 bool IsPacked() const; 218 bool HasPackedMother() const; 219 bool SetNoSort(bool fNoSort); 220 int PreCacheEntries(const char *szSearchPattern, bool cache_previous=false); // pre-load entries to memory. return number of loaded entries. 221 222 const C4GroupHeader &GetHeader() const; 223 const C4GroupEntry *GetFirstEntry() const; 224 225 private: 226 void Init(); 227 bool EnsureChildFilePtr(C4Group *pChild); 228 bool CloseExclusiveMother(); 229 bool Error(const char *szStatus); 230 bool OpenReal(const char *szGroupName); 231 bool OpenRealGrpFile(); 232 bool SetFilePtr(int iOffset); 233 bool RewindFilePtr(); 234 bool AdvanceFilePtr(int iOffset); 235 bool AddEntry(C4GroupEntry::EntryStatus status, 236 bool childgroup, 237 const char *fname, 238 long size, 239 const char *entryname = nullptr, 240 BYTE *membuf = nullptr, 241 bool fDeleteOnDisk = false, 242 bool fHoldBuffer = false, 243 bool fExecutable = false, 244 bool fBufferIsStdbuf = false); 245 bool AddEntryOnDisk(const char *szFilename, const char *szAddAs=nullptr, bool fMove=false); 246 bool SetFilePtr2Entry(const char *szName, bool NeedsToBeAGroup = false); 247 bool AppendEntry2StdFile(C4GroupEntry *centry, CStdFile &stdfile); 248 C4GroupEntry *SearchNextEntry(const char *szName); 249 C4GroupEntry *GetNextFolderEntry(); 250 uint32_t CalcCRC32(C4GroupEntry *pEntry); 251 void PreCacheEntry(C4GroupEntry * p); 252 }; 253 254 #endif 255