Skip to content

Commit 6692387

Browse files
committed
Use normalized path to implement correctResourcePath
1 parent 1b36214 commit 6692387

File tree

5 files changed

+103
-46
lines changed

5 files changed

+103
-46
lines changed

apps/components_tests/misc/testresourcehelpers.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ namespace Misc::ResourceHelpers
3737
TEST(MiscResourceHelpersCorrectResourcePath, shouldFallbackToGivenExtentionIfDoesNotExistInVfs)
3838
{
3939
const std::unique_ptr<const VFS::Manager> vfs = TestingOpenMW::createTestVFS({});
40-
EXPECT_EQ(correctResourcePath({ { "sound" } }, "sound/foo.wav", vfs.get(), ".mp3"), "sound/foo.mp3");
40+
EXPECT_EQ(correctResourcePath({ { "sound" } }, "sound/foo.wav", vfs.get(), "mp3"), "sound/foo.mp3");
4141
}
4242

4343
TEST(MiscResourceHelpersCorrectResourcePath, shouldFallbackToGivenExtentionIfBothExistInVfs)
@@ -48,7 +48,7 @@ namespace Misc::ResourceHelpers
4848
{ wav, nullptr },
4949
{ mp3, nullptr },
5050
});
51-
EXPECT_EQ(correctResourcePath({ { "sound" } }, wav.value(), vfs.get(), ".mp3"), "sound/foo.mp3");
51+
EXPECT_EQ(correctResourcePath({ { "sound" } }, wav.value(), vfs.get(), "mp3"), "sound/foo.mp3");
5252
}
5353

5454
TEST(MiscResourceHelpersCorrectResourcePath, shouldKeepExtentionIfExistInVfs)
@@ -57,13 +57,13 @@ namespace Misc::ResourceHelpers
5757
const std::unique_ptr<const VFS::Manager> vfs = TestingOpenMW::createTestVFS({
5858
{ wav, nullptr },
5959
});
60-
EXPECT_EQ(correctResourcePath({ { "sound" } }, wav.value(), vfs.get(), ".mp3"), "sound/foo.wav");
60+
EXPECT_EQ(correctResourcePath({ { "sound" } }, wav.value(), vfs.get(), "mp3"), "sound/foo.wav");
6161
}
6262

6363
TEST(MiscResourceHelpersCorrectResourcePath, shouldPrefixWithGivenTopDirectory)
6464
{
6565
const std::unique_ptr<const VFS::Manager> vfs = TestingOpenMW::createTestVFS({});
66-
EXPECT_EQ(correctResourcePath({ { "sound" } }, "foo.mp3", vfs.get(), ".mp3"), "sound/foo.mp3");
66+
EXPECT_EQ(correctResourcePath({ { "sound" } }, "foo.mp3", vfs.get(), "mp3"), "sound/foo.mp3");
6767
}
6868

6969
TEST(MiscResourceHelpersCorrectResourcePath, shouldChangeTopDirectoryAndKeepExtensionIfOriginalExistInVfs)
@@ -73,7 +73,7 @@ namespace Misc::ResourceHelpers
7373
{ a, nullptr },
7474
});
7575
EXPECT_EQ(
76-
correctResourcePath({ { "textures", "bookart" } }, "bookart/foo.a", vfs.get(), ".b"), "textures/foo.a");
76+
correctResourcePath({ { "textures", "bookart" } }, "bookart/foo.a", vfs.get(), "b"), "textures/foo.a");
7777
}
7878

7979
TEST(MiscResourceHelpersCorrectResourcePath, shouldChangeTopDirectoryAndChangeExtensionIfFallbackExistInVfs)
@@ -83,31 +83,31 @@ namespace Misc::ResourceHelpers
8383
{ b, nullptr },
8484
});
8585
EXPECT_EQ(
86-
correctResourcePath({ { "textures", "bookart" } }, "bookart/foo.a", vfs.get(), ".b"), "textures/foo.b");
86+
correctResourcePath({ { "textures", "bookart" } }, "bookart/foo.a", vfs.get(), "b"), "textures/foo.b");
8787
}
8888

8989
TEST(MiscResourceHelpersCorrectResourcePath, shouldLowerCase)
9090
{
9191
const std::unique_ptr<const VFS::Manager> vfs = TestingOpenMW::createTestVFS({});
92-
EXPECT_EQ(correctResourcePath({ { "sound" } }, "SOUND\\Foo.MP3", vfs.get(), ".mp3"), "sound/foo.mp3");
92+
EXPECT_EQ(correctResourcePath({ { "sound" } }, "SOUND\\Foo.MP3", vfs.get(), "mp3"), "sound/foo.mp3");
9393
}
9494

9595
TEST(MiscResourceHelpersCorrectResourcePath, shouldRemoveLeadingSlash)
9696
{
9797
const std::unique_ptr<const VFS::Manager> vfs = TestingOpenMW::createTestVFS({});
98-
EXPECT_EQ(correctResourcePath({ { "sound" } }, "\\SOUND\\Foo.MP3", vfs.get(), ".mp3"), "sound/foo.mp3");
98+
EXPECT_EQ(correctResourcePath({ { "sound" } }, "\\SOUND\\Foo.MP3", vfs.get(), "mp3"), "sound/foo.mp3");
9999
}
100100

101101
TEST(MiscResourceHelpersCorrectResourcePath, shouldRemoveDuplicateSlashes)
102102
{
103103
const std::unique_ptr<const VFS::Manager> vfs = TestingOpenMW::createTestVFS({});
104-
EXPECT_EQ(correctResourcePath({ { "sound" } }, "\\\\SOUND\\\\Foo.MP3", vfs.get(), ".mp3"), "sound/foo.mp3");
104+
EXPECT_EQ(correctResourcePath({ { "sound" } }, "\\\\SOUND\\\\Foo.MP3", vfs.get(), "mp3"), "sound/foo.mp3");
105105
}
106106

107107
TEST(MiscResourceHelpersCorrectResourcePath, shouldConvertToForwardSlash)
108108
{
109109
const std::unique_ptr<const VFS::Manager> vfs = TestingOpenMW::createTestVFS({});
110-
EXPECT_EQ(correctResourcePath({ { "sound" } }, "SOUND/Foo.MP3", vfs.get(), ".mp3"), "sound/foo.mp3");
110+
EXPECT_EQ(correctResourcePath({ { "sound" } }, "SOUND/Foo.MP3", vfs.get(), "mp3"), "sound/foo.mp3");
111111
}
112112

113113
TEST(MiscResourceHelpersCorrectResourcePath, shouldHandlePathEqualToDirectory)
@@ -123,7 +123,7 @@ namespace Misc::ResourceHelpers
123123
TEST_P(MiscResourceHelpersCorrectResourcePathShouldRemoveExtraPrefix, shouldMatchExpected)
124124
{
125125
const std::unique_ptr<const VFS::Manager> vfs = TestingOpenMW::createTestVFS({});
126-
EXPECT_EQ(correctResourcePath({ { "sound" } }, GetParam(), vfs.get(), ".mp3"), "sound/foo.mp3");
126+
EXPECT_EQ(correctResourcePath({ { "sound" } }, GetParam(), vfs.get(), "mp3"), "sound/foo.mp3");
127127
}
128128

129129
const std::vector<std::string> pathsWithPrefix = {

apps/components_tests/vfs/testpathutil.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,18 @@ namespace VFS::Path
168168
EXPECT_THROW(value.changeExtension("so/"), std::invalid_argument);
169169
}
170170

171+
TEST(VFSPathNormalizedTest, filenameShouldReturnLastComponentOfThePath)
172+
{
173+
const Normalized value("foo/bar");
174+
EXPECT_EQ(value.filename(), "bar");
175+
}
176+
177+
TEST(VFSPathNormalizedTest, filenameShouldReturnSameValueForPathWithSingleComponent)
178+
{
179+
const Normalized value("foo");
180+
EXPECT_EQ(value.filename(), "foo");
181+
}
182+
171183
template <class T>
172184
struct VFSPathNormalizedOperatorsTest : Test
173185
{
@@ -246,5 +258,17 @@ namespace VFS::Path
246258
const Normalized result = a / b;
247259
EXPECT_EQ(result.value(), "foo/bar/baz");
248260
}
261+
262+
TEST(VFSPathNormalizedViewTest, filenameShouldReturnLastComponentOfThePath)
263+
{
264+
const NormalizedView value("foo/bar");
265+
EXPECT_EQ(value.filename(), "bar");
266+
}
267+
268+
TEST(VFSPathNormalizedViewTest, filenameShouldReturnSameValueForPathWithSingleComponent)
269+
{
270+
const NormalizedView value("foo");
271+
EXPECT_EQ(value.filename(), "foo");
272+
}
249273
}
250274
}

apps/openmw/mwsound/soundbuffer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ namespace MWSound
201201
SoundBuffer* SoundBufferPool::insertSound(const ESM::RefId& soundId, const ESM4::Sound& sound)
202202
{
203203
std::string path = Misc::ResourceHelpers::correctResourcePath(
204-
{ { "sound" } }, sound.mSoundFile, MWBase::Environment::get().getResourceSystem()->getVFS(), ".mp3");
204+
{ { "sound" } }, sound.mSoundFile, MWBase::Environment::get().getResourceSystem()->getVFS(), "mp3");
205205
float volume = 1, min = 1, max = 255; // TODO: needs research
206206
SoundBuffer& sfx = mSoundBuffers.emplace_back(VFS::Path::Normalized(std::move(path)), volume, min, max);
207207
mBufferNameMap.emplace(soundId, &sfx);
@@ -211,7 +211,7 @@ namespace MWSound
211211
SoundBuffer* SoundBufferPool::insertSound(const ESM::RefId& soundId, const ESM4::SoundReference& sound)
212212
{
213213
std::string path = Misc::ResourceHelpers::correctResourcePath(
214-
{ { "sound" } }, sound.mSoundFile, MWBase::Environment::get().getResourceSystem()->getVFS(), ".mp3");
214+
{ { "sound" } }, sound.mSoundFile, MWBase::Environment::get().getResourceSystem()->getVFS(), "mp3");
215215
float volume = 1, min = 1, max = 255; // TODO: needs research
216216
// TODO: sound.mSoundId can link to another SoundReference, probably we will need to add additional lookups to
217217
// ESMStore.

components/misc/resourcehelpers.cpp

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,38 @@ namespace
2525
}
2626
return false;
2727
}
28+
29+
std::size_t findDirectory(VFS::Path::NormalizedView path, std::string_view directory)
30+
{
31+
const std::string_view pathValue = path.value();
32+
const std::size_t directorySize = directory.size();
33+
34+
for (std::size_t offset = 0, pathSize = pathValue.size(); offset < pathSize;)
35+
{
36+
const std::size_t position = pathValue.find(directory, offset);
37+
38+
if (position == std::string_view::npos)
39+
return std::string_view::npos;
40+
41+
if (position + directorySize >= pathSize)
42+
return std::string_view::npos;
43+
44+
if ((position == 0 || pathValue[position - 1] == VFS::Path::separator)
45+
&& pathValue[position + directorySize] == VFS::Path::separator)
46+
return position;
47+
48+
offset = position + directorySize;
49+
}
50+
51+
return std::string_view::npos;
52+
}
53+
54+
VFS::Path::Normalized withPrefix(VFS::Path::NormalizedView path, std::string_view prefix)
55+
{
56+
VFS::Path::Normalized prefixed(prefix);
57+
prefixed /= path;
58+
return prefixed;
59+
}
2860
}
2961

3062
bool Misc::ResourceHelpers::changeExtensionToDds(std::string& path)
@@ -36,38 +68,29 @@ bool Misc::ResourceHelpers::changeExtensionToDds(std::string& path)
3668
std::string Misc::ResourceHelpers::correctResourcePath(std::span<const std::string_view> topLevelDirectories,
3769
std::string_view resPath, const VFS::Manager* vfs, std::string_view ext)
3870
{
39-
std::string correctedPath = VFS::Path::normalizeFilename(resPath);
71+
VFS::Path::Normalized correctedPath(resPath);
4072

4173
// Handle top level directory
4274
bool needsPrefix = true;
43-
for (std::string_view potentialTopLevelDirectory : topLevelDirectories)
75+
76+
for (const std::string_view potentialTopLevelDirectory : topLevelDirectories)
4477
{
45-
if (correctedPath.starts_with(potentialTopLevelDirectory)
46-
&& correctedPath.size() > potentialTopLevelDirectory.size()
47-
&& correctedPath[potentialTopLevelDirectory.size()] == VFS::Path::separator)
78+
if (const std::size_t topLevelPos = findDirectory(correctedPath, potentialTopLevelDirectory);
79+
topLevelPos != std::string::npos)
4880
{
81+
correctedPath = VFS::Path::Normalized(correctedPath.value().substr(topLevelPos));
4982
needsPrefix = false;
5083
break;
5184
}
52-
else
53-
{
54-
std::string topLevelPrefix = std::string{ potentialTopLevelDirectory } + VFS::Path::separator;
55-
size_t topLevelPos = correctedPath.find(VFS::Path::separator + topLevelPrefix);
56-
if (topLevelPos != std::string::npos)
57-
{
58-
correctedPath.erase(0, topLevelPos + 1);
59-
needsPrefix = false;
60-
break;
61-
}
62-
}
6385
}
86+
6487
if (needsPrefix)
65-
correctedPath = std::string{ topLevelDirectories.front() } + VFS::Path::separator + correctedPath;
88+
correctedPath = withPrefix(correctedPath, topLevelDirectories.front());
6689

67-
std::string origExt = correctedPath;
90+
const VFS::Path::Normalized origExt = correctedPath;
6891

6992
// replace extension if `ext` is specified (used for .tga -> .dds, .wav -> .mp3)
70-
bool isExtChanged = !ext.empty() && changeExtension(correctedPath, ext);
93+
const bool isExtChanged = !ext.empty() && correctedPath.changeExtension(ext);
7194

7295
if (vfs->exists(correctedPath))
7396
return correctedPath;
@@ -77,18 +100,15 @@ std::string Misc::ResourceHelpers::correctResourcePath(std::span<const std::stri
77100
return origExt;
78101

79102
// fall back to a resource in the top level directory if it exists
80-
std::string fallback{ topLevelDirectories.front() };
81-
fallback += VFS::Path::separator;
82-
fallback += Misc::getFileName(correctedPath);
83-
84-
if (vfs->exists(fallback))
85-
return fallback;
103+
{
104+
const VFS::Path::Normalized fallback = withPrefix(correctedPath.filename(), topLevelDirectories.front());
105+
if (vfs->exists(fallback))
106+
return fallback;
107+
}
86108

87109
if (isExtChanged)
88110
{
89-
fallback = topLevelDirectories.front();
90-
fallback += VFS::Path::separator;
91-
fallback += Misc::getFileName(origExt);
111+
const VFS::Path::Normalized fallback = withPrefix(origExt.filename(), topLevelDirectories.front());
92112
if (vfs->exists(fallback))
93113
return fallback;
94114
}
@@ -102,17 +122,17 @@ std::string Misc::ResourceHelpers::correctResourcePath(std::span<const std::stri
102122

103123
std::string Misc::ResourceHelpers::correctTexturePath(std::string_view resPath, const VFS::Manager* vfs)
104124
{
105-
return correctResourcePath({ { "textures", "bookart" } }, resPath, vfs, ".dds");
125+
return correctResourcePath({ { "textures", "bookart" } }, resPath, vfs, "dds");
106126
}
107127

108128
std::string Misc::ResourceHelpers::correctIconPath(std::string_view resPath, const VFS::Manager* vfs)
109129
{
110-
return correctResourcePath({ { "icons" } }, resPath, vfs, ".dds");
130+
return correctResourcePath({ { "icons" } }, resPath, vfs, "dds");
111131
}
112132

113133
std::string Misc::ResourceHelpers::correctBookartPath(std::string_view resPath, const VFS::Manager* vfs)
114134
{
115-
return correctResourcePath({ { "bookart", "textures" } }, resPath, vfs, ".dds");
135+
return correctResourcePath({ { "bookart", "textures" } }, resPath, vfs, "dds");
116136
}
117137

118138
std::string Misc::ResourceHelpers::correctBookartPath(
@@ -190,9 +210,9 @@ VFS::Path::Normalized Misc::ResourceHelpers::correctSoundPath(
190210
VFS::Path::NormalizedView resPath, const VFS::Manager& vfs)
191211
{
192212
// Note: likely should be replaced with
193-
// return correctResourcePath({ { "sound" } }, resPath, vfs, ".mp3");
213+
// return correctResourcePath({ { "sound" } }, resPath, vfs, "mp3");
194214
// but there is a slight difference in behaviour:
195-
// - `correctResourcePath(..., ".mp3")` first checks `.mp3`, then tries the original extension
215+
// - `correctResourcePath(..., "mp3")` first checks `.mp3`, then tries the original extension
196216
// - the implementation below first tries the original extension, then falls back to `.mp3`.
197217

198218
// Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav.

components/vfs/pathutil.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,14 @@ namespace VFS::Path
183183
return stem;
184184
}
185185

186+
NormalizedView filename() const
187+
{
188+
NormalizedView result(*this);
189+
if (const std::size_t position = mValue.find_last_of(separator); position != std::string_view::npos)
190+
result.mValue.remove_prefix(position + 1);
191+
return result;
192+
}
193+
186194
private:
187195
std::string_view mValue;
188196
};
@@ -329,6 +337,11 @@ namespace VFS::Path
329337
return NormalizedView(*this).stem();
330338
}
331339

340+
NormalizedView filename() const
341+
{
342+
return NormalizedView(*this).filename();
343+
}
344+
332345
private:
333346
std::string mValue;
334347
};

0 commit comments

Comments
 (0)