leocad/common/file.cpp
2011-09-07 21:06:51 +00:00

571 lines
10 KiB
C++

// File class, can be a memory file or in the disk.
// Needed to work with the clipboard and undo/redo easily.
// NOTE: Because of endianess issues, all I/O must be done from a File class.
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
#include <string.h>
#include "file.h"
#include "defines.h"
#include "config.h"
#include "str.h"
// =============================================================================
// File construction/destruction
File::File ()
{
strcpy(FileName, "");
}
File::~File ()
{
}
// =============================================================================
// Endian-safe functions
// reads 1-byte integers
unsigned long File::ReadByte (void* pBuf, unsigned long nCount)
{
return Read (pBuf, nCount);
}
// reads 2-byte integers
unsigned long File::ReadShort (void* pBuf, unsigned long nCount)
{
unsigned long read;
read = Read (pBuf, nCount*2)/2;
#ifdef LC_BIG_ENDIAN
unsigned long i;
lcuint16* val = (lcuint16*)pBuf, x;
for (i = 0; i < read; i++)
{
x = *val;
*val = ((x>>8) | (x<<8));
val++;
}
#endif
return read;
}
// reads 4-byte integers
unsigned long File::ReadLong (void* pBuf, unsigned long nCount)
{
unsigned long read;
read = Read (pBuf, nCount*4)/4;
#ifdef LC_BIG_ENDIAN
unsigned long i;
lcuint32* val = (lcuint32*)pBuf, x;
for (i = 0; i < read; i++)
{
x = *val;
*val = ((x>>24) | ((x>>8) & 0xff00) | ((x<<8) & 0xff0000) | (x<<24));
val++;
}
#endif
return read;
}
// reads 4-byte floats
unsigned long File::ReadFloat (void* pBuf, unsigned long nCount)
{
unsigned long read;
read = Read (pBuf, nCount*4)/4;
#ifdef LC_BIG_ENDIAN
unsigned long i;
float* val = (float*)pBuf;
union { unsigned char b[4]; float f; } in, out;
for (i = 0; i < read; i++)
{
in.f = *val;
out.b[0] = in.b[3];
out.b[1] = in.b[2];
out.b[2] = in.b[1];
out.b[3] = in.b[0];
*val = out.f;
val++;
}
#endif
return read;
}
// reads 8-byte floats
unsigned long File::ReadDouble (void* pBuf, unsigned long nCount)
{
unsigned long read;
read = Read (pBuf, nCount*8)/8;
#ifdef LC_BIG_ENDIAN
unsigned long i;
double* val = (double*)pBuf;
union { unsigned char b[8]; double d; } in, out;
for (i = 0; i < read; i++)
{
in.d = *val;
out.b[0] = in.b[7];
out.b[1] = in.b[6];
out.b[2] = in.b[5];
out.b[3] = in.b[4];
out.b[4] = in.b[3];
out.b[5] = in.b[2];
out.b[6] = in.b[1];
out.b[7] = in.b[0];
*val = out.d;
val++;
}
#endif
return read;
}
// writes 1-byte integers
unsigned long File::WriteByte (const void* pBuf, unsigned long nCount)
{
return Write (pBuf, nCount);
}
// writes 2-byte integers
unsigned long File::WriteShort (const void* pBuf, unsigned long nCount)
{
#ifdef LC_BIG_ENDIAN
unsigned long wrote = 0, i;
lcuint16* val = (lcuint16*)pBuf, x;
for (i = 0; i < nCount; i++)
{
x = (((*val)>>8) | ((*val)<<8));
val++;
wrote += Write (&x, 2)/2;
}
return wrote;
#else
return Write(pBuf, nCount*2)/2;
#endif
}
// writes 4-byte integers
unsigned long File::WriteLong (const void* pBuf, unsigned long nCount)
{
#ifdef LC_BIG_ENDIAN
unsigned long wrote = 0, i;
lcuint32* val = (lcuint32*)pBuf, x;
for (i = 0; i < nCount; i++)
{
x = (((*val)>>24) | (((*val)>>8) & 0xff00) | (((*val)<<8) & 0xff0000) | ((*val)<<24));
val++;
wrote += Write (&x, 4)/4;
}
return wrote;
#else
return Write (pBuf, nCount*4)/4;
#endif
}
// writes 4-byte floats
unsigned long File::WriteFloat (const void* pBuf, unsigned long nCount)
{
#ifdef LC_BIG_ENDIAN
unsigned long wrote = 0, i;
float* val = (float*)pBuf, x;
union { unsigned char b[4]; float f; } in, out;
for (i = 0; i < nCount; i++)
{
in.f = *val;
val++;
out.b[0] = in.b[3];
out.b[1] = in.b[2];
out.b[2] = in.b[1];
out.b[3] = in.b[0];
x = out.f;
wrote += Write (&x, 4)/4;
}
return wrote;
#else
return Write (pBuf, nCount*4)/4;
#endif
}
// writes 8-byte floats
unsigned long File::WriteDouble (const void* pBuf, unsigned long nCount)
{
#ifdef LC_BIG_ENDIAN
unsigned long wrote = 0, i;
double* val = (double*)pBuf, x;
union { unsigned char b[8]; double d; } in, out;
for (i = 0; i < nCount; i++)
{
in.d = *val;
val++;
out.b[0] = in.b[7];
out.b[1] = in.b[6];
out.b[2] = in.b[5];
out.b[3] = in.b[4];
out.b[4] = in.b[3];
out.b[5] = in.b[2];
out.b[6] = in.b[1];
out.b[7] = in.b[0];
x = out.d;
wrote += Write (&x, 8)/8;
}
return wrote;
#else
return Write (pBuf, nCount*8)/8;
#endif
}
void File::ReadString(String& Value)
{
lcuint32 l;
ReadInt(&l);
Read(Value.GetBuffer(l+1), l);
((char*)Value)[l] = 0;
}
void File::WriteString(const String& Value)
{
WriteInt(Value.GetLength());
Write((const char*)Value, Value.GetLength());
}
// =============================================================================
FileMem::FileMem()
{
m_nGrowBytes = 1024;
m_nPosition = 0;
m_nBufferSize = 0;
m_nFileSize = 0;
m_pBuffer = NULL;
m_bAutoDelete = true;
}
FileDisk::FileDisk()
{
m_hFile = NULL;
m_bCloseOnDelete = false;
}
FileMem::~FileMem()
{
if (m_pBuffer)
Close();
m_nGrowBytes = 0;
m_nPosition = 0;
m_nBufferSize = 0;
m_nFileSize = 0;
}
FileDisk::~FileDisk()
{
if (m_hFile != NULL && m_bCloseOnDelete)
Close();
}
/////////////////////////////////////////////////////////////////////////////
// File operations
char* FileMem::ReadLine(char* pBuf, unsigned long nMax)
{
int nRead = 0;
unsigned char ch;
if (nMax <= 0)
return NULL;
if (m_nPosition >= m_nFileSize)
return NULL;
while ((--nMax))
{
if (m_nPosition == m_nFileSize)
break;
ch = m_pBuffer[m_nPosition];
m_nPosition++;
pBuf[nRead++] = ch;
if (ch == '\n')
break;
}
pBuf[nRead] = '\0';
return pBuf;
}
char* FileDisk::ReadLine(char* pBuf, unsigned long nMax)
{
return fgets(pBuf, nMax, m_hFile);
}
unsigned long FileMem::Read(void* pBuf, unsigned long nCount)
{
if (nCount == 0)
return 0;
if (m_nPosition > m_nFileSize)
return 0;
unsigned long nRead;
if (m_nPosition + nCount > m_nFileSize)
nRead = (unsigned long)(m_nFileSize - m_nPosition);
else
nRead = nCount;
memcpy((unsigned char*)pBuf, (unsigned char*)m_pBuffer + m_nPosition, nRead);
m_nPosition += nRead;
return nRead;
}
unsigned long FileDisk::Read(void* pBuf, unsigned long nCount)
{
return fread(pBuf, 1, nCount, m_hFile);
}
int FileMem::GetChar()
{
if (m_nPosition > m_nFileSize)
return EOF;
unsigned char* ret = (unsigned char*)m_pBuffer + m_nPosition;
m_nPosition++;
return *ret;
}
int FileDisk::GetChar()
{
return fgetc(m_hFile);
}
unsigned long FileMem::Write(const void* pBuf, unsigned long nCount)
{
if (nCount == 0)
return 0;
if (m_nPosition + nCount > m_nBufferSize)
GrowFile(m_nPosition + nCount);
memcpy((unsigned char*)m_pBuffer + m_nPosition, (unsigned char*)pBuf, nCount);
m_nPosition += nCount;
if (m_nPosition > m_nFileSize)
m_nFileSize = m_nPosition;
return nCount;
}
unsigned long FileDisk::Write(const void* pBuf, unsigned long nCount)
{
return fwrite(pBuf, 1, nCount, m_hFile);
}
int FileMem::PutChar(int c)
{
if (m_nPosition + 1 > m_nBufferSize)
GrowFile(m_nPosition + 1);
unsigned char* bt = (unsigned char*)m_pBuffer + m_nPosition;
*bt = c;
m_nPosition++;
if (m_nPosition > m_nFileSize)
m_nFileSize = m_nPosition;
return 1;
}
int FileDisk::PutChar(int c)
{
return fputc(c, m_hFile);
}
bool FileDisk::Open(const char *filename, const char *mode)
{
if (*filename == 0)
return false;
strcpy(FileName, filename);
m_hFile = fopen(filename, mode);
m_bCloseOnDelete = true;
return (m_hFile != NULL);
}
void FileMem::Close()
{
m_nGrowBytes = 0;
m_nPosition = 0;
m_nBufferSize = 0;
m_nFileSize = 0;
if (m_pBuffer && m_bAutoDelete)
free(m_pBuffer);
m_pBuffer = NULL;
strcpy(FileName, "");
}
void FileDisk::Close()
{
if (m_hFile != NULL)
fclose(m_hFile);
m_hFile = NULL;
m_bCloseOnDelete = false;
strcpy(FileName, "");
}
unsigned long FileMem::Seek(long lOff, int nFrom)
{
unsigned long lNewPos = m_nPosition;
if (nFrom == SEEK_SET)
lNewPos = lOff;
else if (nFrom == SEEK_CUR)
lNewPos += lOff;
else if (nFrom == SEEK_END)
lNewPos = m_nFileSize + lOff;
else
return (unsigned long)-1;
m_nPosition = lNewPos;
return 0;
}
unsigned long FileDisk::Seek(long lOff, int nFrom)
{
fseek (m_hFile, lOff, nFrom);
return ftell(m_hFile);
}
unsigned long FileMem::GetPosition() const
{
return m_nPosition;
}
unsigned long FileDisk::GetPosition() const
{
return ftell(m_hFile);
}
void FileMem::GrowFile(unsigned long nNewLen)
{
if (nNewLen > m_nBufferSize)
{
// grow the buffer
unsigned long nNewBufferSize = m_nBufferSize;
// determine new buffer size
while (nNewBufferSize < nNewLen)
nNewBufferSize += m_nGrowBytes;
// allocate new buffer
unsigned char* lpNew;
if (m_pBuffer == NULL)
lpNew = (unsigned char*)malloc(nNewBufferSize);
else
lpNew = (unsigned char*)realloc(m_pBuffer, nNewBufferSize);
m_pBuffer = lpNew;
m_nBufferSize = nNewBufferSize;
}
}
void FileMem::Flush()
{
// Nothing to be done
}
void FileDisk::Flush()
{
if (m_hFile == NULL)
return;
fflush(m_hFile);
}
void FileMem::Abort()
{
Close();
}
void FileDisk::Abort()
{
if (m_hFile != NULL)
{
// close but ignore errors
if (m_bCloseOnDelete)
fclose(m_hFile);
m_hFile = NULL;
m_bCloseOnDelete = false;
}
}
void FileMem::SetLength(unsigned long nNewLen)
{
if (nNewLen > m_nBufferSize)
GrowFile(nNewLen);
if (nNewLen < m_nPosition)
m_nPosition = nNewLen;
m_nFileSize = nNewLen;
}
void FileDisk::SetLength(unsigned long nNewLen)
{
fseek(m_hFile, nNewLen, SEEK_SET);
}
unsigned long FileMem::GetLength() const
{
return m_nFileSize;
}
unsigned long FileDisk::GetLength() const
{
unsigned long nLen, nCur;
// Seek is a non const operation
nCur = ftell(m_hFile);
fseek(m_hFile, 0, SEEK_END);
nLen = ftell(m_hFile);
fseek(m_hFile, nCur, SEEK_SET);
return nLen;
}