diff options
author | cutealien <cutealien@dfc29bdd-3216-0410-991c-e03cc46cb475> | 2020-01-03 19:05:16 +0000 |
---|---|---|
committer | cutealien <cutealien@dfc29bdd-3216-0410-991c-e03cc46cb475> | 2020-01-03 19:05:16 +0000 |
commit | 2ae2a551a6290f46734307bbfdafea4b1a2cf2ba (patch) | |
tree | ba2f0b468640e44899fed3df2d4cc58795f4a003 /source/Irrlicht/CFileSystem.cpp | |
download | irrlicht-2ae2a551a6290f46734307bbfdafea4b1a2cf2ba.tar.xz |
Merging r5975 through r6036 from trunk to ogl-es branch.
GLES drivers adapted, but only did make compile-tests.
git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@6038 dfc29bdd-3216-0410-991c-e03cc46cb475
Diffstat (limited to 'source/Irrlicht/CFileSystem.cpp')
-rw-r--r-- | source/Irrlicht/CFileSystem.cpp | 1127 |
1 files changed, 1127 insertions, 0 deletions
diff --git a/source/Irrlicht/CFileSystem.cpp b/source/Irrlicht/CFileSystem.cpp new file mode 100644 index 0000000..6e336b9 --- /dev/null +++ b/source/Irrlicht/CFileSystem.cpp @@ -0,0 +1,1127 @@ +// Copyright (C) 2002-2012 Nikolaus Gebhardt
+// This file is part of the "Irrlicht Engine".
+// For conditions of distribution and use, see copyright notice in irrlicht.h
+
+#include "IrrCompileConfig.h"
+
+#include "CFileSystem.h"
+#include "IReadFile.h"
+#include "IWriteFile.h"
+#include "CZipReader.h"
+#include "CMountPointReader.h"
+#include "CPakReader.h"
+#include "CNPKReader.h"
+#include "CTarReader.h"
+#include "CWADReader.h"
+#include "CFileList.h"
+#include "CXMLReader.h"
+#include "CXMLWriter.h"
+#include "stdio.h"
+#include "os.h"
+#include "CAttributes.h"
+#include "CReadFile.h"
+#include "CMemoryFile.h"
+#include "CLimitReadFile.h"
+#include "CWriteFile.h"
+#include "irrList.h"
+
+#if defined (__STRICT_ANSI__)
+ #error Compiling with __STRICT_ANSI__ not supported. g++ does set this when compiling with -std=c++11 or -std=c++0x. Use instead -std=gnu++11 or -std=gnu++0x. Or use -U__STRICT_ANSI__ to disable strict ansi.
+#endif
+
+#if defined (_IRR_WINDOWS_API_)
+ #if !defined ( _WIN32_WCE )
+ #include <direct.h> // for _chdir
+ #include <io.h> // for _access
+ #include <tchar.h>
+ #endif
+#elif (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_) || defined(_IRR_IOS_PLATFORM_) || defined(_IRR_ANDROID_PLATFORM_))
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <limits.h>
+ #include <sys/types.h>
+ #include <dirent.h>
+ #include <sys/stat.h>
+ #include <unistd.h>
+#elif defined(_IRR_EMSCRIPTEN_PLATFORM_)
+ #include <unistd.h>
+#endif
+
+namespace irr
+{
+namespace io
+{
+
+//! constructor
+CFileSystem::CFileSystem()
+{
+ #ifdef _DEBUG
+ setDebugName("CFileSystem");
+ #endif
+
+ setFileListSystem(FILESYSTEM_NATIVE);
+ //! reset current working directory
+ getWorkingDirectory();
+
+#ifdef __IRR_COMPILE_WITH_PAK_ARCHIVE_LOADER_
+ ArchiveLoader.push_back(new CArchiveLoaderPAK(this));
+#endif
+
+#ifdef __IRR_COMPILE_WITH_NPK_ARCHIVE_LOADER_
+ ArchiveLoader.push_back(new CArchiveLoaderNPK(this));
+#endif
+
+#ifdef __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_
+ ArchiveLoader.push_back(new CArchiveLoaderTAR(this));
+#endif
+
+#ifdef __IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_
+ ArchiveLoader.push_back(new CArchiveLoaderWAD(this));
+#endif
+
+#ifdef __IRR_COMPILE_WITH_MOUNT_ARCHIVE_LOADER_
+ ArchiveLoader.push_back(new CArchiveLoaderMount(this));
+#endif
+
+#ifdef __IRR_COMPILE_WITH_ZIP_ARCHIVE_LOADER_
+ ArchiveLoader.push_back(new CArchiveLoaderZIP(this));
+#endif
+
+}
+
+
+//! destructor
+CFileSystem::~CFileSystem()
+{
+ u32 i;
+
+ for ( i=0; i < FileArchives.size(); ++i)
+ {
+ FileArchives[i]->drop();
+ }
+
+ for ( i=0; i < ArchiveLoader.size(); ++i)
+ {
+ ArchiveLoader[i]->drop();
+ }
+}
+
+
+//! opens a file for read access
+IReadFile* CFileSystem::createAndOpenFile(const io::path& filename)
+{
+ if ( filename.empty() )
+ return 0;
+
+ IReadFile* file = 0;
+ u32 i;
+
+ for (i=0; i< FileArchives.size(); ++i)
+ {
+ file = FileArchives[i]->createAndOpenFile(filename);
+ if (file)
+ return file;
+ }
+
+ // Create the file using an absolute path so that it matches
+ // the scheme used by CNullDriver::getTexture().
+ return CReadFile::createReadFile(getAbsolutePath(filename));
+}
+
+
+//! Creates an IReadFile interface for treating memory like a file.
+IReadFile* CFileSystem::createMemoryReadFile(const void* memory, s32 len,
+ const io::path& fileName, bool deleteMemoryWhenDropped)
+{
+ if (!memory)
+ return 0;
+ else
+ return new CMemoryReadFile(memory, len, fileName, deleteMemoryWhenDropped);
+}
+
+
+//! Creates an IReadFile interface for reading files inside files
+IReadFile* CFileSystem::createLimitReadFile(const io::path& fileName,
+ IReadFile* alreadyOpenedFile, long pos, long areaSize)
+{
+ if (!alreadyOpenedFile)
+ return 0;
+ else
+ return new CLimitReadFile(alreadyOpenedFile, pos, areaSize, fileName);
+}
+
+
+//! Creates an IReadFile interface for treating memory like a file.
+IWriteFile* CFileSystem::createMemoryWriteFile(void* memory, s32 len,
+ const io::path& fileName, bool deleteMemoryWhenDropped)
+{
+ if (!memory)
+ return 0;
+ else
+ return new CMemoryWriteFile(memory, len, fileName, deleteMemoryWhenDropped);
+}
+
+
+//! Opens a file for write access.
+IWriteFile* CFileSystem::createAndWriteFile(const io::path& filename, bool append)
+{
+ return CWriteFile::createWriteFile(filename, append);
+}
+
+
+//! Adds an external archive loader to the engine.
+void CFileSystem::addArchiveLoader(IArchiveLoader* loader)
+{
+ if (!loader)
+ return;
+
+ loader->grab();
+ ArchiveLoader.push_back(loader);
+}
+
+//! Returns the total number of archive loaders added.
+u32 CFileSystem::getArchiveLoaderCount() const
+{
+ return ArchiveLoader.size();
+}
+
+//! Gets the archive loader by index.
+IArchiveLoader* CFileSystem::getArchiveLoader(u32 index) const
+{
+ if (index < ArchiveLoader.size())
+ return ArchiveLoader[index];
+ else
+ return 0;
+}
+
+//! move the hirarchy of the filesystem. moves sourceIndex relative up or down
+bool CFileSystem::moveFileArchive(u32 sourceIndex, s32 relative)
+{
+ bool r = false;
+ const s32 dest = (s32) sourceIndex + relative;
+ const s32 dir = relative < 0 ? -1 : 1;
+ const s32 sourceEnd = ((s32) FileArchives.size() ) - 1;
+ IFileArchive *t;
+
+ for (s32 s = (s32) sourceIndex;s != dest; s += dir)
+ {
+ if (s < 0 || s > sourceEnd || s + dir < 0 || s + dir > sourceEnd)
+ continue;
+
+ t = FileArchives[s + dir];
+ FileArchives[s + dir] = FileArchives[s];
+ FileArchives[s] = t;
+ r = true;
+ }
+ return r;
+}
+
+
+//! Adds an archive to the file system.
+bool CFileSystem::addFileArchive(const io::path& filename, bool ignoreCase,
+ bool ignorePaths, E_FILE_ARCHIVE_TYPE archiveType,
+ const core::stringc& password,
+ IFileArchive** retArchive)
+{
+ IFileArchive* archive = 0;
+ bool ret = false;
+
+ // see if archive is already added
+ if (changeArchivePassword(filename, password, retArchive))
+ return true;
+
+ s32 i;
+
+ // do we know what type it should be?
+ if (archiveType == EFAT_UNKNOWN || archiveType == EFAT_FOLDER)
+ {
+ // try to load archive based on file name
+ for (i = ArchiveLoader.size()-1; i >=0 ; --i)
+ {
+ if (ArchiveLoader[i]->isALoadableFileFormat(filename))
+ {
+ archive = ArchiveLoader[i]->createArchive(filename, ignoreCase, ignorePaths);
+ if (archive)
+ break;
+ }
+ }
+
+ // try to load archive based on content
+ if (!archive)
+ {
+ io::IReadFile* file = createAndOpenFile(filename);
+ if (file)
+ {
+ for (i = ArchiveLoader.size()-1; i >= 0; --i)
+ {
+ file->seek(0);
+ if (ArchiveLoader[i]->isALoadableFileFormat(file))
+ {
+ file->seek(0);
+ archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths);
+ if (archive)
+ break;
+ }
+ }
+ file->drop();
+ }
+ }
+ }
+ else
+ {
+ // try to open archive based on archive loader type
+
+ io::IReadFile* file = 0;
+
+ for (i = ArchiveLoader.size()-1; i >= 0; --i)
+ {
+ if (ArchiveLoader[i]->isALoadableFileFormat(archiveType))
+ {
+ // attempt to open file
+ if (!file)
+ file = createAndOpenFile(filename);
+
+ // is the file open?
+ if (file)
+ {
+ // attempt to open archive
+ file->seek(0);
+ if (ArchiveLoader[i]->isALoadableFileFormat(file))
+ {
+ file->seek(0);
+ archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths);
+ if (archive)
+ break;
+ }
+ }
+ else
+ {
+ // couldn't open file
+ break;
+ }
+ }
+ }
+
+ // if open, close the file
+ if (file)
+ file->drop();
+ }
+
+ if (archive)
+ {
+ FileArchives.push_back(archive);
+ if (password.size())
+ archive->Password=password;
+ if (retArchive)
+ *retArchive = archive;
+ ret = true;
+ }
+ else
+ {
+ os::Printer::log("Could not create archive for", filename, ELL_ERROR);
+ }
+
+ return ret;
+}
+
+// don't expose!
+bool CFileSystem::changeArchivePassword(const path& filename,
+ const core::stringc& password,
+ IFileArchive** archive)
+{
+ for (s32 idx = 0; idx < (s32)FileArchives.size(); ++idx)
+ {
+ // TODO: This should go into a path normalization method
+ // We need to check for directory names with trailing slash and without
+ const path absPath = getAbsolutePath(filename);
+ const path arcPath = FileArchives[idx]->getFileList()->getPath();
+ if ((absPath == arcPath) || ((absPath+_IRR_TEXT("/")) == arcPath))
+ {
+ if (password.size())
+ FileArchives[idx]->Password=password;
+ if (archive)
+ *archive = FileArchives[idx];
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool CFileSystem::addFileArchive(IReadFile* file, bool ignoreCase,
+ bool ignorePaths, E_FILE_ARCHIVE_TYPE archiveType,
+ const core::stringc& password, IFileArchive** retArchive)
+{
+ if (!file || archiveType == EFAT_FOLDER)
+ return false;
+
+ if (file)
+ {
+ if (changeArchivePassword(file->getFileName(), password, retArchive))
+ return true;
+
+ IFileArchive* archive = 0;
+ s32 i;
+
+ if (archiveType == EFAT_UNKNOWN)
+ {
+ // try to load archive based on file name
+ for (i = ArchiveLoader.size()-1; i >=0 ; --i)
+ {
+ if (ArchiveLoader[i]->isALoadableFileFormat(file->getFileName()))
+ {
+ archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths);
+ if (archive)
+ break;
+ }
+ }
+
+ // try to load archive based on content
+ if (!archive)
+ {
+ for (i = ArchiveLoader.size()-1; i >= 0; --i)
+ {
+ file->seek(0);
+ if (ArchiveLoader[i]->isALoadableFileFormat(file))
+ {
+ file->seek(0);
+ archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths);
+ if (archive)
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ // try to open archive based on archive loader type
+ for (i = ArchiveLoader.size()-1; i >= 0; --i)
+ {
+ if (ArchiveLoader[i]->isALoadableFileFormat(archiveType))
+ {
+ // attempt to open archive
+ file->seek(0);
+ if (ArchiveLoader[i]->isALoadableFileFormat(file))
+ {
+ file->seek(0);
+ archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths);
+ if (archive)
+ break;
+ }
+ }
+ }
+ }
+
+ if (archive)
+ {
+ FileArchives.push_back(archive);
+ if (password.size())
+ archive->Password=password;
+ if (retArchive)
+ *retArchive = archive;
+ return true;
+ }
+ else
+ {
+ os::Printer::log("Could not create archive for", file->getFileName(), ELL_ERROR);
+ }
+ }
+
+ return false;
+}
+
+
+//! Adds an archive to the file system.
+bool CFileSystem::addFileArchive(IFileArchive* archive)
+{
+ if ( archive )
+ {
+ for (u32 i=0; i < FileArchives.size(); ++i)
+ {
+ if (archive == FileArchives[i])
+ {
+ return false;
+ }
+ }
+ FileArchives.push_back(archive);
+ archive->grab();
+
+ return true;
+ }
+
+ return false;
+}
+
+
+//! removes an archive from the file system.
+bool CFileSystem::removeFileArchive(u32 index)
+{
+ bool ret = false;
+ if (index < FileArchives.size())
+ {
+ FileArchives[index]->drop();
+ FileArchives.erase(index);
+ ret = true;
+ }
+ return ret;
+}
+
+
+//! removes an archive from the file system.
+bool CFileSystem::removeFileArchive(const io::path& filename)
+{
+ const path absPath = getAbsolutePath(filename);
+ for (u32 i=0; i < FileArchives.size(); ++i)
+ {
+ if (absPath == FileArchives[i]->getFileList()->getPath())
+ return removeFileArchive(i);
+ }
+ return false;
+}
+
+
+//! Removes an archive from the file system.
+bool CFileSystem::removeFileArchive(const IFileArchive* archive)
+{
+ for (u32 i=0; i < FileArchives.size(); ++i)
+ {
+ if (archive == FileArchives[i])
+ {
+ return removeFileArchive(i);
+ }
+ }
+ return false;
+}
+
+
+//! gets an archive
+u32 CFileSystem::getFileArchiveCount() const
+{
+ return FileArchives.size();
+}
+
+
+IFileArchive* CFileSystem::getFileArchive(u32 index)
+{
+ return index < getFileArchiveCount() ? FileArchives[index] : 0;
+}
+
+
+//! Returns the string of the current working directory
+const io::path& CFileSystem::getWorkingDirectory()
+{
+ EFileSystemType type = FileSystemType;
+
+ if (type != FILESYSTEM_NATIVE)
+ {
+ type = FILESYSTEM_VIRTUAL;
+ }
+ else
+ {
+ #if defined(_IRR_WINDOWS_API_)
+ fschar_t tmp[_MAX_PATH];
+ #if defined(_IRR_WCHAR_FILESYSTEM )
+ _wgetcwd(tmp, _MAX_PATH);
+ WorkingDirectory[FILESYSTEM_NATIVE] = tmp;
+ WorkingDirectory[FILESYSTEM_NATIVE].replace(L'\\', L'/');
+ #else
+ _getcwd(tmp, _MAX_PATH);
+ WorkingDirectory[FILESYSTEM_NATIVE] = tmp;
+ WorkingDirectory[FILESYSTEM_NATIVE].replace('\\', '/');
+ #endif
+ #endif
+
+ #if (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_))
+
+ // getting the CWD is rather complex as we do not know the size
+ // so try it until the call was successful
+ // Note that neither the first nor the second parameter may be 0 according to POSIX
+
+ #if defined(_IRR_WCHAR_FILESYSTEM )
+ u32 pathSize=256;
+ wchar_t *tmpPath = new wchar_t[pathSize];
+ while ((pathSize < (1<<16)) && !(wgetcwd(tmpPath,pathSize)))
+ {
+ delete [] tmpPath;
+ pathSize *= 2;
+ tmpPath = new char[pathSize];
+ }
+ if (tmpPath)
+ {
+ WorkingDirectory[FILESYSTEM_NATIVE] = tmpPath;
+ delete [] tmpPath;
+ }
+ #else
+ u32 pathSize=256;
+ char *tmpPath = new char[pathSize];
+ while ((pathSize < (1<<16)) && !(getcwd(tmpPath,pathSize)))
+ {
+ delete [] tmpPath;
+ pathSize *= 2;
+ tmpPath = new char[pathSize];
+ }
+ if (tmpPath)
+ {
+ WorkingDirectory[FILESYSTEM_NATIVE] = tmpPath;
+ delete [] tmpPath;
+ }
+ #endif
+ #endif
+
+ WorkingDirectory[type].validate();
+ }
+
+ return WorkingDirectory[type];
+}
+
+
+//! Changes the current Working Directory to the given string.
+bool CFileSystem::changeWorkingDirectoryTo(const io::path& newDirectory)
+{
+ bool success=false;
+
+ if (FileSystemType != FILESYSTEM_NATIVE)
+ {
+ WorkingDirectory[FILESYSTEM_VIRTUAL] = newDirectory;
+ // is this empty string constant really intended?
+ flattenFilename(WorkingDirectory[FILESYSTEM_VIRTUAL], _IRR_TEXT(""));
+ success = true;
+ }
+ else
+ {
+ WorkingDirectory[FILESYSTEM_NATIVE] = newDirectory;
+
+#if defined(_MSC_VER)
+ #if defined(_IRR_WCHAR_FILESYSTEM)
+ success = (_wchdir(newDirectory.c_str()) == 0);
+ #else
+ success = (_chdir(newDirectory.c_str()) == 0);
+ #endif
+#else
+ #if defined(_IRR_WCHAR_FILESYSTEM)
+ success = (_wchdir(newDirectory.c_str()) == 0);
+ #else
+ success = (chdir(newDirectory.c_str()) == 0);
+ #endif
+#endif
+ }
+
+ return success;
+}
+
+
+io::path CFileSystem::getAbsolutePath(const io::path& filename) const
+{
+ if ( filename.empty() )
+ return filename;
+#if defined(_IRR_WINDOWS_API_)
+ fschar_t *p=0;
+ fschar_t fpath[_MAX_PATH];
+ #if defined(_IRR_WCHAR_FILESYSTEM )
+ p = _wfullpath(fpath, filename.c_str(), _MAX_PATH);
+ core::stringw tmp(p);
+ tmp.replace(L'\\', L'/');
+ #else
+ p = _fullpath(fpath, filename.c_str(), _MAX_PATH);
+ core::stringc tmp(p);
+ tmp.replace('\\', '/');
+ #endif
+ return tmp;
+#elif (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_))
+ c8* p=0;
+ c8 fpath[4096];
+ fpath[0]=0;
+ p = realpath(filename.c_str(), fpath);
+ if (!p)
+ {
+ // content in fpath is unclear at this point
+ if (!fpath[0]) // seems like fpath wasn't altered, use our best guess
+ {
+ io::path tmp(filename);
+ return flattenFilename(tmp);
+ }
+ else
+ return io::path(fpath);
+ }
+ if (filename[filename.size()-1]=='/')
+ return io::path(p)+_IRR_TEXT("/");
+ else
+ return io::path(p);
+#else
+ return io::path(filename);
+#endif
+}
+
+
+//! returns the directory part of a filename, i.e. all until the first
+//! slash or backslash, excluding it. If no directory path is prefixed, a '.'
+//! is returned.
+io::path CFileSystem::getFileDir(const io::path& filename) const
+{
+ // find last forward or backslash
+ s32 lastSlash = filename.findLast('/');
+ const s32 lastBackSlash = filename.findLast('\\');
+ lastSlash = lastSlash > lastBackSlash ? lastSlash : lastBackSlash;
+
+ if ((u32)lastSlash < filename.size())
+ return filename.subString(0, lastSlash);
+ else
+ return _IRR_TEXT(".");
+}
+
+
+//! returns the base part of a filename, i.e. all except for the directory
+//! part. If no directory path is prefixed, the full name is returned.
+io::path CFileSystem::getFileBasename(const io::path& filename, bool keepExtension) const
+{
+ // find last forward or backslash
+ s32 lastSlash = filename.findLast('/');
+ const s32 lastBackSlash = filename.findLast('\\');
+ lastSlash = core::max_(lastSlash, lastBackSlash);
+
+ // get number of chars after last dot
+ s32 end = 0;
+ if (!keepExtension)
+ {
+ // take care to search only after last slash to check only for
+ // dots in the filename
+ end = filename.findLast('.');
+ if (end == -1 || end < lastSlash)
+ end=0;
+ else
+ end = filename.size()-end;
+ }
+
+ if ((u32)lastSlash < filename.size())
+ return filename.subString(lastSlash+1, filename.size()-lastSlash-1-end);
+ else if (end != 0)
+ return filename.subString(0, filename.size()-end);
+ else
+ return filename;
+}
+
+
+//! flatten a path and file name for example: "/you/me/../." becomes "/you"
+io::path& CFileSystem::flattenFilename(io::path& directory, const io::path& root) const
+{
+ directory.replace('\\', '/');
+ if (directory.lastChar() != '/')
+ directory.append('/');
+
+ io::path dir;
+ io::path subdir;
+
+ s32 lastpos = 0;
+ s32 pos = 0;
+ bool lastWasRealDir=false;
+
+ while ((pos = directory.findNext('/', lastpos)) >= 0)
+ {
+ subdir = directory.subString(lastpos, pos - lastpos + 1);
+
+ if (subdir == _IRR_TEXT("../"))
+ {
+ if (lastWasRealDir)
+ {
+ deletePathFromPath(dir, 2);
+ lastWasRealDir=(dir.size()!=0);
+ }
+ else
+ {
+ dir.append(subdir);
+ lastWasRealDir=false;
+ }
+ }
+ else if (subdir == _IRR_TEXT("/"))
+ {
+ dir = root;
+ }
+ else if (subdir != _IRR_TEXT("./"))
+ {
+ dir.append(subdir);
+ lastWasRealDir=true;
+ }
+
+ lastpos = pos + 1;
+ }
+ directory = dir;
+ return directory;
+}
+
+
+//! Get the relative filename, relative to the given directory
+path CFileSystem::getRelativeFilename(const path& filename, const path& directory) const
+{
+ if ( filename.empty() || directory.empty() )
+ return filename;
+
+ io::path path1, file, ext;
+ core::splitFilename(getAbsolutePath(filename), &path1, &file, &ext);
+ io::path path2(getAbsolutePath(directory));
+ core::list<io::path> list1, list2;
+ path1.split(list1, _IRR_TEXT("/\\"), 2);
+ path2.split(list2, _IRR_TEXT("/\\"), 2);
+ u32 i=0;
+ core::list<io::path>::ConstIterator it1,it2;
+ it1=list1.begin();
+ it2=list2.begin();
+
+ #if defined (_IRR_WINDOWS_API_)
+ fschar_t partition1 = 0, partition2 = 0;
+ io::path prefix1, prefix2;
+ if ( it1 != list1.end() )
+ prefix1 = *it1;
+ if ( it2 != list2.end() )
+ prefix2 = *it2;
+ if ( prefix1.size() > 1 && prefix1[1] == _IRR_TEXT(':') )
+ partition1 = core::locale_lower(prefix1[0]);
+ if ( prefix2.size() > 1 && prefix2[1] == _IRR_TEXT(':') )
+ partition2 = core::locale_lower(prefix2[0]);
+
+ // must have the same prefix or we can't resolve it to a relative filename
+ if ( partition1 != partition2 )
+ {
+ return filename;
+ }
+ #endif
+
+
+ for (; i<list1.size() && i<list2.size()
+#if defined (_IRR_WINDOWS_API_)
+ && (io::path(*it1).make_lower()==io::path(*it2).make_lower())
+#else
+ && (*it1==*it2)
+#endif
+ ; ++i)
+ {
+ ++it1;
+ ++it2;
+ }
+ path1=_IRR_TEXT("");
+ for (; i<list2.size(); ++i)
+ path1 += _IRR_TEXT("../");
+ while (it1 != list1.end())
+ {
+ path1 += *it1++;
+ path1 += _IRR_TEXT('/');
+ }
+ path1 += file;
+ if (ext.size())
+ {
+ path1 += _IRR_TEXT('.');
+ path1 += ext;
+ }
+ return path1;
+}
+
+
+//! Sets the current file systen type
+EFileSystemType CFileSystem::setFileListSystem(EFileSystemType listType)
+{
+ EFileSystemType current = FileSystemType;
+ FileSystemType = listType;
+ return current;
+}
+
+
+//! Creates a list of files and directories in the current working directory
+IFileList* CFileSystem::createFileList()
+{
+ CFileList* r = 0;
+ io::path Path = getWorkingDirectory();
+ Path.replace('\\', '/');
+ if (!Path.empty() && Path.lastChar() != '/')
+ Path.append('/');
+
+ //! Construct from native filesystem
+ if (FileSystemType == FILESYSTEM_NATIVE)
+ {
+ // --------------------------------------------
+ //! Windows version
+ #ifdef _IRR_WINDOWS_API_
+ #if !defined ( _WIN32_WCE )
+
+ r = new CFileList(Path, true, false);
+
+ // TODO: Should be unified once mingw adapts the proper types
+#if defined(__GNUC__)
+ long hFile; //mingw return type declaration
+#else
+ intptr_t hFile;
+#endif
+
+ struct _tfinddata_t c_file;
+ if( (hFile = _tfindfirst( _T("*"), &c_file )) != -1L )
+ {
+ do
+ {
+ r->addItem(Path + c_file.name, 0, c_file.size, (_A_SUBDIR & c_file.attrib) != 0, 0);
+ }
+ while( _tfindnext( hFile, &c_file ) == 0 );
+
+ _findclose( hFile );
+ }
+ #endif
+
+ //TODO add drives
+ //entry.Name = "E:\\";
+ //entry.isDirectory = true;
+ //Files.push_back(entry);
+ #endif
+
+ // --------------------------------------------
+ //! Linux version
+ #if (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_))
+
+
+ r = new CFileList(Path, false, false);
+
+ r->addItem(Path + _IRR_TEXT(".."), 0, 0, true, 0);
+
+ //! We use the POSIX compliant methods instead of scandir
+ DIR* dirHandle=opendir(Path.c_str());
+ if (dirHandle)
+ {
+ struct dirent *dirEntry;
+ while ((dirEntry=readdir(dirHandle)))
+ {
+ u32 size = 0;
+ bool isDirectory = false;
+
+ if((strcmp(dirEntry->d_name, ".")==0) ||
+ (strcmp(dirEntry->d_name, "..")==0))
+ {
+ continue;
+ }
+ struct stat buf;
+ if (stat(dirEntry->d_name, &buf)==0)
+ {
+ size = buf.st_size;
+ isDirectory = S_ISDIR(buf.st_mode);
+ }
+ #if !defined(_IRR_SOLARIS_PLATFORM_) && !defined(__CYGWIN__)
+ // only available on some systems
+ else
+ {
+ isDirectory = dirEntry->d_type == DT_DIR;
+ }
+ #endif
+
+ r->addItem(Path + dirEntry->d_name, 0, size, isDirectory, 0);
+ }
+ closedir(dirHandle);
+ }
+ #endif
+ }
+ else
+ {
+ //! create file list for the virtual filesystem
+ r = new CFileList(Path, false, false);
+
+ //! add relative navigation
+ SFileListEntry e2;
+ SFileListEntry e3;
+
+ //! PWD
+ r->addItem(Path + _IRR_TEXT("."), 0, 0, true, 0);
+
+ //! parent
+ r->addItem(Path + _IRR_TEXT(".."), 0, 0, true, 0);
+
+ //! merge archives
+ for (u32 i=0; i < FileArchives.size(); ++i)
+ {
+ const IFileList *merge = FileArchives[i]->getFileList();
+
+ for (u32 j=0; j < merge->getFileCount(); ++j)
+ {
+ if (core::isInSameDirectory(Path, merge->getFullFileName(j)) == 0)
+ {
+ r->addItem(merge->getFullFileName(j), merge->getFileOffset(j), merge->getFileSize(j), merge->isDirectory(j), 0);
+ }
+ }
+ }
+ }
+
+ if (r)
+ r->sort();
+ return r;
+}
+
+//! Creates an empty filelist
+IFileList* CFileSystem::createEmptyFileList(const io::path& path, bool ignoreCase, bool ignorePaths)
+{
+ return new CFileList(path, ignoreCase, ignorePaths);
+}
+
+
+//! determines if a file exists and would be able to be opened.
+bool CFileSystem::existFile(const io::path& filename) const
+{
+ for (u32 i=0; i < FileArchives.size(); ++i)
+ if (FileArchives[i]->getFileList()->findFile(filename)!=-1)
+ return true;
+
+#if defined(_MSC_VER)
+ #if defined(_IRR_WCHAR_FILESYSTEM)
+ return (_waccess(filename.c_str(), 0) != -1);
+ #else
+ return (_access(filename.c_str(), 0) != -1);
+ #endif
+#elif defined(F_OK)
+ #if defined(_IRR_WCHAR_FILESYSTEM)
+ return (_waccess(filename.c_str(), F_OK) != -1);
+ #else
+ return (access(filename.c_str(), F_OK) != -1);
+ #endif
+#else
+ return (access(filename.c_str(), 0) != -1);
+#endif
+}
+
+
+//! Creates a XML Reader from a file.
+IXMLReader* CFileSystem::createXMLReader(const io::path& filename)
+{
+#ifdef _IRR_COMPILE_WITH_XML_
+ IReadFile* file = createAndOpenFile(filename);
+ if (!file)
+ return 0;
+
+ IXMLReader* reader = createXMLReader(file);
+ file->drop();
+ return reader;
+#else
+ noXML();
+ return 0;
+#endif
+}
+
+
+//! Creates a XML Reader from a file.
+IXMLReader* CFileSystem::createXMLReader(IReadFile* file)
+{
+#ifdef _IRR_COMPILE_WITH_XML_
+ if (!file)
+ return 0;
+
+ return createIXMLReader(file);
+#else
+ noXML();
+ return 0;
+#endif
+}
+
+
+//! Creates a XML Reader from a file.
+IXMLReaderUTF8* CFileSystem::createXMLReaderUTF8(const io::path& filename)
+{
+#ifdef _IRR_COMPILE_WITH_XML_
+ IReadFile* file = createAndOpenFile(filename);
+ if (!file)
+ return 0;
+
+ IXMLReaderUTF8* reader = createIXMLReaderUTF8(file);
+ file->drop();
+ return reader;
+#else
+ noXML();
+ return 0;
+#endif
+}
+
+
+//! Creates a XML Reader from a file.
+IXMLReaderUTF8* CFileSystem::createXMLReaderUTF8(IReadFile* file)
+{
+#ifdef _IRR_COMPILE_WITH_XML_
+ if (!file)
+ return 0;
+
+ return createIXMLReaderUTF8(file);
+#else
+ noXML();
+ return 0;
+#endif
+}
+
+
+//! Creates a XML Writer from a file.
+IXMLWriter* CFileSystem::createXMLWriter(const io::path& filename)
+{
+#ifdef _IRR_COMPILE_WITH_XML_
+ IWriteFile* file = createAndWriteFile(filename);
+ IXMLWriter* writer = 0;
+ if (file)
+ {
+ writer = createXMLWriter(file);
+ file->drop();
+ }
+ return writer;
+#else
+ noXML();
+ return 0;
+#endif
+}
+
+
+//! Creates a XML Writer from a file.
+IXMLWriter* CFileSystem::createXMLWriter(IWriteFile* file)
+{
+#ifdef _IRR_COMPILE_WITH_XML_
+ return createIXMLWriter(file);
+#else
+ noXML();
+ return 0;
+#endif
+}
+
+//! Creates a XML Writer from a file.
+IXMLWriterUTF8* CFileSystem::createXMLWriterUTF8(const io::path& filename)
+{
+#ifdef _IRR_COMPILE_WITH_XML_
+ IWriteFile* file = createAndWriteFile(filename);
+ IXMLWriterUTF8* writer = 0;
+ if (file)
+ {
+ writer = createXMLWriterUTF8(file);
+ file->drop();
+ }
+ return writer;
+#else
+ noXML();
+ return 0;
+#endif
+}
+
+
+//! Creates a XML Writer from a file.
+IXMLWriterUTF8* CFileSystem::createXMLWriterUTF8(IWriteFile* file)
+{
+#ifdef _IRR_COMPILE_WITH_XML_
+ return createIXMLWriterUTF8(file);
+#else
+ noXML();
+ return 0;
+#endif
+}
+
+
+//! creates a filesystem which is able to open files from the ordinary file system,
+//! and out of zipfiles, which are able to be added to the filesystem.
+IFileSystem* createFileSystem()
+{
+ return new CFileSystem();
+}
+
+
+//! Creates a new empty collection of attributes, usable for serialization and more.
+IAttributes* CFileSystem::createEmptyAttributes(video::IVideoDriver* driver)
+{
+ return new CAttributes(driver);
+}
+
+
+} // end namespace irr
+} // end namespace io
|