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