Rev 33 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include "File_IO.h"
#ifdef _WIN32
#include <windows.h>
#endif
#include <locale>
#include "DirIO.h"
#include "File.h"
CFileIO::CFileIO ()
{
m_bOpened = false;
m_lSize = 0;
m_bBinary = true;
m_fIdOld = NULL;
}
CFileIO::CFileIO(CyString filename)
{
m_bOpened = false;
m_lSize = 0;
m_bBinary = true;
m_fIdOld = NULL;
Open ( filename, true );
}
CFileIO::CFileIO(C_File *file)
{
m_bOpened = false;
m_lSize = 0;
m_bBinary = true;
m_fIdOld = NULL;
Open ( file->GetFilePointer(), true );
}
CFileIO::~CFileIO()
{
if ( m_bOpened )
{
if ( m_fIdOld )
fclose(m_fIdOld);
else
m_fId.close();
}
}
bool CFileIO::Open ( CyString filename, bool binary )
{
m_bBinary = binary;
m_sFilename = filename;
m_sFilename = m_sFilename.FindReplace ( "\\", "/" );
if ( m_sFilename.IsIn('/') )
{
m_sDirIO.SetDir(m_sFilename.GetToken ( "/", 1, m_sFilename.NumToken ( "/" ) - 1 ));
m_sFile = m_sFilename.GetToken ( "/", m_sFilename.NumToken ( "/" ) );
}
else
m_sFile = filename;
ReadFileSize();
return true;
}
bool CFileIO::WritePartFile ( size_t *offsets, size_t numOffset )
{
if ( NoFile() )
return false;
FILE *id = fopen ( m_sFilename.c_str(), (m_bBinary) ? "rb+" : "r+" );
if ( !id )
return false;
// first find file size
fseek ( id, 0, SEEK_END );
size_t fullsize = ftell ( id ), size = fullsize;
fseek ( id, 0, SEEK_SET );
FILE *writeId = fopen ( "temp.tmp", (m_bBinary) ? "wb" : "w" );
if ( !writeId )
{
fclose ( id );
return false;
}
size_t off = 0;
size_t startPos = 0;
size_t remainingSize = fullsize;
while ( off < numOffset )
{
startPos = ftell(id);
size_t offset = offsets[off++];
size_t size = offset - startPos;
char *data = new char[size];
fread ( data, sizeof(unsigned char), size, id );
fwrite ( data, sizeof(unsigned char), size, writeId );
delete data;
size_t datasize = offsets[off++];
fseek ( id, datasize, SEEK_CUR );
remainingSize = fullsize - offset - datasize;
}
if ( remainingSize )
{
char data[1000000];
size_t amountLeft = 1000000;
while ( remainingSize )
{
if ( amountLeft > remainingSize )
amountLeft = remainingSize;
fread ( data, sizeof(unsigned char), amountLeft, id );
fwrite ( data, sizeof(unsigned char), amountLeft, writeId );
remainingSize -= amountLeft;
amountLeft = 1000000;
}
}
fclose ( writeId );
fclose ( id );
// now copy to original file
remove ( m_sFilename.c_str() );
rename ( "temp.tmp", m_sFilename.c_str() );
return true;
}
void CFileIO::SetDir ( CyString dir )
{
if ( m_sFile.Empty() )
m_sDirIO.SetDir(dir);
else
Open ( dir + "/" + m_sFile, m_bBinary );
}
void CFileIO::ReadFileSize ()
{
FILE *id = fopen ( m_sFilename.c_str(), (m_bBinary) ? "rb" : "r" );
if ( !id )
{
m_lSize = 0;
return;
}
fseek ( id, 0, SEEK_END );
m_lSize = ftell ( id );
fseek ( id, 0, SEEK_SET );
fclose ( id );
}
bool CFileIO::WipeFile()
{
if ( NoFile() )
return false;
FILE *id = fopen ( m_sFilename.c_str(), (m_bBinary) ? "rb+" : "r+" );
if ( !id )
return false;
fclose(id);
return true;
}
int CFileIO::TruncateFile ( size_t offset, size_t datasize )
{
if ( NoFile() )
return FILEERR_NOFILE;
FILE *id = fopen ( m_sFilename.c_str(), (m_bBinary) ? "rb+" : "r+" );
if ( !id )
return FILEERR_NOOPEN;
// first find file size
fseek ( id, 0, SEEK_END );
size_t fullsize = ftell ( id ), size = fullsize;
fseek ( id, 0, SEEK_SET );
if ( (offset + datasize) > fullsize )
return FILEERR_TOSMALL;
// char data[500000];
#ifdef _WIN32
FILE *writeId = fopen ( "temp.tmp", (m_bBinary) ? "wb" : "w" );
if ( !writeId )
{
fclose ( id );
return FILEERR_NOWRITE;
}
char *data = new char[offset];
fread ( data, sizeof(unsigned char), offset, id );
fwrite ( data, sizeof(unsigned char), offset, writeId );
delete data;
/*
// first write the data before the file
size_t tosize = offset;
while ( tosize )
{
int read = 500000;
if ( read > tosize )
read = tosize;
fread ( data, sizeof(unsigned char), read, id );
fwrite ( data, sizeof(unsigned char), read, writeId );
tosize -= read;
}
*/
// next fseek after and write
fseek ( id, datasize, SEEK_CUR );
size = fullsize - offset - datasize;
data = new char[size];
fread ( data, sizeof(unsigned char), size, id );
fwrite ( data, sizeof(unsigned char), size, writeId );
delete data;
/*
while ( size )
{
int read = 500000;
if ( read > size )
read = size;
fread ( data, sizeof(unsigned char), read, id );
fwrite ( data, sizeof(unsigned char), read, writeId );
size -= read;
}*/
fclose ( writeId );
fclose ( id );
// now copy to original file
remove ( m_sFilename.c_str() );
rename ( "temp.tmp", m_sFilename.c_str() );
#else
// move to beginning of file data to remove
fseek ( id, offset, SEEK_SET );
size_t writepos = offset;
size_t readpos = offset + datasize;
size -= readpos;
while ( size > 0 )
{
int read = 500000;
if ( read > size )
read = size;
// read data
fseek ( id, readpos, SEEK_SET );
fread ( data, sizeof(unsigned char), read, id );
size -= read;
readpos += read;
// now seek back and write
fseek ( id, writepos, SEEK_SET );
fwrite ( data, sizeof(unsigned char), read, id );
writepos += read;
}
truncate ( m_sFilename.c_str(), fullsize - datasize );
fclose ( id );
#endif
return FILEERR_NONE;
}
char *CFileIO::ReadToData ( size_t *size )
{
*size = 0;
if ( NoFile() )
return NULL;
if ( !m_lSize )
ReadFileSize();
if ( !m_lSize )
return NULL;
FILE *id = fopen ( m_sFilename.c_str(), (m_bBinary) ? "rb" : "r" );
if ( !id )
return NULL;
char *data = new char[m_lSize];
fread ( data, sizeof(char), m_lSize, id );
if ( ferror (id) )
{
fclose ( id );
return NULL;
}
*size = m_lSize;
fclose ( id );
return data;
}
bool CFileIO::WriteData ( const char *data, size_t size )
{
if ( NoFile() )
return false;
FILE *id = fopen ( m_sFilename.c_str(), (m_bBinary) ? "wb" : "w" );
if ( !id )
return false;
fwrite ( data, size, sizeof(char), id );
fclose ( id );
ReadFileSize();
return true;
}
bool CFileIO::WriteString ( CyString data )
{
return WriteData ( data.c_str(), data.Length() );
}
bool CFileIO::Exists ()
{
FILE *id = fopen ( m_sFilename.c_str(), (m_bBinary) ? "rb" : "r" );
if ( !id )
return false;
fclose ( id );
return true;
}
bool CFileIO::StartReadOld()
{
if ( !m_sFilename.Empty() )
{
if ( m_bOpened )
StopRead();
m_fIdOld = fopen(m_sFilename.c_str(), "rb");
if ( !m_fIdOld )
return false;
m_bOpened = true;
return true;
}
return false;
}
bool CFileIO::StartRead()
{
if ( !m_sFilename.Empty() )
{
if ( m_bOpened )
StopRead();
m_fId.open(m_sFilename.c_str(), std::ios_base::in);
if ( m_fId.is_open() )
{
m_bOpened = true;
return true;
}
}
return false;
}
std::vector<CyString> *CFileIO::ReadLines()
{
if ( m_sFilename.Empty() )
return 0;
std::vector<CyString> *file = new std::vector<CyString>;
std::string line;
file->clear();
std::ifstream infile (m_sFilename.c_str(), std::ios_base::in);
while (getline(infile, line, '\n'))
{
CyString l = line;
l.RemoveChar((char)0);
file->push_back(l);
}
infile.close();
return file;
}
CyStringList *CFileIO::ReadLinesStr()
{
if ( m_sFilename.Empty() )
return 0;
CyStringList *file = new CyStringList;
std::string line;
std::ifstream infile (m_sFilename.c_str(), std::ios_base::in);
while (getline(infile, line, '\n'))
{
CyString l = line;
l.RemoveChar((char)0);
file->PushBack(l);
}
infile.close();
return file;
}
void CFileIO::StopRead()
{
if ( m_bOpened )
{
if ( m_fIdOld )
fclose(m_fIdOld);
else
m_fId.close();
}
m_fIdOld = NULL;
m_bOpened = false;
}
bool CFileIO::IsOpened()
{
if ( !m_bOpened )
return false;
if ( m_fIdOld )
return true;
if ( m_fId.is_open() )
return true;
return false;
}
CyString CFileIO::ReadToEndLine(bool autoclose)
{
if ( !this->IsOpened() )
{
if ( !StartRead() )
return "";
}
int pos = 0;
char sLine[10000];
char cur = 0;
if ( m_fIdOld )
{
while ( !feof(m_fIdOld) )
{
cur = fgetc(m_fIdOld);
if ( cur == '\n' || cur == '\r' )
break;
sLine[pos++] = cur;
}
}
else
{
while ( !m_fId.eof() )
{
cur = m_fId.get();
if ( cur == '\n' || cur == '\r' )
break;
sLine[pos++] = cur;
}
// m_fId.getline(sLine, 255, '\n');
std::string line;
if ( getline(m_fId, line, '\n') )
return CyString(line);
}
sLine[pos] = 0;
if ( pos )
return CyString(sLine);
if ( autoclose )
StopRead();
return "";
}
bool CFileIO::AtEnd()
{
if ( !m_bOpened )
return true;
if ( m_fIdOld )
{
if ( feof(m_fIdOld) )
return true;
}
else
{
if ( m_fId.eof() )
return true;
}
return false;
}
bool CFileIO::AppendFile ( CyString filename )
{
FILE *id = fopen ( filename.c_str(), (m_bBinary) ? "rb" : "r" );
if ( !id )
return false;
FILE *aid = fopen ( m_sFilename.c_str(), (m_bBinary) ? "ab" : "a" );
if ( !aid )
{
return false;
fclose ( id );
}
// move to the end of the file
fseek ( aid, 0, SEEK_END );
// get size of file
fseek ( id, 0, SEEK_END );
size_t size = ftell ( id );
fseek ( id, 0, SEEK_SET );
char data[500000];
while ( size > 0 )
{
size_t read = 500000;
if ( read > size )
read = size;
size -= read;
fread ( data, sizeof(char), read, id );
fwrite ( data, sizeof(char), read, aid );
}
fclose ( aid );
fclose ( id );
return true;
}
bool CFileIO::AppendData ( const char *d, size_t size )
{
FILE *aid = fopen ( m_sFilename.c_str(), (m_bBinary) ? "ab" : "a" );
if ( !aid )
return false;
// move to the end of the file
fseek ( aid, 0, SEEK_END );
char *pos = (char *)d;
while ( size > 0 )
{
size_t read = 500000;
if ( read > size )
read = size;
size -= read;
fwrite ( pos, sizeof(char), read, aid );
pos += read;
}
fclose ( aid );
return true;
}
bool CFileIO::AppendDataToPos ( const char *d, size_t size, size_t start )
{
FILE *aid = fopen ( m_sFilename.c_str(), (m_bBinary) ? "ab" : "a" );
if ( !aid )
return false;
// move to the end of the file
fseek ( aid, 0, SEEK_END );
size_t end = ftell(aid);
if ( start > end )
{
fclose ( aid);
return false;
}
fseek ( aid, start, SEEK_SET );
char *pos = (char *)d;
while ( size > 0 )
{
size_t read = 500000;
if ( read > size )
read = size;
size -= read;
fwrite ( pos, sizeof(char), read, aid );
pos += read;
}
fclose ( aid );
return true;
}
CyString CFileIO::GetBaseName()
{
return m_sFile.GetTokenRev(".", 1, -1);
}
CyString CFileIO::GetFileExtension ()
{
if ( m_sFilename.Empty() )
return NullString;
CyString ext = m_sFilename.GetToken ( ".", m_sFilename.NumToken ( "." ) );
return ext;
}
CyString CFileIO::ChangeFileExtension ( CyString ext )
{
if ( m_sFilename.Empty() )
return NullString;
CyString noext = m_sFilename.GetToken ( ".", 1, m_sFilename.NumToken ( "." ) - 1 );
return noext + "." + ext;
}
bool CFileIO::Remove()
{
if ( !Exists() )
return false;
if ( remove(m_sFilename.c_str()) == 0 )
return true;
return false;
}
bool CFileIO::WriteFileUTF(std::vector<CyString> *lines)
{
if ( !lines || m_sFilename.Empty() )
return false;
// we need to create the directory
if ( !m_sDirIO.Exists() )
{
if ( !m_sDirIO.Create() )
return false;
}
#ifdef _WIN32
TCHAR buf[5000];
wsprintf(buf, L"%hs", m_sFilename.c_str());
FILE *id = _wfopen(buf, L"wt+,ccs=UTF-8");
if ( !id )
return false;
// write the rest
for ( int i = 0; i < (int)lines->size(); i++ )
{
CyString l = lines->at(i);
if ( l.IsIn('\n') )
{
int max;
CyString *strs = l.SplitToken("\n", &max);
if ( strs && max )
{
for ( int i = 0; i < max; i++ )
{
CyString line = strs[i];
line += "\n";
int size = wsprintf(buf, L"%hs", line.c_str());
fwrite(buf, sizeof(TCHAR), wcslen(buf), id);
}
CLEANSPLIT(strs, max);
}
}
else
{
l += "\n";
int size = wsprintf(buf, L"%hs", l.c_str());
fwrite(buf, sizeof(TCHAR), wcslen(buf), id);
}
}
fclose(id);
return true;
#else
//TODO: write utf8 file writing function
return false;
#endif
}
bool CFileIO::WriteFile(std::vector<CyString> *lines)
{
if ( !lines || m_sFilename.Empty() )
return false;
// we need to create the directory
if ( !m_sDirIO.Exists() )
{
if ( !m_sDirIO.Create() )
return false;
}
std::ofstream out(m_sFilename.c_str());
if ( !out )
return false;
for ( int i = 0; i < (int)lines->size(); i++ )
{
CyString l = lines->at(i);
out << l.c_str() << std::endl;
}
out.close();
return true;
}
bool CFileIO::WriteFile(CyStringList *lines)
{
if ( !lines || m_sFilename.Empty() )
return false;
// we need to create the directory
if ( !m_sDirIO.Exists() )
{
if ( !m_sDirIO.Create() )
return false;
}
std::ofstream out(m_sFilename.c_str());
if ( !out )
return false;
/*
if ( utf )
{
unsigned char smarker[4];
smarker[0] = 0xEF;
smarker[1] = 0xBB;
smarker[2] = 0xBF;
smarker[3] = 0x00;
out << smarker;
}
*/
for ( int i = 0; i < (int)lines->Count(); i++ )
{
CyString l = lines->StringAt(i);
out << l.c_str() << std::endl;
}
out.close();
return true;
}
bool CFileIO::Rename(CyString toFile)
{
if ( rename(m_sFilename.c_str(), toFile.c_str()) == 0 )
return true;
return false;
}
CyString CFileIO::GetWindowsFilename()
{
CyString returnString = m_sFilename;
returnString = returnString.FindReplace("/", "\\");
return returnString;
}
void CFileIO::SetCreationTime(time_t time)
{
#ifdef _WIN32
// Note that LONGLONG is a 64-bit value
LONGLONG ll;
FILETIME ft;
ll = Int32x32To64(time, 10000000) + 116444736000000000;
ft.dwLowDateTime = (DWORD)ll;
ft.dwHighDateTime = ll >> 32;
HANDLE filename = CreateFile((LPCWSTR)GetWindowsFilename().c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
// Set the file time on the file
SetFileTime(filename,(LPFILETIME) NULL,(LPFILETIME) NULL,&ft);
// Close our handle.
CloseHandle(filename);
#endif
}
time_t CFileIO::GetCreationTime()
{
#ifdef _WIN32
WIN32_FILE_ATTRIBUTE_DATA wfad;
GetFileAttributesEx((LPCWSTR)GetWindowsFilename().c_str(), GetFileExInfoStandard, &wfad);
LARGE_INTEGER date, adjust;
date.HighPart = wfad.ftCreationTime.dwHighDateTime;
date.LowPart = wfad.ftCreationTime.dwLowDateTime;
// 100-nanoseconds = milliseconds * 10000
adjust.QuadPart = 11644473600000 * 10000;
// removes the diff between 1970 and 1601
date.QuadPart -= adjust.QuadPart;
// converts back from 100-nanoseconds to seconds
return (time_t)(date.QuadPart / 10000000);
#else
struct stat fileStat;
if ( !stat(GetWindowsFilename().c_str(), &fileStat) )
return (time_t)fileStat.st_atime;
#endif
return 0;
}
/**
* Copys the contents of a file to another
*
* Reads and writes the files in block
*/
bool CFileIO::Copy(CyString toFile, bool keepTime)
{
//open both files
FILE *id = fopen(GetWindowsFilename().c_str(), "rb");
if ( !id )
return false;
FILE *toID = fopen(toFile.c_str(), "wb");
if ( !toID )
{
fclose(id);
return false;
}
time_t time = GetCreationTime();
// get length of file
fseek(id, 0, SEEK_END);
size_t remainingLen = ftell(id);
fseek(id, 0, SEEK_SET);
if ( remainingLen <= 0 )
{
fclose(id);
fclose(toID);
return false;
}
// read then write a block
char block[100000];
while ( remainingLen )
{
size_t amt = 100000;
if ( amt > remainingLen )
amt = remainingLen;
fread(block, amt, sizeof(char), id);
fwrite(block, amt, sizeof(char), toID);
remainingLen -= amt;
}
fclose(id);
fclose(toID);
if ( keepTime )
CFileIO(toFile.c_str()).SetCreationTime(time);
return true;
}