mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-08-03 07:16:31 -04:00
Fix path handling for files in BSAs
This commit is contained in:
parent
53feb29a5b
commit
206d38f3d7
@ -155,7 +155,7 @@ namespace
|
||||
|
||||
VFS::Manager vfs;
|
||||
|
||||
VFS::registerArchives(&vfs, fileCollections, archives, true);
|
||||
VFS::registerArchives(&vfs, fileCollections, archives, true, &encoder.getStatelessEncoder());
|
||||
|
||||
Settings::Manager::load(config);
|
||||
|
||||
|
@ -113,7 +113,8 @@ namespace
|
||||
|
||||
void compile(const std::string& name)
|
||||
{
|
||||
mTechnique = std::make_unique<Technique>(*mVFS.get(), mImageManager, name, 1, 1, true, true);
|
||||
mTechnique = std::make_unique<Technique>(
|
||||
*mVFS.get(), mImageManager, Technique::makeFileName(name), name, 1, 1, true, true);
|
||||
mTechnique->compile();
|
||||
}
|
||||
};
|
||||
|
@ -189,7 +189,7 @@ namespace NavMeshTool
|
||||
|
||||
VFS::Manager vfs;
|
||||
|
||||
VFS::registerArchives(&vfs, fileCollections, archives, true);
|
||||
VFS::registerArchives(&vfs, fileCollections, archives, true, &encoder.getStatelessEncoder());
|
||||
|
||||
Settings::Manager::load(config);
|
||||
|
||||
|
@ -113,7 +113,7 @@ bool isBSA(const std::filesystem::path& path)
|
||||
std::unique_ptr<VFS::Archive> makeArchive(const std::filesystem::path& path)
|
||||
{
|
||||
if (isBSA(path))
|
||||
return VFS::makeBsaArchive(path);
|
||||
return VFS::makeBsaArchive(path, nullptr);
|
||||
if (std::filesystem::is_directory(path))
|
||||
return std::make_unique<VFS::FileSystemArchive>(path);
|
||||
return nullptr;
|
||||
@ -198,7 +198,7 @@ void readVFS(std::unique_ptr<VFS::Archive>&& archive, const std::filesystem::pat
|
||||
{
|
||||
try
|
||||
{
|
||||
readVFS(VFS::makeBsaArchive(file.second), file.second, quiet);
|
||||
readVFS(VFS::makeBsaArchive(file.second, nullptr), file.second, quiet);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
@ -143,7 +143,7 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
|
||||
, mArchives(archives)
|
||||
, mVFS(std::make_unique<VFS::Manager>())
|
||||
{
|
||||
VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths), mArchives, true);
|
||||
VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths), mArchives, true, &mEncoder.getStatelessEncoder());
|
||||
|
||||
mResourcesManager.setVFS(mVFS.get());
|
||||
|
||||
@ -1465,7 +1465,7 @@ std::vector<ESM::RefId> CSMWorld::Data::getIds(bool listDeleted) const
|
||||
void CSMWorld::Data::assetsChanged()
|
||||
{
|
||||
mVFS.get()->reset();
|
||||
VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths), mArchives, true);
|
||||
VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths), mArchives, true, &mEncoder.getStatelessEncoder());
|
||||
|
||||
const UniversalId assetTableIds[] = { UniversalId::Type_Meshes, UniversalId::Type_Icons, UniversalId::Type_Musics,
|
||||
UniversalId::Type_SoundsRes, UniversalId::Type_Textures, UniversalId::Type_Videos };
|
||||
|
@ -729,7 +729,7 @@ void OMW::Engine::prepareEngine()
|
||||
|
||||
mVFS = std::make_unique<VFS::Manager>();
|
||||
|
||||
VFS::registerArchives(mVFS.get(), mFileCollections, mArchives, true);
|
||||
VFS::registerArchives(mVFS.get(), mFileCollections, mArchives, true, &mEncoder.get()->getStatelessEncoder());
|
||||
|
||||
mResourceSystem = std::make_unique<Resource::ResourceSystem>(
|
||||
mVFS.get(), Settings::cells().mCacheExpiryDelay, &mEncoder.get()->getStatelessEncoder());
|
||||
|
@ -33,6 +33,14 @@
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::shared_ptr<fx::Technique>& getTechnique(const MyGUI::ListBox& list, size_t selected)
|
||||
{
|
||||
return *list.getItemDataAt<std::shared_ptr<fx::Technique>>(selected);
|
||||
}
|
||||
}
|
||||
|
||||
void PostProcessorHud::ListWrapper::onKeyButtonPressed(MyGUI::KeyCode key, MyGUI::Char ch)
|
||||
{
|
||||
if (MyGUI::InputManager::getInstance().isShiftPressed()
|
||||
@ -117,7 +125,7 @@ namespace MWGui
|
||||
if (index >= sender->getItemCount())
|
||||
return;
|
||||
|
||||
updateConfigView(sender->getItemNameAt(index));
|
||||
updateConfigView(getTechnique(*sender, index)->getFileName());
|
||||
}
|
||||
|
||||
void PostProcessorHud::toggleTechnique(bool enabled)
|
||||
@ -131,7 +139,7 @@ namespace MWGui
|
||||
auto* processor = MWBase::Environment::get().getWorld()->getPostProcessor();
|
||||
mOverrideHint = list->getItemNameAt(selected);
|
||||
|
||||
auto technique = *list->getItemDataAt<std::shared_ptr<fx::Technique>>(selected);
|
||||
auto technique = getTechnique(*list, selected);
|
||||
if (technique->getDynamic())
|
||||
return;
|
||||
|
||||
@ -167,7 +175,7 @@ namespace MWGui
|
||||
|
||||
if (static_cast<size_t>(index) != selected)
|
||||
{
|
||||
auto technique = *mActiveList->getItemDataAt<std::shared_ptr<fx::Technique>>(selected);
|
||||
auto technique = getTechnique(*mActiveList, selected);
|
||||
if (technique->getDynamic() || technique->getInternal())
|
||||
return;
|
||||
|
||||
@ -290,16 +298,16 @@ namespace MWGui
|
||||
return;
|
||||
|
||||
if (mInactiveList->getIndexSelected() != MyGUI::ITEM_NONE)
|
||||
updateConfigView(mInactiveList->getItemNameAt(mInactiveList->getIndexSelected()));
|
||||
updateConfigView(getTechnique(*mInactiveList, mInactiveList->getIndexSelected())->getFileName());
|
||||
else if (mActiveList->getIndexSelected() != MyGUI::ITEM_NONE)
|
||||
updateConfigView(mActiveList->getItemNameAt(mActiveList->getIndexSelected()));
|
||||
updateConfigView(getTechnique(*mActiveList, mActiveList->getIndexSelected())->getFileName());
|
||||
}
|
||||
|
||||
void PostProcessorHud::updateConfigView(const std::string& name)
|
||||
void PostProcessorHud::updateConfigView(VFS::Path::NormalizedView path)
|
||||
{
|
||||
auto* processor = MWBase::Environment::get().getWorld()->getPostProcessor();
|
||||
|
||||
auto technique = processor->loadTechnique(name);
|
||||
auto technique = processor->loadTechnique(path);
|
||||
|
||||
if (technique->getStatus() == fx::Technique::Status::File_Not_exists)
|
||||
return;
|
||||
@ -423,22 +431,22 @@ namespace MWGui
|
||||
|
||||
auto* processor = MWBase::Environment::get().getWorld()->getPostProcessor();
|
||||
|
||||
std::vector<std::string> techniques;
|
||||
for (const auto& [name, _] : processor->getTechniqueMap())
|
||||
techniques.push_back(name);
|
||||
std::sort(techniques.begin(), techniques.end(), Misc::StringUtils::ciLess);
|
||||
std::vector<VFS::Path::NormalizedView> techniques;
|
||||
for (const auto& vfsPath : processor->getTechniqueFiles())
|
||||
techniques.emplace_back(vfsPath);
|
||||
std::sort(techniques.begin(), techniques.end());
|
||||
|
||||
for (const std::string& name : techniques)
|
||||
for (VFS::Path::NormalizedView path : techniques)
|
||||
{
|
||||
auto technique = processor->loadTechnique(name);
|
||||
auto technique = processor->loadTechnique(path);
|
||||
|
||||
if (!technique->getHidden() && !processor->isTechniqueEnabled(technique))
|
||||
{
|
||||
std::string lowerName = Utf8Stream::lowerCaseUtf8(name);
|
||||
std::string lowerName = Utf8Stream::lowerCaseUtf8(technique->getName());
|
||||
std::string lowerCaption = mFilter->getCaption();
|
||||
lowerCaption = Utf8Stream::lowerCaseUtf8(lowerCaption);
|
||||
if (lowerName.find(lowerCaption) != std::string::npos)
|
||||
mInactiveList->addItem(name, technique);
|
||||
mInactiveList->addItem(technique->getName(), technique);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <MyGUI_ListBox.h>
|
||||
|
||||
#include <components/settings/shadermanager.hpp>
|
||||
#include <components/vfs/pathutil.hpp>
|
||||
|
||||
namespace MyGUI
|
||||
{
|
||||
@ -48,7 +49,7 @@ namespace MWGui
|
||||
|
||||
void notifyFilterChanged(MyGUI::EditBox* sender);
|
||||
|
||||
void updateConfigView(const std::string& name);
|
||||
void updateConfigView(VFS::Path::NormalizedView path);
|
||||
|
||||
void notifyResetButtonClicked(MyGUI::Widget* sender);
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <osg/Texture3D>
|
||||
|
||||
#include <components/files/conversion.hpp>
|
||||
#include <components/misc/pathhelpers.hpp>
|
||||
#include <components/misc/strings/algorithm.hpp>
|
||||
#include <components/misc/strings/lower.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
@ -250,14 +251,12 @@ namespace MWRender
|
||||
|
||||
void PostProcessor::populateTechniqueFiles()
|
||||
{
|
||||
for (const auto& name : mVFS->getRecursiveDirectoryIterator(fx::Technique::sSubdir))
|
||||
for (const auto& path : mVFS->getRecursiveDirectoryIterator(fx::Technique::sSubdir))
|
||||
{
|
||||
std::filesystem::path path = Files::pathFromUnicodeString(name);
|
||||
std::string fileExt = Misc::StringUtils::lowerCase(Files::pathToUnicodeString(path.extension()));
|
||||
if (!path.parent_path().has_parent_path() && fileExt == fx::Technique::sExt)
|
||||
std::string_view fileExt = Misc::getFileExtension(path);
|
||||
if (path.parent().parent().empty() && fileExt == fx::Technique::sExt)
|
||||
{
|
||||
const auto absolutePath = mVFS->getAbsoluteFileName(path);
|
||||
mTechniqueFileMap[Files::pathToUnicodeString(absolutePath.stem())] = absolutePath;
|
||||
mTechniqueFiles.emplace(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -351,7 +350,7 @@ namespace MWRender
|
||||
if (technique->getStatus() == fx::Technique::Status::File_Not_exists)
|
||||
continue;
|
||||
|
||||
const auto lastWriteTime = std::filesystem::last_write_time(mTechniqueFileMap[technique->getName()]);
|
||||
const auto lastWriteTime = mVFS->getLastModified(technique->getFileName());
|
||||
const bool isDirty = technique->setLastModificationTime(lastWriteTime);
|
||||
|
||||
if (!isDirty)
|
||||
@ -363,7 +362,7 @@ namespace MWRender
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
|
||||
if (technique->compile())
|
||||
Log(Debug::Info) << "Reloaded technique : " << mTechniqueFileMap[technique->getName()];
|
||||
Log(Debug::Info) << "Reloaded technique : " << technique->getFileName();
|
||||
|
||||
mReload = technique->isValid();
|
||||
}
|
||||
@ -750,27 +749,31 @@ namespace MWRender
|
||||
}
|
||||
|
||||
std::shared_ptr<fx::Technique> PostProcessor::loadTechnique(const std::string& name, bool loadNextFrame)
|
||||
{
|
||||
VFS::Path::Normalized path = fx::Technique::makeFileName(name);
|
||||
return loadTechnique(VFS::Path::NormalizedView(path), loadNextFrame);
|
||||
}
|
||||
|
||||
std::shared_ptr<fx::Technique> PostProcessor::loadTechnique(VFS::Path::NormalizedView path, bool loadNextFrame)
|
||||
{
|
||||
for (const auto& technique : mTemplates)
|
||||
if (Misc::StringUtils::ciEqual(technique->getName(), name))
|
||||
if (technique->getFileName() == path)
|
||||
return technique;
|
||||
|
||||
for (const auto& technique : mQueuedTemplates)
|
||||
if (Misc::StringUtils::ciEqual(technique->getName(), name))
|
||||
if (technique->getFileName() == path)
|
||||
return technique;
|
||||
|
||||
std::string realName = name;
|
||||
auto fileIter = mTechniqueFileMap.find(name);
|
||||
if (fileIter != mTechniqueFileMap.end())
|
||||
realName = fileIter->first;
|
||||
if (!mTechniqueFiles.contains(path))
|
||||
return {};
|
||||
|
||||
auto technique = std::make_shared<fx::Technique>(*mVFS, *mRendering.getResourceSystem()->getImageManager(),
|
||||
std::move(realName), renderWidth(), renderHeight(), mUBO, mNormalsSupported);
|
||||
path, mVFS->getStem(path), renderWidth(), renderHeight(), mUBO, mNormalsSupported);
|
||||
|
||||
technique->compile();
|
||||
|
||||
if (technique->getStatus() != fx::Technique::Status::File_Not_exists)
|
||||
technique->setLastModificationTime(std::filesystem::last_write_time(fileIter->second));
|
||||
technique->setLastModificationTime(mVFS->getLastModified(path));
|
||||
|
||||
if (loadNextFrame)
|
||||
{
|
||||
@ -802,7 +805,10 @@ namespace MWRender
|
||||
if (techniqueName.empty())
|
||||
continue;
|
||||
|
||||
mTechniques.push_back(loadTechnique(techniqueName));
|
||||
auto technique = loadTechnique(techniqueName);
|
||||
if (!technique)
|
||||
continue;
|
||||
mTechniques.push_back(std::move(technique));
|
||||
}
|
||||
|
||||
dirtyTechniques();
|
||||
|
@ -128,7 +128,7 @@ namespace MWRender
|
||||
|
||||
const TechniqueList& getTemplates() const { return mTemplates; }
|
||||
|
||||
const auto& getTechniqueMap() const { return mTechniqueFileMap; }
|
||||
const auto& getTechniqueFiles() const { return mTechniqueFiles; }
|
||||
|
||||
void resize();
|
||||
|
||||
@ -176,6 +176,7 @@ namespace MWRender
|
||||
|
||||
void toggleMode();
|
||||
|
||||
std::shared_ptr<fx::Technique> loadTechnique(VFS::Path::NormalizedView path, bool loadNextFrame = false);
|
||||
std::shared_ptr<fx::Technique> loadTechnique(const std::string& name, bool loadNextFrame = false);
|
||||
|
||||
TechniqueList getChain();
|
||||
@ -232,8 +233,7 @@ namespace MWRender
|
||||
TechniqueList mQueuedTemplates;
|
||||
TechniqueList mInternalTechniques;
|
||||
|
||||
std::unordered_map<std::string, std::filesystem::path, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual>
|
||||
mTechniqueFileMap;
|
||||
std::unordered_set<VFS::Path::Normalized, VFS::Path::Hash, std::equal_to<>> mTechniqueFiles;
|
||||
|
||||
RenderingManager& mRendering;
|
||||
osgViewer::Viewer* mViewer;
|
||||
|
@ -50,6 +50,7 @@ namespace Bsa
|
||||
public:
|
||||
using BSAFile::getFilename;
|
||||
using BSAFile::getList;
|
||||
using BSAFile::getPath;
|
||||
using BSAFile::open;
|
||||
|
||||
BA2DX10File();
|
||||
|
@ -38,6 +38,7 @@ namespace Bsa
|
||||
public:
|
||||
using BSAFile::getFilename;
|
||||
using BSAFile::getList;
|
||||
using BSAFile::getPath;
|
||||
using BSAFile::open;
|
||||
|
||||
BA2GNRLFile();
|
||||
|
@ -84,15 +84,15 @@ namespace Bsa
|
||||
protected:
|
||||
bool mHasChanged = false;
|
||||
|
||||
/// True when an archive has been loaded
|
||||
bool mIsLoaded = false;
|
||||
|
||||
/// Table of files in this archive
|
||||
FileList mFiles;
|
||||
|
||||
/// Filename string buffer
|
||||
std::vector<char> mStringBuf;
|
||||
|
||||
/// True when an archive has been loaded
|
||||
bool mIsLoaded;
|
||||
|
||||
/// Used for error messages
|
||||
std::filesystem::path mFilepath;
|
||||
|
||||
@ -109,11 +109,6 @@ namespace Bsa
|
||||
* -----------------------------------
|
||||
*/
|
||||
|
||||
BSAFile()
|
||||
: mIsLoaded(false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~BSAFile()
|
||||
{
|
||||
close();
|
||||
@ -148,6 +143,11 @@ namespace Bsa
|
||||
return Files::pathToUnicodeString(mFilepath);
|
||||
}
|
||||
|
||||
const std::filesystem::path& getPath() const
|
||||
{
|
||||
return mFilepath;
|
||||
}
|
||||
|
||||
// checks version of BSA from file header
|
||||
static BsaVersion detectVersion(const std::filesystem::path& filePath);
|
||||
};
|
||||
|
@ -117,6 +117,7 @@ namespace Bsa
|
||||
public:
|
||||
using BSAFile::getFilename;
|
||||
using BSAFile::getList;
|
||||
using BSAFile::getPath;
|
||||
using BSAFile::open;
|
||||
|
||||
CompressedBSAFile() = default;
|
||||
|
@ -37,22 +37,20 @@ namespace
|
||||
|
||||
namespace fx
|
||||
{
|
||||
namespace
|
||||
{
|
||||
VFS::Path::Normalized makeFilePath(std::string_view name)
|
||||
VFS::Path::Normalized Technique::makeFileName(std::string_view name)
|
||||
{
|
||||
std::string fileName(name);
|
||||
fileName += '.';
|
||||
fileName += Technique::sExt;
|
||||
VFS::Path::Normalized result(Technique::sSubdir);
|
||||
result /= fileName;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Technique::Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, std::string name, int width,
|
||||
int height, bool ubo, bool supportsNormals)
|
||||
Technique::Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager,
|
||||
VFS::Path::NormalizedView fileName, std::string name, int width, int height, bool ubo, bool supportsNormals)
|
||||
: mName(std::move(name))
|
||||
, mFilePath(makeFilePath(mName))
|
||||
, mFilePath(fileName)
|
||||
, mLastModificationTime(std::filesystem::file_time_type::clock::now())
|
||||
, mWidth(width)
|
||||
, mHeight(height)
|
||||
|
@ -105,8 +105,8 @@ namespace fx
|
||||
using UniformMap = std::vector<std::shared_ptr<Types::UniformBase>>;
|
||||
using RenderTargetMap = std::unordered_map<std::string_view, Types::RenderTarget>;
|
||||
|
||||
static constexpr std::string_view sExt = ".omwfx";
|
||||
static constexpr std::string_view sSubdir = "shaders";
|
||||
static constexpr std::string_view sExt = "omwfx";
|
||||
static constexpr VFS::Path::NormalizedView sSubdir{ "shaders" };
|
||||
|
||||
enum class Status
|
||||
{
|
||||
@ -123,8 +123,10 @@ namespace fx
|
||||
static constexpr FlagsType Flag_Disable_SunGlare = (1 << 4);
|
||||
static constexpr FlagsType Flag_Hidden = (1 << 5);
|
||||
|
||||
Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, std::string name, int width,
|
||||
int height, bool ubo, bool supportsNormals);
|
||||
static VFS::Path::Normalized makeFileName(std::string_view name);
|
||||
|
||||
Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, VFS::Path::NormalizedView fileName,
|
||||
std::string name, int width, int height, bool ubo, bool supportsNormals);
|
||||
|
||||
bool compile();
|
||||
|
||||
|
@ -56,7 +56,9 @@ namespace TestingOpenMW
|
||||
|
||||
Files::IStreamPtr open() override { return std::make_unique<std::stringstream>(mContent, std::ios_base::in); }
|
||||
|
||||
std::filesystem::path getPath() override { return "TestFile"; }
|
||||
std::filesystem::file_time_type getLastModified() const override { return {}; }
|
||||
|
||||
std::string getStem() const override { return "TestFile"; }
|
||||
|
||||
private:
|
||||
const std::string mContent;
|
||||
|
@ -10,45 +10,72 @@
|
||||
#include <components/bsa/bsafile.hpp>
|
||||
#include <components/bsa/compressedbsafile.hpp>
|
||||
|
||||
#include <components/toutf8/toutf8.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace VFS
|
||||
{
|
||||
template <typename BSAFileType>
|
||||
class BsaArchive;
|
||||
|
||||
template <typename FileType>
|
||||
class BsaArchiveFile : public File
|
||||
{
|
||||
public:
|
||||
BsaArchiveFile(const Bsa::BSAFile::FileStruct* info, FileType* bsa)
|
||||
BsaArchiveFile(const Bsa::BSAFile::FileStruct* info, const BsaArchive<FileType>* bsa)
|
||||
: mInfo(info)
|
||||
, mFile(bsa)
|
||||
{
|
||||
}
|
||||
|
||||
Files::IStreamPtr open() override { return mFile->getFile(mInfo); }
|
||||
Files::IStreamPtr open() override { return mFile->getFile()->getFile(mInfo); }
|
||||
|
||||
std::filesystem::path getPath() override { return mInfo->name(); }
|
||||
std::filesystem::file_time_type getLastModified() const override
|
||||
{
|
||||
return std::filesystem::last_write_time(mFile->getFile()->getPath());
|
||||
}
|
||||
|
||||
std::string getStem() const override
|
||||
{
|
||||
std::string_view name = mInfo->name();
|
||||
auto index = name.find_last_of("\\/");
|
||||
if (index != std::string_view::npos)
|
||||
name = name.substr(index + 1);
|
||||
index = name.find_last_of('.');
|
||||
if (index != std::string_view::npos && index != 0)
|
||||
name = name.substr(0, index);
|
||||
std::string out;
|
||||
std::string_view utf8 = mFile->getUtf8(name, out);
|
||||
if (out.data() == utf8.data())
|
||||
out.resize(utf8.size());
|
||||
else
|
||||
out = utf8;
|
||||
return out;
|
||||
}
|
||||
|
||||
const Bsa::BSAFile::FileStruct* mInfo;
|
||||
FileType* mFile;
|
||||
const BsaArchive<FileType>* mFile;
|
||||
};
|
||||
|
||||
template <typename BSAFileType>
|
||||
class BsaArchive : public Archive
|
||||
{
|
||||
public:
|
||||
BsaArchive(const std::filesystem::path& filename)
|
||||
BsaArchive(const std::filesystem::path& filename, const ToUTF8::StatelessUtf8Encoder* encoder)
|
||||
: Archive()
|
||||
, mEncoder(encoder)
|
||||
{
|
||||
mFile = std::make_unique<BSAFileType>();
|
||||
mFile->open(filename);
|
||||
|
||||
const Bsa::BSAFile::FileList& filelist = mFile->getList();
|
||||
for (Bsa::BSAFile::FileList::const_iterator it = filelist.begin(); it != filelist.end(); ++it)
|
||||
std::string buffer;
|
||||
for (const Bsa::BSAFile::FileStruct& file : mFile->getList())
|
||||
{
|
||||
mResources.emplace_back(&*it, mFile.get());
|
||||
mFiles.emplace_back(it->name());
|
||||
mResources.emplace_back(&file, this);
|
||||
mFiles.emplace_back(getUtf8(file.name(), buffer));
|
||||
}
|
||||
|
||||
std::sort(mFiles.begin(), mFiles.end());
|
||||
@ -56,8 +83,12 @@ namespace VFS
|
||||
|
||||
void listResources(FileMap& out) override
|
||||
{
|
||||
std::string buffer;
|
||||
for (auto& resource : mResources)
|
||||
out[VFS::Path::Normalized(resource.mInfo->name())] = &resource;
|
||||
{
|
||||
std::string_view path = getUtf8(resource.mInfo->name(), buffer);
|
||||
out[VFS::Path::Normalized(path)] = &resource;
|
||||
}
|
||||
}
|
||||
|
||||
bool contains(Path::NormalizedView file) const override
|
||||
@ -67,26 +98,37 @@ namespace VFS
|
||||
|
||||
std::string getDescription() const override { return std::string{ "BSA: " } + mFile->getFilename(); }
|
||||
|
||||
BSAFileType* getFile() const { return mFile.get(); }
|
||||
|
||||
std::string_view getUtf8(std::string_view input, std::string& buffer) const
|
||||
{
|
||||
if (mEncoder == nullptr)
|
||||
return input;
|
||||
return mEncoder->getUtf8(input, ToUTF8::BufferAllocationPolicy::UseGrowFactor, buffer);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<BSAFileType> mFile;
|
||||
std::vector<BsaArchiveFile<BSAFileType>> mResources;
|
||||
std::vector<VFS::Path::Normalized> mFiles;
|
||||
const ToUTF8::StatelessUtf8Encoder* mEncoder;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<VFS::Archive> makeBsaArchive(const std::filesystem::path& path)
|
||||
inline std::unique_ptr<VFS::Archive> makeBsaArchive(
|
||||
const std::filesystem::path& path, const ToUTF8::StatelessUtf8Encoder* encoder)
|
||||
{
|
||||
switch (Bsa::BSAFile::detectVersion(path))
|
||||
{
|
||||
case Bsa::BsaVersion::Unknown:
|
||||
break;
|
||||
case Bsa::BsaVersion::Uncompressed:
|
||||
return std::make_unique<BsaArchive<Bsa::BSAFile>>(path);
|
||||
return std::make_unique<BsaArchive<Bsa::BSAFile>>(path, encoder);
|
||||
case Bsa::BsaVersion::Compressed:
|
||||
return std::make_unique<BsaArchive<Bsa::CompressedBSAFile>>(path);
|
||||
return std::make_unique<BsaArchive<Bsa::CompressedBSAFile>>(path, encoder);
|
||||
case Bsa::BsaVersion::BA2GNRL:
|
||||
return std::make_unique<BsaArchive<Bsa::BA2GNRLFile>>(path);
|
||||
return std::make_unique<BsaArchive<Bsa::BA2GNRLFile>>(path, encoder);
|
||||
case Bsa::BsaVersion::BA2DX10:
|
||||
return std::make_unique<BsaArchive<Bsa::BA2DX10File>>(path);
|
||||
return std::make_unique<BsaArchive<Bsa::BA2DX10File>>(path, encoder);
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unknown archive type '" + Files::pathToUnicodeString(path) + "'");
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define OPENMW_COMPONENTS_VFS_FILE_H
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
#include <components/files/istreamptr.hpp>
|
||||
|
||||
@ -14,7 +15,9 @@ namespace VFS
|
||||
|
||||
virtual Files::IStreamPtr open() = 0;
|
||||
|
||||
virtual std::filesystem::path getPath() = 0;
|
||||
virtual std::filesystem::file_time_type getLastModified() const = 0;
|
||||
|
||||
virtual std::string getStem() const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -81,4 +81,14 @@ namespace VFS
|
||||
return Files::openConstrainedFileStream(mPath);
|
||||
}
|
||||
|
||||
std::filesystem::file_time_type FileSystemArchiveFile::getLastModified() const
|
||||
{
|
||||
return std::filesystem::last_write_time(mPath);
|
||||
}
|
||||
|
||||
std::string FileSystemArchiveFile::getStem() const
|
||||
{
|
||||
return Files::pathToUnicodeString(mPath.stem());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,7 +17,9 @@ namespace VFS
|
||||
|
||||
Files::IStreamPtr open() override;
|
||||
|
||||
std::filesystem::path getPath() override { return mPath; }
|
||||
std::filesystem::file_time_type getLastModified() const override;
|
||||
|
||||
std::string getStem() const override;
|
||||
|
||||
private:
|
||||
std::filesystem::path mPath;
|
||||
|
@ -81,15 +81,20 @@ namespace VFS
|
||||
return {};
|
||||
}
|
||||
|
||||
std::filesystem::path Manager::getAbsoluteFileName(const std::filesystem::path& name) const
|
||||
std::filesystem::file_time_type Manager::getLastModified(VFS::Path::NormalizedView name) const
|
||||
{
|
||||
std::string normalized = Files::pathToUnicodeString(name);
|
||||
Path::normalizeFilenameInPlace(normalized);
|
||||
|
||||
const auto found = mIndex.find(normalized);
|
||||
const auto found = mIndex.find(name);
|
||||
if (found == mIndex.end())
|
||||
throw std::runtime_error("Resource '" + normalized + "' is not found");
|
||||
return found->second->getPath();
|
||||
throw std::runtime_error("Resource '" + std::string(name.value()) + "' not found");
|
||||
return found->second->getLastModified();
|
||||
}
|
||||
|
||||
std::string Manager::getStem(VFS::Path::NormalizedView name) const
|
||||
{
|
||||
const auto found = mIndex.find(name);
|
||||
if (found == mIndex.end())
|
||||
throw std::runtime_error("Resource '" + std::string(name.value()) + "' not found");
|
||||
return found->second->getStem();
|
||||
}
|
||||
|
||||
RecursiveDirectoryRange Manager::getRecursiveDirectoryIterator(std::string_view path) const
|
||||
|
@ -72,10 +72,9 @@ namespace VFS
|
||||
|
||||
RecursiveDirectoryRange getRecursiveDirectoryIterator() const;
|
||||
|
||||
/// Retrieve the absolute path to the file
|
||||
/// @note Throws an exception if the file can not be found.
|
||||
/// @note May be called from any thread once the index has been built.
|
||||
std::filesystem::path getAbsoluteFileName(const std::filesystem::path& name) const;
|
||||
std::filesystem::file_time_type getLastModified(VFS::Path::NormalizedView name) const;
|
||||
// Equivalent to std::filesystem::path::stem. The result isn't normalized.
|
||||
std::string getStem(VFS::Path::NormalizedView name) const;
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<Archive>> mArchives;
|
||||
|
@ -127,6 +127,15 @@ namespace VFS::Path
|
||||
return stream << value.mValue;
|
||||
}
|
||||
|
||||
NormalizedView parent() const
|
||||
{
|
||||
NormalizedView p;
|
||||
const std::size_t pos = mValue.find_last_of(separator);
|
||||
if (pos != std::string_view::npos)
|
||||
p.mValue = mValue.substr(0, pos);
|
||||
return p;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string_view mValue;
|
||||
};
|
||||
@ -259,6 +268,11 @@ namespace VFS::Path
|
||||
return stream << value.mValue;
|
||||
}
|
||||
|
||||
NormalizedView parent() const
|
||||
{
|
||||
return NormalizedView(*this).parent();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string mValue;
|
||||
};
|
||||
|
@ -14,7 +14,7 @@ namespace VFS
|
||||
{
|
||||
|
||||
void registerArchives(VFS::Manager* vfs, const Files::Collections& collections,
|
||||
const std::vector<std::string>& archives, bool useLooseFiles)
|
||||
const std::vector<std::string>& archives, bool useLooseFiles, const ToUTF8::StatelessUtf8Encoder* encoder)
|
||||
{
|
||||
const Files::PathContainer& dataDirs = collections.getPaths();
|
||||
|
||||
@ -25,7 +25,7 @@ namespace VFS
|
||||
// Last BSA has the highest priority
|
||||
const auto archivePath = collections.getPath(*archive);
|
||||
Log(Debug::Info) << "Adding BSA archive " << archivePath;
|
||||
vfs->addArchive(makeBsaArchive(archivePath));
|
||||
vfs->addArchive(makeBsaArchive(archivePath, encoder));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3,13 +3,18 @@
|
||||
|
||||
#include <components/files/collections.hpp>
|
||||
|
||||
namespace ToUTF8
|
||||
{
|
||||
class StatelessUtf8Encoder;
|
||||
}
|
||||
|
||||
namespace VFS
|
||||
{
|
||||
class Manager;
|
||||
|
||||
/// @brief Register BSA and file system archives based on the given OpenMW configuration.
|
||||
void registerArchives(VFS::Manager* vfs, const Files::Collections& collections,
|
||||
const std::vector<std::string>& archives, bool useLooseFiles);
|
||||
const std::vector<std::string>& archives, bool useLooseFiles, const ToUTF8::StatelessUtf8Encoder* encoder);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user