#ifndef FILE_H
#define FILE_H
#include <stdio.h>
#include "platform.h"
#include <string>
#include <list>
using namespace std;
enum {
FILE_TEXT = 1,
FILE_BINARY = 2,
FILE_APPEND = 4,
FILE_SIMUL = 8, // simultaneous read/write
FILE_READ = 16,
FILE_WRITE = 32,
FILE_LITTLE = 64,
FILE_BIG = 128
};
#define DEFAULT_MAX_SIZE 2048
#ifdef __BIG_ENDIAN__
#define SYSTEM_ENDIAN 128
#else
#define SYSTEM_ENDIAN 64
#endif
typedef struct REF
{
REF(FILE *_f) { f = _f; Count = 1; }
FILE *f;
uint32 Count;
} REF;
std::list <REF> RefCount;
std::list <REF>::iterator Iter;
class CFile
{
public:
CFile()
{
this->File = NULL;
this->OpenMode = TEXT;
this->TermString = " /\n\r\t";
this->Endian = SYSTEM_ENDIAN;
}
CFile(char *_FileName, char *_Mode = "rb")
{
this->File = fopen(_FileName, _Mode);
this->OpenMode = this->SetMode(_Mode);
this->TermString = " /\n\r\t";
this->Endian = SYSTEM_ENDIAN;
}
CFile(std::string &_FileName, std::string &_Mode = string("rb"))
{
this->File = fopen(_FileName.c_str(), _Mode.c_str());
this->OpenMode = this->SetMode((char*)_Mode.c_str());
this->TermString = " /\n\r\t";
this->Endian = SYSTEM_ENDIAN;
}
CFile(char *_FileName, uint32 _Mode)
{
std::string Mode;
if (_Mode == 0) {
*this = CFile();
return;
}
if (_Mode & FILE_APPEND) {
Mode += "a";
}
if (_Mode & FILE_SIMUL) {
Mode += "+";
}
if (_Mode & FILE_READ) {
Mode += "r";
}
if (_Mode & FILE_WRITE) {
Mode += "w";
}
if (_Mode & FILE_TEXT) {
Mode += "t";
this->OpenMode = TEXT;
}
if (_Mode & FILE_BINARY) {
Mode += "b";
this->OpenMode = BINARY;
}
this->TermString = " /\n\r\t";
this->File = fopen(_FileName, (char*)Mode.c_str());
this->Endian = SYSTEM_ENDIAN;
return;
}
CFile(string &_FileName, uint32 _Mode)
{
*this = CFile((char*)_FileName.c_str(), _Mode);
}
CFile(FILE *_File)
{
this->File = _File;
this->OpenMode = BINARY; // basically just have to assume...
this->TermString = " /\n\r\t";
this->Endian = SYSTEM_ENDIAN;
this->AddRef(_File);
}
CFile(CFile &_File)
{
this->File = _File.GetFile();
this->OpenMode = _File.OpenMode;
this->TermString = _File.TermString;
this->Endian = _File.Endian;
this->AddRef(_File.GetFile());
}
virtual ~CFile()
{
if (this->File && SafeToDel(this->File))
fclose(this->File);
this->File = NULL;
}
inline boolean Open(char *_FileName, char *_Mode = "rb")
{
if (this->File && SafeToDel(this->File))
fclose(this->File);
return (this->File = fopen(_FileName, _Mode)) != NULL;
}
inline boolean Open(string &_FileName, string &_Mode = string("rb"))
{
return this->Open((char*)_FileName.c_str(), (char*)_Mode.c_str());
}
inline void Close(void)
{
if (this->File && SafeToDel(this->File)) {
fclose(this->File);
this->File = NULL;
}
}
inline void SetEndian(int32 _Endian)
{
if (_Endian != FILE_LITTLE && _Endian != FILE_BIG)
return;
this->Endian = _Endian;
}
inline uint32 Read(void *_Ptr, uint32 _Size)
{
return fread(_Ptr, 1, _Size, this->File);
}
inline uint32 Write(void *_Ptr, uint32 _Size)
{
return fwrite(_Ptr, 1, _Size, this->File);
}
inline int32 Seek(int32 _Offset, int32 _Mode)
{
return fseek(this->File, _Offset, _Mode);
}
inline void Rewind(void)
{
rewind(this->File);
}
inline int32 Eof(void)
{
return feof(this->File);
}
inline int32 Flush(void)
{
return fflush(this->File);
}
inline byte GetChar(void)
{
return fgetc(this->File);
}
inline uint16 GetShort(void)
{
static uint16 S;
fread(&S, sizeof(uint16), 1, this->File);
if (this->Endian != SYSTEM_ENDIAN)
return (S>>8) | (S<<8);
else
return S;
}
inline uint32 GetInt(void)
{
static uint32 I;
fread(&I, sizeof(uint32), 1, this->File);
if (this->Endian != SYSTEM_ENDIAN)
return (I>>24) | ((I>>8) & 0xff00) | ((I<<8) & 0xff0000) | (I<<24);
else
return I;
}
inline int32 Reverse(void)
{
return fseek(this->File, -1, SEEK_CUR);
}
inline char *GetS(char *_String, uint32 _MaxLen = DEFAULT_MAX_SIZE)
{
return fgets(_String, _MaxLen, this->File);
}
inline string &GetS(string &_String)
{
char *String = new char[DEFAULT_MAX_SIZE];
this->GetS(String);
_String = String;
delete []String;
return _String;
}
inline string &GetS(void)
{
string String;
return this->GetS(String);
}
inline int32 Print(const char *_Format, ...)
{
return fprintf(this->File, _Format);
}
inline int32 Pos(void)
{
return ftell(this->File);
}
inline boolean Temp(void)
{
if (this->File && SafeToDel(this->File))
fclose(this->File);
return (this->File = tmpfile()) != NULL;
}
// Sets the terminating characters for the >> operator
inline void SetTerm(char *_TermString)
{
if (_TermString)
TermString = _TermString;
return;
}
// Same as above
inline void SetTerm(string &_TermString)
{
TermString = _TermString;
return;
}
inline boolean Valid(void)
{
return (this->File != NULL);
}
inline FILE *GetFile(void)
{
return this->File;
}
inline CFile& operator = (FILE *_File)
{
if (this->File && SafeToDel(this->File))
fclose(this->File);
this->File = _File;
this->OpenMode = TEXT; // Just have to guess...?
this->TermString = " /\n\r\t";
this->AddRef(_File);
return *this;
}
inline CFile& operator = (CFile &_File)
{
if (this->File && SafeToDel(this->File))
fclose(this->File);
this->File = _File.GetFile();
this->OpenMode = _File.OpenMode;
this->TermString = _File.TermString;
this->AddRef(_File.GetFile());
return *this;
}
// Can possibly go too far...?
inline CFile& operator >> (string &_String)
{
char Current;
_String = string(); // reset string
while (1) {
fread(&Current, 1, 1, this->File);
if (!NotTerm(Current) || feof(this->File)) {
while (1) { // Take care of multiple terminating characters
fread(&Current, 1, 1, this->File);
if (NotTerm(Current) || feof(this->File))
return *this;
}
}
_String += Current;
}
return *this;
}
inline CFile& operator >> (char *_String)
{
string String;
this->operator >> (String);
_String = strdup(String.c_str());
return *this;
}
inline CFile& operator << (string &_String)
{
fwrite((void*)_String.c_str(), 1, _String.length(), this->File);
return *this;
}
inline CFile& operator << (char *_String)
{
fwrite(_String, 1, strlen(_String), this->File);
return *this;
}
inline CFile& operator << (int32 _Num)
{
if (this->OpenMode == BINARY)
fwrite(&_Num, 1, sizeof(_Num), this->File);
else
fprintf(this->File, "%d", _Num);
return *this;
}
inline CFile& operator << (real64 _Num)
{
if (this->OpenMode == BINARY)
fwrite(&_Num, 1, sizeof(_Num), this->File);
else
fprintf(this->File, "%f", _Num);
return *this;
}
inline boolean operator ! (void)
{
return (this->File == NULL);
}
int32 OpenMode; // Wish it could be protected...oh well.
string TermString; // Same here
int32 Endian;
protected:
FILE *File;
enum { BINARY, TEXT };
// Just returns if _Char is a terminating character in TermString
inline boolean NotTerm(char _Char)
{
uint32 Count = 0;
while (Count < TermString.length()) {
if (TermString[Count++] == _Char)
return false;
}
return true;
}
// Returns what kind of mode _String specifies or else TEXT
inline int32 SetMode(char *_String)
{
uint32 Len = strlen(_String);
for (uint32 i = 0; i < Len; i++) {
if (_String[i] == 'b') {
return BINARY;
}
else if (_String[i] == 't') {
return TEXT;
}
}
return TEXT; // Default is text.
}
private:
void AddRef(FILE *_File)
{
for (Iter = RefCount.begin(); Iter != RefCount.end(); Iter++) {
if (Iter->f == File) {
Iter->Count++;
return;
}
}
RefCount.insert(RefCount.begin(), REF(_File));
}
boolean SafeToDel(FILE *_File)
{
boolean InList = false;
for (Iter = RefCount.begin(); Iter != RefCount.end(); Iter++) {
if (Iter->f == File) {
InList = true;
if (Iter->Count == 0) {
RefCount.erase(Iter);
return true;
}
}
Iter->f--;
}
if (InList)
return false;
return true;
}
};
#endif//FILE_H |