2009-05-08 13:28:41 +00:00
|
|
|
/*
|
|
|
|
* OpenClonk, http://www.openclonk.org
|
|
|
|
*
|
2009-06-05 13:41:20 +00:00
|
|
|
* Copyright (c) 1998-2000 Matthes Bender
|
|
|
|
* Copyright (c) 2004, 2008 Peter Wortmann
|
|
|
|
* Copyright (c) 2005-2006 Sven Eberhardt
|
|
|
|
* Copyright (c) 2005, 2007, 2009 Günther Brammer
|
2009-05-08 13:28:41 +00:00
|
|
|
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
|
|
|
|
*
|
|
|
|
* Portions might be copyrighted by other authors who have contributed
|
|
|
|
* to OpenClonk.
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
* See isc_license.txt for full license and disclaimer.
|
|
|
|
*
|
|
|
|
* "Clonk" is a registered trademark of Matthes Bender.
|
|
|
|
* See clonk_trademark_license.txt for full license.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* A handy wrapper class to gzio files */
|
|
|
|
|
|
|
|
#include <Standard.h>
|
|
|
|
#include <StdFile.h>
|
|
|
|
#include <CStdFile.h>
|
|
|
|
|
|
|
|
#include <zlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
CStdFile::CStdFile()
|
|
|
|
{
|
2009-08-15 18:50:32 +00:00
|
|
|
Status=false;
|
2009-05-08 13:28:41 +00:00
|
|
|
hFile=NULL;
|
|
|
|
hgzFile=NULL;
|
|
|
|
pMemory=NULL;
|
|
|
|
ClearBuffer();
|
2009-08-15 18:50:32 +00:00
|
|
|
ModeWrite=false;
|
2009-05-08 13:28:41 +00:00
|
|
|
Name[0]=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
CStdFile::~CStdFile()
|
|
|
|
{
|
|
|
|
Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CStdFile::Create(const char *szFilename, bool fCompressed, bool fExecutable, bool fMemory)
|
|
|
|
{
|
|
|
|
SCopy(szFilename,Name,_MAX_PATH);
|
|
|
|
// Set modes
|
2009-08-15 18:50:32 +00:00
|
|
|
ModeWrite=true;
|
2009-05-08 13:28:41 +00:00
|
|
|
// Open in memory?
|
|
|
|
if (fMemory)
|
|
|
|
{
|
|
|
|
if(!(pMemory = new StdBuf())) return false;
|
|
|
|
MemoryPtr = 0;
|
|
|
|
}
|
|
|
|
// Open standard file
|
|
|
|
else if (fCompressed)
|
|
|
|
{
|
|
|
|
if (!(hgzFile=gzopen(Name,"wb1"))) return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (fExecutable)
|
|
|
|
{
|
|
|
|
// Create an executable file
|
|
|
|
#ifdef _WIN32
|
2009-06-04 10:43:38 +00:00
|
|
|
int mode = _S_IREAD|_S_IWRITE;
|
|
|
|
int flags = _O_BINARY|_O_CREAT|_O_WRONLY|_O_TRUNC;
|
2009-05-08 13:28:41 +00:00
|
|
|
#else
|
2009-06-04 10:43:38 +00:00
|
|
|
mode_t mode = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH;
|
|
|
|
int flags = O_CREAT|O_WRONLY|O_TRUNC;
|
2009-05-08 13:28:41 +00:00
|
|
|
#endif
|
2009-06-04 10:43:38 +00:00
|
|
|
int fd = open(Name, flags, mode);
|
2009-05-08 13:28:41 +00:00
|
|
|
if (fd == -1) return false;
|
|
|
|
if (!(hFile = fdopen(fd,"wb"))) return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!(hFile=fopen(Name,"wb"))) return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Reset buffer
|
|
|
|
ClearBuffer();
|
|
|
|
// Set status
|
2009-08-15 18:50:32 +00:00
|
|
|
Status=true;
|
2009-05-08 13:28:41 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CStdFile::Open(const char *szFilename, bool fCompressed)
|
|
|
|
{
|
|
|
|
SCopy(szFilename,Name,_MAX_PATH);
|
|
|
|
// Set modes
|
2009-08-15 18:50:32 +00:00
|
|
|
ModeWrite=false;
|
2009-05-08 13:28:41 +00:00
|
|
|
// Open standard file
|
|
|
|
if (fCompressed)
|
|
|
|
{ if (!(hgzFile=gzopen(Name,"rb"))) return false; }
|
|
|
|
else
|
|
|
|
{ if (!(hFile=fopen(Name,"rb"))) return false; }
|
|
|
|
// Reset buffer
|
|
|
|
ClearBuffer();
|
|
|
|
// Set status
|
2009-08-15 18:50:32 +00:00
|
|
|
Status=true;
|
2009-05-08 13:28:41 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CStdFile::Append(const char *szFilename)
|
|
|
|
{
|
|
|
|
SCopy(szFilename,Name,_MAX_PATH);
|
|
|
|
// Set modes
|
2009-08-15 18:50:32 +00:00
|
|
|
ModeWrite=true;
|
2009-05-08 13:28:41 +00:00
|
|
|
// Open standard file
|
2009-08-15 18:50:32 +00:00
|
|
|
if (!(hFile=fopen(Name,"ab"))) return false;
|
2009-05-08 13:28:41 +00:00
|
|
|
// Reset buffer
|
|
|
|
ClearBuffer();
|
|
|
|
// Set status
|
2009-08-15 18:50:32 +00:00
|
|
|
Status=true;
|
|
|
|
return true;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CStdFile::Close(StdBuf **ppMemory)
|
|
|
|
{
|
2009-08-15 18:50:32 +00:00
|
|
|
bool rval=true;
|
|
|
|
Status=false;
|
2009-05-08 13:28:41 +00:00
|
|
|
Name[0]=0;
|
|
|
|
// Save buffer if in write mode
|
2009-08-15 18:50:32 +00:00
|
|
|
if (ModeWrite && BufferLoad) if (!SaveBuffer()) rval=false;
|
2009-05-08 13:28:41 +00:00
|
|
|
// Close file(s)
|
2009-08-15 18:50:32 +00:00
|
|
|
if (hgzFile) if (gzclose(hgzFile)!=Z_OK) rval=false;
|
|
|
|
if (hFile) if (fclose(hFile)!=0) rval=false;
|
2009-05-08 13:28:41 +00:00
|
|
|
if (pMemory)
|
|
|
|
if(ppMemory)
|
|
|
|
{ *ppMemory = pMemory; pMemory = NULL; }
|
|
|
|
else
|
|
|
|
delete pMemory;
|
|
|
|
MemoryPtr=0;
|
|
|
|
hgzFile=NULL; hFile=NULL;
|
|
|
|
return !!rval;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CStdFile::Default()
|
|
|
|
{
|
2009-08-15 18:50:32 +00:00
|
|
|
Status=false;
|
2009-05-08 13:28:41 +00:00
|
|
|
Name[0]=0;
|
|
|
|
hgzFile=NULL;
|
|
|
|
hFile=NULL;
|
|
|
|
pMemory=NULL;
|
|
|
|
MemoryPtr=0;
|
|
|
|
BufferLoad=BufferPtr=0;
|
2009-08-15 18:50:32 +00:00
|
|
|
return true;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CStdFile::Read(void *pBuffer, size_t iSize, size_t *ipFSize)
|
|
|
|
{
|
|
|
|
int transfer;
|
2009-08-15 18:50:32 +00:00
|
|
|
if (!pBuffer) return false;
|
|
|
|
if (ModeWrite) return false;
|
2009-05-08 13:28:41 +00:00
|
|
|
BYTE *bypBuffer= (BYTE*) pBuffer;
|
|
|
|
if (ipFSize) *ipFSize = 0;
|
|
|
|
while (iSize>0)
|
|
|
|
{
|
|
|
|
// Valid data in the buffer: Transfer as much as possible
|
|
|
|
if (BufferLoad>BufferPtr)
|
|
|
|
{
|
|
|
|
transfer=Min<size_t>(BufferLoad-BufferPtr,iSize);
|
|
|
|
memmove(bypBuffer, Buffer+BufferPtr, transfer);
|
|
|
|
BufferPtr+=transfer;
|
|
|
|
bypBuffer+=transfer;
|
|
|
|
iSize-=transfer;
|
|
|
|
if (ipFSize) *ipFSize += transfer;
|
|
|
|
}
|
|
|
|
// Buffer empty: Load
|
2009-08-15 18:50:32 +00:00
|
|
|
else if (LoadBuffer()<=0) return false;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
2009-08-15 18:50:32 +00:00
|
|
|
return true;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int CStdFile::LoadBuffer()
|
|
|
|
{
|
|
|
|
if (hFile) BufferLoad = fread(Buffer,1,CStdFileBufSize,hFile);
|
|
|
|
if (hgzFile) BufferLoad = gzread(hgzFile, Buffer,CStdFileBufSize);
|
|
|
|
BufferPtr=0;
|
|
|
|
return BufferLoad;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CStdFile::SaveBuffer()
|
|
|
|
{
|
|
|
|
int saved = 0;
|
|
|
|
if (hFile) saved=fwrite(Buffer,1,BufferLoad,hFile);
|
|
|
|
if (hgzFile) saved=gzwrite(hgzFile,Buffer,BufferLoad);
|
|
|
|
if (pMemory) { pMemory->Append(Buffer, BufferLoad); saved = BufferLoad; }
|
2009-08-15 18:50:32 +00:00
|
|
|
if (saved!=BufferLoad) return false;
|
2009-05-08 13:28:41 +00:00
|
|
|
BufferLoad=0;
|
2009-08-15 18:50:32 +00:00
|
|
|
return true;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CStdFile::ClearBuffer()
|
|
|
|
{
|
|
|
|
BufferLoad=BufferPtr=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CStdFile::Write(const void *pBuffer, int iSize)
|
|
|
|
{
|
|
|
|
int transfer;
|
2009-08-15 18:50:32 +00:00
|
|
|
if (!pBuffer) return false;
|
|
|
|
if (!ModeWrite) return false;
|
2009-05-08 13:28:41 +00:00
|
|
|
BYTE *bypBuffer= (BYTE*) pBuffer;
|
|
|
|
while (iSize>0)
|
|
|
|
{
|
|
|
|
// Space in buffer: Transfer as much as possible
|
|
|
|
if (BufferLoad<CStdFileBufSize)
|
|
|
|
{
|
|
|
|
transfer=Min(CStdFileBufSize-BufferLoad,iSize);
|
|
|
|
memcpy(Buffer+BufferLoad,bypBuffer,transfer);
|
|
|
|
BufferLoad+=transfer;
|
|
|
|
bypBuffer+=transfer;
|
|
|
|
iSize-=transfer;
|
|
|
|
}
|
|
|
|
// Buffer full: Save
|
2009-08-15 18:50:32 +00:00
|
|
|
else if (!SaveBuffer()) return false;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
2009-08-15 18:50:32 +00:00
|
|
|
return true;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CStdFile::WriteString(const char *szStr)
|
|
|
|
{
|
|
|
|
BYTE nl[2]={0x0D,0x0A};
|
2009-08-15 18:50:32 +00:00
|
|
|
if (!szStr) return false;
|
2009-05-08 13:28:41 +00:00
|
|
|
int size=SLen(szStr);
|
2009-08-15 18:50:32 +00:00
|
|
|
if (!Write((void*)szStr,size)) return false;
|
|
|
|
if (!Write(nl,2)) return false;
|
|
|
|
return true;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CStdFile::Rewind()
|
|
|
|
{
|
2009-08-15 18:50:32 +00:00
|
|
|
if (ModeWrite) return false;
|
2009-05-08 13:28:41 +00:00
|
|
|
ClearBuffer();
|
|
|
|
if (hFile) rewind(hFile);
|
|
|
|
if (hgzFile)
|
|
|
|
{
|
2009-08-15 18:50:32 +00:00
|
|
|
if (gzclose(hgzFile)!=Z_OK) { hgzFile=NULL; return false; }
|
|
|
|
if (!(hgzFile=gzopen(Name,"rb"))) return false;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
2009-08-15 18:50:32 +00:00
|
|
|
return true;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CStdFile::Advance(int iOffset)
|
|
|
|
{
|
2009-08-15 18:50:32 +00:00
|
|
|
if (ModeWrite) return false;
|
2009-05-08 13:28:41 +00:00
|
|
|
while (iOffset > 0)
|
|
|
|
{
|
|
|
|
// Valid data in the buffer: Transfer as much as possible
|
|
|
|
if (BufferLoad > BufferPtr)
|
|
|
|
{
|
|
|
|
int transfer = Min(BufferLoad-BufferPtr,iOffset);
|
|
|
|
BufferPtr += transfer;
|
|
|
|
iOffset -= transfer;
|
|
|
|
}
|
|
|
|
// Buffer empty: Load or skip
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (hFile) return !fseek(hFile, iOffset, SEEK_CUR); // uncompressed: Just skip
|
2009-08-15 18:50:32 +00:00
|
|
|
if (LoadBuffer()<=0) return false; // compressed: Read...
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
}
|
2009-08-15 18:50:32 +00:00
|
|
|
return true;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CStdFile::Save(const char *szFilename, const BYTE *bpBuf,
|
|
|
|
int iSize, bool fCompressed)
|
|
|
|
{
|
2009-08-15 18:50:32 +00:00
|
|
|
if (!bpBuf || (iSize<1)) return false;
|
|
|
|
if (!Create(szFilename,fCompressed)) return false;
|
|
|
|
if (!Write(bpBuf,iSize)) return false;
|
|
|
|
if (!Close()) return false;
|
|
|
|
return true;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CStdFile::Load(const char *szFilename, BYTE **lpbpBuf,
|
|
|
|
int *ipSize, int iAppendZeros,
|
|
|
|
bool fCompressed)
|
|
|
|
{
|
|
|
|
int iSize = fCompressed ? UncompressedFileSize(szFilename) : FileSize(szFilename);
|
2009-08-15 18:50:32 +00:00
|
|
|
if (!lpbpBuf || (iSize<1)) return false;
|
|
|
|
if (!Open(szFilename,fCompressed)) return false;
|
|
|
|
if (!(*lpbpBuf = new BYTE [iSize+iAppendZeros])) return false;
|
|
|
|
if (!Read(*lpbpBuf,iSize)) { delete [] *lpbpBuf; return false; }
|
2009-05-08 13:28:41 +00:00
|
|
|
if (iAppendZeros) ZeroMem( (*lpbpBuf)+iSize, iAppendZeros );
|
|
|
|
if (ipSize) *ipSize=iSize;
|
|
|
|
Close();
|
2009-08-15 18:50:32 +00:00
|
|
|
return true;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int UncompressedFileSize(const char *szFilename)
|
|
|
|
{
|
|
|
|
int rd,rval=0;
|
|
|
|
BYTE buf[16384];
|
|
|
|
gzFile hFile;
|
|
|
|
if (!(hFile = gzopen(szFilename,"rb"))) return 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
rd = gzread(hFile,&buf,sizeof(buf));
|
|
|
|
if(rd < 0) break;
|
|
|
|
rval += rd;
|
|
|
|
}
|
|
|
|
while(rd == sizeof buf);
|
|
|
|
gzclose(hFile);
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CStdFile::AccessedEntrySize()
|
|
|
|
{
|
|
|
|
if(hFile)
|
|
|
|
return FileSize(fileno(hFile));
|
|
|
|
assert(!hgzFile);
|
|
|
|
return 0;
|
|
|
|
}
|