fix smpackage file routines and registry writing

This commit is contained in:
Chris Danford
2006-01-21 12:18:26 +00:00
parent 9ed7548de1
commit 477e67a8aa
17 changed files with 312 additions and 219 deletions
+16 -1
View File
@@ -64,6 +64,7 @@ Medium=STANDARD
[EditInstallations]
You must type a program directory before clicking Add.=You must type a program directory before clicking Add.
'%s' is not a valid installation directory.='%s' is not a valid installation directory.
[EditMenuAction]
Create=Create New
@@ -142,6 +143,7 @@ Failed to delete file '%s'.=Failed to delete file '%s'.
Failed to open '%s': %s=Failed to open '%s': %s
Music file=Music file
Success. Created the song '%s'=Success. Created the song '%s'
The song directory '%s' already exists. You cannot override an existing song.=The song directory '%s' already exists. You cannot override an existing song.
[MenuButton]
Coin=Coin
@@ -1444,4 +1446,17 @@ StepMania Tools Main Menu=StepMania Tools Main Menu
Troubleshooting=Troubleshooting
[ChangeGameSettings]
Error writing file '%s': %s=Error writing file '%s': %s
Error writing file '%s': %s=Error writing file '%s': %s
[Tools-Name Your Package]
Name Your Package=Name Your Package
Enter a name for your new package:=Enter a name for your new package:
OK=OK
Cancel=Cancel
Note: leave off the ".smzip" extention=Note: leave off the ".smzip" extention
[Tools-StepMania Tools]
Finish >=Finish >
Cancel=Cancel
< Back=< Back
Install a package=Install a package
+2
View File
@@ -25,6 +25,8 @@
#define VIDEO_TROUBLESHOOTING_URL "http://www.stepmania.com/stepmania/mediawiki.php?title=Video_Driver_Troubleshooting"
#define REPORT_BUG_URL "http://sourceforge.net/tracker/?func=add&group_id=37892&atid=421366"
#define CAN_INSTALL_PACKAGES true
#endif
/*
+17
View File
@@ -871,6 +871,23 @@ void GetDirListingRecursive( const RString &sDir, const RString &sMatch, vector<
}
}
void GetDirListingRecursive( RageFileDriver *prfd, const RString &sDir, const RString &sMatch, vector<RString> &AddTo )
{
ASSERT( sDir.Right(1) == "/" );
prfd->GetDirListing( sDir+sMatch, AddTo, false, true );
prfd->GetDirListing( sDir+"*", AddTo, true, true );
for( unsigned i=0; i<AddTo.size(); i++ )
{
if( prfd->GetFileType(AddTo[i]) == RageFileManager::TYPE_DIR )
{
prfd->GetDirListing( AddTo[i]+"/"+sMatch, AddTo, false, true );
prfd->GetDirListing( AddTo[i]+"/*", AddTo, true, true );
AddTo.erase( AddTo.begin()+i );
i--;
}
}
}
bool DeleteRecursive( const RString &sDir )
{
ASSERT( sDir.Right(1) == "/" );
+1 -1
View File
@@ -1839,7 +1839,7 @@ void FileWrite( RageFileBasic& f, float fWrite )
f.PutLine( ssprintf("%f", fWrite) );
}
bool FileCopy( RString sSrcFile, RString sDstFile )
bool FileCopy( const RString &sSrcFile, const RString &sDstFile )
{
if( !sSrcFile.CompareNoCase(sDstFile) )
{
+3 -1
View File
@@ -6,6 +6,7 @@
#include <map>
#include <vector>
#include "Foreach.h"
class RageFileDriver;
#define SAFE_DELETE(p) { delete (p); (p)=NULL; }
#define SAFE_DELETE_ARRAY(p) { delete[] (p); (p)=NULL; }
@@ -435,6 +436,7 @@ typedef basic_string<char,char_traits_char_nocase> istring;
* declared here since they're used in many places. */
void GetDirListing( const RString &sPath, vector<RString> &AddTo, bool bOnlyDirs=false, bool bReturnPathToo=false );
void GetDirListingRecursive( const RString &sDir, const RString &sMatch, vector<RString> &AddTo ); /* returns path too */
void GetDirListingRecursive( RageFileDriver *prfd, const RString &sDir, const RString &sMatch, vector<RString> &AddTo ); /* returns path too */
bool DeleteRecursive( const RString &sDir ); /* delete the dir and all files/subdirs inside it */
bool DoesFileExist( const RString &sPath );
bool IsAFile( const RString &sPath );
@@ -470,7 +472,7 @@ void FileWrite( RageFileBasic& f, int iWrite );
void FileWrite( RageFileBasic& f, size_t uWrite );
void FileWrite( RageFileBasic& f, float fWrite );
bool FileCopy( RString sSrcFile, RString sDstFile );
bool FileCopy( const RString &sSrcFile, const RString &sDstFile );
bool FileCopy( RageFileBasic &in, RageFileBasic &out, RString &sError, bool *bReadError = NULL );
template<class T>
@@ -36,7 +36,8 @@ static bool GetRegKeyType( const RString &sIn, RString &sOut, HKEY &key )
/* Given a full key, eg. "HKEY_LOCAL_MACHINE\hardware\foo", open it and return it.
* On error, return NULL. */
static HKEY OpenRegKey( const RString &sKey, bool bWarnOnError = true )
enum RegKeyMode { READ, WRITE };
static HKEY OpenRegKey( const RString &sKey, RegKeyMode mode, bool bWarnOnError = true )
{
RString sSubkey;
HKEY hType;
@@ -44,7 +45,7 @@ static HKEY OpenRegKey( const RString &sKey, bool bWarnOnError = true )
return NULL;
HKEY hRetKey;
LONG retval = RegOpenKeyEx( hType, sSubkey, 0, KEY_READ, &hRetKey );
LONG retval = RegOpenKeyEx( hType, sSubkey, 0, (mode==READ) ? KEY_READ:KEY_WRITE, &hRetKey );
if ( retval != ERROR_SUCCESS )
{
if( bWarnOnError )
@@ -57,7 +58,7 @@ static HKEY OpenRegKey( const RString &sKey, bool bWarnOnError = true )
bool RegistryAccess::GetRegValue( const RString &sKey, const RString &sName, RString &sVal )
{
HKEY hKey = OpenRegKey( sKey );
HKEY hKey = OpenRegKey( sKey, READ );
if( hKey == NULL )
return false;
@@ -83,7 +84,7 @@ bool RegistryAccess::GetRegValue( const RString &sKey, const RString &sName, RSt
bool RegistryAccess::GetRegValue( const RString &sKey, const RString &sName, int &iVal, bool bWarnOnError )
{
HKEY hKey = OpenRegKey( sKey, bWarnOnError );
HKEY hKey = OpenRegKey( sKey, READ, bWarnOnError );
if( hKey == NULL )
return false;
@@ -112,7 +113,7 @@ bool RegistryAccess::GetRegValue( const RString &sKey, const RString &sName, boo
bool RegistryAccess::GetRegSubKeys( const RString &sKey, vector<RString> &lst, const RString &regex, bool bReturnPathToo )
{
HKEY hKey = OpenRegKey( sKey );
HKEY hKey = OpenRegKey( sKey, READ );
if( hKey == NULL )
return false;
@@ -152,7 +153,7 @@ bool RegistryAccess::GetRegSubKeys( const RString &sKey, vector<RString> &lst, c
bool RegistryAccess::SetRegValue( const RString &sKey, const RString &sName, const RString &sVal )
{
HKEY hKey = OpenRegKey( sKey );
HKEY hKey = OpenRegKey( sKey, WRITE );
if( hKey == NULL )
return false;
@@ -164,9 +165,8 @@ bool RegistryAccess::SetRegValue( const RString &sKey, const RString &sName, con
strcpy( sz, sVal.c_str() );
if (::RegSetValueEx(hKey, LPCTSTR(sName), 0,
REG_SZ, (LPBYTE)sz, strlen(sz) + 1)
!= ERROR_SUCCESS)
LONG lResult = ::RegSetValueEx(hKey, LPCTSTR(sName), 0, REG_SZ, (LPBYTE)sz, strlen(sz) + 1);
if( lResult != ERROR_SUCCESS )
bSuccess = false;
::RegCloseKey(hKey);
@@ -175,7 +175,7 @@ bool RegistryAccess::SetRegValue( const RString &sKey, const RString &sName, con
bool RegistryAccess::SetRegValue( const RString &sKey, const RString &sName, bool bVal )
{
HKEY hKey = OpenRegKey( sKey );
HKEY hKey = OpenRegKey( sKey, WRITE );
if( hKey == NULL )
return false;
+29 -9
View File
@@ -10,6 +10,7 @@
#include "archutils/Win32/DialogUtil.h"
#include ".\editinsallations.h"
#include "LocalizedString.h"
#include "RageUtil.h"
#ifdef _DEBUG
#define new DEBUG_NEW
@@ -64,12 +65,10 @@ BOOL EditInsallations::OnInitDialog()
for( unsigned i=0; i<vs.size(); i++ )
m_list.AddString( vs[i] );
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void EditInsallations::OnButtonRemove()
{
// TODO: Add your control notification handler code here
@@ -90,33 +89,54 @@ void EditInsallations::OnButtonMakeDefault()
m_list.InsertString( 0, sText );
}
static LocalizedString YOU_MUST_TYPE_IN ("EditInstallations","You must type a program directory before clicking Add.");
static LocalizedString YOU_MUST_TYPE_IN ("EditInstallations","You must type a program directory before clicking Add.");
static LocalizedString NOT_A_VALID_INSTALLATION_DIR ("EditInstallations","'%s' is not a valid installation directory.");
void EditInsallations::OnButtonAdd()
{
// TODO: Add your control notification handler code here
CString sText;
m_edit.GetWindowText( sText );
RString sNewDir;
{
CString s;
m_edit.GetWindowText( s );
sNewDir = s;
}
if( sText == "" )
if( sNewDir == "" )
{
AfxMessageBox( YOU_MUST_TYPE_IN.GetValue() );
return;
}
m_list.AddString( sText );
bool bAlreadyInList = false;
for( int i=0; i<m_list.GetCount(); i++ )
{
CString sDir;
m_list.GetText( i, sDir );
if( sDir.CompareNoCase(sNewDir)==0 )
return;
}
if( !SMPackageUtil::IsValidInstallDir(sNewDir) )
{
AfxMessageBox( ssprintf(NOT_A_VALID_INSTALLATION_DIR.GetValue(),sNewDir.c_str()) );
return;
}
m_list.AddString( sNewDir );
}
void EditInsallations::OnOK()
{
m_vsReturnedInstallDirs.clear();
vector<RString> vs;
for( int i=0; i<m_list.GetCount(); i++ )
{
CString sDir;
m_list.GetText( i, sDir );
RString s = sDir;
m_vsReturnedInstallDirs.push_back( s );
vs.push_back( s );
}
SMPackageUtil::WriteGameInstallDirs( vs );
CDialog::OnOK();
}
@@ -16,8 +16,6 @@ class EditInsallations : public CDialog
public:
EditInsallations(CWnd* pParent = NULL); // standard constructor
vector<RString> m_vsReturnedInstallDirs;
// Dialog Data
//{{AFX_DATA(EditInsallations)
enum { IDD = IDD_EDIT_INSTALLATIONS };
+31 -44
View File
@@ -20,6 +20,7 @@
#include ".\mainmenudlg.h"
#include "archutils/Win32/DialogUtil.h"
#include "LocalizedString.h"
#include "RageFileManager.h"
#ifdef _DEBUG
#define new DEBUG_NEW
@@ -107,12 +108,11 @@ RString GetLastErrorString()
return s;
}
static LocalizedString MUSIC_FILE ( "MainMenuDlg", "Music file" );
static LocalizedString FAILED_TO_CREATE_DIRECTORY ( "MainMenuDlg", "Failed to create directory '%s': %s" );
static LocalizedString FAILED_TO_CREATE_SONG_DIRECTORY ( "MainMenuDlg", "Failed to create song directory '%s': %s" );
static LocalizedString MUSIC_FILE ( "MainMenuDlg", "Music file" );
static LocalizedString THE_SONG_DIRECTORY_ALREADY_EXISTS ( "MainMenuDlg", "The song directory '%s' already exists. You cannot override an existing song." );
static LocalizedString FAILED_TO_COPY_MUSIC_FILE ( "MainMenuDlg", "Failed to copy music file '%s' to '%s': %s" );
static LocalizedString FAILED_TO_CREATE_THE_SONG_FILE ( "MainMenuDlg", "Failed to create the song file '%s'" );
static LocalizedString SUCCESS_CREATED_THE_SONG ( "MainMenuDlg", "Success. Created the song '%s'" );
static LocalizedString FAILED_TO_CREATE_THE_SONG_FILE ( "MainMenuDlg", "Failed to create the song file '%s'" );
static LocalizedString SUCCESS_CREATED_THE_SONG ( "MainMenuDlg", "Success. Created the song '%s'" );
void MainMenuDlg::OnCreateSong()
{
// TODO: Add your control notification handler code here
@@ -123,58 +123,44 @@ void MainMenuDlg::OnCreateSong()
NULL, // default file extension
NULL, // default file name
OFN_HIDEREADONLY | OFN_NOCHANGEDIR, // flags
""//MUSIC_FILE.GetValue()+" (*.mp3;*.ogg)|*.mp3;*.ogg|||"
ConvertUTF8ToACP(MUSIC_FILE.GetValue()+" (*.mp3;*.ogg)|*.mp3;*.ogg|||").c_str()
);
int iRet = dialog.DoModal();
RString sMusicFile = dialog.GetPathName();
if( iRet != IDOK )
return;
BOOL bSuccess;
RString sSongDirectory = "Songs/My Creations/" + GetFileNameWithoutExtension(sMusicFile) + "/";
RString sNewMusicFile = sSongDirectory + Basename(sMusicFile);
RString sSongDirectory = "Songs\\My Creations\\";
bSuccess = CreateDirectory( sSongDirectory, NULL );
if( !bSuccess )
if( DoesFileExist(sSongDirectory) )
{
DWORD dwError = ::GetLastError();
switch( dwError )
{
case ERROR_ALREADY_EXISTS:
// This failure is ok. We probably created this directory already while importing another song.
break;
default:
MessageBox( ssprintf(FAILED_TO_CREATE_DIRECTORY.GetValue(),sSongDirectory.c_str(),GetLastErrorString().c_str()) );
return;
}
}
sSongDirectory += Basename( sMusicFile );
bSuccess = CreateDirectory( sSongDirectory, NULL ); // CreateDirectory doesn't like a trailing slash
if( !bSuccess )
{
MessageBox( ssprintf(FAILED_TO_CREATE_SONG_DIRECTORY.GetValue(),sSongDirectory.c_str(),GetLastErrorString().c_str()) );
MessageBox( ssprintf(THE_SONG_DIRECTORY_ALREADY_EXISTS.GetValue(),sSongDirectory.c_str()) );
return;
}
sSongDirectory += "\\";
RString sNewMusicFile = sSongDirectory + Basename(sMusicFile);
bSuccess = CopyFile( sMusicFile, sNewMusicFile, TRUE );
RageFileOsAbsolute fileIn;
fileIn.Open( sMusicFile, RageFile::READ );
RageFile fileOut;
fileOut.Open( sNewMusicFile, RageFile::WRITE );
RString sError;
bool bSuccess = FileCopy( fileIn, fileOut, sError );
if( !bSuccess )
{
MessageBox( ssprintf(FAILED_TO_COPY_MUSIC_FILE.GetValue(),sMusicFile.c_str(),sNewMusicFile.c_str(),GetLastErrorString().c_str()) );
MessageBox( ssprintf(FAILED_TO_COPY_MUSIC_FILE.GetValue(),sMusicFile.c_str(),sNewMusicFile.c_str(),sError.c_str()) );
return;
}
// create a blank .sm file
RString sNewSongFile = sMusicFile;
SetExtension( sNewSongFile, "sm" );
FILE *fp = fopen( sNewSongFile, "w" );
if( fp == NULL )
RageFile file;
if( file.Open(sNewSongFile, RageFile::WRITE) )
{
MessageBox( ssprintf(FAILED_TO_CREATE_THE_SONG_FILE.GetValue(),sNewSongFile.c_str()) );
return;
}
fclose( fp );
file.Close();
MessageBox( ssprintf(SUCCESS_CREATED_THE_SONG.GetValue(),sSongDirectory.c_str()) );
}
@@ -197,8 +183,9 @@ BOOL MainMenuDlg::OnInitDialog()
// EXCEPTION: OCX Property Pages should return FALSE
}
static LocalizedString FAILED_TO_DELETE_FILE ( "MainMenuDlg", "Failed to delete file '%s'." );
static LocalizedString IS_ALREADY_CLEARED ( "MainMenuDlg", "'%s' is already cleared." );
static LocalizedString FAILED_TO_DELETE_FILE ( "MainMenuDlg", "Failed to delete file '%s'." );
static LocalizedString IS_ALREADY_CLEARED ( "MainMenuDlg", "'%s' is already cleared." );
static LocalizedString CLEARED( "MainMenuDlg", "'%s' cleared" );
void MainMenuDlg::OnBnClickedClearKeymaps()
{
// TODO: Add your control notification handler code here
@@ -206,12 +193,13 @@ void MainMenuDlg::OnBnClickedClearKeymaps()
if( !DoesFileExist( SpecialFiles::KEYMAPS_PATH ) )
{
MessageBox( ssprintf(IS_ALREADY_CLEARED.GetValue(),SpecialFiles::KEYMAPS_PATH.c_str()) );
return;
}
else
{
if( !DeleteFile( SpecialFiles::KEYMAPS_PATH ) )
MessageBox( ssprintf(FAILED_TO_DELETE_FILE.GetValue(), SpecialFiles::KEYMAPS_PATH.c_str()) );
}
if( !FILEMAN->Remove(SpecialFiles::KEYMAPS_PATH) )
MessageBox( ssprintf(FAILED_TO_DELETE_FILE.GetValue(), SpecialFiles::KEYMAPS_PATH.c_str()) );
MessageBox( ssprintf(CLEARED.GetValue(),SpecialFiles::PREFERENCES_INI_PATH.c_str()) );
}
void MainMenuDlg::OnBnClickedChangePreferences()
@@ -237,17 +225,16 @@ void MainMenuDlg::OnBnClickedOpenPreferences()
}
}
static LocalizedString CLEARED( "MainMenuDlg", "'%s' cleared" );
void MainMenuDlg::OnBnClickedClearPreferences()
{
// TODO: Add your control notification handler code here
if( !DoesFileExist( SpecialFiles::PREFERENCES_INI_PATH ) )
if( !DoesFileExist(SpecialFiles::PREFERENCES_INI_PATH) )
{
MessageBox( ssprintf(IS_ALREADY_CLEARED.GetValue(),SpecialFiles::PREFERENCES_INI_PATH.c_str()) );
return;
}
if( !DeleteFile( SpecialFiles::PREFERENCES_INI_PATH ) )
if( !FILEMAN->Remove(SpecialFiles::PREFERENCES_INI_PATH) )
{
MessageBox( ssprintf(FAILED_TO_DELETE_FILE.GetValue(),SpecialFiles::PREFERENCES_INI_PATH.c_str()) );
return;
+59 -37
View File
@@ -24,13 +24,11 @@
static char THIS_FILE[] = __FILE__;
#endif
static const RString TEMP_MOUNT_POINT = "/@package/";
/////////////////////////////////////////////////////////////////////////////
// CSMPackageInstallDlg dialog
CSMPackageInstallDlg::CSMPackageInstallDlg(CString sPackagePath, CWnd* pParent /*=NULL*/)
CSMPackageInstallDlg::CSMPackageInstallDlg(RString sPackagePath, CWnd* pParent /*=NULL*/)
: CDialog(CSMPackageInstallDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CSMPackageInstallDlg)
@@ -87,8 +85,12 @@ BOOL CSMPackageInstallDlg::OnInitDialog()
DialogUtil::LocalizeDialogAndContents( *this );
DialogUtil::SetHeaderFont( *this, IDC_STATIC_HEADER_TEXT );
ASSERT(0); // TEST ME
// mount the zip
if( !FILEMAN->Mount( "zip", m_sPackagePath, TEMP_MOUNT_POINT ) )
RageFileDriverZip fileDriver;
int iErr;
if( !fileDriver.Open(m_sPackagePath, RageFile::READ, iErr) )
{
AfxMessageBox( ssprintf(IS_NOT_A_VALID_ZIP.GetValue(), m_sPackagePath), MB_ICONSTOP );
exit( 1 );
@@ -114,7 +116,7 @@ BOOL CSMPackageInstallDlg::OnInitDialog()
//
{
vector<RString> vs;
GetDirListingRecursive( TEMP_MOUNT_POINT, "*.*", vs );
GetDirListingRecursive( &fileDriver, "", "*", vs );
CEdit* pEdit2 = (CEdit*)GetDlgItem(IDC_EDIT_MESSAGE2);
RString sText = "\t" + join( "\r\n\t", vs );
pEdit2->SetWindowText( sText );
@@ -169,12 +171,16 @@ void CSMPackageInstallDlg::OnPaint()
#include <direct.h>
#include ".\smpackageinstalldlg.h"
bool CSMPackageInstallDlg::CheckPackages()
static bool CheckPackages( RageFileDriverZip &fileDriver )
{
IniFile ini;
if( !ini.ReadFile(TEMP_MOUNT_POINT + "smzip.ctl") )
int iErr;
RageFileBasic *pFile = fileDriver.Open( "smzip.ctl", RageFile::READ, iErr );
if( pFile == NULL )
return true;
IniFile ini;
ini.ReadFile( *pFile );
int version = 0;
ini.GetValue( "SMZIP", "Version", version );
if( version != 1 )
@@ -221,23 +227,11 @@ bool CSMPackageInstallDlg::CheckPackages()
for( i = 0; i < (int) Directories.size(); ++i )
{
RString path = cwd+Directories[i];
char buf[1024];
memcpy( buf, path, path.size()+1 );
buf[path.size()+1] = 0;
SHFILEOPSTRUCT op;
memset(&op, 0, sizeof(op));
op.wFunc = FO_DELETE;
op.pFrom = buf;
op.pTo = NULL;
op.fFlags = FOF_NOCONFIRMATION;
if( !SHFileOperation(&op) )
continue;
/* Something failed. SHFileOperation displayed the error dialog, so just cancel. */
return false;
RString sDir = Directories[i];
if( !DeleteRecursive(sDir) ) // error deleting
{
return false;
}
}
return true;
@@ -262,7 +256,8 @@ void CSMPackageInstallDlg::OnOK()
m_comboDir.GetWindowText( s );
sInstallDir = s;
}
// selected install dir becomes the new default
int iSelectedInstallDirIndex = m_comboDir.GetCurSel();
if( iSelectedInstallDirIndex == -1 )
{
@@ -272,11 +267,20 @@ void CSMPackageInstallDlg::OnOK()
SMPackageUtil::SetDefaultInstallDir( iSelectedInstallDirIndex );
// mount the zip
RageFileDriverZip fileDriver;
int iErr;
if( !fileDriver.Open(m_sPackagePath, RageFile::READ, iErr) )
{
AfxMessageBox( ssprintf(IS_NOT_A_VALID_ZIP.GetValue(), m_sPackagePath), MB_ICONSTOP );
exit( 1 );
}
// Show comment (if any)
{
RageFileDriverZip zip;
zip.Load( m_sPackagePath );
RString sComment = zip.GetGlobalComment();
RString sComment = fileDriver.GetGlobalComment();
bool DontShowComment;
if( sComment != "" && (!SMPackageUtil::GetPref("DontShowComment", DontShowComment) || !DontShowComment) )
{
@@ -291,13 +295,13 @@ void CSMPackageInstallDlg::OnOK()
}
/* Check for installed packages that should be deleted before installing. */
if( !CheckPackages() )
if( !CheckPackages(fileDriver) )
return; // cancelled
// Unzip the SMzip package into the installation folder
vector<RString> vs;
GetDirListingRecursive( TEMP_MOUNT_POINT, "*.*", vs );
GetDirListingRecursive( &fileDriver, "/", "*", vs );
for( unsigned i=0; i<vs.size(); i++ )
{
// Throw some text up so the user has something to look at during the long pause.
@@ -332,12 +336,31 @@ retry_unzip:
if( Basename(sFile).CompareNoCase("thumbs.db") == 0 )
continue;
RString sBareFile = sFile;
sBareFile.erase( sBareFile.begin(), sBareFile.begin()+TEMP_MOUNT_POINT.length() );
RString sTo = sInstallDir + sTo;
if( !FileCopy( sFile, sTo ) )
bool bSuccess = true;
RString sError;
int iErr;
RageFileBasic *pFileFrom = fileDriver.Open( sFile, RageFile::READ, iErr );
if( pFileFrom == NULL )
{
RString sError = ssprintf( ERROR_COPYING_FILE.GetValue(), sBareFile.c_str() );
bSuccess = false;
}
RageFile fileTo;
if( !fileTo.Open(sFile, RageFile::WRITE) )
{
bSuccess = false;
sError = fileTo.GetError();
}
if( bSuccess )
{
bSuccess = FileCopy(*pFileFrom, fileTo, sError);
}
if( !bSuccess )
{
RString sError = ssprintf( ERROR_COPYING_FILE.GetValue(), sFile.c_str() );
switch( MessageBox( sError, NULL, MB_ABORTRETRYIGNORE|MB_ICONEXCLAMATION ) )
{
case IDABORT:
@@ -369,7 +392,6 @@ void CSMPackageInstallDlg::OnButtonEdit()
int nResponse = dlg.DoModal();
if( nResponse == IDOK )
{
SMPackageUtil::WriteGameInstallDirs( dlg.m_vsReturnedInstallDirs );
RefreshInstallationList();
}
}
@@ -14,7 +14,7 @@ class CSMPackageInstallDlg : public CDialog
{
// Construction
public:
CSMPackageInstallDlg(CString sPackagePath, CWnd* pParent = NULL); // standard constructor
CSMPackageInstallDlg(RString sPackagePath, CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CSMPackageInstallDlg)
@@ -34,7 +34,6 @@ public:
// Implementation
protected:
void RefreshInstallationList();
bool CheckPackages();
HICON m_hIcon;
RString m_sPackagePath;
+20 -8
View File
@@ -26,7 +26,6 @@ void SMPackageUtil::WriteGameInstallDirs( const vector<RString>& asInstallDirsTo
RString sName = ssprintf("%d",i);
RegistryAccess::SetRegValue( INSTALLATIONS_KEY, sName, asInstallDirsToWrite[i] );
}
}
void SMPackageUtil::GetGameInstallDirs( vector<RString>& asInstallDirsOut )
@@ -41,11 +40,10 @@ void SMPackageUtil::GetGameInstallDirs( vector<RString>& asInstallDirsOut )
if( !RegistryAccess::GetRegValue(INSTALLATIONS_KEY, sName, sPath) )
continue;
if( sPath == "" ) // read failed
if( sPath == "" ) // blank entry
continue; // skip
RString sProgramDir = sPath+"\\Program";
if( !DoesFileExist(sProgramDir) )
if( !IsValidInstallDir(sPath) )
continue; // skip
asInstallDirsOut.push_back( sPath );
@@ -55,7 +53,7 @@ void SMPackageUtil::GetGameInstallDirs( vector<RString>& asInstallDirsOut )
WriteGameInstallDirs( asInstallDirsOut );
}
void SMPackageUtil::AddGameInstallDir( RString sNewInstallDir )
void SMPackageUtil::AddGameInstallDir( const RString &sNewInstallDir )
{
vector<RString> asInstallDirs;
GetGameInstallDirs( asInstallDirs );
@@ -88,7 +86,7 @@ void SMPackageUtil::SetDefaultInstallDir( int iInstallDirIndex )
WriteGameInstallDirs( asInstallDirs );
}
void SMPackageUtil::SetDefaultInstallDir( RString sInstallDir )
void SMPackageUtil::SetDefaultInstallDir( const RString &sInstallDir )
{
vector<RString> asInstallDirs;
GetGameInstallDirs( asInstallDirs );
@@ -103,6 +101,11 @@ void SMPackageUtil::SetDefaultInstallDir( RString sInstallDir )
}
}
bool SMPackageUtil::IsValidInstallDir( const RString &sInstallDir )
{
return DoesOsAbsoluteFileExist( sInstallDir + "/Songs" );
}
bool SMPackageUtil::GetPref( const RString &name, bool &val )
{
return RegistryAccess::GetRegValue( SMPACKAGE_KEY, name, val );
@@ -115,7 +118,7 @@ bool SMPackageUtil::SetPref( const RString &name, bool val )
/* Get a package directory. For most paths, this is the first two components. For
* songs and note skins, this is the first three. */
RString SMPackageUtil::GetPackageDirectory(RString path)
RString SMPackageUtil::GetPackageDirectory(const RString &path)
{
if( path.find("CVS") != string::npos )
return ""; // skip
@@ -137,7 +140,7 @@ RString SMPackageUtil::GetPackageDirectory(RString path)
return ret;
}
bool SMPackageUtil::IsValidPackageDirectory( RString path )
bool SMPackageUtil::IsValidPackageDirectory( const RString &path )
{
/* Make sure the path contains only second-level directories, and doesn't
* contain any ".", "..", "...", etc. dirs. */
@@ -212,6 +215,15 @@ RString SMPackageUtil::GetLanguageCodeFromDisplayString( const RString &sDisplay
return s;
}
bool SMPackageUtil::DoesOsAbsoluteFileExist( const RString &sOsAbsoluteFile )
{
#if defined(WIN32)
DWORD dwAttr = ::GetFileAttributes( sOsAbsoluteFile );
return bool(dwAttr != (DWORD)-1);
#endif
}
static const RString TEMP_MOUNT_POINT = "/@package/";
RageFileOsAbsolute::~RageFileOsAbsolute()
+52 -37
View File
@@ -17,6 +17,7 @@
#include "archutils/Win32/SpecialDirs.h"
#include "archutils/Win32/DialogUtil.h"
#include "LocalizedString.h"
#include "RageFileDriverDirect.h"
#include <vector>
#include <algorithm>
@@ -98,14 +99,14 @@ RString ReplaceInvalidFileNameChars( RString sOldFileName )
}
static LocalizedString ERROR_ADDING_FILE ( "SmpackageExportDlg", "Error adding file '%s'." );
static bool ExportPackage( RString sPackageName, const vector<RString>& asDirectoriesToExport, RString sComment )
static bool ExportPackage( const RString &sPackageName, const RString &sSourceInstallDir, const vector<RString>& asDirectoriesToExport, const RString &sComment )
{
CZipArchive zip;
//
// Create the package zip file
//
const RString sPackagePath = "Desktop/" + sPackageName;
const RString sPackagePath = SpecialDirs::GetDesktopDir() + sPackageName;
try
{
zip.Open( sPackagePath, CZipArchive::zipCreate );
@@ -118,13 +119,23 @@ static bool ExportPackage( RString sPackageName, const vector<RString>& asDirect
return false;
}
zip.SetGlobalComment( sComment );
/* Find files to add to zip. */
vector<RString> asFilePaths;
for( unsigned i=0; i<asDirectoriesToExport.size(); i++ )
GetDirListingRecursive( asDirectoriesToExport[i], "*.*", asFilePaths );
{
RageFileDriverDirect fileDriver( sSourceInstallDir );
for( unsigned i=0; i<asDirectoriesToExport.size(); i++ )
{
RString sDir = asDirectoriesToExport[i];
if( sDir.Right(1) != "/" )
sDir += "/";
GetDirListingRecursive( &fileDriver, sDir, "*", asFilePaths );
}
}
// Must use backslashes in the path, or else WinZip and WinRAR don't see the files.
// Not sure if this is ZipArchive's fault.
@@ -135,7 +146,7 @@ static bool ExportPackage( RString sPackageName, const vector<RString>& asDirect
ini.SetValue( "SMZIP", "Version", 1 );
set<RString> Directories;
for( i=0; i<asFilePaths.size(); i++ )
for( unsigned i=0; i<asFilePaths.size(); i++ )
{
const RString name = SMPackageUtil::GetPackageDirectory( asFilePaths[i] );
if( name != "" )
@@ -186,7 +197,7 @@ static bool ExportPackage( RString sPackageName, const vector<RString>& asDirect
try
{
zip.AddNewFile( sFilePath, bUseCompression?Z_BEST_COMPRESSION:Z_NO_COMPRESSION, true );
zip.AddNewFile( sSourceInstallDir+sFilePath, bUseCompression?Z_BEST_COMPRESSION:Z_NO_COMPRESSION, true );
}
catch (CException* e)
{
@@ -229,7 +240,7 @@ void CSmpackageExportDlg::OnButtonExportAsOne()
vector<RString> asPaths;
GetCheckedPaths( asPaths );
if( asPaths.size() >= 0 )
if( asPaths.size() == 0 )
{
AfxMessageBox( NO_ITEMS_ARE_CHECKED.GetValue() );
return;
@@ -254,7 +265,7 @@ void CSmpackageExportDlg::OnButtonExportAsOne()
if( !MakeComment(sComment) )
return; // cancelled
if( ExportPackage( sPackageName, asPaths, sComment ) )
if( ExportPackage( sPackageName, GetCurrentInstallDir(), asPaths, sComment ) )
AfxMessageBox( ssprintf(SUCCESSFULLY_EXPORTED.GetValue(),sPackageName.c_str()) );
}
@@ -285,14 +296,14 @@ void CSmpackageExportDlg::OnButtonExportAsIndividual()
RString sPackageName;
vector<RString> asPathBits;
split( sPath, "\\", asPathBits, true );
split( sPath, "/", asPathBits, true );
sPackageName = asPathBits[ asPathBits.size()-1 ] + ".smzip";
sPackageName = ReplaceInvalidFileNameChars( sPackageName );
vector<RString> asPathsToExport;
asPathsToExport.push_back( sPath );
if( ExportPackage( sPackageName, asPathsToExport, sComment ) )
if( ExportPackage( sPackageName, GetCurrentInstallDir(), asPathsToExport, sComment ) )
asExportedPackages.push_back( sPackageName );
else
asFailedPackages.push_back( sPackageName );
@@ -368,11 +379,11 @@ void CSmpackageExportDlg::GetCheckedPaths( vector<RString>& aPathsOut )
while( item )
{
sPath = (LPCTSTR)m_tree.GetItemText(item) + '\\' + sPath;
sPath = RString((LPCTSTR)m_tree.GetItemText(item)) + '/' + sPath;
item = m_tree.GetParentItem(item);
}
TrimRight( sPath, "\\" ); // strip off last slash
TrimRight( sPath, "/" ); // strip off last slash
aPathsOut.push_back( sPath );
}
@@ -386,7 +397,6 @@ void CSmpackageExportDlg::OnButtonEdit()
int nResponse = dlg.DoModal();
if( nResponse == IDOK )
{
SMPackageUtil::WriteGameInstallDirs( dlg.m_vsReturnedInstallDirs );
RefreshInstallationList();
RefreshTree();
}
@@ -411,24 +421,27 @@ void CSmpackageExportDlg::OnSelchangeComboDir()
RefreshTree();
}
RString CSmpackageExportDlg::GetCurrentInstallDir()
{
CString s;
m_comboDir.GetWindowText( s );
RString s2 = s;
if( s2.Right(1) != "/" )
s2 += "/";
return s2;
}
void CSmpackageExportDlg::RefreshTree()
{
m_tree.DeleteAllItems();
RString sDir;
{
CString s;
m_comboDir.GetWindowText( s );
sDir = s;
}
SetCurrentDirectory( sDir );
RageFileDriverDirect fileDriver( GetCurrentInstallDir() );
// Add announcers
{
vector<RString> as1;
HTREEITEM item1 = m_tree.InsertItem( "Announcers" );
GetDirListing( "Announcers\\*.*", as1, true, false );
fileDriver.GetDirListing( "Announcers/*", as1, true, false );
for( unsigned i=0; i<as1.size(); i++ )
m_tree.InsertItem( as1[i], item1 );
}
@@ -437,7 +450,7 @@ void CSmpackageExportDlg::RefreshTree()
{
vector<RString> as1;
HTREEITEM item1 = m_tree.InsertItem( "Characters" );
GetDirListing( "Characters\\*.*", as1, true, false );
fileDriver.GetDirListing( "Characters/*", as1, true, false );
for( unsigned i=0; i<as1.size(); i++ )
m_tree.InsertItem( as1[i], item1 );
}
@@ -446,7 +459,7 @@ void CSmpackageExportDlg::RefreshTree()
{
vector<RString> as1;
HTREEITEM item1 = m_tree.InsertItem( "Themes" );
GetDirListing( "Themes\\*.*", as1, true, false );
fileDriver.GetDirListing( "Themes/*", as1, true, false );
for( unsigned i=0; i<as1.size(); i++ )
m_tree.InsertItem( as1[i], item1 );
}
@@ -455,7 +468,7 @@ void CSmpackageExportDlg::RefreshTree()
{
vector<RString> as1;
HTREEITEM item1 = m_tree.InsertItem( "BGAnimations" );
GetDirListing( "BGAnimations\\*.*", as1, true, false );
fileDriver.GetDirListing( "BGAnimations/*", as1, true, false );
for( unsigned i=0; i<as1.size(); i++ )
m_tree.InsertItem( as1[i], item1 );
}
@@ -464,9 +477,9 @@ void CSmpackageExportDlg::RefreshTree()
{
vector<RString> as1;
HTREEITEM item1 = m_tree.InsertItem( "RandomMovies" );
GetDirListing( "RandomMovies\\*.avi", as1, false, false );
GetDirListing( "RandomMovies\\*.mpg", as1, false, false );
GetDirListing( "RandomMovies\\*.mpeg", as1, false, false );
fileDriver.GetDirListing( "RandomMovies/*.avi", as1, false, false );
fileDriver.GetDirListing( "RandomMovies/*.mpg", as1, false, false );
fileDriver.GetDirListing( "RandomMovies/*.mpeg", as1, false, false );
for( unsigned i=0; i<as1.size(); i++ )
m_tree.InsertItem( as1[i], item1 );
}
@@ -475,9 +488,9 @@ void CSmpackageExportDlg::RefreshTree()
{
vector<RString> as1;
HTREEITEM item1 = m_tree.InsertItem( "Visualizations" );
GetDirListing( "Visualizations\\*.avi", as1, false, false );
GetDirListing( "Visualizations\\*.mpg", as1, false, false );
GetDirListing( "Visualizations\\*.mpeg", as1, false, false );
fileDriver.GetDirListing( "Visualizations/*.avi", as1, false, false );
fileDriver.GetDirListing( "Visualizations/*.mpg", as1, false, false );
fileDriver.GetDirListing( "Visualizations/*.mpeg", as1, false, false );
for( unsigned i=0; i<as1.size(); i++ )
m_tree.InsertItem( as1[i], item1 );
}
@@ -486,7 +499,7 @@ void CSmpackageExportDlg::RefreshTree()
{
vector<RString> as1;
HTREEITEM item1 = m_tree.InsertItem( "Courses" );
GetDirListing( "Courses\\*.crs", as1, false, false );
fileDriver.GetDirListing( "Courses/*.crs", as1, false, false );
for( unsigned i=0; i<as1.size(); i++ )
{
as1[i] = as1[i].Left(as1[i].size()-4); // strip off ".crs"
@@ -501,12 +514,12 @@ void CSmpackageExportDlg::RefreshTree()
{
vector<RString> as1;
HTREEITEM item1 = m_tree.InsertItem( "NoteSkins" );
GetDirListing( "NoteSkins\\*.*", as1, true, false );
fileDriver.GetDirListing( "NoteSkins/*", as1, true, false );
for( unsigned i=0; i<as1.size(); i++ )
{
vector<RString> as2;
HTREEITEM item2 = m_tree.InsertItem( as1[i], item1 );
GetDirListing( "NoteSkins\\" + as1[i] + "\\*.*", as2, true, false );
fileDriver.GetDirListing( "NoteSkins/" + as1[i] + "/*", as2, true, false );
for( unsigned j=0; j<as2.size(); j++ )
m_tree.InsertItem( as2[j], item2 );
}
@@ -518,12 +531,12 @@ void CSmpackageExportDlg::RefreshTree()
{
vector<RString> as1;
HTREEITEM item1 = m_tree.InsertItem( "Songs" );
GetDirListing( "Songs\\*.*", as1, true, false );
fileDriver.GetDirListing( "Songs/*", as1, true, false );
for( unsigned i=0; i<as1.size(); i++ )
{
vector<RString> as2;
HTREEITEM item2 = m_tree.InsertItem( as1[i], item1 );
GetDirListing( "Songs\\" + as1[i] + "\\*.*", as2, true, false );
fileDriver.GetDirListing( "Songs/" + as1[i] + "/*", as2, true, false );
for( unsigned j=0; j<as2.size(); j++ )
m_tree.InsertItem( as2[j], item2 );
}
@@ -534,8 +547,10 @@ void CSmpackageExportDlg::RefreshTree()
CArray<HTREEITEM,HTREEITEM> aItems;
GetTreeItems( aItems );
for( int i=0; i<aItems.GetSize(); i++ )
{
if( m_tree.GetItemText(aItems[i]).CompareNoCase("CVS")==0 )
m_tree.DeleteItem( aItems[i] );
}
}
void CSmpackageExportDlg::OnButtonOpen()
@@ -44,6 +44,7 @@ protected:
void GetCheckedTreeItems( CArray<HTREEITEM,HTREEITEM>& aCheckedItemsOut );
void GetCheckedPaths( vector<RString>& aCheckedItemsOut );
bool MakeComment( RString &comment );
RString GetCurrentInstallDir();
// Generated message map functions
//{{AFX_MSG(CSmpackageExportDlg)
+59 -59
View File
@@ -56,65 +56,13 @@ BOOL CSmpackageApp::InitInstance()
LOG = new RageLog();
if( DoesFileExist("Songs") ) // this is a SM program directory
TCHAR szCurrentDirectory[MAX_PATH];
GetCurrentDirectory( ARRAYSIZE(szCurrentDirectory), szCurrentDirectory );
if( CAN_INSTALL_PACKAGES && SMPackageUtil::IsValidInstallDir(szCurrentDirectory) )
{
TCHAR szCurrentDirectory[MAX_PATH];
GetCurrentDirectory( ARRAYSIZE(szCurrentDirectory), szCurrentDirectory );
SMPackageUtil::AddGameInstallDir( szCurrentDirectory ); // add this if it doesn't already exist
}
// check if there's a .smzip command line argument
vector<RString> arrayCommandLineBits;
split( ::GetCommandLine(), " ", arrayCommandLineBits );
for( unsigned i=0; i<arrayCommandLineBits.size(); i++ )
{
CString sArg = arrayCommandLineBits[i];
if( sArg == "--machine-profile-stats" )
{
RString sPersonalDir = SpecialDirs::GetMyDocumentsDir();
RString sFile = sPersonalDir + PRODUCT_ID +"/Save/MachineProfile/Stats.xml";
if( NULL == ::ShellExecute( NULL, "open", sFile, "", "", SW_SHOWNORMAL ) )
AfxMessageBox( ssprintf(FAILED_TO_OPEN.GetValue(),sFile.c_str(),GetLastErrorString().c_str()) );
exit(0);
}
}
split( ::GetCommandLine(), "\"", arrayCommandLineBits );
for( unsigned i=0; i<arrayCommandLineBits.size(); i++ )
{
RString sPath = arrayCommandLineBits[i];
TrimLeft( sPath );
TrimRight( sPath );
RString sPathLower = sPath;
sPathLower.MakeLower();
// test to see if this is a smzip file
if( sPathLower.Right(3) == "zip" )
{
if( !FILEMAN->DoesFileExist(sPath) )
{
AfxMessageBox( ssprintf(THE_FILE_DOES_NOT_EXIST.GetValue(),sPath.c_str()), MB_ICONERROR );
exit(0);
}
// We found a zip package. Prompt the user to install it!
CSMPackageInstallDlg dlg( CString(sPath.c_str()) );
int nResponse = dlg.DoModal();
if( nResponse == IDOK )
{
CSmpackageExportDlg dlg;
int nResponse = dlg.DoModal();
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
else if (nResponse == IDCANCEL)
{
// the user cancelled. Don't fall through to the Manager.
exit(0);
}
}
}
FILEMAN = new RageFileManager( "" );
LUA = new LuaManager();
@@ -133,11 +81,63 @@ BOOL CSmpackageApp::InitInstance()
THEME->SwitchThemeAndLanguage( SpecialFiles::BASE_THEME_NAME, sLanguage, bPseudoLocalize );
// Show the Manager Dialog
MainMenuDlg dlg;
int nResponse = dlg.DoModal();
// if (nResponse == IDOK)
// check for --machine-profile-stats and launch Stats.xml
for( int i=0; i<argc; i++ )
{
CString sArg = argv[i];
if( sArg == "--machine-profile-stats" )
{
RString sPersonalDir = SpecialDirs::GetMyDocumentsDir();
RString sFile = sPersonalDir + PRODUCT_ID +"/Save/MachineProfile/Stats.xml";
if( NULL == ::ShellExecute( NULL, "open", sFile, "", "", SW_SHOWNORMAL ) )
AfxMessageBox( ssprintf(FAILED_TO_OPEN.GetValue(),sFile.c_str(),GetLastErrorString().c_str()) );
goto command_line_handled;
}
}
// check if there's a .smzip command line argument and install it
for( int i=0; i<argc; i++ )
{
RString sPath = argv[i];
TrimLeft( sPath );
TrimRight( sPath );
RString sPathLower = sPath;
sPathLower.MakeLower();
// test to see if this is a smzip file
if( sPathLower.Right(3) == "zip" )
{
if( !SMPackageUtil::DoesOsAbsoluteFileExist(sPath) )
{
AfxMessageBox( ssprintf(THE_FILE_DOES_NOT_EXIST.GetValue(),sPath.c_str()), MB_ICONERROR );
goto command_line_handled;
}
// We found a zip package. Prompt the user to install it!
CSMPackageInstallDlg dlg( sPath );
int nResponse = dlg.DoModal();
if( nResponse == IDOK )
{
CSmpackageExportDlg dlg;
int nResponse = dlg.DoModal();
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
goto command_line_handled;
}
else if (nResponse == IDCANCEL)
{
// the user cancelled. Don't fall through to the Manager.
goto command_line_handled;
}
}
}
{
MainMenuDlg dlg;
int nResponse = dlg.DoModal();
}
command_line_handled:
SAFE_DELETE( THEME );
SAFE_DELETE( LUA );
+4 -4
View File
@@ -96,7 +96,7 @@ BEGIN
PUSHBUTTON "Edit Installations",IDC_BUTTON_EDIT,233,194,59,14
CONTROL "",IDC_PROGRESS1,"msctls_progress32",NOT WS_VISIBLE |
WS_BORDER,7,60,318,14
LTEXT "Install a package",IDC_STATIC_HEADER_TEXT,5,2,280,24
LTEXT "Install a package",IDC_STATIC_HEADER_TEXT,5,5,280,24
END
IDD_EXPORTER DIALOGEX 0, 0, 349, 222
@@ -131,8 +131,8 @@ BEGIN
EDITTEXT IDC_EDIT,17,20,178,13,ES_AUTOHSCROLL
DEFPUSHBUTTON "OK",IDOK,200,7,54,14
PUSHBUTTON "Cancel",IDCANCEL,200,24,54,14
LTEXT "NOTE: (leave off the "".smzip"" extension)",IDC_STATIC,
18,38,179,12
LTEXT "Note: leave off the "".smzip"" extension",IDC_STATIC,18,
38,179,12
END
IDD_EDIT_INSTALLATIONS DIALOGEX 0, 0, 243, 221
@@ -188,7 +188,7 @@ BEGIN
PUSHBUTTON "Languages",IDC_LANGUAGES,14,232,91,15
LTEXT "Create a new or manage existing language translations.",
IDC_STATIC,109,232,213,20
LTEXT "StepMania Tools Main Menu",IDC_STATIC_HEADER_TEXT,5,2,
LTEXT "StepMania Tools Main Menu",IDC_STATIC_HEADER_TEXT,5,5,
280,24
LTEXT "Open the preferences file to make changes by hand.",
IDC_STATIC,109,127,213,18
+7 -4
View File
@@ -7,15 +7,16 @@ namespace SMPackageUtil
{
void WriteGameInstallDirs( const vector<RString>& asInstallDirsToWrite );
void GetGameInstallDirs( vector<RString>& asInstallDirsOut );
void AddGameInstallDir( RString sNewInstallDir );
void AddGameInstallDir( const RString &sNewInstallDir );
void SetDefaultInstallDir( int iInstallDirIndex );
void SetDefaultInstallDir( RString sInstallDir );
void SetDefaultInstallDir( const RString &sInstallDir );
bool IsValidInstallDir( const RString &sInstallDir );
bool GetPref( const RString &name, bool &val );
bool SetPref( const RString &name, bool val );
RString GetPackageDirectory(RString path);
bool IsValidPackageDirectory(RString path);
RString GetPackageDirectory( const RString &path );
bool IsValidPackageDirectory( const RString &path );
bool LaunchGame();
@@ -23,6 +24,8 @@ namespace SMPackageUtil
RString GetLanguageCodeFromDisplayString( const RString &sDisplayString );
bool GetFileContentsOsAbsolute( const RString &sAbsoluteOsFile, RString &sOut );
bool DoesOsAbsoluteFileExist( const RString &sOsAbsoluteFile );
}
#include "RageFile.h"