mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-07 03:12:36 +01:00
Replace findPathRealCase with FileIndex methods
This introduces indexGameDirectory and findFilePath. indexGameDirectory indexes the files in the game directory. findFilePath returns the on-disk location of a case-insensitive game data path.
This commit is contained in:
parent
772c93d463
commit
674ce55af3
@ -49,6 +49,7 @@ GameData::~GameData()
|
||||
|
||||
void GameData::load()
|
||||
{
|
||||
index.indexGameDirectory(datpath);
|
||||
index.indexTree(datpath);
|
||||
|
||||
parseDAT(datpath+"/data/default.dat");
|
||||
@ -109,9 +110,9 @@ void GameData::parseDAT(const std::string& path)
|
||||
}
|
||||
else if(cmd == "IPL")
|
||||
{
|
||||
std::string fixedpath = fixPath(line.substr(space+1));
|
||||
fixedpath = findPathRealCase(datpath, fixedpath);
|
||||
loadIPL(fixedpath);
|
||||
auto path = line.substr(space+1);
|
||||
auto systempath = index.findFilePath(path);
|
||||
loadIPL(systempath.native());
|
||||
}
|
||||
else if(cmd == "TEXDICTION")
|
||||
{
|
||||
@ -182,10 +183,9 @@ void GameData::loadCOL(const size_t zone, const std::string& name)
|
||||
|
||||
LoaderCOL col;
|
||||
|
||||
std::string realPath = fixPath(name);
|
||||
realPath = findPathRealCase(datpath, realPath);
|
||||
auto systempath = index.findFilePath(name).native();
|
||||
|
||||
if(col.load(realPath)) {
|
||||
if(col.load(systempath)) {
|
||||
for( size_t i = 0; i < col.instances.size(); ++i ) {
|
||||
collisions[col.instances[i]->name] = std::move(col.instances[i]);
|
||||
}
|
||||
@ -434,13 +434,13 @@ void GameData::loadWeaponDAT(const std::string &name)
|
||||
|
||||
bool GameData::loadAudioStream(const std::string &name)
|
||||
{
|
||||
auto filePath = findPathRealCase(datpath + "/audio/", name);
|
||||
auto systempath = index.findFilePath("audio/" + name).native();
|
||||
|
||||
if (engine->cutsceneAudio.length() > 0) {
|
||||
engine->sound.stopMusic(engine->cutsceneAudio);
|
||||
}
|
||||
|
||||
if (engine->sound.loadMusic(name, filePath)) {
|
||||
if (engine->sound.loadMusic(name, systempath)) {
|
||||
engine->cutsceneAudio = name;
|
||||
return true;
|
||||
}
|
||||
@ -450,18 +450,18 @@ bool GameData::loadAudioStream(const std::string &name)
|
||||
|
||||
bool GameData::loadAudioClip(const std::string& name, const std::string& fileName)
|
||||
{
|
||||
auto filePath = findPathRealCase(datpath + "/audio/", fileName);
|
||||
|
||||
if (fileName.find(".mp3") != fileName.npos)
|
||||
auto systempath = index.findFilePath("audio/" + fileName).native();
|
||||
|
||||
if (systempath.find(".mp3") != std::string::npos)
|
||||
{
|
||||
logger->error("Data", "MP3 Audio unsupported outside cutscenes");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool loaded = engine->sound.loadSound(name, filePath);
|
||||
bool loaded = engine->sound.loadSound(name, systempath);
|
||||
|
||||
if ( ! loaded) {
|
||||
logger->error("Data", "Error loading audio clip "+ filePath);
|
||||
logger->error("Data", "Error loading audio clip "+ systempath);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1,47 +1,23 @@
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <platform/FileIndex.hpp>
|
||||
#include <loaders/LoaderIMG.hpp>
|
||||
|
||||
using namespace boost::filesystem;
|
||||
|
||||
/**
|
||||
* Finds the 'real' case for a path, to get around the fact that Rockstar's data is usually the wrong case.
|
||||
* @param base The base of the path to start looking from.
|
||||
* @param path the lowercase path.
|
||||
*/
|
||||
std::string findPathRealCase(const std::string& base_src, const std::string& path_src)
|
||||
void FileIndex::indexGameDirectory(const fs::path& base_path)
|
||||
{
|
||||
path base(base_src);
|
||||
path searchpath(path_src);
|
||||
gamedatapath_ = base_path;
|
||||
|
||||
// Iterate over each component of the path
|
||||
for(const path& path_component : boost::make_iterator_range(searchpath.begin(), searchpath.end())) {
|
||||
std::string cmpLower = path_component.string();
|
||||
std::transform(cmpLower.begin(), cmpLower.end(), cmpLower.begin(), ::tolower);
|
||||
for(const path& entry : boost::make_iterator_range(recursive_directory_iterator(base_path), {})) {
|
||||
if(is_regular_file(entry)) {
|
||||
std::string name = entry.native();
|
||||
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
||||
|
||||
// Search the current base path for a filename matching the component we're searching for
|
||||
bool found = false;
|
||||
for(const path& entry : boost::make_iterator_range(directory_iterator(base), {})) {
|
||||
std::string lowerName = entry.filename().string();
|
||||
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), ::tolower);
|
||||
|
||||
if(lowerName == cmpLower) {
|
||||
// We got a match, so add it to base and continue
|
||||
base /= entry.filename();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
throw std::runtime_error("Can't find real path case of " + path_src);
|
||||
filesystemfiles_[name] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
return base.string();
|
||||
}
|
||||
|
||||
void FileIndex::indexTree(const std::string& root)
|
||||
|
@ -2,15 +2,66 @@
|
||||
#define RWENGINE_FILEINDEX_HPP
|
||||
#include "FileHandle.hpp"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
std::string findPathRealCase(const std::string& base_src, const std::string& path_src);
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<> struct hash<fs::path>
|
||||
{
|
||||
size_t operator()(const fs::path& p) const
|
||||
{
|
||||
return fs::hash_value(p);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class FileIndex
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* Mapping type (lower case name) => (on disk name)
|
||||
*/
|
||||
using FileSystemMap = std::unordered_map<fs::path, fs::path>;
|
||||
|
||||
fs::path gamedatapath_;
|
||||
FileSystemMap filesystemfiles_;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief indexDirectory finds the true case for each file in the tree
|
||||
* @param base_path
|
||||
*
|
||||
* This is used to build the mapping of lower-case file paths to the
|
||||
* true case on the file system for platforms where this is an issue.
|
||||
*
|
||||
*/
|
||||
void indexGameDirectory(const fs::path& base_path);
|
||||
|
||||
/**
|
||||
* @brief findFilePath finds disk path for a game data file
|
||||
* @param path
|
||||
* @return The file path as it exists on disk
|
||||
*/
|
||||
fs::path findFilePath(std::string path)
|
||||
{
|
||||
auto backslash = std::string::npos;
|
||||
while ((backslash = path.find("\\")) != std::string::npos) {
|
||||
path.replace(backslash, 1, "/");
|
||||
}
|
||||
auto realpath = gamedatapath_ / path;
|
||||
std::string name = realpath.native();
|
||||
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
||||
|
||||
return filesystemfiles_[name];
|
||||
}
|
||||
|
||||
struct IndexData
|
||||
{
|
||||
/// Lowercase identifying filename
|
||||
|
@ -5,6 +5,33 @@
|
||||
BOOST_AUTO_TEST_SUITE(FileIndexTests)
|
||||
|
||||
#if RW_TEST_WITH_DATA
|
||||
BOOST_AUTO_TEST_CASE(test_directory_paths)
|
||||
{
|
||||
FileIndex index;
|
||||
|
||||
index.indexGameDirectory(Global::getGamePath());
|
||||
|
||||
{
|
||||
std::string upperpath { "DATA/CULLZONE.DAT" };
|
||||
auto truepath = index.findFilePath(upperpath);
|
||||
BOOST_ASSERT(! truepath.empty());
|
||||
BOOST_CHECK(upperpath != truepath);
|
||||
fs::path expected {Global::getGamePath()};
|
||||
expected /= "data/CULLZONE.DAT";
|
||||
BOOST_CHECK_EQUAL(truepath.native(), expected.native());
|
||||
}
|
||||
{
|
||||
std::string upperpath { "DATA/MAPS/COMNBTM/COMNBTM.IPL" };
|
||||
auto truepath = index.findFilePath(upperpath);
|
||||
BOOST_ASSERT(! truepath.empty());
|
||||
BOOST_CHECK(upperpath != truepath);
|
||||
fs::path expected {Global::getGamePath()};
|
||||
expected /= "data/maps/comnbtm/comNbtm.ipl";
|
||||
BOOST_CHECK_EQUAL(truepath.native(), expected.native());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_index)
|
||||
{
|
||||
FileIndex index;
|
||||
|
Loading…
Reference in New Issue
Block a user