OpenClonk
CStdFile.cpp
Go to the documentation of this file.
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 /* A handy wrapper class to gzio files */
19 
20 #include "C4Include.h"
21 #include "c4group/CStdFile.h"
22 #ifdef _WIN32
24 #endif
25 #include "lib/SHA1.h"
26 
27 #include <zlib.h>
28 #include "zlib/gzio.h"
29 
30 #include <sys/stat.h>
31 
33 {
34  thread_check.Set();
35  Status=false;
36  hFile=nullptr;
37  hgzFile=nullptr;
38  pMemory=nullptr;
39  ClearBuffer();
40  ModeWrite=false;
41  Name[0]=0;
42 }
43 
45 {
46  Close();
47 }
48 
49 bool CStdFile::Create(const char *szFilename, bool fCompressed, bool fExecutable, bool fMemory)
50 {
51  thread_check.Set();
52  // Set modes
53  ModeWrite=true;
54  // Open in memory?
55  if (fMemory)
56  {
57  if (!(pMemory = new StdBuf())) return false;
58  MemoryPtr = 0;
59 
60  StdStrBuf buf;
61  buf.Format("<%p>", pMemory);
62  SCopy(buf.getData(), Name, _MAX_PATH);
63  }
64  // Open standard file
65  else
66  {
67  SCopy(szFilename,Name,_MAX_PATH);
68  int flags = _O_BINARY|O_CLOEXEC|O_CREAT|O_WRONLY|O_TRUNC;
69 #ifdef _WIN32
70  int mode = _S_IREAD|_S_IWRITE;
71  int fd = _wopen(GetWideChar(Name), flags, mode);
72 #else
73  mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
74  if (fExecutable)
75  mode |= S_IXUSR|S_IXGRP|S_IXOTH;
76  int fd = open(Name, flags, mode);
77 #endif
78  if (fd == -1) return false;
79  if (fCompressed)
80  {
81  if (!(hgzFile = c4_gzdopen(fd,"wb1"))) return false;
82  }
83  else
84  {
85  if (!(hFile = fdopen(fd,"wb"))) return false;
86  }
87  }
88  // Reset buffer
89  ClearBuffer();
90  // Set status
91  Status=true;
92  return true;
93 }
94 
95 bool CStdFile::Open(const char *szFilename, bool fCompressed)
96 {
97  SCopy(szFilename,Name,_MAX_PATH);
98  thread_check.Set();
99  // Set modes
100  ModeWrite=false;
101  int flags = _O_BINARY|O_CLOEXEC|O_RDONLY;
102 #ifdef _WIN32
103  int mode = _S_IREAD|_S_IWRITE;
104  int fd = _wopen(GetWideChar(Name), flags, mode);
105 #else
106  mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
107  int fd = open(Name, flags, mode);
108 #endif
109  if(fd == -1) return false;
110  if (fCompressed)
111  {
112  if (!(hgzFile = c4_gzdopen(fd,"rb"))) { close(fd); return false; }
113  /* Reject uncompressed files */
114  if(c4_gzdirect(hgzFile))
115  {
117  hgzFile = nullptr;
118  return false;
119  }
120  }
121  else
122  {
123  if (!(hFile = fdopen(fd,"rb"))) return false;
124  }
125  // Reset buffer
126  ClearBuffer();
127  // Set status
128  Status=true;
129  return true;
130 }
131 
132 bool CStdFile::Append(const char *szFilename, bool text)
133 {
134  SCopy(szFilename,Name,_MAX_PATH);
135  thread_check.Set();
136  // Set modes
137  ModeWrite=true;
138  // Open standard file
139 #ifdef _WIN32
140  if (!(hFile = _wfopen(GetWideChar(Name), text ? L"at" : L"ab"))) return false;
141 #else
142  if (!(hFile=fopen(Name,text ? "at" : "ab"))) return false;
143 #endif
144  // Reset buffer
145  ClearBuffer();
146  // Set status
147  Status=true;
148  return true;
149 }
150 
151 bool CStdFile::Close(StdBuf **ppMemory)
152 {
154  bool rval=true;
155  Status=false;
156  Name[0]=0;
157  // Save buffer if in write mode
158  if (ModeWrite && BufferLoad) if (!SaveBuffer()) rval=false;
159  // Close file(s)
160  if (hgzFile) if (c4_gzclose(hgzFile)!=Z_OK) rval=false;
161  if (hFile) if (fclose(hFile)!=0) rval=false;
162  if (pMemory)
163  {
164  if (ppMemory)
165  { *ppMemory = pMemory; pMemory = nullptr; }
166  else
167  delete pMemory;
168  }
169  MemoryPtr=0;
170  hgzFile=nullptr; hFile=nullptr;
171  return !!rval;
172 }
173 
175 {
176  Status=false;
177  Name[0]=0;
178  hgzFile=nullptr;
179  hFile=nullptr;
180  pMemory=nullptr;
181  MemoryPtr=0;
183  thread_check.Set();
184  return true;
185 }
186 
187 bool CStdFile::Read(void *pBuffer, size_t iSize, size_t *ipFSize)
188 {
190  int transfer;
191  if (!pBuffer) return false;
192  if (ModeWrite) return false;
193  BYTE *bypBuffer= (BYTE*) pBuffer;
194  if (ipFSize) *ipFSize = 0;
195  while (iSize>0)
196  {
197  // Valid data in the buffer: Transfer as much as possible
198  if (BufferLoad>BufferPtr)
199  {
200  transfer=std::min<size_t>(BufferLoad-BufferPtr,iSize);
201  memmove(bypBuffer, Buffer+BufferPtr, transfer);
202  BufferPtr+=transfer;
203  bypBuffer+=transfer;
204  iSize-=transfer;
205  if (ipFSize) *ipFSize += transfer;
206  }
207  // Buffer empty: Load
208  else if (LoadBuffer()<=0) return false;
209  }
210  return true;
211 }
212 
214 {
216  if (hFile) BufferLoad = fread(Buffer,1,CStdFileBufSize,hFile);
218  BufferPtr=0;
219  return BufferLoad;
220 }
221 
223 {
225  int saved = 0;
226  if (hFile) saved=fwrite(Buffer,1,BufferLoad,hFile);
228  if (pMemory) { pMemory->Append(Buffer, BufferLoad); saved = BufferLoad; }
229  if (saved!=BufferLoad) return false;
230  BufferLoad=0;
231  return true;
232 }
233 
235 {
238 }
239 
240 bool CStdFile::Write(const void *pBuffer, int iSize)
241 {
243  int transfer;
244  if (!pBuffer) return false;
245  if (!ModeWrite) return false;
246  const BYTE *bypBuffer= (const BYTE*) pBuffer;
247  while (iSize>0)
248  {
249  // Space in buffer: Transfer as much as possible
251  {
252  transfer=std::min(CStdFileBufSize-BufferLoad,iSize);
253  memcpy(Buffer+BufferLoad,bypBuffer,transfer);
254  BufferLoad+=transfer;
255  bypBuffer+=transfer;
256  iSize-=transfer;
257  }
258  // Buffer full: Save
259  else if (!SaveBuffer()) return false;
260  }
261  return true;
262 }
263 
264 bool CStdFile::WriteString(const char *szStr)
265 {
267  BYTE nl[2]={0x0D,0x0A};
268  if (!szStr) return false;
269  int size=SLen(szStr);
270  if (!Write((const void*)szStr,size)) return false;
271  if (!Write(nl,2)) return false;
272  return true;
273 }
274 
276 {
278  if (ModeWrite) return false;
279  ClearBuffer();
280  if (hFile) rewind(hFile);
282  return true;
283 }
284 
285 bool CStdFile::Advance(int iOffset)
286 {
288  if (ModeWrite) return false;
289  while (iOffset > 0)
290  {
291  // Valid data in the buffer: Transfer as much as possible
292  if (BufferLoad > BufferPtr)
293  {
294  int transfer = std::min(BufferLoad-BufferPtr,iOffset);
295  BufferPtr += transfer;
296  iOffset -= transfer;
297  }
298  // Buffer empty: Load or skip
299  else
300  {
301  if (hFile) return !fseek(hFile, iOffset, SEEK_CUR); // uncompressed: Just skip
302  if (LoadBuffer()<=0) return false; // compressed: Read...
303  }
304  }
305  return true;
306 }
307 
308 int CStdFile::Seek(long int offset, int whence)
309 {
310  // seek in file by offset and stdio-style SEEK_* constants. Only implemented for uncompressed files.
311  assert(!hgzFile);
312  return fseek(hFile, offset, whence);
313 }
314 
315 long int CStdFile::Tell()
316 {
317  // get current file pos. Only implemented for uncompressed files.
318  assert(!hgzFile);
319  return ftell(hFile);
320 }
321 
322 int UncompressedFileSize(const char *szFilename)
323 {
324  int rd,rval=0;
325  BYTE buf[1024];
326  int flags = _O_BINARY|O_CLOEXEC|O_RDONLY;
327 #ifdef _WIN32
328  int mode = _S_IREAD|_S_IWRITE;
329  int fd = _wopen(GetWideChar(szFilename), flags, mode);
330 #else
331  mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
332  int fd = open(szFilename, flags, mode);
333 #endif
334  gzFile hFile;
335  if (!(hFile = c4_gzdopen(fd,"rb"))) return 0;
336  do
337  {
338  rd = c4_gzread(hFile,&buf,sizeof(buf));
339  if (rd < 0) break;
340  rval += rd;
341  }
342  while (rd == sizeof buf);
343  c4_gzclose(hFile);
344  return rval;
345 }
346 
348 {
349  if (hFile)
350  return FileSize(fileno(hFile));
351  assert(!hgzFile);
352  return 0;
353 }
354 
355 bool GetFileCRC(const char *szFilename, uint32_t *pCRC32)
356 {
357  if (!pCRC32) return false;
358  // open file
359  CStdFile File;
360  if (!File.Open(szFilename))
361  return false;
362  // calculcate CRC
363  uint32_t iCRC32 = 0;
364  for (;;)
365  {
366  // read a chunk of data
367  BYTE szData[CStdFileBufSize]; size_t iSize = 0;
368  if (!File.Read(szData, CStdFileBufSize, &iSize))
369  if (!iSize)
370  break;
371  // update CRC
372  iCRC32 = crc32(iCRC32, szData, iSize);
373  }
374  // close file
375  File.Close();
376  // okay
377  *pCRC32 = iCRC32;
378  return true;
379 }
380 
381 bool GetFileSHA1(const char *szFilename, BYTE *pSHA1)
382 {
383  if (!pSHA1) return false;
384  // open file
385  CStdFile File;
386  if (!File.Open(szFilename))
387  return false;
388  // calculcate CRC
389  sha1 ctx;
390  for (;;)
391  {
392  // read a chunk of data
393  BYTE szData[CStdFileBufSize]; size_t iSize = 0;
394  if (!File.Read(szData, CStdFileBufSize, &iSize))
395  if (!iSize)
396  break;
397  // update CRC
398  ctx.process_bytes(szData, iSize);
399  }
400  // close file
401  File.Close();
402  // finish calculation
403  ctx.get_digest((sha1::digest_type) *pSHA1);
404  return true;
405 }
StdStrBuf::wchar_t_holder GetWideChar(const char *utf8, bool double_null_terminate=false)
int UncompressedFileSize(const char *szFilename)
Definition: CStdFile.cpp:322
bool GetFileSHA1(const char *szFilename, BYTE *pSHA1)
Definition: CStdFile.cpp:381
bool GetFileCRC(const char *szFilename, uint32_t *pCRC32)
Definition: CStdFile.cpp:355
const int CStdFileBufSize
Definition: CStdFile.h:26
#define _O_BINARY
#define _MAX_PATH
uint8_t BYTE
#define O_CLOEXEC
void SCopy(const char *szSource, char *sTarget, size_t iMaxL)
Definition: Standard.cpp:152
size_t SLen(const char *sptr)
Definition: Standard.h:74
size_t FileSize(const char *fname)
int iSize
Definition: TstC4NetIO.cpp:32
int Seek(long int offset, int whence)
Definition: CStdFile.cpp:308
bool Close(StdBuf **ppMemory=nullptr)
Definition: CStdFile.cpp:151
bool ModeWrite
Definition: CStdFile.h:52
int BufferPtr
Definition: CStdFile.h:51
BYTE Buffer[CStdFileBufSize]
Definition: CStdFile.h:50
long int Tell()
Definition: CStdFile.cpp:315
bool Create(const char *szFileName, bool fCompressed=false, bool fExecutable=false, bool fMemory=false)
Definition: CStdFile.cpp:49
bool Status
Definition: CStdFile.h:43
CStdFile()
Definition: CStdFile.cpp:32
bool SaveBuffer()
Definition: CStdFile.cpp:222
gzFile hgzFile
Definition: CStdFile.h:47
bool Write(const void *pBuffer, int iSize)
Definition: CStdFile.cpp:240
~CStdFile() override
Definition: CStdFile.cpp:44
size_t AccessedEntrySize() const override
Definition: CStdFile.cpp:347
bool WriteString(const char *szStr)
Definition: CStdFile.cpp:264
bool Default()
Definition: CStdFile.cpp:174
bool Advance(int iOffset) override
Definition: CStdFile.cpp:285
bool Append(const char *szFilename, bool text=false)
Definition: CStdFile.cpp:132
void ClearBuffer()
Definition: CStdFile.cpp:234
char Name[_MAX_PATH_LEN]
Definition: CStdFile.h:44
int BufferLoad
Definition: CStdFile.h:51
bool Read(void *pBuffer, size_t iSize) override
Definition: CStdFile.h:60
StdBuf * pMemory
Definition: CStdFile.h:48
FILE * hFile
Definition: CStdFile.h:46
int LoadBuffer()
Definition: CStdFile.cpp:213
StdThreadCheck thread_check
Definition: CStdFile.h:53
bool Open(const char *szFileName, bool fCompressed=false)
Definition: CStdFile.cpp:95
int MemoryPtr
Definition: CStdFile.h:49
bool Rewind()
Definition: CStdFile.cpp:275
Definition: StdBuf.h:30
void Append(const void *pnData, size_t inSize)
Definition: StdBuf.h:254
const char * getData() const
Definition: StdBuf.h:442
void Format(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:174
void Check()
Definition: StdSync.h:295
void Set()
Definition: StdSync.h:294
Definition: SHA1.h:45
unsigned int(& digest_type)[5]
Definition: SHA1.h:47
void process_bytes(void const *buffer, std::size_t byte_count)
Definition: SHA1.h:111
void get_digest(digest_type digest)
Definition: SHA1.h:169
int ZEXPORT c4_gzread(gzFile file, voidp buf, unsigned len)
Definition: gzio.c:405
int ZEXPORT c4_gzdirect(gzFile file)
Definition: gzio.c:919
gzFile ZEXPORT c4_gzdopen(int fd, const char *mode)
Definition: gzio.c:228
int ZEXPORT c4_gzrewind(gzFile file)
Definition: gzio.c:868
int ZEXPORT c4_gzclose(gzFile file)
Definition: gzio.c:964
int ZEXPORT c4_gzwrite(gzFile file, voidpc buf, unsigned len)
Definition: gzio.c:570