1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-04-16 17:42:31 +00:00

Merge branch 'vfs_normalized_path_5' into 'master'

Use normalized path for NifFileManager::get

See merge request OpenMW/openmw!3944
This commit is contained in:
Alexei Kotov 2024-03-13 19:18:39 +00:00
commit 288a911ece
14 changed files with 61 additions and 43 deletions

View File

@ -65,10 +65,10 @@ void readNIF(
std::cout << " from '" << Files::pathToUnicodeString(isBSA(source) ? source.filename() : source) << "'"; std::cout << " from '" << Files::pathToUnicodeString(isBSA(source) ? source.filename() : source) << "'";
std::cout << std::endl; std::cout << std::endl;
} }
std::filesystem::path fullPath = !source.empty() ? source / path : path; const std::filesystem::path fullPath = !source.empty() ? source / path : path;
try try
{ {
Nif::NIFFile file(fullPath); Nif::NIFFile file(Files::pathToUnicodeString(fullPath));
Nif::Reader reader(file, nullptr); Nif::Reader reader(file, nullptr);
if (vfs != nullptr) if (vfs != nullptr)
reader.parse(vfs->get(pathStr)); reader.parse(vfs->get(pathStr));

View File

@ -10,6 +10,8 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <components/files/conversion.hpp>
#include "../testing_util.hpp" #include "../testing_util.hpp"
namespace namespace
@ -35,7 +37,8 @@ namespace
std::fill_n(std::back_inserter(content), 1, 'a'); std::fill_n(std::back_inserter(content), 1, 'a');
std::istringstream stream(content); std::istringstream stream(content);
stream.exceptions(std::ios::failbit | std::ios::badbit); stream.exceptions(std::ios::failbit | std::ios::badbit);
EXPECT_THAT(getHash(fileName, stream), ElementsAre(9607679276477937801ull, 16624257681780017498ull)); EXPECT_THAT(getHash(Files::pathToUnicodeString(fileName), stream),
ElementsAre(9607679276477937801ull, 16624257681780017498ull));
} }
TEST_P(FilesGetHash, shouldReturnHashForStringStream) TEST_P(FilesGetHash, shouldReturnHashForStringStream)
@ -44,7 +47,7 @@ namespace
std::string content; std::string content;
std::fill_n(std::back_inserter(content), GetParam().mSize, 'a'); std::fill_n(std::back_inserter(content), GetParam().mSize, 'a');
std::istringstream stream(content); std::istringstream stream(content);
EXPECT_EQ(getHash(fileName, stream), GetParam().mHash); EXPECT_EQ(getHash(Files::pathToUnicodeString(fileName), stream), GetParam().mHash);
} }
TEST_P(FilesGetHash, shouldReturnHashForConstrainedFileStream) TEST_P(FilesGetHash, shouldReturnHashForConstrainedFileStream)
@ -57,7 +60,7 @@ namespace
std::fstream(file, std::ios_base::out | std::ios_base::binary) std::fstream(file, std::ios_base::out | std::ios_base::binary)
.write(content.data(), static_cast<std::streamsize>(content.size())); .write(content.data(), static_cast<std::streamsize>(content.size()));
const auto stream = Files::openConstrainedFileStream(file, 0, content.size()); const auto stream = Files::openConstrainedFileStream(file, 0, content.size());
EXPECT_EQ(getHash(file, *stream), GetParam().mHash); EXPECT_EQ(getHash(Files::pathToUnicodeString(file), *stream), GetParam().mHash);
} }
INSTANTIATE_TEST_SUITE_P(Params, FilesGetHash, INSTANTIATE_TEST_SUITE_P(Params, FilesGetHash,

View File

@ -1,5 +1,4 @@
#include "hash.hpp" #include "hash.hpp"
#include "conversion.hpp"
#include <extern/smhasher/MurmurHash3.h> #include <extern/smhasher/MurmurHash3.h>
@ -10,7 +9,7 @@
namespace Files namespace Files
{ {
std::array<std::uint64_t, 2> getHash(const std::filesystem::path& fileName, std::istream& stream) std::array<std::uint64_t, 2> getHash(std::string_view fileName, std::istream& stream)
{ {
std::array<std::uint64_t, 2> hash{ 0, 0 }; std::array<std::uint64_t, 2> hash{ 0, 0 };
try try
@ -35,8 +34,11 @@ namespace Files
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
throw std::runtime_error( std::string message = "Error while reading \"";
"Error while reading \"" + Files::pathToUnicodeString(fileName) + "\" to get hash: " + e.what()); message += fileName;
message += "\" to get hash: ";
message += e.what();
throw std::runtime_error(message);
} }
return hash; return hash;
} }

View File

@ -3,12 +3,12 @@
#include <array> #include <array>
#include <cstdint> #include <cstdint>
#include <filesystem>
#include <iosfwd> #include <iosfwd>
#include <string_view>
namespace Files namespace Files
{ {
std::array<std::uint64_t, 2> getHash(const std::filesystem::path& fileName, std::istream& stream); std::array<std::uint64_t, 2> getHash(std::string_view fileName, std::istream& stream);
} }
#endif #endif

View File

@ -1,18 +1,21 @@
#ifndef OPENMW_COMPONENTS_NIF_EXCEPTION_HPP #ifndef OPENMW_COMPONENTS_NIF_EXCEPTION_HPP
#define OPENMW_COMPONENTS_NIF_EXCEPTION_HPP #define OPENMW_COMPONENTS_NIF_EXCEPTION_HPP
#include <filesystem>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <components/files/conversion.hpp>
namespace Nif namespace Nif
{ {
struct Exception : std::runtime_error struct Exception : std::runtime_error
{ {
explicit Exception(const std::string& message, const std::filesystem::path& path) explicit Exception(std::string_view message, std::string_view path)
: std::runtime_error("NIFFile Error: " + message + " when reading " + Files::pathToUnicodeString(path)) : std::runtime_error([&] {
std::string result = "NIFFile Error: ";
result += message;
result += " when reading ";
result += path;
return result;
}())
{ {
} }
}; };

View File

@ -4,7 +4,7 @@
#define OPENMW_COMPONENTS_NIF_NIFFILE_HPP #define OPENMW_COMPONENTS_NIF_NIFFILE_HPP
#include <atomic> #include <atomic>
#include <filesystem> #include <cstdint>
#include <vector> #include <vector>
#include <components/files/istreamptr.hpp> #include <components/files/istreamptr.hpp>
@ -45,7 +45,7 @@ namespace Nif
std::uint32_t mBethVersion = 0; std::uint32_t mBethVersion = 0;
/// File name, used for error messages and opening the file /// File name, used for error messages and opening the file
std::filesystem::path mPath; std::string mPath;
std::string mHash; std::string mHash;
/// Record list /// Record list
@ -56,7 +56,7 @@ namespace Nif
bool mUseSkinning = false; bool mUseSkinning = false;
explicit NIFFile(const std::filesystem::path& path) explicit NIFFile(std::string_view path)
: mPath(path) : mPath(path)
{ {
} }
@ -77,7 +77,7 @@ namespace Nif
std::size_t numRoots() const { return mFile->mRoots.size(); } std::size_t numRoots() const { return mFile->mRoots.size(); }
/// Get the name of the file /// Get the name of the file
const std::filesystem::path& getFilename() const { return mFile->mPath; } const std::string& getFilename() const { return mFile->mPath; }
const std::string& getHash() const { return mFile->mHash; } const std::string& getHash() const { return mFile->mHash; }
@ -104,7 +104,7 @@ namespace Nif
std::uint32_t& mBethVersion; std::uint32_t& mBethVersion;
/// File name, used for error messages and opening the file /// File name, used for error messages and opening the file
std::filesystem::path& mFilename; std::string_view mFilename;
std::string& mHash; std::string& mHash;
/// Record list /// Record list
@ -144,7 +144,7 @@ namespace Nif
void setUseSkinning(bool skinning); void setUseSkinning(bool skinning);
/// Get the name of the file /// Get the name of the file
std::filesystem::path getFilename() const { return mFilename; } std::string_view getFilename() const { return mFilename; }
/// Get the version of the NIF format used /// Get the version of the NIF format used
std::uint32_t getVersion() const { return mVersion; } std::uint32_t getVersion() const { return mVersion; }

View File

@ -50,7 +50,7 @@ namespace NifBullet
if (node) if (node)
roots.emplace_back(node); roots.emplace_back(node);
} }
mShape->mFileName = Files::pathToUnicodeString(nif.getFilename()); mShape->mFileName = nif.getFilename();
if (roots.empty()) if (roots.empty())
{ {
warn("Found no root nodes in NIF file " + mShape->mFileName); warn("Found no root nodes in NIF file " + mShape->mFileName);

View File

@ -110,7 +110,7 @@ namespace Resource
osg::ref_ptr<const BulletShape> BulletShapeManager::getShape(const std::string& name) osg::ref_ptr<const BulletShape> BulletShapeManager::getShape(const std::string& name)
{ {
const std::string normalized = VFS::Path::normalizeFilename(name); const VFS::Path::Normalized normalized(name);
osg::ref_ptr<BulletShape> shape; osg::ref_ptr<BulletShape> shape;
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(normalized); osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(normalized);

View File

@ -41,14 +41,14 @@ namespace Resource
NifFileManager::~NifFileManager() = default; NifFileManager::~NifFileManager() = default;
Nif::NIFFilePtr NifFileManager::get(const std::string& name) Nif::NIFFilePtr NifFileManager::get(VFS::Path::NormalizedView name)
{ {
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(name); osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(name);
if (obj) if (obj)
return static_cast<NifFileHolder*>(obj.get())->mNifFile; return static_cast<NifFileHolder*>(obj.get())->mNifFile;
else else
{ {
auto file = std::make_shared<Nif::NIFFile>(name); auto file = std::make_shared<Nif::NIFFile>(name.value());
Nif::Reader reader(*file, mEncoder); Nif::Reader reader(*file, mEncoder);
reader.parse(mVFS->get(name)); reader.parse(mVFS->get(name));
obj = new NifFileHolder(file); obj = new NifFileHolder(file);

View File

@ -26,7 +26,7 @@ namespace Resource
/// Retrieve a NIF file from the cache, or load it from the VFS if not cached yet. /// Retrieve a NIF file from the cache, or load it from the VFS if not cached yet.
/// @note For performance reasons the NifFileManager does not handle case folding, needs /// @note For performance reasons the NifFileManager does not handle case folding, needs
/// to be done in advance by other managers accessing the NifFileManager. /// to be done in advance by other managers accessing the NifFileManager.
Nif::NIFFilePtr get(const std::string& name); Nif::NIFFilePtr get(VFS::Path::NormalizedView name);
void reportStats(unsigned int frameNumber, osg::Stats* stats) const override; void reportStats(unsigned int frameNumber, osg::Stats* stats) const override;
}; };

View File

@ -3,6 +3,8 @@
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <components/vfs/pathutil.hpp>
#include "objectcache.hpp" #include "objectcache.hpp"
namespace VFS namespace VFS
@ -70,11 +72,11 @@ namespace Resource
double mExpiryDelay; double mExpiryDelay;
}; };
class ResourceManager : public GenericResourceManager<std::string> class ResourceManager : public GenericResourceManager<VFS::Path::Normalized>
{ {
public: public:
explicit ResourceManager(const VFS::Manager* vfs, double expiryDelay) explicit ResourceManager(const VFS::Manager* vfs, double expiryDelay)
: GenericResourceManager<std::string>(vfs, expiryDelay) : GenericResourceManager(vfs, expiryDelay)
{ {
} }
}; };

View File

@ -545,9 +545,9 @@ namespace Resource
namespace namespace
{ {
osg::ref_ptr<osg::Node> loadNonNif( osg::ref_ptr<osg::Node> loadNonNif(
const std::string& normalizedFilename, std::istream& model, Resource::ImageManager* imageManager) VFS::Path::NormalizedView normalizedFilename, std::istream& model, Resource::ImageManager* imageManager)
{ {
auto ext = Misc::getFileExtension(normalizedFilename); const std::string_view ext = Misc::getFileExtension(normalizedFilename.value());
osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(std::string(ext)); osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(std::string(ext));
if (!reader) if (!reader)
{ {
@ -566,7 +566,7 @@ namespace Resource
if (ext == "dae") if (ext == "dae")
options->setOptionString("daeUseSequencedTextureUnits"); options->setOptionString("daeUseSequencedTextureUnits");
const std::array<std::uint64_t, 2> fileHash = Files::getHash(normalizedFilename, model); const std::array<std::uint64_t, 2> fileHash = Files::getHash(normalizedFilename.value(), model);
osgDB::ReaderWriter::ReadResult result = reader->readNode(model, options); osgDB::ReaderWriter::ReadResult result = reader->readNode(model, options);
if (!result.success()) if (!result.success())
@ -721,10 +721,10 @@ namespace Resource
} }
} }
osg::ref_ptr<osg::Node> load(const std::string& normalizedFilename, const VFS::Manager* vfs, osg::ref_ptr<osg::Node> load(VFS::Path::NormalizedView normalizedFilename, const VFS::Manager* vfs,
Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager) Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager)
{ {
auto ext = Misc::getFileExtension(normalizedFilename); const std::string_view ext = Misc::getFileExtension(normalizedFilename.value());
if (ext == "nif") if (ext == "nif")
return NifOsg::Loader::load(*nifFileManager->get(normalizedFilename), imageManager); return NifOsg::Loader::load(*nifFileManager->get(normalizedFilename), imageManager);
else if (ext == "spt") else if (ext == "spt")
@ -778,12 +778,12 @@ namespace Resource
} }
}; };
bool canOptimize(const std::string& filename) static bool canOptimize(std::string_view filename)
{ {
size_t slashpos = filename.find_last_of("\\/"); const std::string_view::size_type slashpos = filename.find_last_of('/');
if (slashpos != std::string::npos && slashpos + 1 < filename.size()) if (slashpos != std::string_view::npos && slashpos + 1 < filename.size())
{ {
std::string basename = filename.substr(slashpos + 1); const std::string_view basename = filename.substr(slashpos + 1);
// xmesh.nif can not be optimized because there are keyframes added in post // xmesh.nif can not be optimized because there are keyframes added in post
if (!basename.empty() && basename[0] == 'x') if (!basename.empty() && basename[0] == 'x')
return false; return false;
@ -796,7 +796,7 @@ namespace Resource
// For spell VFX, DummyXX nodes must remain intact. Not adding those to reservedNames to avoid being overly // For spell VFX, DummyXX nodes must remain intact. Not adding those to reservedNames to avoid being overly
// cautious - instead, decide on filename // cautious - instead, decide on filename
if (filename.find("vfx_pattern") != std::string::npos) if (filename.find("vfx_pattern") != std::string_view::npos)
return false; return false;
return true; return true;
} }
@ -843,11 +843,12 @@ namespace Resource
{ {
try try
{ {
VFS::Path::Normalized path("meshes/marker_error.****");
for (const auto meshType : { "nif", "osg", "osgt", "osgb", "osgx", "osg2", "dae" }) for (const auto meshType : { "nif", "osg", "osgt", "osgb", "osgx", "osg2", "dae" })
{ {
const std::string normalized = "meshes/marker_error." + std::string(meshType); path.changeExtension(meshType);
if (mVFS->exists(normalized)) if (mVFS->exists(path))
return load(normalized, mVFS, mImageManager, mNifFileManager); return load(path, mVFS, mImageManager, mNifFileManager);
} }
} }
catch (const std::exception& e) catch (const std::exception& e)
@ -869,7 +870,7 @@ namespace Resource
osg::ref_ptr<const osg::Node> SceneManager::getTemplate(std::string_view name, bool compile) osg::ref_ptr<const osg::Node> SceneManager::getTemplate(std::string_view name, bool compile)
{ {
std::string normalized = VFS::Path::normalizeFilename(name); const VFS::Path::Normalized normalized(name);
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(normalized); osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(normalized);
if (obj) if (obj)

View File

@ -43,6 +43,11 @@ namespace VFS
return getNormalized(name); return getNormalized(name);
} }
Files::IStreamPtr Manager::get(Path::NormalizedView name) const
{
return getNormalized(name.value());
}
Files::IStreamPtr Manager::getNormalized(std::string_view normalizedName) const Files::IStreamPtr Manager::getNormalized(std::string_view normalizedName) const
{ {
assert(Path::isNormalized(normalizedName)); assert(Path::isNormalized(normalizedName));

View File

@ -50,6 +50,8 @@ namespace VFS
/// @note May be called from any thread once the index has been built. /// @note May be called from any thread once the index has been built.
Files::IStreamPtr get(const Path::Normalized& name) const; Files::IStreamPtr get(const Path::Normalized& name) const;
Files::IStreamPtr get(Path::NormalizedView name) const;
/// Retrieve a file by name (name is already normalized). /// Retrieve a file by name (name is already normalized).
/// @note Throws an exception if the file can not be found. /// @note Throws an exception if the file can not be found.
/// @note May be called from any thread once the index has been built. /// @note May be called from any thread once the index has been built.