2014-06-25 16:29:58 +00:00
# include "FileData.h"
2017-11-01 22:21:10 +00:00
2018-01-09 22:55:09 +00:00
# include "utils/FileSystemUtil.h"
2017-11-29 19:57:43 +00:00
# include "utils/StringUtil.h"
2017-11-22 21:01:12 +00:00
# include "utils/TimeUtil.h"
2017-11-01 22:21:10 +00:00
# include "AudioManager.h"
# include "CollectionSystemManager.h"
# include "FileFilterIndex.h"
2017-06-12 16:38:59 +00:00
# include "FileSorts.h"
# include "Log.h"
2018-02-09 17:23:58 +00:00
# include "MameNames.h"
2017-11-01 22:21:10 +00:00
# include "platform.h"
2018-01-30 00:49:08 +00:00
# include "Scripting.h"
2017-11-01 22:21:10 +00:00
# include "SystemData.h"
# include "VolumeControl.h"
# include "Window.h"
2018-01-29 22:50:10 +00:00
# include <assert.h>
2014-06-25 16:29:58 +00:00
2018-01-29 22:50:10 +00:00
FileData : : FileData ( FileType type , const std : : string & path , SystemEnvironmentData * envData , SystemData * system )
2017-06-12 16:38:59 +00:00
: mType ( type ) , mPath ( path ) , mSystem ( system ) , mEnvData ( envData ) , mSourceFileData ( NULL ) , mParent ( NULL ) , metadata ( type = = GAME ? GAME_METADATA : FOLDER_METADATA ) // metadata is REALLY set in the constructor!
2014-06-25 16:29:58 +00:00
{
// metadata needs at least a name field (since that's what getName() will return)
if ( metadata . get ( " name " ) . empty ( ) )
2016-03-29 15:33:19 +00:00
metadata . set ( " name " , getDisplayName ( ) ) ;
2017-06-12 16:38:59 +00:00
mSystemName = system - > getName ( ) ;
2019-09-04 02:39:19 +00:00
metadata . resetChangedFlag ( ) ;
2014-06-25 16:29:58 +00:00
}
FileData : : ~ FileData ( )
{
if ( mParent )
mParent - > removeChild ( this ) ;
2017-07-18 09:45:50 +00:00
if ( mType = = GAME )
mSystem - > getIndex ( ) - > removeFromIndex ( this ) ;
2017-06-12 16:38:59 +00:00
mChildren . clear ( ) ;
2014-06-25 16:29:58 +00:00
}
2016-03-29 15:33:19 +00:00
std : : string FileData : : getDisplayName ( ) const
2014-06-25 16:29:58 +00:00
{
2018-01-29 22:50:10 +00:00
std : : string stem = Utils : : FileSystem : : getStem ( mPath ) ;
2020-05-18 17:00:43 +00:00
// if(mSystem && mSystem->hasPlatformId(PlatformIds::ARCADE) || mSystem->hasPlatformId(PlatformIds::NEOGEO))
// stem = MameNames::getInstance()->getRealName(stem);
2014-06-25 16:29:58 +00:00
2015-09-19 01:25:31 +00:00
return stem ;
2014-06-25 16:29:58 +00:00
}
2016-03-29 15:33:19 +00:00
std : : string FileData : : getCleanName ( ) const
{
2018-01-26 18:53:19 +00:00
return Utils : : String : : removeParenthesis ( this - > getDisplayName ( ) ) ;
2016-03-29 15:33:19 +00:00
}
2017-06-12 16:38:59 +00:00
const std : : string & FileData : : getName ( )
{
return metadata . get ( " name " ) ;
}
2018-04-25 05:07:25 +00:00
const std : : string & FileData : : getSortName ( )
{
if ( metadata . get ( " sortname " ) . empty ( ) )
return metadata . get ( " name " ) ;
else
return metadata . get ( " sortname " ) ;
}
2020-05-15 15:42:36 +00:00
const bool FileData : : getFavorite ( )
{
if ( metadata . get ( " favorite " ) = = " true " )
return true ;
else
return false ;
}
2020-05-18 17:00:43 +00:00
const std : : string FileData : : getMediaDirectory ( ) const
{
std : : string mediaDirSetting = Settings : : getInstance ( ) - > getString ( " MediaDirectory " ) ;
std : : string mediaDirPath = " " ;
2017-05-18 10:16:57 +00:00
2020-05-18 17:00:43 +00:00
if ( mediaDirSetting = = " " )
{
mediaDirPath = Utils : : FileSystem : : getHomePath ( ) + " /.emulationstation/downloaded_media/ " ;
}
else
{
mediaDirPath = mediaDirSetting ;
// Expand home symbol if the path starts with ~
if ( mediaDirPath [ 0 ] = = ' ~ ' )
2017-03-18 17:54:39 +00:00
{
2020-05-18 17:00:43 +00:00
mediaDirPath . erase ( 0 , 1 ) ;
mediaDirPath . insert ( 0 , Utils : : FileSystem : : getHomePath ( ) ) ;
2017-03-18 17:54:39 +00:00
}
2020-05-18 17:00:43 +00:00
if ( mediaDirPath . back ( ) ! = ' / ' )
{
mediaDirPath = mediaDirPath + " / " ;
}
2017-03-18 17:54:39 +00:00
}
2020-05-18 17:00:43 +00:00
return mediaDirPath ;
}
const std : : string FileData : : getThumbnailPath ( ) const
{
const char * extList [ 2 ] = { " .png " , " .jpg " } ;
std : : string tempPath = getMediaDirectory ( ) + mSystemName + " /thumbnails/ " + getDisplayName ( ) ;
// Look for media in the media directory
for ( int i = 0 ; i < 2 ; i + + )
2017-03-18 17:54:39 +00:00
{
2020-05-18 17:00:43 +00:00
std : : string mediaPath = tempPath + extList [ i ] ;
if ( Utils : : FileSystem : : exists ( mediaPath ) )
return mediaPath ;
2017-03-18 17:54:39 +00:00
}
2020-05-18 17:00:43 +00:00
// No media found in the media directory, so look for local art as well (if configured to do so)
if ( Settings : : getInstance ( ) - > getBool ( " LocalArt " ) )
{
for ( int i = 0 ; i < 2 ; i + + )
{
std : : string localMediaPath = mEnvData - > mStartPath + " /images/ " + getDisplayName ( ) + " -thumbnail " + extList [ i ] ;
if ( Utils : : FileSystem : : exists ( localMediaPath ) )
return localMediaPath ;
}
}
return " " ;
2017-03-18 17:54:39 +00:00
}
2017-10-22 23:04:17 +00:00
const std : : string FileData : : getVideoPath ( ) const
{
2020-05-18 17:00:43 +00:00
const char * extList [ 5 ] = { " .avi " , " .mkv " , " .mov " , " .mp4 " , " .wmv " } ;
std : : string tempPath = getMediaDirectory ( ) + mSystemName + " /videos/ " + getDisplayName ( ) ;
// Look for media in the media directory
for ( int i = 0 ; i < 5 ; i + + )
{
std : : string mediaPath = tempPath + extList [ i ] ;
if ( Utils : : FileSystem : : exists ( mediaPath ) )
return mediaPath ;
}
2017-10-22 23:04:17 +00:00
2020-05-18 17:00:43 +00:00
// No media found in the media directory, so look for local art as well (if configured to do so)
if ( Settings : : getInstance ( ) - > getBool ( " LocalArt " ) )
2017-10-22 23:04:17 +00:00
{
2020-05-18 17:00:43 +00:00
for ( int i = 0 ; i < 5 ; i + + )
{
std : : string localMediaPath = mEnvData - > mStartPath + " /images/ " + getDisplayName ( ) + " -video " + extList [ i ] ;
if ( Utils : : FileSystem : : exists ( localMediaPath ) )
return localMediaPath ;
}
2017-10-22 23:04:17 +00:00
}
2020-05-18 17:00:43 +00:00
return " " ;
2017-10-22 23:04:17 +00:00
}
const std : : string FileData : : getMarqueePath ( ) const
2016-12-04 23:47:34 +00:00
{
2020-05-18 17:00:43 +00:00
const char * extList [ 2 ] = { " .png " , " .jpg " } ;
std : : string tempPath = getMediaDirectory ( ) + mSystemName + " /marquees/ " + getDisplayName ( ) ;
// Look for media in the media directory
for ( int i = 0 ; i < 2 ; i + + )
{
std : : string mediaPath = tempPath + extList [ i ] ;
if ( Utils : : FileSystem : : exists ( mediaPath ) )
return mediaPath ;
}
2017-10-22 23:04:17 +00:00
2020-05-18 17:00:43 +00:00
// No media found in the media directory, so look for local art as well (if configured to do so)
if ( Settings : : getInstance ( ) - > getBool ( " LocalArt " ) )
2017-10-22 23:04:17 +00:00
{
for ( int i = 0 ; i < 2 ; i + + )
{
2020-05-18 17:00:43 +00:00
std : : string localMediaPath = mEnvData - > mStartPath + " /images/ " + getDisplayName ( ) + " -marquee " + extList [ i ] ;
if ( Utils : : FileSystem : : exists ( localMediaPath ) )
return localMediaPath ;
2017-10-22 23:04:17 +00:00
}
}
2020-05-18 17:00:43 +00:00
return " " ;
2016-12-04 23:47:34 +00:00
}
2017-10-22 23:04:17 +00:00
const std : : string FileData : : getImagePath ( ) const
2016-12-04 23:47:34 +00:00
{
2020-05-18 17:00:43 +00:00
const char * extList [ 2 ] = { " .png " , " .jpg " } ;
// Look for mix image (a combination of screenshot, 3D box and marquee) in the media directory
std : : string tempPath = getMediaDirectory ( ) + mSystemName + " /miximages/ " + getDisplayName ( ) ;
for ( int i = 0 ; i < 2 ; i + + )
{
std : : string mediaPath = tempPath + extList [ i ] ;
if ( Utils : : FileSystem : : exists ( mediaPath ) )
return mediaPath ;
}
2017-10-22 23:04:17 +00:00
2020-05-18 17:00:43 +00:00
// If no mix image exists, try normal screenshot
tempPath = getMediaDirectory ( ) + mSystemName + " /screenshots/ " + getDisplayName ( ) ;
for ( int i = 0 ; i < 2 ; i + + )
{
std : : string mediaPath = tempPath + extList [ i ] ;
if ( Utils : : FileSystem : : exists ( mediaPath ) )
return mediaPath ;
}
// No media found in the media directory, so look for local art as well (if configured to do so)
if ( Settings : : getInstance ( ) - > getBool ( " LocalArt " ) )
2017-10-22 23:04:17 +00:00
{
for ( int i = 0 ; i < 2 ; i + + )
{
2020-05-18 17:00:43 +00:00
std : : string localMediaPath = mEnvData - > mStartPath + " /images/ " + getDisplayName ( ) + " -image " + extList [ i ] ;
if ( Utils : : FileSystem : : exists ( localMediaPath ) )
return localMediaPath ;
2017-10-22 23:04:17 +00:00
}
}
2020-05-18 17:00:43 +00:00
return " " ;
}
const std : : vector < FileData * > & FileData : : getChildrenListToDisplay ( )
{
FileFilterIndex * idx = CollectionSystemManager : : get ( ) - > getSystemToView ( mSystem ) - > getIndex ( ) ;
if ( idx - > isFiltered ( ) ) {
mFilteredChildren . clear ( ) ;
for ( auto it = mChildren . cbegin ( ) ; it ! = mChildren . cend ( ) ; it + + )
{
if ( idx - > showFile ( ( * it ) ) ) {
mFilteredChildren . push_back ( * it ) ;
}
}
return mFilteredChildren ;
}
else
{
return mChildren ;
}
2016-12-04 23:47:34 +00:00
}
2017-03-18 17:54:39 +00:00
std : : vector < FileData * > FileData : : getFilesRecursive ( unsigned int typeMask , bool displayedOnly ) const
2014-06-25 16:29:58 +00:00
{
std : : vector < FileData * > out ;
2017-03-18 17:54:39 +00:00
FileFilterIndex * idx = mSystem - > getIndex ( ) ;
2014-06-25 16:29:58 +00:00
2017-11-11 14:56:22 +00:00
for ( auto it = mChildren . cbegin ( ) ; it ! = mChildren . cend ( ) ; it + + )
2014-06-25 16:29:58 +00:00
{
if ( ( * it ) - > getType ( ) & typeMask )
2017-03-18 17:54:39 +00:00
{
if ( ! displayedOnly | | ! idx - > isFiltered ( ) | | idx - > showFile ( * it ) )
out . push_back ( * it ) ;
}
2017-05-18 10:16:57 +00:00
2014-06-25 16:29:58 +00:00
if ( ( * it ) - > getChildren ( ) . size ( ) > 0 )
{
2017-03-18 17:54:39 +00:00
std : : vector < FileData * > subchildren = ( * it ) - > getFilesRecursive ( typeMask , displayedOnly ) ;
2017-11-11 14:56:22 +00:00
out . insert ( out . cend ( ) , subchildren . cbegin ( ) , subchildren . cend ( ) ) ;
2014-06-25 16:29:58 +00:00
}
}
return out ;
}
2017-06-12 16:38:59 +00:00
std : : string FileData : : getKey ( ) {
return getFileName ( ) ;
}
2018-05-10 01:29:46 +00:00
const bool FileData : : isArcadeAsset ( )
{
const std : : string stem = Utils : : FileSystem : : getStem ( mPath ) ;
return (
( mSystem & & ( mSystem - > hasPlatformId ( PlatformIds : : ARCADE ) | | mSystem - > hasPlatformId ( PlatformIds : : NEOGEO ) ) )
& &
( MameNames : : getInstance ( ) - > isBios ( stem ) | | MameNames : : getInstance ( ) - > isDevice ( stem ) )
) ;
}
2017-06-12 16:38:59 +00:00
FileData * FileData : : getSourceFileData ( )
{
return this ;
}
2014-06-25 16:29:58 +00:00
void FileData : : addChild ( FileData * file )
{
assert ( mType = = FOLDER ) ;
assert ( file - > getParent ( ) = = NULL ) ;
2017-06-12 16:38:59 +00:00
const std : : string key = file - > getKey ( ) ;
2017-11-11 14:56:22 +00:00
if ( mChildrenByFilename . find ( key ) = = mChildrenByFilename . cend ( ) )
2016-08-09 20:26:30 +00:00
{
mChildrenByFilename [ key ] = file ;
mChildren . push_back ( file ) ;
file - > mParent = this ;
}
2014-06-25 16:29:58 +00:00
}
void FileData : : removeChild ( FileData * file )
{
assert ( mType = = FOLDER ) ;
assert ( file - > getParent ( ) = = this ) ;
2017-06-12 16:38:59 +00:00
mChildrenByFilename . erase ( file - > getKey ( ) ) ;
2017-11-11 14:56:22 +00:00
for ( auto it = mChildren . cbegin ( ) ; it ! = mChildren . cend ( ) ; it + + )
2014-06-25 16:29:58 +00:00
{
if ( * it = = file )
{
2017-07-18 09:45:50 +00:00
file - > mParent = NULL ;
2014-06-25 16:29:58 +00:00
mChildren . erase ( it ) ;
return ;
}
}
// File somehow wasn't in our children.
assert ( false ) ;
2016-08-09 20:26:30 +00:00
2014-06-25 16:29:58 +00:00
}
void FileData : : sort ( ComparisonFunction & comparator , bool ascending )
{
2017-06-12 16:38:59 +00:00
std : : stable_sort ( mChildren . begin ( ) , mChildren . end ( ) , comparator ) ;
2014-06-25 16:29:58 +00:00
2017-11-11 14:56:22 +00:00
for ( auto it = mChildren . cbegin ( ) ; it ! = mChildren . cend ( ) ; it + + )
2014-06-25 16:29:58 +00:00
{
if ( ( * it ) - > getChildren ( ) . size ( ) > 0 )
( * it ) - > sort ( comparator , ascending ) ;
}
if ( ! ascending )
std : : reverse ( mChildren . begin ( ) , mChildren . end ( ) ) ;
}
void FileData : : sort ( const SortType & type )
{
sort ( * type . comparisonFunction , type . ascending ) ;
}
2017-06-12 16:38:59 +00:00
void FileData : : launchGame ( Window * window )
{
LOG ( LogInfo ) < < " Attempting to launch game... " ;
AudioManager : : getInstance ( ) - > deinit ( ) ;
VolumeControl : : getInstance ( ) - > deinit ( ) ;
2020-05-15 15:51:32 +00:00
// window->deinit();
2017-06-12 16:38:59 +00:00
2020-05-19 15:52:11 +00:00
std : : string command = " " ;
// Check if there is a launch string override for the game and the corresponding option has been set
if ( Settings : : getInstance ( ) - > getBool ( " LaunchstringOverride " ) & & ! metadata . get ( " launchstring " ) . empty ( ) )
{
command = metadata . get ( " launchstring " ) ;
}
else
{
command = mEnvData - > mLaunchCommand ;
}
2017-06-12 16:38:59 +00:00
2018-01-29 22:50:10 +00:00
const std : : string rom = Utils : : FileSystem : : getEscapedPath ( getPath ( ) ) ;
const std : : string basename = Utils : : FileSystem : : getStem ( getPath ( ) ) ;
2018-04-12 03:17:58 +00:00
const std : : string rom_raw = Utils : : FileSystem : : getPreferredPath ( getPath ( ) ) ;
2017-06-12 16:38:59 +00:00
2018-01-27 17:04:28 +00:00
command = Utils : : String : : replace ( command , " %ROM% " , rom ) ;
command = Utils : : String : : replace ( command , " %BASENAME% " , basename ) ;
command = Utils : : String : : replace ( command , " %ROM_RAW% " , rom_raw ) ;
2017-06-12 16:38:59 +00:00
2018-01-30 00:49:08 +00:00
Scripting : : fireEvent ( " game-start " , rom , basename ) ;
2017-06-12 16:38:59 +00:00
LOG ( LogInfo ) < < " " < < command ;
int exitCode = runSystemCommand ( command ) ;
if ( exitCode ! = 0 )
{
LOG ( LogWarning ) < < " ...launch terminated with nonzero exit code " < < exitCode < < " ! " ;
}
2018-01-30 00:49:08 +00:00
Scripting : : fireEvent ( " game-end " ) ;
2020-05-15 15:51:32 +00:00
// window->init();
2017-06-12 16:38:59 +00:00
VolumeControl : : getInstance ( ) - > init ( ) ;
window - > normalizeNextUpdate ( ) ;
//update number of times the game has been launched
FileData * gameToUpdate = getSourceFileData ( ) ;
int timesPlayed = gameToUpdate - > metadata . getInt ( " playcount " ) + 1 ;
gameToUpdate - > metadata . set ( " playcount " , std : : to_string ( static_cast < long long > ( timesPlayed ) ) ) ;
//update last played time
2017-11-22 21:01:12 +00:00
gameToUpdate - > metadata . set ( " lastplayed " , Utils : : Time : : DateTime ( Utils : : Time : : now ( ) ) ) ;
2017-07-18 09:45:50 +00:00
CollectionSystemManager : : get ( ) - > refreshCollectionSystems ( gameToUpdate ) ;
2019-08-24 14:22:02 +00:00
gameToUpdate - > mSystem - > onMetaDataSavePoint ( ) ;
2017-06-12 16:38:59 +00:00
}
CollectionFileData : : CollectionFileData ( FileData * file , SystemData * system )
2017-07-18 09:45:50 +00:00
: FileData ( file - > getSourceFileData ( ) - > getType ( ) , file - > getSourceFileData ( ) - > getPath ( ) , file - > getSourceFileData ( ) - > getSystemEnvData ( ) , system )
2017-06-12 16:38:59 +00:00
{
// we use this constructor to create a clone of the filedata, and change its system
mSourceFileData = file - > getSourceFileData ( ) ;
refreshMetadata ( ) ;
mParent = NULL ;
metadata = mSourceFileData - > metadata ;
mSystemName = mSourceFileData - > getSystem ( ) - > getName ( ) ;
}
CollectionFileData : : ~ CollectionFileData ( )
{
// need to remove collection file data at the collection object destructor
if ( mParent )
mParent - > removeChild ( this ) ;
mParent = NULL ;
}
std : : string CollectionFileData : : getKey ( ) {
return getFullPath ( ) ;
}
FileData * CollectionFileData : : getSourceFileData ( )
{
return mSourceFileData ;
}
void CollectionFileData : : refreshMetadata ( )
{
metadata = mSourceFileData - > metadata ;
mDirty = true ;
}
2019-08-25 15:23:02 +00:00
const std : : string & CollectionFileData : : getName ( )
{
if ( mDirty ) {
mCollectionFileName = Utils : : String : : removeParenthesis ( mSourceFileData - > metadata . get ( " name " ) ) ;
mCollectionFileName + = " [ " + Utils : : String : : toUpper ( mSourceFileData - > getSystem ( ) - > getName ( ) ) + " ] " ;
mDirty = false ;
}
if ( Settings : : getInstance ( ) - > getBool ( " CollectionShowSystemInfo " ) )
return mCollectionFileName ;
return mSourceFileData - > metadata . get ( " name " ) ;
2017-07-18 09:45:50 +00:00
}
// returns Sort Type based on a string description
FileData : : SortType getSortTypeFromString ( std : : string desc ) {
std : : vector < FileData : : SortType > SortTypes = FileSorts : : SortTypes ;
// find it
for ( unsigned int i = 0 ; i < FileSorts : : SortTypes . size ( ) ; i + + )
{
const FileData : : SortType & sort = FileSorts : : SortTypes . at ( i ) ;
if ( sort . description = = desc )
{
return sort ;
}
}
// if not found default to name, ascending
return FileSorts : : SortTypes . at ( 0 ) ;
2017-09-14 01:26:33 +00:00
}