Subversion Repositories spk

Rev

Blame | Last modification | View Log | RSS feed

#include "pch.h"
#include "DirIO.h"

#include <sys/types.h>  // For stat().
#include <sys/stat.h>   // For stat().
#include <fcntl.h>
#include "File_IO.h"

#ifdef _WIN32
#include <windows.h>
#include <io.h>
#include <direct.h>
#define ACCESS _access
#else
#include <dirent.h>
#define ACCESS access
#endif

using namespace XLib;

/////////////////////////////////////////
// STATIC FUNCTIONS
bool DirIO::Exists(const XLib::String &dir)
{
        return DirIO(dir).exists();
}


////////////////////////////////////////
// Ctor/Dtor

DirIO::DirIO()
{
}

DirIO::~DirIO()
{
}

DirIO::DirIO(const XLib::String &dir)
{
        setDir(dir);
}

DirIO::DirIO(const FileIO &file)
{
        setDir(file.dir());
}

/////////////////////////////////////////////////////////
//

void DirIO::setDir(const XLib::String &dir)
{
        m_sCurrentDir = dir;
        m_sCurrentDir.toFilename();
}


bool DirIO::exists() const
{
        XLib::String dir = m_sCurrentDir;

        if (dir.empty())
                return false;

        if (ACCESS((const char *)dir, 0) == 0)
                return true;

        return false;
}

bool DirIO::exists(const XLib::String &dir) const
{
        XLib::String d = _parseDir(dir);

        if (d.empty())
                return false;

        if (ACCESS((const char *)d, 0) == 0)
                return true;

        return false;
}

XLib::String DirIO::_parseDir(const XLib::String &dir) const
{
        XLib::String sDir = dir.asFilename();
        if ( !m_sCurrentDir.empty() && !sDir.isin(":") )
        {
                if ( sDir.empty() )
                        sDir = m_sCurrentDir;
                else
                        sDir = m_sCurrentDir + "/" + sDir;
        }

        return sDir.asFilename();
}

bool DirIO::isDir(const XLib::String &sDir) const
{
        XLib::String dir = _parseDir(sDir);
        if (ACCESS(dir.c_str(), 0) != -1)
        {
                struct stat status;
                stat(dir.c_str(), &status);

                if (status.st_mode & S_IFDIR)
                        return true;
        }
        else {
                return !dir.token("/", -1).isin(".");
        }

        return false;
}

bool DirIO::isDir() const
{
        return isDir(m_sCurrentDir);
}

bool DirIO::isFile() const
{
        return isFile(m_sCurrentDir);
}
bool DirIO::isFile(const XLib::String &sDir) const
{
        XLib::String dir = _parseDir(sDir);
        if (ACCESS(dir.c_str(), 0) != -1)
        {
                struct stat status;
                stat(dir.c_str(), &status);

                if (status.st_mode & S_IFDIR)
                        return false;
                else
                        return true;
        }
        else {
                return dir.token("/", -1).isin(".");
        }

        return false;
}

bool DirIO::create() const
{
        return create(XLib::String::Null());
}
bool DirIO::create(const XLib::String &sDir) const
{
        XLib::String dir = sDir;
        if ( dir.empty() )
                dir = m_sCurrentDir;
        dir = _parseDir(dir);

        // split up directorys
        StringList dirs = dir.findReplace( "/", "\\" ).findReplace( "\\\\", "\\" ).tokenise("\\");

        // check if full dir, or relative
        int start = 1;
        XLib::String curDir;
        
        if (!dirs.empty())
                curDir = dirs.front();

        if ( !curDir.isin(":") )
        {
                curDir = m_sCurrentDir;
                start = 0;
        }

        // process each dir
        for(auto itr = dirs.begin(); itr != dirs.end(); itr++)
        {
                if ( !curDir.empty() )
                        curDir += "/";
                curDir += *itr;

                // check if the directory exists
                if ( !exists(curDir) )
                {
#ifdef _WIN32
                        if ( _mkdir(curDir.c_str()) )
#else
                        if ( mkdir(curDir.c_str(), 0755) )
#endif
                        {
                                return false;
                        }
                }
        }

        return true;
}

bool DirIO::move(const XLib::String &sTo)
{
        XLib::String to = _parseDir(sTo);

        if (exists(to))
                return false;

        if (!rename(m_sCurrentDir.c_str(), to.c_str()))
        {
                m_sCurrentDir = to;
                return true;
        }

        return false;
}


bool DirIO::move(const XLib::String &sFrom, const XLib::String &sTo)
{
        if ( !exists(sTo) )
        {
                if ( !create(sTo) )
                        return false;
        }

        if ( !rename(sFrom.c_str(), sTo.c_str()) )
                return true;

        return false;
}

bool DirIO::isEmptyDir(const StringList &dirList) const
{
        // not found any files, most likly empty
        if ( !dirList.size() )
                return true;
        
        // check for any valid files
        for (auto itr = dirList.begin(); itr != dirList.end(); itr++)
        {
                if (*itr == "." || *itr == "..")
                        continue;
                return false;
        }

        return true;
}

bool DirIO::removeDir(const XLib::String &dir, bool doFiles, bool recursive, StringList *errors)
{
        StringList files;
        dirList(files, dir);
        if (isEmptyDir(files))
        {
                XLib::String remDir = _parseDir(dir);
#ifdef _WIN32
                if (_rmdir(remDir.c_str()) == 0)
#else
                if (rmdir(remDir.c_str()) == 0)
#endif
                {
                        if (errors)
                                errors->push_back(remDir);
                }
                return true;
        }

        // not empty
        if ( doFiles || recursive )
        {
                for (auto itr = files.begin(); itr != files.end(); itr++)
                {
                        if (*itr == "." || *itr == "..")
                                continue;

                        XLib::String fullFile = (dir + "\\" + *itr);
                        if (doFiles && isFile(fullFile))
                        {
                                XLib::String remFile = _parseDir(fullFile);
                                if (remove(remFile.c_str()) == 0)
                                {
                                        if (errors)
                                                errors->push_back(remFile);
                                }
                        }
                        else if (recursive && isDir(fullFile))
                                removeDir(fullFile, doFiles, recursive, errors);
                }
        }

        // now check if its empty
        files.clear();
        dirList(files, dir);
        if (isEmptyDir(files))
        {
                XLib::String remDir = _parseDir(dir);
                #ifdef _WIN32
                if ( _rmdir(remDir.c_str()) == 0 )
                #else
                if ( rmdir(remDir.c_str()) == 0 )
                #endif
                {
                        if ( errors )
                                errors->push_back(remDir);
                }
                return true;
        }

        return false;
}

StringList DirIO::dirList(XLib::String dir, XLib::String filePattern) const
{
        StringList files;
        dirList(files, dir, filePattern);
        return files;
}
bool DirIO::dirList(StringList &files, XLib::String dir, XLib::String filePattern) const
{
        dir = _parseDir(dir);
        if ( dir.empty() )
                return false;

        dir = dir.findReplace("\\", "/");
        if (filePattern.empty())
                dir += "/*";
        else
        {
                dir += "/";
                dir += filePattern;
        }
        dir = dir.findReplace("//", "/");

#ifdef _WIN32
        dir = dir.findReplace("/", "\\");

        WIN32_FIND_DATA data;
        TCHAR buf[5000];
        wsprintf(buf, L"%hs", dir.c_str());

        HANDLE h = FindFirstFile(buf, &data);
        if ( h != INVALID_HANDLE_VALUE)
        {
                std::wstring ws(data.cFileName);
                std::string s(ws.begin(), ws.end());

                XLib::String checkFile(s);
                if ( !checkFile.Compare(".") && !checkFile.Compare("..") )
                        files.push_back(checkFile);

                while ( FindNextFile(h, &data) )
                {
                        std::wstring ws(data.cFileName);
                        std::string s(ws.begin(), ws.end());

                        XLib::String checkFile(s);
                        if ( checkFile != "." && checkFile != ".." )
                                files.push_back(checkFile);
                }

                FindClose(h);
                return true;
        }
        return false;
#else
        DIR *dir;
        struct dirent *ent;
        if ((dir = opendir(dir.c_str())) != NULL) {
                while ((ent = readdir(dir)) != NULL) {
                        XLib::String checkFile(ent->d_name);
                        if (checkFile != "." && checkFile != "..")
                                files.pushBack(checkFile);
                }
                closedir(dir);
        }
        return true;
#endif//_WIN32

}

XLib::String DirIO::file(const XLib::String &filename) const
{
        if (m_sCurrentDir.empty())
                return filename;

        return m_sCurrentDir + "/" + filename;
}

XLib::String DirIO::dir(const XLib::String &sDir) const
{
        return _parseDir(sDir);
}

const XLib::String &DirIO::dir() const
{
        return m_sCurrentDir;
}

bool DirIO::cd(const XLib::String &sDir)
{
        if ( m_sCurrentDir.empty() )
                m_sCurrentDir = sDir;
        else
                m_sCurrentDir = m_sCurrentDir + "/" + sDir;
        m_sCurrentDir = m_sCurrentDir.asFilename();

        return exists();
}

bool DirIO::createAndChange(const XLib::String &dir)
{
        if ( create(dir) )
                return cd(dir);
        return false;
}


XLib::String DirIO::topDir() const
{
        if ( m_sCurrentDir.empty() )
                return XLib::String("");

        return m_sCurrentDir.token("/", -1);
}

const XLib::String &DirIO::moveBack()
{
        m_sCurrentDir = m_sCurrentDir.tokens("/", 1, -2);
        return m_sCurrentDir;
}
XLib::String DirIO::back() const
{
        return m_sCurrentDir.tokens("/", 1, -2);
}