Skip to content

Commit

Permalink
TOOLS: Make Common::File and isDirectory() case insensitive
Browse files Browse the repository at this point in the history
This fixes some tool adding hardcoded upper case directories (e.g.
AUDIO/) to the input path to look for files when run on case
sensitive systems.
  • Loading branch information
criezy committed Nov 22, 2011
1 parent 8ba485e commit d38124f
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 1 deletion.
73 changes: 72 additions & 1 deletion common/file.cpp
Expand Up @@ -24,6 +24,8 @@
#include <stdarg.h>
#include <stdio.h>
#include <assert.h>
#include <deque>
#include <algorithm>
#include <sys/stat.h> // for stat()
#include <sys/types.h>
#ifndef _MSC_VER
Expand Down Expand Up @@ -111,6 +113,10 @@ bool Filename::exists() const {
// This fails if we don't have permission to read the file
// but in most cases, that's the same thing for us.
FILE *f = fopen(_path.c_str(), "r");
if (!f) {
std::string fixedPath = fixPathCase(_path);
f = fopen(_path.c_str(), "r");
}
if (f) {
fclose(f);
return true;
Expand Down Expand Up @@ -236,6 +242,10 @@ void File::open(const Filename &filepath, const char *mode) {
close();

_file = fopen(filepath.getFullPath().c_str(), mode);
if (!_file) {
std::string fixedPath = fixPathCase(filepath.getFullPath());
_file = fopen(fixedPath.c_str(), mode);
}

FileMode m = FILEMODE_READ;
do {
Expand Down Expand Up @@ -520,7 +530,68 @@ int removeFile(const char *path) {

bool isDirectory(const char *path) {
struct stat st;
return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
if (stat(path, &st) == 0) {
return S_ISDIR(st.st_mode);
}
// Try to fix the case
std::string fixedPath = fixPathCase(path);
return stat(fixedPath.c_str(), &st) == 0 && S_ISDIR(st.st_mode);
}

std::string fixPathCase(const std::string& originalPath) {
std::string result = originalPath;
std::deque<std::string> parts;
struct stat st;

// Remove the last part of the path until we get to a path that exists
while (stat(result.c_str(), &st) != 0) {
size_t slash = result.rfind('/', result.size() - 2);
if (slash == std::string::npos)
slash = result.rfind('\\', result.size() - 2);
if (slash == std::string::npos) {
parts.push_back(result);
result.clear();
break;
} else {
parts.push_back(result.substr(slash + 1));
result.erase(slash + 1);
if (slash == 0)
break;
}
}

// Reconstruct the path by changing the case
while (!parts.empty()) {
std::string directory = parts.back();
// Try first original case, then all lower case and finally all upper case
std::string path = result + directory;
if (stat(path.c_str(), &st) == 0) {
result = path;
} else {
std::transform(directory.begin(), directory.end(), directory.begin(), ::tolower);
path = result + directory;
if (stat(path.c_str(), &st) == 0) {
result = path;
} else {
std::transform(directory.begin(), directory.end(), directory.begin(), ::toupper);
path = result + directory;
if (stat(path.c_str(), &st) == 0) {
result = path;
} else {
// Does not exists whatever the case used.
// Add back all the remaining parts and return.
while (!parts.empty()) {
result += parts.back();
parts.pop_back();
}
return result;
}
}
}
parts.pop_back();
}

return result;
}

} // End of namespace Common
Expand Down
7 changes: 7 additions & 0 deletions common/file.h
Expand Up @@ -407,6 +407,13 @@ int removeFile(const char *path);
*/
bool isDirectory(const char *path);

/**
* Transform the given path into an existing path if possible
* by changing the case of each path element to either the
* original case, all lower case or all upper case.
*/
std::string fixPathCase(const std::string& originalPath);

} // End of namespace Common


Expand Down

0 comments on commit d38124f

Please sign in to comment.