Subversion Repositories spk

Rev

Rev 223 | 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 <codecvt>

#include "DirIO.h"
#include "File.h"
#include "Logging/Log.h"
#include "Packages.h"

CFileIO::CFileIO () : m_lSize(0), m_bBinary(true), m_bAutoDelete(false), m_bSeekP(false)
{
}

CFileIO::CFileIO(const Utils::WString &sFilename, bool bBinary) : m_lSize(0), m_bBinary(bBinary), m_bAutoDelete(false)
{
        open(sFilename, bBinary);
}

CFileIO::CFileIO(const Utils::WString &filename) : m_lSize(0), m_bBinary(true), m_bAutoDelete(false), m_bSeekP(false)
{
        open(filename, true);
}

CFileIO::CFileIO(C_File *file) : m_lSize(0), m_bBinary(true), m_bAutoDelete(false), m_bSeekP(false)
{
        open(file->filePointer(), true);
}

CFileIO::~CFileIO()
{
        if ( this->isOpened() ) m_fId.close();
        if ( m_bAutoDelete ) this->remove();
}

void CFileIO::setAutoDelete(bool bDelete)
{
        m_bAutoDelete = true;
}

bool CFileIO::open(const Utils::WString& sFilename, bool bBinary)
{
        m_bBinary = bBinary;
        _sFilename = sFilename.asFilename();

        // check if there are any directories, and split the file and directory parts
        if ( _sFilename.contains('/') ) {
                _sDirIO.setDir(_sFilename.tokens(L"/", 1, -2));
                _sFile = _sFilename.token(L"/", -1);
        }
        else
                _sFile = _sFilename;

        _sFile.removeFirstSpace();
        _sFile.removeChar(13);

        _updateFilename();

        this->_readFileSize();
        return true;
}

unsigned char *CFileIO::read(size_t iAmount)
{
        if ( !this->isOpened() ) startRead();
        if ( !this->isOpened() ) return NULL;

        if ( iAmount > m_lSize ) iAmount = m_lSize;

        unsigned char *data;
        try {
                data = new unsigned char[iAmount + 1];
        }
        catch (std::exception &e) {
                CLog::logf(CLog::Log_IO, 2, L"ERROR: CFileIO::read(size_t) unable to malloc data, %d (%hs)", iAmount + 1, e.what());
                return NULL;
        }

        if ( !read(data, iAmount, true) ) {
                CLog::logf(CLog::Log_IO, 2, L"ERROR: CFileIO::read(size_t) unable to read data from file, %s/%d", _sFilename.c_str(), iAmount);
                delete[] data;
                return NULL;
        }

        return data;
}

unsigned char *CFileIO::readAll(size_t *pSize)
{
        if ( pSize ) (*pSize) = 0;
        if ( !this->isOpened() ) startRead();
        if ( !this->isOpened() ) return NULL;

        unsigned char *data;
        try {
                data = new unsigned char[m_lSize + 1];
        }
        catch (std::exception &e) {
                CLog::logf(CLog::Log_IO, 2, L"ERROR: CFileIO::readAll() unable to malloc data, %d (%hs)", m_lSize + 1, e.what());
                return NULL;
        }

        if ( !read(data, m_lSize, true) ) {
                CLog::logf(CLog::Log_IO, 2, L"ERROR: CFileIO::readAll() unable to read data from file, %s/%d", _sFilename.c_str(), m_lSize);
                delete[] data;
                return NULL;
        }

        if ( pSize ) (*pSize) = m_lSize;
        return data;
}

bool CFileIO::read(wchar_t* buf, size_t iSize, bool bEndChar)
{
        if (!this->isOpened()) startRead();
        if (!this->isOpened()) return false;

        if (iSize > m_lSize) iSize = m_lSize;
        try {
                m_fId.read((char*)buf, iSize);
        }
        catch (std::exception& e) {
                CLog::logf(CLog::Log_IO, 3, L"ERROR: CFileIO::read() unable to read from file: %s (%hs)", _sFilename.c_str(), e.what());
                return false;
        }

        if (bEndChar) buf[iSize] = '\0';

        return !m_fId.bad();
}
bool CFileIO::read(unsigned char* buf, size_t iSize, bool bEndChar)
{
        if (!this->isOpened()) startRead();
        if (!this->isOpened()) return false;

        if (iSize > m_lSize) iSize = m_lSize;
        try {
                m_fId.read((char*)buf, iSize);
        }
        catch (std::exception& e) {
                CLog::logf(CLog::Log_IO, 3, L"ERROR: CFileIO::read() unable to read from file: %s (%hs)", _sFilename.c_str(), e.what());
                return false;
        }

        if (bEndChar) buf[iSize] = '\0';

        return !m_fId.bad();
}

bool CFileIO::WritePartFile ( size_t *offsets, size_t numOffset )
{
        if ( NoFile() ) return false;

        std::fstream File(_sFilename, _in());
        if ( !File.is_open() ) return false;

        // first find file size
        File.seekg(0, std::ios::end);
        size_t fullsize = static_cast<size_t>(File.tellg()), size = fullsize;
        File.seekg(0, std::ios::beg);

        std::fstream writeFile(CPackages::tempDirectory() + "/temp.tmp", _out());
        if ( !File.is_open() ) {
                File.close();
                return false;
        }

        size_t off = 0;
        size_t startPos = 0;
        size_t remainingSize = fullsize;

        while ( off < numOffset ) {
                startPos = static_cast<size_t>(File.tellg());
                size_t offset = offsets[off++];
                size_t size = offset - startPos;
                try {
                        char *data = new char[size];
                        File.read(data, size);
                        writeFile.write(data, size);
                        delete []data;
                }
                catch(std::exception &e) {
                        CLog::logf(CLog::Log_IO, 2, L"CFileIO::WritePartFilea() unable to read data from file: %s (%hs)", _sFilename.c_str(), e.what());
                        return false;
                }

                size_t datasize = offsets[off++];
                File.seekg(datasize, std::ios::beg);
                remainingSize = fullsize - offset - datasize;
        }

        if ( remainingSize ) {
                char data[1000000];
                size_t amountLeft = 1000000;
                while ( remainingSize )
                {
                        if ( amountLeft > remainingSize ) amountLeft = remainingSize;
                        try {
                                File.read(data, amountLeft);
                                writeFile.write(data, amountLeft);
                        }
                        catch(std::exception &e) {
                                CLog::logf(CLog::Log_IO, 2, L"CFileIO::WritePartFilea() unable to read data from file: %s (%hs)", _sFilename.c_str(), e.what());
                                return false;
                        }

                        remainingSize -= amountLeft;
                        amountLeft = 1000000;
                }
        }

        File.close();
        writeFile.close();

        // now copy to original file
        CFileIO::Remove(_sFilename);
        return CFileIO::Rename(CPackages::tempDirectory() + L"/temp.tmp", _sFilename);
}


void CFileIO::setDir(const Utils::WString &dir)
{
        if ( _sFile.empty() )   _sDirIO.setDir(dir);
        else                                    open(dir + "/" + _sFile, m_bBinary);
}

void CFileIO::_readFileSize ()
{
        m_lSize = 0;

        std::fstream file(_sFilename, (m_bBinary) ? (std::ios::in | std::ios::binary) : (std::ios::in));
        if ( !file.is_open() ) return;

        file.seekg(0, std::ios::end);
        m_lSize = static_cast<size_t>(file.tellg());
        file.close();
}

bool CFileIO::WipeFile()
{
        if ( NoFile() ) return false;
        std::ofstream file;
        file.open(_sFilename, std::ios::out | std::ios::trunc);
        bool bDone = file.is_open();
        file.close();

        return bDone;
}


int CFileIO::TruncateFile ( size_t offset, size_t datasize )
{
        if ( NoFile() ) return FILEERR_NOFILE;

        if ( !this->startRead() ) return FILEERR_NOOPEN;
        if ( (offset + datasize) > m_lSize ) return FILEERR_TOSMALL;

        CFileIO File(CPackages::tempDirectory() + "/temp.tmp");
        if ( !File.startWrite() ) return FILEERR_NOWRITE;
        File.setAutoDelete(true);

        if ( !File.write(*this, offset) ) return false;

        // next fseek after and write
        this->seek(datasize);
        size_t size = m_lSize - offset - datasize;
        if ( size > 0 ) {
                File.write(*this, size);
        }

        File.close();
        this->close();
        File.setAutoDelete(false);

        // now copy to original file
        if (CFileIO::Remove(_sFilename)) {
                if (CFileIO::Rename(CPackages::tempDirectory() + L"/temp.tmp", _sFilename))
                {
                        size_t oldSize = m_lSize;
                        size_t checkFileSize = m_lSize - datasize;
                        this->_readFileSize();
                        if (checkFileSize != m_lSize) {
                                CLog::log(CLog::Log_IO, 3, Utils::WString(L"WARNING: CFileIO::TruncateFile, file size mismatch, ") + (long)checkFileSize + L" => " + (long)m_lSize);
                        }
                        return FILEERR_NONE;
                }
                return FILEERR_NOWRITE;
        }

        return FILEERR_NOWRITE;
}

int CFileIO::_in() const
{
        if ( m_bBinary ) return std::ios::in | std::ios::binary;
        return std::ios::in;
}

int CFileIO::_out() const
{
        if ( m_bBinary ) return std::ios::out | std::ios::binary;
        return std::ios::out;
}
int CFileIO::_inout() const
{
        if ( m_bBinary ) return std::ios::in | std::ios::out | std::ios::binary;
        return std::ios::in | std::ios::out;
}

int CFileIO::_append() const
{
        if ( m_bBinary ) return std::ios::out | std::ios::binary | std::ios::app;
        return std::ios::out | std::ios::app;
}

char *CFileIO::ReadToData ( size_t *size )
{
        *size = 0;

        if ( NoFile() ) return NULL;
        if ( !m_lSize ) this->_readFileSize();
        if ( !m_lSize ) return NULL;

        std::fstream file(_sFilename, _in());
        if ( !file.is_open() ) return NULL;

        char *data;
        try {
                data = new char[m_lSize + 1];
        }
        catch (std::exception &e) {
                CLog::logf(CLog::Log_IO, 2, L"CFileIO::ReadToData() unable to malloc storage, %d (%hs)", m_lSize + 1, e.what());
                file.close();
                return NULL;
        }

        try {
                file.read((char *)data, m_lSize);
        }
        catch (std::exception &e) {
                CLog::logf(CLog::Log_IO, 2, L"CFileIO::ReadToData() unable to read data from file (%hs)", e.what());
                file.close();
                return NULL;
        }

        *size = m_lSize;
        file.close();

        return data;
}

bool CFileIO::WriteData ( const char *data, size_t size )
{
        if ( NoFile() )
                return false;

        std::fstream File(_sFilename.c_str(), _out());
        if ( !File.is_open() ) return false;

        bool ret = true;
        try {
                File.write(data, size);
        }
        catch (std::exception &e) {
                CLog::logf(CLog::Log_IO, 2, L"CFileIO::ReadToData() unable to read data from file: %s (%hs)", _sFilename.c_str(), e.what());
                ret = false;
        }

        File.close();

        if ( ret ) this->_readFileSize();
        return ret;
}

bool CFileIO::writeString ( const Utils::String &data )
{
        return WriteData ( data.c_str(), data.length() );
}

bool CFileIO::Exists(const Utils::WString &filename)
{
        std::wfstream File(filename, std::ios::in | std::ios::binary);
        bool bRet = File.good();
        File.close();
        return bRet;
}

bool CFileIO::exists () const
{
        if ( this->isOpened() ) return true;
        std::fstream File(_sFilename, _in());
        bool bRet = File.good();
        File.close();
        return bRet;
}

bool CFileIO::startRead()
{
        return _start(_in(), false);
}

bool CFileIO::startWrite()
{
        return _start(_out(), true);
}

bool CFileIO::startModify()
{
        return _start(_inout(), true);
}

bool CFileIO::startAppend()
{
        return _start(_append(), false);
}

bool CFileIO::_start(int iFlags, bool bSeekP)
{
        if ( !_sFilename.empty() ) {
                if ( this->isOpened() ) this->close();

                m_fId.open(_sFilename, iFlags);
        }
        m_bSeekP = bSeekP;
        return m_fId.is_open();
}

size_t CFileIO::readLines(std::vector<Utils::String>& to) const
{
        if (_sFilename.empty()) return 0;

        Utils::String line;
        std::ifstream infile(_sFilename.c_str(), std::ios_base::in);
        while (getline(infile, line, '\n')) {
                to.push_back(Utils::String(line).removeChar((char)0));
        }

        infile.close();

        return to.size();
}

size_t CFileIO::readLines(std::vector<Utils::WString>& to) const
{
        if (_sFilename.empty()) return 0;

        std::wstring line;
        std::wifstream infile(_sFilename.c_str(), std::ios_base::in);

        if (getline(infile, line, L'\n'))
        {
                if (line.length() > 3)
                {
                        // check for UTF-8 header
                        if (line[0] == 239 && line[1] == 187 && line[2] == 191)
                        {
                                infile.close();
                                return readLinesUTF(to);
                        }
                        to.push_back(Utils::WString(line).remove((char)0));
                }
                while (getline(infile, line, L'\n')) {
                        to.push_back(Utils::WString(line).remove((char)0));
                }
        }


        infile.close();

        return to.size();
}
size_t CFileIO::readLinesUTF(std::vector<Utils::WString>& to) const
{
        if (_sFilename.empty()) return 0;

        std::wstring line;
        std::wifstream infile(_sFilename.c_str(), std::ios_base::in);
        infile.imbue(std::locale(std::locale::empty(), new std::codecvt_utf8<wchar_t>));

        if (getline(infile, line, L'\n'))
        {
                if (line.length() > 3)
                {
                        // check for UTF-8 header
                        if (line[0] == 239 && line[1] == 187 && line[2] == 191)
                                line = line.erase(0, 3);
                        to.push_back(Utils::WString(line).remove((char)0).remove(65279));
                }
                while (getline(infile, line, L'\n')) {
                        to.push_back(Utils::WString(line).remove((char)0).remove(65279));
                }
        }


        infile.close();

        return to.size();
}

size_t CFileIO::readLines(Utils::WStringList& to) const
{
        if (_sFilename.empty()) return 0;

        std::wstring line;
        std::wifstream infile(_sFilename.c_str(), std::ios_base::in);
        while (getline(infile, line, L'\n')) {
                to.pushBack(Utils::WString(line).remove((char)0));
        }

        infile.close();

        return to.size();
}

bool CFileIO::put(const unsigned char c)
{
        if ( !this->isOpened() ) return false;

        m_fId.put(c);
        return !m_fId.bad();
}

bool CFileIO::writeSize(size_t iSize)
{
        if ( !this->isOpened() ) return false;
        if ( !this->put(static_cast<unsigned char>(iSize >> 24)) ) return false;
        if ( !this->put(static_cast<unsigned char>(iSize >> 16)) ) return false;
        if ( !this->put(static_cast<unsigned char>(iSize >> 8)) ) return false;
        if ( !this->put(static_cast<unsigned char>(iSize)) ) return false;
        m_lSize += 4;
        return true;
}

bool CFileIO::write(CFileIO &file, size_t iSize)
{
        if ( !this->isOpened() ) startWrite();
        if ( !this->isOpened() ) return false;

        int iMaxSize = 1000000;

        unsigned char *data;
        try {
                data = new unsigned char[iMaxSize + 1];
        }
        catch (std::exception &e) {
                CLog::logf(CLog::Log_IO, 2, L"ERROR: CFileIO::write(CFileIO, size_t) unable to malloc data, %d (%hs)", iMaxSize + 1, e.what());
                return false;
        }

        int iSizeLeft = iSize;
        bool bSuccess = true;
        while ( iSizeLeft > 0 ) {
                int iDoSize = iMaxSize;
                if ( iDoSize > iSizeLeft ) iDoSize = iSizeLeft;

                if ( !file.read(data, iDoSize) ) bSuccess = false;
                if ( bSuccess && !this->write(data, iDoSize) ) bSuccess = false;
                if ( !bSuccess ) break;
                iSizeLeft -= iDoSize;
        }

        delete data;

        return bSuccess;
}

bool CFileIO::write(const char *buf, size_t iSize)
{
        if ( !this->isOpened() ) startWrite();
        if ( !this->isOpened() ) return false;
        try {
                m_fId.write((char*)buf, iSize);
        }
        catch (std::exception &e) {
                CLog::logf(CLog::Log_IO, 2, L"CFileIO::write() unable to write to file: %s (%hs)", _sFilename.c_str(), e.what());
                return false;
        }
        m_lSize += iSize;
        return !m_fId.bad();
}
bool CFileIO::write(const unsigned char *buf, size_t iSize)
{
        return this->write((char *)buf, iSize);
}

bool CFileIO::write(const unsigned char *buf, ...)
{
        va_list args;
        va_start(args, buf);
        bool ret = this->_write((char *)buf, args);
        va_end(args);
        return ret;
}
bool CFileIO::_write(const char* buf, va_list args)
{
        if (!this->isOpened()) return false;

        char buffer[10000];

        vsprintf(buffer, buf, args);
        try {
                int iLen = strlen(buffer);
                m_fId.write((char*)buffer, iLen);
                m_lSize += iLen;
        }
        catch (std::exception& e) {
                CLog::logf(CLog::Log_IO, 2, L"CFileIO::write() unable to write to file: %s (%hs)", _sFilename.c_str(), e.what());
                return false;
        }
        return !m_fId.bad();
}
bool CFileIO::_write(const wchar_t* buf, va_list args)
{
        if (!this->isOpened()) return false;

        wchar_t buffer[10000];

#ifdef _WIN32
        vswprintf_s(buffer, 10000, buf, args);
#else
        vswprintf(buffer, buf, args);
#endif
        try {
                size_t iLen = wcslen(buffer);
                m_fId.write((char*)buffer, iLen);
                m_lSize += iLen;
        }
        catch (std::exception& e) {
                CLog::logf(CLog::Log_IO, 2, L"CFileIO::write() unable to write to file: %ls (%hs)", _sFilename.c_str(), e.what());
                return false;
        }
        return !m_fId.bad();
}

bool CFileIO::write(const char *buf, ...)
{
        va_list args;
        va_start(args, buf);
        bool ret = this->_write((char *)buf, args);
        va_end(args);
        return ret;
}

void CFileIO::_seek(int iPos, int iFrom)
{
        if ( !this->isOpened() ) {
                if ( !this->startRead() ) return;
        }
        if ( m_bSeekP ) m_fId.seekp(iPos, iFrom);
        else m_fId.seekg(iPos, iFrom);
}

void CFileIO::seek(size_t iPos)
{
        _seek(iPos, std::ios::cur);
}

void CFileIO::seekEnd(size_t iPos)
{
        _seek(iPos, std::ios::end);
}

void CFileIO::seekStart(size_t iPos)
{
        _seek(iPos, std::ios::beg);
}

std::fstream &CFileIO::stream()
{
        return m_fId;
}

bool CFileIO::isOpened() const
{
        if ( m_fId.is_open() )
                return true;
        return false;
}

void CFileIO::close()
{
        if ( this->isOpened() ) m_fId.close();
        this->_readFileSize();
}

int CFileIO::readSize()
{
        unsigned char size[4];
        if ( this->read(size, 4) ) return (size[0] << 24) + (size[1] << 16) + (size[2] << 8) + size[3];
        return 0;
}

bool CFileIO::atEnd() const
{
        if ( !this->isOpened() ) return true;
        if ( m_fId.eof() )               return true;
        return false;
}

bool CFileIO::appendFile ( const Utils::String &filename )
{
        std::fstream fromFile(filename, _in());
        if ( !fromFile.is_open() ) return false;

        std::fstream toFile(_sFilename, _append());
        if ( !toFile.is_open() ) {
                fromFile.close();
                return false;
        }

        // move to the end of the file
        toFile.seekg(0, std::ios::end);

        // get size of file
        fromFile.seekg(0, std::ios::end);
        size_t size = static_cast<size_t>(fromFile.tellg());
        fromFile.seekg(0, std::ios::beg);

        char data[500000];
        while ( size > 0 )
        {
                size_t read = 500000;
                if ( read > size )
                        read = size;

                size -= read;

                fromFile.read(data, read);
                toFile.write(data, read);
        }

        fromFile.close();
        toFile.close();
        return true;
}


bool CFileIO::AppendData ( const char *d, size_t size )
{
        std::ofstream File(_sFilename, _append());
        if ( !File.is_open() ) return false;

        // move to the end of the file
        //File.seekg(0, std::ios::end);

        char *pos = (char *)d;
        while ( size > 0 ) {
                size_t read = 500000;
                if ( read > size ) read = size;

                size -= read;

                try {
                        File.write(pos, read);
                } 
                catch(std::exception &e) {
                        CLog::logf(CLog::Log_IO, 2, L"CFileIO::AppendData() unable to write data to file: %s (%hs)", _sFilename.c_str(), e.what());
                        File.close();
                        return false;
                }
                pos += read;
        }

        File.close();
        return true;
}

bool CFileIO::AppendDataToPos ( const char *d, size_t size, size_t start )
{
        if ( start > m_lSize ) return false;
        if ( m_lSize <= 0 ) {
                if ( !this->startWrite() ) return false;
        }
        else if ( start == m_lSize ) {
                if ( !this->startAppend() ) return false;
        }
        else {
                if ( !this->startModify() ) return false;
                this->seekStart(start);
        }

        return this->write(d, size);
}

Utils::String CFileIO::readEndOfLineStr()
{
        if (!this->isOpened()) {
                if (!startRead())       return "";
        }

        std::string str;
        std::getline(m_fId, str, '\n');
        return str;
}
Utils::WString CFileIO::readEndOfLine()
{
        if (!this->isOpened()) {
                if (!startRead())       return L"";
        }

        std::string str;
        std::getline(m_fId, str, '\n');
        return str;
}

Utils::WString CFileIO::baseName() const
{
        return _sFile.tokens(L".", 1, -2);
}

const Utils::WString& CFileIO::fullFilename() const { return _sFilename; }
const Utils::WString& CFileIO::filename() const { return _sFile; }

Utils::WString CFileIO::extension () const
{
        if ( _sFilename.empty() ) return Utils::WString::Null();
        return _sFilename.token(L".", -1);
}

Utils::WString CFileIO::changeFileExtension(const Utils::WString &ext) const
{
        if ( _sFilename.empty() )
                return Utils::WString::Null();
        
        return _sFilename.tokens(L".", 1, -2) + L"." + ext;
}

bool CFileIO::Remove(const Utils::WString& rem)
{
#ifdef _WIN32
        return DeleteFile(rem.c_str());
#else
        //if ( !Exists() ) return false;
        return (std::remove(_toFileData(rem)) == 0) ? true : false;
#endif
}

bool CFileIO::Rename(const Utils::WString& from, const Utils::WString &to) 
{
        if (_wrename(from.c_str(), to.c_str()) == 0)
                return true;
        return false;
}

bool CFileIO::remove()
{
        if ( this->isOpened() ) this->close();
        if ( !this->exists() ) return false;
        if ( CFileIO::Remove(_sFilename)) return true;
        return false;
}

bool CFileIO::writeFileUTF(const std::vector<Utils::WString>* lines)
{
        if (!lines || _sFilename.empty())
                return false;

        // we need to create the directory
        if (!_sDirIO.exists())
        {
                if (!_sDirIO.create())
                        return false;
        }

#ifdef _WIN32
        FILE* id = _wfopen(_sFilename.c_str(), L"wt+,ccs=UTF-8");
        if (!id)
                return false;

        // write the rest
        for (auto itr = lines->begin(); itr != lines->end(); itr++)
        {
                Utils::WString l = (*itr);
                if (l.contains('\n'))
                {
                        std::vector<Utils::WString> strs;
                        if (l.tokenise(L"\n", strs) && !strs.empty())
                        {
                                for (auto itr = strs.begin(); itr != strs.end(); itr++)
                                {
                                        Utils::WString line = *itr;
                                        line += L"\n";
                                        fwrite(l.c_str(), sizeof(TCHAR), wcslen(l.c_str()), id);
                                }
                        }
                }
                else
                {
                        l += L"\n";
                        fwrite(l.c_str(), sizeof(TCHAR), wcslen(l.c_str()), id);
                }
        }

        fclose(id);

        return true;
#else
        //TODO: write utf8 file writing function
        return false;
#endif
}
bool CFileIO::writeFileUTF(const Utils::WStringList &lines)
{
        if (lines.empty() || _sFilename.empty())
                return false;

        // we need to create the directory
        if (!_sDirIO.exists())
        {
                if (!_sDirIO.create())
                        return false;
        }

#ifdef _WIN32
        FILE* id = _wfopen(_sFilename.c_str(), L"wt+,ccs=UTF-8");
        if (!id)
                return false;

        // write the rest
        for (auto itr = lines.begin(); itr != lines.end(); itr++)
        {
                Utils::WString l = (*itr)->str;
                if (l.contains('\n'))
                {
                        std::vector<Utils::WString> strs;
                        if (l.tokenise(L"\n", strs) && !strs.empty())
                        {
                                for (auto itr = strs.begin(); itr != strs.end(); itr++)
                                {
                                        Utils::WString line = *itr;
                                        line += L"\n";
                                        fwrite(line.c_str(), sizeof(TCHAR), wcslen(line.c_str()), id);
                                }
                        }
                }
                else
                {
                        l += L"\n";
                        fwrite(l.c_str(), sizeof(TCHAR), wcslen(l.c_str()), id);
                }
        }

        fclose(id);

        return true;
#else
        //TODO: write utf8 file writing function
        return false;
#endif
}

bool CFileIO::writeFile(std::vector<Utils::String> *lines)
{
        if (!lines || _sFilename.empty())
                return false;

        // we need to create the directory
        if (!_sDirIO.exists())
        {
                if (!_sDirIO.create())
                        return false;
        }


        std::ofstream out(_sFilename.c_str());
        if (!out)
                return false;

        for (auto itr = lines->begin(); itr != lines->end(); itr++)
                out << (*itr).c_str() << std::endl;

        out.close();

        return true;
}

bool CFileIO::writeFile(const std::vector<Utils::WString> &lines) const
{
        if (lines.empty() || _sFilename.empty())
                return false;

        // we need to create the directory
        if (!_sDirIO.exists())
        {
                if (!_sDirIO.create())
                        return false;
        }


        std::wofstream out(_sFilename.c_str());
        if (!out)
                return false;

        for (auto itr = lines.begin(); itr != lines.end(); itr++)
                out << (*itr).c_str() << std::endl;

        out.close();

        return true;
}


bool CFileIO::writeFile(Utils::WStringList* lines)
{
        if (!lines || _sFilename.empty())
                return false;

        // we need to create the directory
        if (!_sDirIO.exists())
        {
                if (!_sDirIO.create())
                        return false;
        }

        std::wofstream out(_sFilename.c_str());
        if (!out)
                return false;

        for (auto itr = lines->begin(); itr != lines->end(); itr++)
                out << (*itr)->str.c_str() << std::endl;

        out.close();

        return true;
}
bool CFileIO::Rename(const Utils::WString &toFile)
{       
        return CFileIO::Rename(_sFilename, toFile);
}

Utils::WString CFileIO::getWindowsFilename() const
{
        return _sFilename.findReplace(L"/", L"\\");
}

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;

        Utils::WString windowsFilename = getWindowsFilename();

        HANDLE filename = CreateFile(windowsFilename.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::creationTime() const
{
        return modifiedTime();
}

time_t CFileIO::modifiedTime() const
{
#ifdef _WIN32
        Utils::WString windowsFilename = getWindowsFilename();

        WIN32_FILE_ATTRIBUTE_DATA wfad;
        GetFileAttributesEx(windowsFilename.c_str(), GetFileExInfoStandard, &wfad);

        LARGE_INTEGER date, adjust;
        date.HighPart = wfad.ftLastWriteTime.dwHighDateTime;
        date.LowPart = wfad.ftLastWriteTime.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;
}

size_t CFileIO::position()
{
        return static_cast<size_t>(m_fId.tellg());
}

/**
 * Copys the contents of a file to another
 *
 * Reads and writes the files in block
 */
bool CFileIO::copy(const Utils::WString &toFile, bool keepTime)
{
        time_t time = creationTime();

        CFileIO File(toFile);
        if ( File.write(*this, m_lSize) ) {
                this->close();
                File.close();
                if ( keepTime ) File.setCreationTime(time);
                return true;
        }
/*
        std::fstream f(GetWindowsFilename().c_str(), std::fstream::in | std::fstream::binary);
        f << std::noskipws;
        std::istream_iterator<unsigned char> begin(f);
        std::istream_iterator<unsigned char> end;
 
        std::fstream f2(toFile.c_str(), std::fstream::out | std::fstream::trunc | std::fstream::binary);
        std::ostream_iterator<char> begin2(f2);
 
        std::copy(begin, end, begin2);
        return f2.good();
*/
        return false;
}

size_t CFileIO::fileSize() const
{
        return m_lSize;
}


void CFileIO::_updateFilename()
{
        if (_sFilename.empty()) _sExt = Utils::WString::Null();
        _sExt = _sFilename.token(L".", -1);
}

std::string CFileIO::_fileData() const
{
        return _toFileData(_sFilename);
}
std::string CFileIO::_toFileData(const Utils::WString &str)
{
#pragma warning(disable:4244)
        return std::string(str.begin(), str.end());
#pragma warning(default:4244)
}