Subversion Repositories spk

Rev

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;
}