Merge pull request #5746 from IntelOrca/fix/5507

Fix #5507: RCT1 path check is case-sensitive on Linux
This commit is contained in:
Ted John 2017-07-02 12:18:40 +01:00 committed by GitHub
commit cb28381990
3 changed files with 97 additions and 23 deletions

View File

@ -14,6 +14,10 @@
*****************************************************************************/
#pragma endregion
#ifndef _WIN32
#include <dirent.h>
#endif
extern "C"
{
#include "../platform/platform.h"
@ -21,6 +25,7 @@ extern "C"
#include "../util/util.h"
}
#include "File.h"
#include "Math.hpp"
#include "Memory.hpp"
#include "Path.hpp"
@ -218,4 +223,45 @@ namespace Path
#endif
return String::Equals(a, b, ignoreCase);
}
std::string ResolveCasing(const std::string &path)
{
std::string result;
if (File::Exists(path))
{
// Windows is case insensitive so it will exist and that is all that matters
// for now. We can properly resolve the casing if we ever need to.
result = path;
}
#ifndef _WIN32
else
{
std::string fileName = Path::GetFileName(path);
std::string directory = Path::GetDirectory(path);
struct dirent * * files;
auto count = scandir(directory.c_str(), &files, nullptr, alphasort);
if (count != -1)
{
// Find a file which matches by name (case insensitive)
for (sint32 i = 0; i < count; i++)
{
if (String::Equals(files[i]->d_name, fileName.c_str(), true))
{
result = Path::Combine(directory, std::string(files[i]->d_name));
break;
}
}
// Free memory
for (sint32 i = 0; i < count; i++)
{
free(files[i]);
}
free(files);
}
}
#endif
return result;
}
}

View File

@ -43,4 +43,12 @@ namespace Path
utf8 * GetAbsolute(utf8 * buffer, size_t bufferSize, const utf8 * relativePath);
bool Equals(const std::string &a, const std::string &b);
bool Equals(const utf8 * a, const utf8 * b);
/**
* Checks if the given path is a file. If not, checks to see if
* there are any files with different casing and selects the first
* one found based on a straight forward character sort.
* Note: This will not resolve the case for Windows.
*/
std::string ResolveCasing(const std::string &path);
}

View File

@ -21,6 +21,7 @@
#include "../core/File.h"
#include "../core/FileStream.hpp"
#include "../core/Memory.hpp"
#include "../core/Path.hpp"
#include "../core/Util.hpp"
#include "../OpenRCT2.h"
#include "../sprites.h"
@ -188,6 +189,44 @@ extern "C"
return false;
}
static utf8 * gfx_get_csg_header_path()
{
char path[MAX_PATH];
safe_strcpy(path, gConfigGeneral.rct1_path, sizeof(path));
safe_strcat_path(path, "Data", sizeof(path));
safe_strcat_path(path, "csg1i.dat", sizeof(path));
auto fixedPath = Path::ResolveCasing(path);
utf8 * fixedPathC = new utf8[fixedPath.size() + 1];
Memory::Copy(fixedPathC, fixedPath.data(), fixedPath.size() + 1);
return fixedPathC;
}
static utf8 * gfx_get_csg_data_path()
{
// csg1.1 and csg1.dat are the same file.
// In the CD version, it's called csg1.1 on the CD and csg1.dat on the disk.
// In the GOG version, it's always called csg1.1.
// In the Steam version, it's always called csg1.dat.
char path[MAX_PATH];
safe_strcpy(path, gConfigGeneral.rct1_path, sizeof(path));
safe_strcat_path(path, "Data", sizeof(path));
safe_strcat_path(path, "csg1.1", sizeof(path));
auto fixedPath = Path::ResolveCasing(path);
if (fixedPath.empty())
{
safe_strcpy(path, gConfigGeneral.rct1_path, sizeof(path));
safe_strcat_path(path, "Data", sizeof(path));
safe_strcat_path(path, "csg1.dat", sizeof(path));
fixedPath = Path::ResolveCasing(path);
}
utf8 * fixedPathC = new utf8[fixedPath.size() + 1];
Memory::Copy(fixedPathC, fixedPath.data(), fixedPath.size() + 1);
return fixedPathC;
}
bool gfx_load_csg()
{
log_verbose("gfx_load_csg()");
@ -198,31 +237,12 @@ extern "C"
return false;
}
char pathHeader[MAX_PATH];
safe_strcpy(pathHeader, gConfigGeneral.rct1_path, sizeof(pathHeader));
safe_strcat_path(pathHeader, "Data", sizeof(pathHeader));
safe_strcat_path(pathHeader, "csg1i.dat", sizeof(pathHeader));
// csg1.1 and csg1.dat are the same file.
// In the CD version, it's called csg1.1 on the CD and csg1.dat on the disk.
// In the GOG version, it's always called csg1.1.
// In the Steam version, it's always called csg1.dat.
char pathData[MAX_PATH];
safe_strcpy(pathData, gConfigGeneral.rct1_path, sizeof(pathData));
safe_strcat_path(pathData, "Data", sizeof(pathData));
safe_strcat_path(pathData, "csg1.1", sizeof(pathData));
if (!File::Exists(pathData))
{
safe_strcpy(pathData, gConfigGeneral.rct1_path, sizeof(pathData));
safe_strcat_path(pathData, "Data", sizeof(pathData));
safe_strcat_path(pathData, "csg1.dat", sizeof(pathData));
}
auto pathHeaderPath = std::unique_ptr<utf8[]>(gfx_get_csg_header_path());
auto pathDataPath = std::unique_ptr<utf8[]>(gfx_get_csg_data_path());
try
{
auto fileHeader = FileStream(pathHeader, FILE_MODE_OPEN);
auto fileData = FileStream(pathData, FILE_MODE_OPEN);
auto fileHeader = FileStream(pathHeaderPath.get(), FILE_MODE_OPEN);
auto fileData = FileStream(pathDataPath.get(), FILE_MODE_OPEN);
size_t fileHeaderSize = fileHeader.GetLength();
size_t fileDataSize = fileData.GetLength();