@@ -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
3062bool Misc::ResourceHelpers::changeExtensionToDds (std::string& path)
@@ -36,38 +68,29 @@ bool Misc::ResourceHelpers::changeExtensionToDds(std::string& path)
3668std::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
103123std::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
108128std::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
113133std::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
118138std::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.
0 commit comments