diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6a4154e184..ffc0705b03 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -209,8 +209,9 @@ namespace MWGui SDL_GL_GetDrawableSize(window, &dw, &dh); mScalingFactor = Settings::gui().mScalingFactor * (dw / w); + constexpr VFS::Path::NormalizedView resourcePath("mygui"); mGuiPlatform = std::make_unique(viewer, guiRoot, resourceSystem->getImageManager(), - resourceSystem->getVFS(), mScalingFactor, "mygui", logpath / "MyGUI.log"); + resourceSystem->getVFS(), mScalingFactor, resourcePath, logpath / "MyGUI.log"); mGui = std::make_unique(); mGui->initialise({}); diff --git a/components/bsa/ba2dx10file.cpp b/components/bsa/ba2dx10file.cpp index c16a3bacd2..c834ac7692 100644 --- a/components/bsa/ba2dx10file.cpp +++ b/components/bsa/ba2dx10file.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include @@ -11,9 +10,8 @@ #include #include -#include #include -#include +#include #include "ba2file.hpp" #include "memorystream.hpp" @@ -148,20 +146,10 @@ namespace Bsa } } -#ifdef _WIN32 - const auto& path = str; -#else - // Force-convert the path into something UNIX can handle first - // to make sure std::filesystem::path doesn't think the entire path is the filename on Linux - // and subsequently purge it to determine the file folder. - std::string path(str); - std::replace(path.begin(), path.end(), '\\', '/'); -#endif + const VFS::Path::Normalized path(str); - const auto p = std::filesystem::path{ path }; // Purposefully damage Unicode strings. - const auto fileName = Misc::StringUtils::lowerCase(p.stem().string()); - const auto ext = Misc::StringUtils::lowerCase(p.extension().string()); // Purposefully damage Unicode strings. - const auto folder = Misc::StringUtils::lowerCase(p.parent_path().string()); + const std::string_view fileName = path.stem(); + const std::string_view folder = path.parent().value(); uint32_t folderHash = generateHash(folder); auto it = mFolders.find(folderHash); @@ -169,7 +157,7 @@ namespace Bsa return std::nullopt; // folder not found uint32_t fileHash = generateHash(fileName); - uint32_t extHash = generateExtensionHash(ext); + uint32_t extHash = generateExtensionHash(path.filename()); auto iter = it->second.find({ fileHash, extHash }); if (iter == it->second.end()) return std::nullopt; // file not found @@ -229,13 +217,6 @@ namespace Bsa fail("Add file is not implemented for compressed BSA: " + filename); } - Files::IStreamPtr BA2DX10File::getFile(const char* file) - { - if (auto fileRec = getFileRecord(file); fileRec) - return getFile(*fileRec); - fail("File not found: " + std::string(file)); - } - constexpr const uint32_t DDSD_CAPS = 0x00000001; constexpr const uint32_t DDSD_HEIGHT = 0x00000002; constexpr const uint32_t DDSD_WIDTH = 0x00000004; diff --git a/components/bsa/ba2dx10file.hpp b/components/bsa/ba2dx10file.hpp index aed727dc1a..f0499f7b67 100644 --- a/components/bsa/ba2dx10file.hpp +++ b/components/bsa/ba2dx10file.hpp @@ -59,7 +59,6 @@ namespace Bsa /// Read header information from the input source void readHeader(std::istream& stream) override; - Files::IStreamPtr getFile(const char* filePath); Files::IStreamPtr getFile(const FileStruct* fileStruct); void addFile(const std::string& filename, std::istream& file); }; diff --git a/components/bsa/ba2file.cpp b/components/bsa/ba2file.cpp index 17cfb03866..55d24ef2d7 100644 --- a/components/bsa/ba2file.cpp +++ b/components/bsa/ba2file.cpp @@ -1,5 +1,7 @@ #include "ba2file.hpp" +#include + namespace Bsa { constexpr const uint32_t crc32table[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, @@ -32,7 +34,7 @@ namespace Bsa 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; - uint32_t generateHash(const std::string& name) + uint32_t generateHash(std::string_view name) { uint32_t result = 0; for (auto c : name) @@ -46,8 +48,15 @@ namespace Bsa return result; } - uint32_t generateExtensionHash(std::string_view extension) + uint32_t generateExtensionHash(VFS::Path::NormalizedView file) { + std::string_view extension; + if (const std::size_t pos = Misc::findExtension(file.value()); pos != std::string_view::npos) + { + // ext including . + extension = file.value(); + extension.remove_prefix(pos); + } uint32_t result = 0; for (size_t i = 0; i < 4 && i < extension.size() - 1; i++) result |= static_cast(extension[i + 1]) << (8 * i); diff --git a/components/bsa/ba2file.hpp b/components/bsa/ba2file.hpp index 0d51be4c0e..cfb2cd11bf 100644 --- a/components/bsa/ba2file.hpp +++ b/components/bsa/ba2file.hpp @@ -4,10 +4,12 @@ #include #include +#include + namespace Bsa { - uint32_t generateHash(const std::string& name); - uint32_t generateExtensionHash(std::string_view extension); + uint32_t generateHash(std::string_view name); + uint32_t generateExtensionHash(VFS::Path::NormalizedView file); enum class BA2Version : std::uint32_t { diff --git a/components/bsa/ba2gnrlfile.cpp b/components/bsa/ba2gnrlfile.cpp index 30e9b1eb0a..47bce25d81 100644 --- a/components/bsa/ba2gnrlfile.cpp +++ b/components/bsa/ba2gnrlfile.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -10,9 +9,8 @@ #include #include -#include #include -#include +#include #include "ba2file.hpp" #include "memorystream.hpp" @@ -139,20 +137,10 @@ namespace Bsa } } -#ifdef _WIN32 - const auto& path = str; -#else - // Force-convert the path into something UNIX can handle first - // to make sure std::filesystem::path doesn't think the entire path is the filename on Linux - // and subsequently purge it to determine the file folder. - std::string path(str); - std::replace(path.begin(), path.end(), '\\', '/'); -#endif + const VFS::Path::Normalized path(str); - const auto p = std::filesystem::path{ path }; // Purposefully damage Unicode strings. - const auto fileName = Misc::StringUtils::lowerCase(p.stem().string()); - const auto ext = Misc::StringUtils::lowerCase(p.extension().string()); // Purposefully damage Unicode strings. - const auto folder = Misc::StringUtils::lowerCase(p.parent_path().string()); + const std::string_view fileName = path.stem(); + const std::string_view folder = path.parent().value(); uint32_t folderHash = generateHash(folder); auto it = mFolders.find(folderHash); @@ -160,7 +148,7 @@ namespace Bsa return FileRecord(); // folder not found, return default which has offset of sInvalidOffset uint32_t fileHash = generateHash(fileName); - uint32_t extHash = generateExtensionHash(ext); + uint32_t extHash = generateExtensionHash(path.filename()); auto iter = it->second.find({ fileHash, extHash }); if (iter == it->second.end()) return FileRecord(); // file not found, return default which has offset of sInvalidOffset @@ -183,16 +171,6 @@ namespace Bsa fail("Add file is not implemented for compressed BSA: " + filename); } - Files::IStreamPtr BA2GNRLFile::getFile(const char* file) - { - FileRecord fileRec = getFileRecord(file); - if (!fileRec.isValid()) - { - fail("File not found: " + std::string(file)); - } - return getFile(fileRec); - } - Files::IStreamPtr BA2GNRLFile::getFile(const FileRecord& fileRecord) { const uint32_t inputSize = fileRecord.packedSize ? fileRecord.packedSize : fileRecord.size; diff --git a/components/bsa/ba2gnrlfile.hpp b/components/bsa/ba2gnrlfile.hpp index 371fe3d072..711682033b 100644 --- a/components/bsa/ba2gnrlfile.hpp +++ b/components/bsa/ba2gnrlfile.hpp @@ -47,7 +47,6 @@ namespace Bsa /// Read header information from the input source void readHeader(std::istream& input) override; - Files::IStreamPtr getFile(const char* filePath); Files::IStreamPtr getFile(const FileStruct* fileStruct); void addFile(const std::string& filename, std::istream& file); }; diff --git a/components/bsa/compressedbsafile.cpp b/components/bsa/compressedbsafile.cpp index 8ad7221105..2cfa642b00 100644 --- a/components/bsa/compressedbsafile.cpp +++ b/components/bsa/compressedbsafile.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -38,7 +37,8 @@ #include #include #include -#include +#include +#include #include "memorystream.hpp" @@ -218,26 +218,26 @@ namespace Bsa } } -#ifdef _WIN32 - const auto& path = str; -#else - // Force-convert the path into something UNIX can handle first - // to make sure std::filesystem::path doesn't think the entire path is the filename on Linux - // and subsequently purge it to determine the file folder. - std::string path(str); - std::replace(path.begin(), path.end(), '\\', '/'); -#endif + const VFS::Path::Normalized path(str); - const auto p = std::filesystem::path{ path }; // Purposefully damage Unicode strings. - const auto stem = p.stem(); - const auto ext = p.extension().string(); // Purposefully damage Unicode strings. + const std::string_view stem = path.stem(); + const std::string_view folder = path.parent().value(); - std::uint64_t folderHash = generateHash(p.parent_path(), {}); + std::uint64_t folderHash = generateHash(folder, {}); auto it = mFolders.find(folderHash); if (it == mFolders.end()) return FileRecord(); + const std::string_view file = path.filename().value(); + std::string_view ext; + if (const std::size_t pos = Misc::findExtension(file); pos != std::string_view::npos) + { + // ext including . + ext = file; + ext.remove_prefix(pos); + } + std::uint64_t fileHash = generateHash(stem, ext); auto iter = it->second.mFiles.find(fileHash); if (iter == it->second.mFiles.end()) @@ -262,16 +262,6 @@ namespace Bsa fail("Add file is not implemented for compressed BSA: " + filename); } - Files::IStreamPtr CompressedBSAFile::getFile(const char* file) - { - FileRecord fileRec = getFileRecord(file); - if (fileRec.mOffset == std::numeric_limits::max()) - { - fail("File not found: " + std::string(file)); - } - return getFile(fileRec); - } - Files::IStreamPtr CompressedBSAFile::getFile(const FileRecord& fileRecord) { size_t size = fileRecord.mSize & (~FileSizeFlag_Compression); @@ -337,29 +327,31 @@ namespace Bsa return std::make_unique>(std::move(memoryStreamPtr)); } - std::uint64_t CompressedBSAFile::generateHash(const std::filesystem::path& stem, std::string extension) + std::uint64_t CompressedBSAFile::generateHash(std::string_view str, std::string_view extension) { - auto str = stem.u8string(); - size_t len = str.length(); - if (len == 0) + if (str.empty()) return 0; - std::replace(str.begin(), str.end(), '/', '\\'); - Misc::StringUtils::lowerCaseInPlace(str); - uint64_t result = str[len - 1]; + const auto at = [&](std::size_t i) -> char { + const char c = str[i]; + if (c == '/') + return '\\'; + return c; + }; + const size_t len = str.length(); + uint64_t result = at(len - 1); if (len >= 3) - result |= str[len - 2] << 8; + result |= at(len - 2) << 8; result |= len << 16; - result |= static_cast(str[0] << 24); + result |= static_cast(at(0) << 24); if (len >= 4) { uint32_t hash = 0; for (size_t i = 1; i <= len - 3; ++i) - hash = hash * 0x1003f + str[i]; + hash = hash * 0x1003f + at(i); result += static_cast(hash) << 32; } if (extension.empty()) return result; - Misc::StringUtils::lowerCaseInPlace(extension); if (extension == ".kf") result |= 0x80; else if (extension == ".nif") diff --git a/components/bsa/compressedbsafile.hpp b/components/bsa/compressedbsafile.hpp index 6eae44cec1..11c0e1459b 100644 --- a/components/bsa/compressedbsafile.hpp +++ b/components/bsa/compressedbsafile.hpp @@ -26,7 +26,6 @@ #ifndef OPENMW_COMPONENTS_BSA_COMPRESSEDBSAFILE_HPP #define OPENMW_COMPONENTS_BSA_COMPRESSEDBSAFILE_HPP -#include #include #include @@ -112,7 +111,7 @@ namespace Bsa FileRecord getFileRecord(std::string_view str) const; /// \brief Normalizes given filename or folder and generates format-compatible hash. - static std::uint64_t generateHash(const std::filesystem::path& stem, std::string extension); + static std::uint64_t generateHash(std::string_view stem, std::string_view extension); Files::IStreamPtr getFile(const FileRecord& fileRecord); public: @@ -127,7 +126,6 @@ namespace Bsa /// Read header information from the input source void readHeader(std::istream& input) override; - Files::IStreamPtr getFile(const char* filePath); Files::IStreamPtr getFile(const FileStruct* fileStruct); void addFile(const std::string& filename, std::istream& file); }; diff --git a/components/esm4/reader.cpp b/components/esm4/reader.cpp index 93de160e5e..e041626c41 100644 --- a/components/esm4/reader.cpp +++ b/components/esm4/reader.cpp @@ -57,16 +57,16 @@ namespace ESM4 return header + ": code " + std::to_string(errorCode) + ", " + std::string(msg != nullptr ? msg : "(null)"); } - std::u8string_view getStringsSuffix(LocalizedStringType type) + std::string_view getStringsSuffix(LocalizedStringType type) { switch (type) { case LocalizedStringType::Strings: - return u8".STRINGS"; + return ".STRINGS"; case LocalizedStringType::ILStrings: - return u8".ILSTRINGS"; + return ".ILSTRINGS"; case LocalizedStringType::DLStrings: - return u8".DLSTRINGS"; + return ".DLSTRINGS"; } throw std::logic_error("Unsupported LocalizedStringType: " + std::to_string(static_cast(type))); @@ -304,29 +304,35 @@ namespace ESM4 if ((mHeader.mFlags & Rec_ESM) == 0 || (mHeader.mFlags & Rec_Localized) == 0) return; - const std::u8string prefix = mCtx.filename.stem().filename().u8string(); + const std::string prefix = Files::pathToUnicodeString(mCtx.filename.stem().filename()); buildLStringIndex(LocalizedStringType::Strings, prefix); buildLStringIndex(LocalizedStringType::ILStrings, prefix); buildLStringIndex(LocalizedStringType::DLStrings, prefix); } - void Reader::buildLStringIndex(LocalizedStringType stringType, const std::u8string& prefix) + void Reader::buildLStringIndex(LocalizedStringType stringType, std::string_view prefix) { - static const std::filesystem::path strings("Strings"); - const std::u8string language(u8"_En"); - const std::u8string altLanguage(u8"_English"); - const std::u8string suffix(getStringsSuffix(stringType)); - std::filesystem::path path = strings / (prefix + language + suffix); + const std::string_view suffix = getStringsSuffix(stringType); + constexpr std::string_view language("_En"); + constexpr std::string_view altLanguage("_English"); if (mVFS != nullptr) { - VFS::Path::Normalized vfsPath(Files::pathToUnicodeString(path)); + constexpr VFS::Path::NormalizedView strings("strings"); + std::string fileName(prefix); + fileName += language; + fileName += suffix; + VFS::Path::Normalized vfsPath(strings); + vfsPath /= fileName; Files::IStreamPtr stream = mVFS->find(vfsPath); if (stream == nullptr) { - path = strings / (prefix + altLanguage + suffix); - vfsPath = VFS::Path::Normalized(Files::pathToUnicodeString(path)); + fileName = prefix; + fileName += altLanguage; + fileName += suffix; + vfsPath = strings; + vfsPath /= fileName; stream = mVFS->find(vfsPath); } @@ -337,28 +343,33 @@ namespace ESM4 } if (mIgnoreMissingLocalizedStrings) - { Log(Debug::Warning) << "Ignore missing VFS strings file: " << vfsPath; + } + else + { + static const std::filesystem::path strings("Strings"); + std::string fileName(prefix); + fileName += language; + fileName += suffix; + std::filesystem::path fsPath = mCtx.filename.parent_path() / strings / fileName; + if (!std::filesystem::exists(fsPath)) + { + fileName = prefix; + fileName += altLanguage; + fileName += suffix; + fsPath = mCtx.filename.parent_path() / strings / fileName; + } + + if (std::filesystem::exists(fsPath)) + { + const Files::IStreamPtr stream = Files::openConstrainedFileStream(fsPath); + buildLStringIndex(stringType, *stream); return; } - } - std::filesystem::path fsPath = mCtx.filename.parent_path() / path; - if (!std::filesystem::exists(fsPath)) - { - path = strings / (prefix + altLanguage + suffix); - fsPath = mCtx.filename.parent_path() / path; + if (mIgnoreMissingLocalizedStrings) + Log(Debug::Warning) << "Ignore missing strings file: " << fsPath; } - - if (std::filesystem::exists(fsPath)) - { - const Files::IStreamPtr stream = Files::openConstrainedFileStream(fsPath); - buildLStringIndex(stringType, *stream); - return; - } - - if (mIgnoreMissingLocalizedStrings) - Log(Debug::Warning) << "Ignore missing strings file: " << fsPath; } void Reader::buildLStringIndex(LocalizedStringType stringType, std::istream& stream) diff --git a/components/esm4/reader.hpp b/components/esm4/reader.hpp index e8be484355..0f026e09b3 100644 --- a/components/esm4/reader.hpp +++ b/components/esm4/reader.hpp @@ -167,7 +167,7 @@ namespace ESM4 bool mIgnoreMissingLocalizedStrings = false; - void buildLStringIndex(LocalizedStringType stringType, const std::u8string& prefix); + void buildLStringIndex(LocalizedStringType stringType, std::string_view prefix); void buildLStringIndex(LocalizedStringType stringType, std::istream& stream); diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 5a1198a54b..91b030a9b6 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -289,8 +289,9 @@ namespace Gui MyGUI::IntSize bookSize = getBookSize(layersStream.get()); float bookScale = MyGUIPlatform::ScalingLayer::getScaleFactor(bookSize); - const auto oldDataPath = dataManager->getDataPath({}); - dataManager->setResourcePath("fonts"); + const VFS::Path::Normalized oldDataPath(dataManager->getResourcePath()); + constexpr VFS::Path::NormalizedView fonts("fonts"); + dataManager->setResourcePath(fonts); std::unique_ptr dataStream(dataManager->getData(fileName)); MyGUI::xml::Document xmlDocument; diff --git a/components/myguiplatform/myguidatamanager.cpp b/components/myguiplatform/myguidatamanager.cpp index 71e963a4ba..a5fc1531ac 100644 --- a/components/myguiplatform/myguidatamanager.cpp +++ b/components/myguiplatform/myguidatamanager.cpp @@ -5,7 +5,6 @@ #include -#include #include namespace @@ -27,12 +26,17 @@ namespace namespace MyGUIPlatform { - void DataManager::setResourcePath(const std::filesystem::path& path) + void DataManager::setResourcePath(VFS::Path::NormalizedView path) { mResourcePath = path; } - DataManager::DataManager(const std::string& resourcePath, const VFS::Manager* vfs) + VFS::Path::NormalizedView DataManager::getResourcePath() const + { + return mResourcePath; + } + + DataManager::DataManager(VFS::Path::NormalizedView resourcePath, const VFS::Manager* vfs) : mResourcePath(resourcePath) , mVfs(vfs) { @@ -40,7 +44,9 @@ namespace MyGUIPlatform MyGUI::IDataStream* DataManager::getData(const std::string& name) const { - return new DataStream(mVfs->get(Files::pathToUnicodeString(mResourcePath / name))); + VFS::Path::Normalized path(mResourcePath); + path /= name; + return new DataStream(mVfs->get(path)); } void DataManager::freeData(MyGUI::IDataStream* data) @@ -50,7 +56,9 @@ namespace MyGUIPlatform bool DataManager::isDataExist(const std::string& name) const { - return mVfs->exists(Files::pathToUnicodeString(mResourcePath / name)); + VFS::Path::Normalized path(mResourcePath); + path /= name; + return mVfs->exists(path); } const MyGUI::VectorString& DataManager::getDataListNames(const std::string& /*pattern*/) const @@ -60,15 +68,12 @@ namespace MyGUIPlatform std::string DataManager::getDataPath(const std::string& name) const { - if (name.empty()) - { - return Files::pathToUnicodeString(mResourcePath); - } - - if (!isDataExist(name)) + VFS::Path::Normalized path(mResourcePath); + path /= name; + if (!mVfs->exists(path)) return {}; - return Files::pathToUnicodeString(mResourcePath / name); + return path; } } diff --git a/components/myguiplatform/myguidatamanager.hpp b/components/myguiplatform/myguidatamanager.hpp index 427d2aa2c4..efc386e34b 100644 --- a/components/myguiplatform/myguidatamanager.hpp +++ b/components/myguiplatform/myguidatamanager.hpp @@ -3,9 +3,10 @@ #include -#include #include +#include + namespace VFS { class Manager; @@ -17,9 +18,10 @@ namespace MyGUIPlatform class DataManager : public MyGUI::DataManager { public: - explicit DataManager(const std::string& path, const VFS::Manager* vfs); + explicit DataManager(VFS::Path::NormalizedView path, const VFS::Manager* vfs); - void setResourcePath(const std::filesystem::path& path); + void setResourcePath(VFS::Path::NormalizedView path); + VFS::Path::NormalizedView getResourcePath() const; /** Get data stream from specified resource name. @param name Resource name (usually file name). @@ -48,7 +50,7 @@ namespace MyGUIPlatform std::string getDataPath(const std::string& name) const override; private: - std::filesystem::path mResourcePath; + VFS::Path::Normalized mResourcePath; const VFS::Manager* mVfs; }; diff --git a/components/myguiplatform/myguiplatform.cpp b/components/myguiplatform/myguiplatform.cpp index 9d24e13ca1..d2774f9528 100644 --- a/components/myguiplatform/myguiplatform.cpp +++ b/components/myguiplatform/myguiplatform.cpp @@ -4,17 +4,15 @@ #include "myguiloglistener.hpp" #include "myguirendermanager.hpp" -#include "components/files/conversion.hpp" - namespace MyGUIPlatform { Platform::Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ImageManager* imageManager, - const VFS::Manager* vfs, float uiScalingFactor, const std::filesystem::path& resourcePath, + const VFS::Manager* vfs, float uiScalingFactor, VFS::Path::NormalizedView resourcePath, const std::filesystem::path& logName) : mLogFacility(logName.empty() ? nullptr : std::make_unique(logName, false)) , mLogManager(std::make_unique()) - , mDataManager(std::make_unique(Files::pathToUnicodeString(resourcePath), vfs)) + , mDataManager(std::make_unique(resourcePath, vfs)) , mRenderManager(std::make_unique(viewer, guiRoot, imageManager, uiScalingFactor)) { if (mLogFacility != nullptr) diff --git a/components/myguiplatform/myguiplatform.hpp b/components/myguiplatform/myguiplatform.hpp index ff7e4a339f..be464181eb 100644 --- a/components/myguiplatform/myguiplatform.hpp +++ b/components/myguiplatform/myguiplatform.hpp @@ -5,6 +5,8 @@ #include #include +#include + namespace osgViewer { class Viewer; @@ -37,7 +39,7 @@ namespace MyGUIPlatform { public: Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ImageManager* imageManager, - const VFS::Manager* vfs, float uiScalingFactor, const std::filesystem::path& resourcePath, + const VFS::Manager* vfs, float uiScalingFactor, VFS::Path::NormalizedView resourcePath, const std::filesystem::path& logName = "MyGUI.log"); ~Platform();