diff options
author | jackpoz <giacomopoz@gmail.com> | 2014-08-22 16:58:23 +0200 |
---|---|---|
committer | jackpoz <giacomopoz@gmail.com> | 2014-08-22 21:00:56 +0200 |
commit | 5e8277e923c5545a15bae7c740ab6afaa597a59f (patch) | |
tree | 4cf5212c080588a7e868ee60134fc7fff51e400a /dep/g3dlite/source/FileSystem.cpp | |
parent | a63aa858dcb400eafb97eed1f590e34c27d934a4 (diff) |
Core/Dependencies: Update G3D to v9.0 r4036
Diffstat (limited to 'dep/g3dlite/source/FileSystem.cpp')
-rw-r--r-- | dep/g3dlite/source/FileSystem.cpp | 369 |
1 files changed, 261 insertions, 108 deletions
diff --git a/dep/g3dlite/source/FileSystem.cpp b/dep/g3dlite/source/FileSystem.cpp index f082937a908..32a84e77048 100644 --- a/dep/g3dlite/source/FileSystem.cpp +++ b/dep/g3dlite/source/FileSystem.cpp @@ -1,10 +1,10 @@ /** - @file FileSystem.cpp + \file FileSystem.cpp - @author Morgan McGuire, http://graphics.cs.williams.edu + \author Morgan McGuire, http://graphics.cs.williams.edu - @author 2002-06-06 - @edited 2010-04-10 + \author 2002-06-06 + \edited 2010-10-10 */ #include "G3D/FileSystem.h" #include "G3D/System.h" @@ -19,7 +19,7 @@ #include "G3D/BinaryInput.h" #include "G3D/BinaryOutput.h" -#ifdef G3D_WIN32 +#ifdef G3D_WINDOWS // Needed for _getcwd # include <direct.h> @@ -36,16 +36,16 @@ # include <unistd.h> # define _getcwd getcwd # define _stat stat -#endif - -#ifdef __CYGWIN__ -#define stat64 stat +# define stricmp strcasecmp +# define strnicmp strncasecmp #endif namespace G3D { static FileSystem* common = NULL; +GMutex FileSystem::mutex; + FileSystem& FileSystem::instance() { init(); return *common; @@ -70,24 +70,24 @@ FileSystem::FileSystem() : m_cacheLifetime(10) {} ///////////////////////////////////////////////////////////// -bool FileSystem::Dir::contains(const std::string& f) const { +bool FileSystem::Dir::contains(const std::string& f, bool caseSensitive) const { for (int i = 0; i < nodeArray.size(); ++i) { -# ifdef G3D_WIN32 - if (stricmp(f.c_str(), nodeArray[i].name.c_str()) == 0) { - return true; - } -# else + if (caseSensitive) { if (f == nodeArray[i].name) { return true; } -# endif + } else if (stricmp(f.c_str(), nodeArray[i].name.c_str()) == 0) { + return true; + } } return false; } + -void FileSystem::Dir::computeZipListing(const std::string& zipfile, const std::string& pathInsideZipfile) { +void FileSystem::Dir::computeZipListing(const std::string& zipfile, const std::string& _pathInsideZipfile) { #if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */ + const std::string& pathInsideZipfile = FilePath::canonicalize(_pathInsideZipfile); struct zip* z = zip_open( FilePath::removeTrailingSlash(zipfile).c_str(), ZIP_CHECKCONS, NULL ); debugAssert(z); @@ -99,22 +99,23 @@ void FileSystem::Dir::computeZipListing(const std::string& zipfile, const std::s zip_stat_index( z, i, ZIP_FL_NOCASE, &info ); // Fully-qualified name of a file inside zipfile - std::string name = info.name; + std::string name = FilePath::canonicalize(info.name); if (beginsWith(name, pathInsideZipfile)) { // We found something inside the directory we were looking for, - // so the directory itself must exist + // so the directory itself must exist exists = true; // For building the cached directory listing, extract only elements that do not contain // additional subdirectories. - int start = pathInsideZipfile.size(); - if ((int(name.length()) > start) && isSlash(name[start])) { + size_t start = pathInsideZipfile.size(); + if ((name.length() > start) && isSlash(name[start])) { ++start; } - int end = findSlash(name, start); - if (end == -1) { + + size_t end = findSlash(name, start); + if (end == std::string::npos) { // There are no more slashes; add this name name = name.substr(start); if (alreadyAdded.insert(name)) { @@ -126,8 +127,8 @@ void FileSystem::Dir::computeZipListing(const std::string& zipfile, const std::s // There are more slashes, indicating that this is a directory name = name.substr(start, end); if (alreadyAdded.insert(name)) { - Entry& e = nodeArray.next(); - e.name = name; + Entry& e = nodeArray.next(); + e.name = FilePath::removeTrailingSlash(name); e.type = DIR_TYPE; } } @@ -142,7 +143,7 @@ void FileSystem::Dir::computeZipListing(const std::string& zipfile, const std::s FileSystem::Dir& FileSystem::getContents(const std::string& path, bool forceUpdate) { const std::string& key = -# if defined(G3D_WIN32) +# if defined(G3D_WINDOWS) FilePath::canonicalize(FilePath::removeTrailingSlash(toLower(FilePath::canonicalize(resolve(path))))); # else FilePath::canonicalize(FilePath::removeTrailingSlash(FilePath::canonicalize(resolve(path)))); @@ -156,10 +157,17 @@ FileSystem::Dir& FileSystem::getContents(const std::string& path, bool forceUpda // Out of date: update dir.lastChecked = now; - - struct _stat st; - const bool exists = _stat(key.c_str(), &st) != -1; - const bool isDirectory = (st.st_mode & S_IFDIR) != 0; +# ifdef G3D_WINDOWS + // On windows, we have to use GetFileAttributes (http://msdn.microsoft.com/en-us/library/aa364944(v=vs.85).aspx) instead of + // stat in order to work with network shares + const DWORD st = GetFileAttributesA(key.c_str()); + const bool exists = (st != INVALID_FILE_ATTRIBUTES); + const bool isDirectory = (st & FILE_ATTRIBUTE_DIRECTORY) != 0; +# else + struct _stat st; + const bool exists = _stat(key.c_str(), &st) != -1; + const bool isDirectory = (st.st_mode & S_IFDIR) != 0; +# endif // Does this path exist on the real filesystem? if (exists && isDirectory) { @@ -168,7 +176,7 @@ FileSystem::Dir& FileSystem::getContents(const std::string& path, bool forceUpda if (isDirectory) { dir.exists = true; // Update contents -# ifdef G3D_WIN32 +# ifdef G3D_WINDOWS const std::string& filespec = FilePath::concat(key, "*"); struct _finddata_t fileinfo; intptr_t handle = _findfirst(filespec.c_str(), &fileinfo); @@ -238,7 +246,6 @@ FileSystem::Dir& FileSystem::getContents(const std::string& path, bool forceUpda // There is a zipfile somewhere in the path. Does // the rest of the path exist inside the zipfile? dir.inZipfile = true; - dir.computeZipListing(zip, path.substr(zip.length() + 1)); } } @@ -248,27 +255,24 @@ FileSystem::Dir& FileSystem::getContents(const std::string& path, bool forceUpda } -bool FileSystem::_inZipfile(const std::string& path, std::string& z) { +bool FileSystem::_inZipfile(const std::string& _path, std::string& z) { + const std::string& path = FilePath::expandEnvironmentVariables(_path); + // Reject trivial cases before parsing - if (path.find('.') == std::string::npos) { - // There is no zipfile possible, since G3D requires - // an extension on zipfiles. - return false; - } // Look at all sub-paths containing periods. // For each, ask if it is a zipfile. - int current = 0; + size_t current = 0; current = path.find('.', current); - while (current != -1) { + while (current != std::string::npos) { // xxxxx/foo.zip/yyyyy current = path.find('.', current); // Look forward for the next slash - int s = findSlash(path, current); + size_t s = findSlash(path, current); - if (s == -1) { + if (s == std::string::npos) { // No more slashes return false; } @@ -286,17 +290,17 @@ bool FileSystem::_inZipfile(const std::string& path, std::string& z) { } -bool FileSystem::_isZipfile(const std::string& filename) { - if (FilePath::ext(filename).empty()) { - return false; - } +bool FileSystem::_isZipfile(const std::string& _filename) { + const std::string& filename = FilePath::canonicalize(FilePath::expandEnvironmentVariables(_filename)); + + FILE* f = fopen(FilePath::removeTrailingSlash(filename).c_str(), "r"); if (f == NULL) { return false; } uint8 header[4]; - fread(header, 4, 1, f); + (void)fread(header, 4, 1, f); const uint8 zipHeader[4] = {0x50, 0x4b, 0x03, 0x04}; for (int i = 0; i < 4; ++i) { @@ -311,7 +315,9 @@ bool FileSystem::_isZipfile(const std::string& filename) { } -FILE* FileSystem::_fopen(const char* filename, const char* mode) { +FILE* FileSystem::_fopen(const char* _filename, const char* mode) { + const std::string& filename = FilePath::canonicalize(FilePath::expandEnvironmentVariables(_filename)); + for (const char* m = mode; *m != '\0'; ++m) { if (*m == 'w') { // Purge the cache entry for the parent of this directory @@ -319,11 +325,15 @@ FILE* FileSystem::_fopen(const char* filename, const char* mode) { break; } } - return ::fopen(filename, mode); + + markFileUsed(filename); + return ::fopen(filename.c_str(), mode); } -void FileSystem::_clearCache(const std::string& path) { +void FileSystem::_clearCache(const std::string& _path) { + const std::string& path = FilePath::expandEnvironmentVariables(_path); + if ((path == "") || FilePath::isRoot(path)) { m_cache.clear(); } else { @@ -331,7 +341,7 @@ void FileSystem::_clearCache(const std::string& path) { m_cache.getKeys(keys); const std::string& prefix = -# ifdef G3D_WIN32 +# ifdef G3D_WINDOWS toLower(FilePath::canonicalize(FilePath::removeTrailingSlash(_resolve(path)))); # else FilePath::canonicalize(FilePath::removeTrailingSlash(_resolve(path))); @@ -353,8 +363,9 @@ void FileSystem::_setCacheLifetime(float t) { } -void FileSystem::_createDirectory(const std::string& dir) { - +void FileSystem::_createDirectory(const std::string& _dir) { + const std::string& dir = FilePath::expandEnvironmentVariables(_dir); + if (dir == "") { return; } @@ -395,7 +406,7 @@ void FileSystem::_createDirectory(const std::string& dir) { if (! _exists(p)) { // Windows only requires one argument to mkdir, // where as unix also requires the permissions. -# ifndef G3D_WIN32 +# ifndef G3D_WINDOWS mkdir(p.c_str(), 0777); # else _mkdir(p.c_str()); @@ -407,8 +418,10 @@ void FileSystem::_createDirectory(const std::string& dir) { } -void FileSystem::_copyFile(const std::string& source, const std::string& dest) { -# ifdef G3D_WIN32 +void FileSystem::_copyFile(const std::string& _source, const std::string& _dest) { + const std::string& source = FilePath::expandEnvironmentVariables(_source); + const std::string& dest = FilePath::expandEnvironmentVariables(_dest); +# ifdef G3D_WINDOWS // TODO: handle case where srcPath is in a zipfile CopyFileA(source.c_str(), dest.c_str(), FALSE); _clearCache(FilePath::parent(_resolve(dest))); @@ -422,10 +435,11 @@ void FileSystem::_copyFile(const std::string& source, const std::string& dest) { } -bool FileSystem::_exists(const std::string& f, bool trustCache) { +bool FileSystem::_exists(const std::string& _f, bool trustCache, bool caseSensitive) { + const std::string& f = FilePath::expandEnvironmentVariables(_f); if (FilePath::isRoot(f)) { -# ifdef G3D_WIN32 +# ifdef G3D_WINDOWS const std::string& winname = toLower(f.substr(0, 1)) + ":\\"; return _drives().contains(winname); # else @@ -433,10 +447,11 @@ bool FileSystem::_exists(const std::string& f, bool trustCache) { # endif } - std::string path = FilePath::removeTrailingSlash(f); - std::string parentPath = FilePath::parent(path); + const std::string& path = FilePath::removeTrailingSlash(f); + const std::string& parentPath = FilePath::parent(path); - const Dir& entry = getContents(parentPath, ! trustCache); + const bool forceUpdate = ! trustCache; + const Dir& entry = getContents(parentPath, forceUpdate); if (FilePath::containsWildcards(f)) { if (! entry.exists) { @@ -446,15 +461,9 @@ bool FileSystem::_exists(const std::string& f, bool trustCache) { const std::string& pattern = FilePath::baseExt(path); -# ifdef G3D_WIN32 - static const int flags = FNM_CASEFOLD; -# else - static const int flags = 0; -# endif - // See if any element of entry matches the wild card for (int i = 0; i < entry.nodeArray.size(); ++i) { - if (FilePath::matches(entry.nodeArray[i].name, pattern, flags)) { + if (FilePath::matches(entry.nodeArray[i].name, pattern, caseSensitive)) { return true; } } @@ -463,12 +472,13 @@ bool FileSystem::_exists(const std::string& f, bool trustCache) { return false; } else { - return entry.exists && entry.contains(FilePath::baseExt(path)); + return entry.exists && entry.contains(FilePath::baseExt(path), caseSensitive); } } -bool FileSystem::_isDirectory(const std::string& filename) { +bool FileSystem::_isDirectory(const std::string& _filename) { + const std::string& filename = FilePath::expandEnvironmentVariables(_filename); // TODO: work with zipfiles and cache struct _stat st; const bool exists = _stat(FilePath::removeTrailingSlash(filename).c_str(), &st) != -1; @@ -476,14 +486,33 @@ bool FileSystem::_isDirectory(const std::string& filename) { } -std::string FileSystem::_resolve(const std::string& filename, const std::string& cwd) { +void FileSystem::_removeFile(const std::string& path) { + alwaysAssertM(! inZipfile(path), "Cannot invoke removeFile() on files inside zipfiles."); + Array<std::string> files; + getFiles(path, files, true); + + for (int i = 0; i < files.size(); ++i) { + const std::string& filename = files[i]; + int retval = ::remove(filename.c_str()); + (void)retval; + } + + // Remove from cache + _clearCache(FilePath::parent(path)); +} + + +std::string FileSystem::_resolve(const std::string& _filename, const std::string& _cwd) { + const std::string& filename = FilePath::expandEnvironmentVariables(_filename); + const std::string& cwd = FilePath::expandEnvironmentVariables(_cwd); + if (filename.size() >= 1) { if (isSlash(filename[0])) { // Already resolved return filename; } else { - #ifdef G3D_WIN32 + #ifdef G3D_WINDOWS if ((filename.size() >= 2) && (filename[1] == ':')) { // There is a drive spec on the front. if ((filename.size() >= 3) && isSlash(filename[2])) { @@ -511,12 +540,29 @@ std::string FileSystem::_currentDirectory() { static const int N = 2048; char buffer[N]; - _getcwd(buffer, N); + (void)_getcwd(buffer, N); return std::string(buffer); } -bool FileSystem::_isNewer(const std::string& src, const std::string& dst) { +static Set<std::string> _filesUsed; + +void FileSystem::markFileUsed(const std::string& filename) { + mutex.lock(); + _filesUsed.insert(filename); + mutex.unlock(); +} + + +const Set<std::string>& FileSystem::usedFiles() { + return _filesUsed; +} + + +bool FileSystem::_isNewer(const std::string& _src, const std::string& _dst) { + const std::string& src = FilePath::expandEnvironmentVariables(_src); + const std::string& dst = FilePath::expandEnvironmentVariables(_dst); + // TODO: work with cache and zipfiles struct _stat sts; bool sexists = _stat(src.c_str(), &sts) != -1; @@ -528,7 +574,9 @@ bool FileSystem::_isNewer(const std::string& src, const std::string& dst) { } -int64 FileSystem::_size(const std::string& filename) { +int64 FileSystem::_size(const std::string& _filename) { + const std::string& filename = FilePath::canonicalize(FilePath::expandEnvironmentVariables(_filename)); + struct stat64 st; int result = stat64(filename.c_str(), &st); @@ -544,6 +592,7 @@ int64 FileSystem::_size(const std::string& filename) { struct zip_stat info; zip_stat_init( &info ); // Docs unclear if zip_stat_init is required. int success = zip_stat( z, contents.c_str(), ZIP_FL_NOCASE, &info ); + (void) success; debugAssertM(success == 0, zip + ": " + contents + ": zip stat failed."); requiredMem = info.size; } @@ -553,7 +602,7 @@ int64 FileSystem::_size(const std::string& filename) { #endif return -1; #if _HAVE_ZIP /* G3DFIX: Use ZIP-library only if defined */ - } + } #endif } @@ -561,7 +610,12 @@ int64 FileSystem::_size(const std::string& filename) { } -void FileSystem::listHelper(const std::string& shortSpec, const std::string& parentPath, Array<std::string>& result, const ListSettings& settings) { +void FileSystem::listHelper +(const std::string& shortSpec, + const std::string& parentPath, + Array<std::string>& result, + const ListSettings& settings) { + Dir& dir = getContents(parentPath, false); if (! dir.exists) { @@ -573,8 +627,10 @@ void FileSystem::listHelper(const std::string& shortSpec, const std::string& par // See if it matches the spec if (FilePath::matches(entry.name, shortSpec, settings.caseSensitive)) { - if ((entry.type == UNKNOWN) && ! (settings.files && settings.directories)) { - // Update the type + if ((entry.type == UNKNOWN) && + (! (settings.files && settings.directories) || + settings.recursive)) { + // Update the type: it is unknown and we'll need to branch onit below entry.type = isDirectory(FilePath::concat(parentPath, entry.name)) ? DIR_TYPE : FILE_TYPE; } @@ -589,15 +645,23 @@ void FileSystem::listHelper(const std::string& shortSpec, const std::string& par } } } // match + + if (settings.recursive) { + if (entry.type == UNKNOWN) { + entry.type = isDirectory(FilePath::concat(parentPath, entry.name)) ? DIR_TYPE : FILE_TYPE; + } - if (settings.recursive && (entry.type == DIR_TYPE)) { - listHelper(shortSpec, FilePath::concat(parentPath, entry.name), result, settings); + if (entry.type == DIR_TYPE) { + listHelper(shortSpec, FilePath::concat(parentPath, entry.name), result, settings); + } } } // for } -void FileSystem::_list(const std::string& spec, Array<std::string>& result, const ListSettings& settings) { +void FileSystem::_list(const std::string& _spec, Array<std::string>& result, const ListSettings& settings) { + const std::string& spec = FilePath::expandEnvironmentVariables(_spec); + const std::string& shortSpec = FilePath::baseExt(spec); const std::string& parentPath = FilePath::parent(spec); @@ -606,7 +670,7 @@ void FileSystem::_list(const std::string& spec, Array<std::string>& result, cons -#ifdef G3D_WIN32 +#ifdef G3D_WINDOWS const Array<std::string>& FileSystem::_drives() { if (m_winDrive.length() == 0) { // See http://msdn.microsoft.com/en-us/library/aa364975(VS.85).aspx @@ -615,10 +679,10 @@ const Array<std::string>& FileSystem::_drives() { GetLogicalDriveStringsA(bufSize, bufData); // Drive list is a series of NULL-terminated strings, itself terminated with a NULL. - for (int i = 0; bufData[i] != '\0'; ++i) { + for (size_t i = 0; bufData[i] != '\0'; ++i) { const char* thisString = bufData + i; m_winDrive.append(toLower(thisString)); - i += strlen(thisString) + 1; + i += strlen(thisString); } } @@ -629,7 +693,7 @@ const Array<std::string>& FileSystem::_drives() { ///////////////////////////////////////////////////////////////////// bool FilePath::isRoot(const std::string& f) { -# ifdef G3D_WIN32 +# ifdef G3D_WINDOWS if (f.length() < 2) { return false; } @@ -644,9 +708,17 @@ bool FilePath::isRoot(const std::string& f) { } } - if (isSlash(f[0]) && isSlash(f[1])) { - // e.g., "\\foo\" - return true; + // Windows shares are considered roots, but only if this does not include a path inside the share + if (isSlash(f[0]) && isSlash(f[1])) { + size_t i = f.find("/", 3); + size_t j = f.find("\\", 3); + + if (i == std::string::npos) { + i = j; + } + + // e.g., "\\foo\", "\\foo" + return ((i == std::string::npos) || (i == f.length() - 1)); } # else if (f == "/") { @@ -678,8 +750,8 @@ std::string FilePath::concat(const std::string& dirname, const std::string& file std::string FilePath::ext(const std::string& filename) { - int i = filename.rfind("."); - if (i >= 0) { + size_t i = filename.rfind("."); + if (i != std::string::npos) { return filename.substr(i + 1, filename.length() - i); } else { return ""; @@ -688,16 +760,16 @@ std::string FilePath::ext(const std::string& filename) { std::string FilePath::baseExt(const std::string& filename) { - int i = findLastSlash(filename); + size_t i = findLastSlash(filename); -# ifdef G3D_WIN32 - int j = filename.rfind(":"); - if ((i == -1) && (j >= 0)) { +# ifdef G3D_WINDOWS + size_t j = filename.rfind(":"); + if ((i == std::string::npos) && (j != std::string::npos)) { i = j; } # endif - if (i == -1) { + if (i == std::string::npos) { return filename; } else { return filename.substr(i + 1, filename.length() - i); @@ -707,8 +779,8 @@ std::string FilePath::baseExt(const std::string& filename) { std::string FilePath::base(const std::string& path) { std::string filename = baseExt(path); - int i = filename.rfind("."); - if (i == -1) { + size_t i = filename.rfind("."); + if (i == std::string::npos) { // No extension return filename; } else { @@ -718,16 +790,16 @@ std::string FilePath::base(const std::string& path) { std::string FilePath::parent(const std::string& path) { - int i = findLastSlash(removeTrailingSlash(path)); + size_t i = findLastSlash(removeTrailingSlash(path)); -# ifdef G3D_WIN32 - int j = path.rfind(":"); - if ((i == -1) && (j >= 0)) { +# ifdef G3D_WINDOWS + size_t j = path.rfind(":"); + if ((i == std::string::npos) && (j != std::string::npos)) { i = j; } # endif - if (i == -1) { + if (i == std::string::npos) { return ""; } else { return path.substr(0, i + 1); @@ -759,7 +831,6 @@ std::string FilePath::canonicalize(std::string x) { return x; } - void FilePath::parse (const std::string& filename, std::string& root, @@ -796,7 +867,7 @@ void FilePath::parse } - } else if ((f.size() >= 2) & isSlash(f[0]) && isSlash(f[1])) { + } else if ((f.size() >= 2) && isSlash(f[0]) && isSlash(f[1])) { // e.g. //foo root = f.substr(0, 2); @@ -816,7 +887,7 @@ void FilePath::parse if (i != std::string::npos) { // Make sure it is after the last slash! - size_t j = iMax(f.rfind('/'), f.rfind('\\')); + size_t j = findLastSlash(f); if ((j == std::string::npos) || (i > j)) { ext = f.substr(i + 1, f.size() - i - 1); f = f.substr(0, i); @@ -827,7 +898,7 @@ void FilePath::parse // Pull the basename off { // Find the last slash - size_t i = iMax(f.rfind('/'), f.rfind('\\')); + size_t i = findLastSlash(f); if (i == std::string::npos) { @@ -860,7 +931,7 @@ void FilePath::parse j = f.size(); } - cur = iMin(i, j); + cur = min(i, j); if (cur == std::string::npos) { cur = f.size(); @@ -871,4 +942,86 @@ void FilePath::parse } } + +std::string FilePath::expandEnvironmentVariables(const std::string& path) { + // Search for pattern + size_t end = path.find_first_of('$', 0); + if (end == std::string::npos) { + // Pattern does not exist + return path; + } + + size_t start = 0; + std::string result; + while (end != std::string::npos) { + const std::string& before = path.substr(start, end - start); + result += before; + start = end + 1; + std::string var; + if (path[start] == '(') { + // Search for close paren + end = path.find_first_of(')', start + 1); + if (end == std::string::npos) { + throw std::string("Missing close paren in environment variable in \"") + path + "\""; + } + var = path.substr(start + 1, end - start - 1); + } else { + // Search for slash or end of string + end = path.find_first_of('/', start); + size_t i = path.find_first_of('\\', start); + if ((size_t(i) != std::string::npos) && ((end == std::string::npos) || (size_t(i) < end))) { + end = i; + } + if (end == std::string::npos) { + // If the varible goes to the end of the string, it is the rest of the string + end = path.size(); + } else { + --end; + } + var = path.substr(start, end - start + 1); + } + + if (! var.empty()) { + const char* value = getenv(var.c_str()); + + if (value == NULL) { + throw (std::string("LocalLightingEnvironment variable \"") + var + "\" not defined for path \"" + path + "\""); + } else { + result += value; + } + } else { + // We just parsed an "empty" variable, which was probably a default share on Windows, e.g., + // "\\mycomputer\c$", and not a variable name. + result += "$"; + } + + start = end + 1; + end = path.find_first_of('$', start); + } + + // Paste on the remainder of the source path + if (start < path.size()) { + result += path.substr(start); + } + + return result; +} + + +/** Generate a unique filename based on the provided hint */ +std::string FilePath::makeLegalFilename(const std::string& f, size_t maxLength) { + std::string tentative; + + for (size_t i = 0; i < G3D::min(maxLength, f.size()); ++i) { + const char c = f[i]; + if (isLetter(c) || isDigit(c) || (c == '-') || (c == '+') || (c == '=') || (c == '(') || (c == ')')) { + tentative += c; + } else { + tentative += "_"; + } + } + + return tentative; +} + } |