2727#include < algorithm>
2828#include < cassert>
2929#include < cerrno>
30- #include < filesystem>
3130#include < format>
3231#include < istream>
3332#include < system_error>
3837#include < components/files/constrainedfilestream.hpp>
3938#include < components/files/conversion.hpp>
4039#include < components/files/utils.hpp>
41- #include < components/misc/strings/lower.hpp>
40+ #include < components/misc/pathhelpers.hpp>
41+ #include < components/vfs/pathutil.hpp>
4242
4343#include " memorystream.hpp"
4444
@@ -218,26 +218,26 @@ namespace Bsa
218218 }
219219 }
220220
221- #ifdef _WIN32
222- const auto & path = str;
223- #else
224- // Force-convert the path into something UNIX can handle first
225- // to make sure std::filesystem::path doesn't think the entire path is the filename on Linux
226- // and subsequently purge it to determine the file folder.
227- std::string path (str);
228- std::replace (path.begin (), path.end (), ' \\ ' , ' /' );
229- #endif
221+ const VFS::Path::Normalized path (str);
230222
231- const auto p = std::filesystem::path{ path }; // Purposefully damage Unicode strings.
232- const auto stem = p.stem ();
233- const auto ext = p.extension ().string (); // Purposefully damage Unicode strings.
223+ const std::string_view stem = path.stem ();
224+ const std::string_view folder = path.parent ().value ();
234225
235- std::uint64_t folderHash = generateHash (p. parent_path () , {});
226+ std::uint64_t folderHash = generateHash (folder , {});
236227
237228 auto it = mFolders .find (folderHash);
238229 if (it == mFolders .end ())
239230 return FileRecord ();
240231
232+ const std::string_view file = path.filename ().value ();
233+ std::string_view ext;
234+ if (const std::size_t pos = Misc::findExtension (file); pos != std::string_view::npos)
235+ {
236+ // ext including .
237+ ext = file;
238+ ext.remove_prefix (pos);
239+ }
240+
241241 std::uint64_t fileHash = generateHash (stem, ext);
242242 auto iter = it->second .mFiles .find (fileHash);
243243 if (iter == it->second .mFiles .end ())
@@ -262,16 +262,6 @@ namespace Bsa
262262 fail (" Add file is not implemented for compressed BSA: " + filename);
263263 }
264264
265- Files::IStreamPtr CompressedBSAFile::getFile (const char * file)
266- {
267- FileRecord fileRec = getFileRecord (file);
268- if (fileRec.mOffset == std::numeric_limits<uint32_t >::max ())
269- {
270- fail (" File not found: " + std::string (file));
271- }
272- return getFile (fileRec);
273- }
274-
275265 Files::IStreamPtr CompressedBSAFile::getFile (const FileRecord& fileRecord)
276266 {
277267 size_t size = fileRecord.mSize & (~FileSizeFlag_Compression);
@@ -337,29 +327,31 @@ namespace Bsa
337327 return std::make_unique<Files::StreamWithBuffer<MemoryInputStream>>(std::move (memoryStreamPtr));
338328 }
339329
340- std::uint64_t CompressedBSAFile::generateHash (const std::filesystem::path& stem , std::string extension)
330+ std::uint64_t CompressedBSAFile::generateHash (std::string_view str , std::string_view extension)
341331 {
342- auto str = stem.u8string ();
343- size_t len = str.length ();
344- if (len == 0 )
332+ if (str.empty ())
345333 return 0 ;
346- std::replace (str.begin (), str.end (), ' /' , ' \\ ' );
347- Misc::StringUtils::lowerCaseInPlace (str);
348- uint64_t result = str[len - 1 ];
334+ const auto at = [&](std::size_t i) -> char {
335+ const char c = str[i];
336+ if (c == ' /' )
337+ return ' \\ ' ;
338+ return c;
339+ };
340+ const size_t len = str.length ();
341+ uint64_t result = at (len - 1 );
349342 if (len >= 3 )
350- result |= str[ len - 2 ] << 8 ;
343+ result |= at ( len - 2 ) << 8 ;
351344 result |= len << 16 ;
352- result |= static_cast <uint32_t >(str[ 0 ] << 24 );
345+ result |= static_cast <uint32_t >(at ( 0 ) << 24 );
353346 if (len >= 4 )
354347 {
355348 uint32_t hash = 0 ;
356349 for (size_t i = 1 ; i <= len - 3 ; ++i)
357- hash = hash * 0x1003f + str[i] ;
350+ hash = hash * 0x1003f + at (i) ;
358351 result += static_cast <uint64_t >(hash) << 32 ;
359352 }
360353 if (extension.empty ())
361354 return result;
362- Misc::StringUtils::lowerCaseInPlace (extension);
363355 if (extension == " .kf" )
364356 result |= 0x80 ;
365357 else if (extension == " .nif" )
0 commit comments