diff --git a/Makefile.vita b/Makefile.vita index 24a4a9dd1bf..6b2be96c063 100644 --- a/Makefile.vita +++ b/Makefile.vita @@ -1,6 +1,6 @@ ########################################################################### # fheroes2: https://github.com/ihhub/fheroes2 # -# Copyright (C) 2021 - 2023 # +# Copyright (C) 2021 - 2024 # # # # This program is free software; you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # @@ -29,6 +29,7 @@ MAKE := make PROJECT_TITLE := fheroes2 PROJECT_TITLEID := FHOMM0002 +PROJECT_VERSION := $(file < version.txt) .PHONY: all clean $(TARGET).vpk param.sfo $(TARGET).elf translations @@ -56,7 +57,7 @@ eboot.bin: $(TARGET).velf vita-make-fself $(TARGET).velf eboot.bin param.sfo: - vita-mksfoex -s TITLE_ID="$(PROJECT_TITLEID)" "$(PROJECT_TITLE)" param.sfo + vita-mksfoex -s TITLE_ID="$(PROJECT_TITLEID)" -s APP_VER="$(PROJECT_VERSION)" "$(PROJECT_TITLE)" param.sfo $(TARGET).velf: $(TARGET).elf arm-vita-eabi-strip -g $< diff --git a/src/engine/dir.cpp b/src/engine/dir.cpp index ba7ed8ab4a7..27337dc02b3 100644 --- a/src/engine/dir.cpp +++ b/src/engine/dir.cpp @@ -23,9 +23,14 @@ #include "dir.h" +#include + +#if defined( TARGET_PS_VITA ) +#include +#else #include #include -#include +#endif #if defined( _WIN32 ) #include @@ -57,7 +62,7 @@ namespace return ( strCmp( filenamePtr, filter.c_str() ) == 0 ); } - void getFilesFromDirectory( const std::string_view path, const std::string & filter, const bool needExactMatch, ListFiles & files ) + void getFilesFromDirectory( const std::string & path, const std::string & filter, const bool needExactMatch, ListFiles & files ) { std::string correctedPath; if ( !System::GetCaseInsensitivePath( path, correctedPath ) ) { @@ -70,6 +75,62 @@ namespace auto * const strCmp = strcasecmp; #endif +#if defined( TARGET_PS_VITA ) + // On PS Vita, getting a list of files using std::filesystem for some reason works much slower than using the native file system API + class SceUIDWrapper + { + public: + SceUIDWrapper( const std::string & path ) + : uid( sceIoDopen( path.c_str() ) ) + {} + + SceUIDWrapper( const SceUIDWrapper & ) = delete; + + ~SceUIDWrapper() + { + if ( !isValid() ) { + return; + } + + sceIoDclose( uid ); + } + + SceUIDWrapper & operator=( const SceUIDWrapper & ) = delete; + + bool isValid() const + { + return uid >= 0; + } + + SceUID get() const + { + return uid; + } + + private: + const SceUID uid; + }; + + const SceUIDWrapper uid( path ); + if ( !uid.isValid() ) { + return; + } + + SceIoDirent entry; + + while ( sceIoDread( uid.get(), &entry ) > 0 ) { + // Ensure that this directory entry is a regular file + if ( !SCE_S_ISREG( entry.d_stat.st_mode ) ) { + continue; + } + + if ( !nameFilter( entry.d_name, needExactMatch, filter, strCmp ) ) { + continue; + } + + files.emplace_back( System::concatPath( path, entry.d_name ) ); + } +#else std::error_code ec; // Using the non-throwing overload @@ -87,6 +148,7 @@ namespace files.emplace_back( System::fsPathToString( entryPath ) ); } +#endif } } @@ -97,17 +159,30 @@ void ListFiles::Append( ListFiles && files ) } } -void ListFiles::ReadDir( const std::string_view path, const std::string & filter ) +void ListFiles::ReadDir( const std::string & path, const std::string & filter ) { getFilesFromDirectory( path, filter, false, *this ); } -void ListFiles::FindFileInDir( const std::string_view path, const std::string & fileName ) +void ListFiles::FindFileInDir( const std::string_view path, const std::string_view fileName ) { - getFilesFromDirectory( path, fileName, true, *this ); + std::string correctedFilePath; + // If the file system is case-sensitive, then here we will get the actual file path using the case-insensitive + // search (if such a file exists). If the file system is case-insensitive, we will just get the passed path to + // the file back intact. + if ( !System::GetCaseInsensitivePath( System::concatPath( path, fileName ), correctedFilePath ) ) { + return; + } + + // In case the file system is case-insensitive, we additionally check the file for existence. + if ( !System::IsFile( correctedFilePath ) ) { + return; + } + + emplace_back( std::move( correctedFilePath ) ); } -bool ListFiles::IsEmpty( const std::string_view path, const std::string & filter ) +bool ListFiles::IsEmpty( const std::string & path, const std::string & filter ) { ListFiles list; list.ReadDir( path, filter ); diff --git a/src/engine/dir.h b/src/engine/dir.h index 4ec343dec18..bc268f3a737 100644 --- a/src/engine/dir.h +++ b/src/engine/dir.h @@ -32,13 +32,13 @@ struct ListFiles : public std::list void Append( ListFiles && files ); // Adds files from the 'path' directory ending in 'filter' to the list, case-insensitive. - void ReadDir( const std::string_view path, const std::string & filter ); + void ReadDir( const std::string & path, const std::string & filter ); - // Adds files from the 'path' directory with names matching 'fileName' to the list, case-insensitive. - void FindFileInDir( const std::string_view path, const std::string & fileName ); + // Adds the first found file from the 'path' directory with a name matching 'fileName' to the list, case-insensitive. + void FindFileInDir( const std::string_view path, const std::string_view fileName ); // Returns true if there are no files in the 'path' directory with names ending in 'filter', case-insensitive, otherwise returns false. - static bool IsEmpty( const std::string_view path, const std::string & filter ); + static bool IsEmpty( const std::string & path, const std::string & filter ); }; #endif diff --git a/src/engine/system.cpp b/src/engine/system.cpp index 9ad035a6e0e..5cc24979b00 100644 --- a/src/engine/system.cpp +++ b/src/engine/system.cpp @@ -42,7 +42,7 @@ #include #endif -#if !defined( _WIN32 ) && !defined( ANDROID ) +#if !defined( _WIN32 ) && !defined( ANDROID ) && !defined( TARGET_PS_VITA ) #include #include #endif @@ -447,7 +447,7 @@ bool System::IsDirectory( const std::string_view path ) bool System::GetCaseInsensitivePath( const std::string_view path, std::string & correctedPath ) { -#if !defined( _WIN32 ) && !defined( ANDROID ) +#if !defined( _WIN32 ) && !defined( ANDROID ) && !defined( TARGET_PS_VITA ) // The following code is based on https://github.com/OneSadCookie/fcaseopen and assumes the use of POSIX IEEE Std 1003.1-2001 pathnames correctedPath.clear();