diff --git a/stepmania/src/CryptManager.cpp b/stepmania/src/CryptManager.cpp index c0f019ea56..56c2a2ff07 100644 --- a/stepmania/src/CryptManager.cpp +++ b/stepmania/src/CryptManager.cpp @@ -2,6 +2,7 @@ #include "CryptManager.h" #include "RageUtil.h" #include "RageLog.h" +#include "PrefsManager.h" static const CString SIGNATURE_APPEND = ".sig.rsa"; @@ -35,6 +36,13 @@ void CryptManager::DigestFile(const char *filename) { } using namespace CryptoPP; using namespace std; +static const CString SIGNATURE_POSPEND = ".sig.rsa"; +static const CString PRIVATE_KEY_PATH = "Data/private.key.rsa"; +static const CString PUBLIC_KEY_PATH = "Data/public.key.rsa"; +static const int KEY_LENGTH = 1024; + +CryptManager* CRYPTMAN = NULL; // global and accessable from anywhere in our program + CryptManager::CryptManager() { // @@ -42,12 +50,15 @@ CryptManager::CryptManager() // /* This is crashing in crypto51/integer.cpp CryptoPP::RecursiveInverseModPower2 * in Linux. -glenn */ - if( !DoesFileExist(PRIVATE_KEY_PATH) || !DoesFileExist(PUBLIC_KEY_PATH) ) - { - LOG->Warn( "Keys missing. Generating new keys" ); - GenerateRSAKey( KEY_LENGTH, PRIVATE_KEY_PATH, PUBLIC_KEY_PATH, "aoksdjaksd" ); - FlushDirCache(); - } +// if( PREFSMAN->m_bSignProfileData ) +// { +// if( !DoesFileExist(PRIVATE_KEY_PATH) || !DoesFileExist(PUBLIC_KEY_PATH) ) +// { +// LOG->Warn( "Keys missing. Generating new keys" ); +// GenerateRSAKey( KEY_LENGTH, PRIVATE_KEY_PATH, PUBLIC_KEY_PATH, "aoksdjaksd" ); +// FlushDirCache(); +// } +// } } CryptManager::~CryptManager() @@ -57,6 +68,8 @@ CryptManager::~CryptManager() void CryptManager::GenerateRSAKey(unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed ) { + ASSERT( PREFSMAN->m_bSignProfileData ); + AutoSeededRandomPool rng; RSAES_OAEP_SHA_Decryptor priv(rng, keyLength); @@ -72,6 +85,8 @@ void CryptManager::GenerateRSAKey(unsigned int keyLength, const char *privFilena void CryptManager::SignFile( CString sPath ) { + ASSERT( PREFSMAN->m_bSignProfileData ); + CString sPrivFilename = PRIVATE_KEY_PATH; CString sMessageFilename = sPath;; CString sSignatureFilename = sPath + SIGNATURE_APPEND; @@ -93,6 +108,8 @@ void CryptManager::SignFile( CString sPath ) bool CryptManager::VerifyFile( CString sPath ) { + ASSERT( PREFSMAN->m_bSignProfileData ); + CString sPubFilename = PUBLIC_KEY_PATH; CString sMessageFilename = sPath;; CString sSignatureFilename = sPath + SIGNATURE_APPEND; @@ -125,6 +142,8 @@ bool CryptManager::VerifyFile( CString sPath ) CString CryptManager::GetFileSignature( CString sPath ) { + ASSERT( PREFSMAN->m_bSignProfileData ); + CString sPrivFilename = PRIVATE_KEY_PATH; CString sMessageFilename = sPath; @@ -147,6 +166,8 @@ CString CryptManager::GetFileSignature( CString sPath ) bool CryptManager::VerifyFile( CString sPath, CString sSignature ) { + ASSERT( PREFSMAN->m_bSignProfileData ); + CString sPubFilename = PUBLIC_KEY_PATH; CString sMessageFilename = sPath; @@ -175,6 +196,8 @@ bool CryptManager::VerifyFile( CString sPath, CString sSignature ) void CryptManager::DigestFile(const char *filename) { + ASSERT( PREFSMAN->m_bSignProfileData ); + // MD5 md5; // HashFilter md5Filter(md5); // @@ -190,5 +213,7 @@ void CryptManager::DigestFile(const char *filename) CString CryptManager::GetPublicKeyFileName() { + ASSERT( PREFSMAN->m_bSignProfileData ); + return PUBLIC_KEY_PATH; } diff --git a/stepmania/src/Profile.cpp b/stepmania/src/Profile.cpp index 2b22eca614..f60a9fb396 100644 --- a/stepmania/src/Profile.cpp +++ b/stepmania/src/Profile.cpp @@ -28,6 +28,7 @@ #include "PrefsManager.h" #include "ProfileHtml.h" #include "ProfileManager.h" +#include "RageFileManager.h" // // Old file versions for backward compatibility @@ -37,6 +38,7 @@ #define SM_390A12_CATEGORY_SCORES_DAT "CategoryScores.dat" #define SM_390A12_SONG_SCORES_DAT "SongScores.dat" #define SM_390A12_COURSE_SCORES_DAT "CourseScores.dat" +#define SM_390A12_PROFILE_INI "Profile.ini" const int SM_390A12_CATEGORY_RANKING_VERSION = 6; const int SM_390A12_SONG_SCORES_VERSION = 9; const int SM_390A12_COURSE_SCORES_VERSION = 8; @@ -44,20 +46,20 @@ const int SM_390A12_COURSE_SCORES_VERSION = 8; // // Current file versions // -#define PROFILE_INI "Profile.ini" -#define CATEGORY_SCORES_XML "CategoryScores.xml" -#define SONG_SCORES_XML "SongScores.xml" -#define COURSE_SCORES_XML "CourseScores.xml" -#define SCREENSHOT_DATA_XML "ScreenshotData.xml" +#define STATS_XML "Stats.xml" +#define EDITABLE_XML "Editable.xml" + +#define REASONABLE_EDITABLE_XML_SIZE_BYTES 1000 // 1kb -#define DEFAULT_PROFILE_NAME "" - +void Profile::InitEditableData() +{ + m_sDisplayName = ""; + m_fWeightPounds = 0; +} void Profile::InitGeneralData() { - // Fill in a default value in case ini doesn't have it. - m_sName = DEFAULT_PROFILE_NAME; m_sLastUsedHighScoreName = ""; m_bUsingProfileDefaultModifiers = false; m_sDefaultModifiers = ""; @@ -65,7 +67,6 @@ void Profile::InitGeneralData() m_iTotalPlaySeconds = 0; m_iTotalGameplaySeconds = 0; m_iCurrentCombo = 0; - m_fWeightPounds = 0; m_fCaloriesBurned = 0; m_sLastMachinePlayed = ""; @@ -104,8 +105,8 @@ void Profile::InitScreenshotData() CString Profile::GetDisplayName() const { - if( !m_sName.empty() ) - return m_sName; + if( !m_sDisplayName.empty() ) + return m_sDisplayName; else if( !m_sLastUsedHighScoreName.empty() ) return m_sLastUsedHighScoreName; else @@ -130,9 +131,8 @@ int Profile::GetTotalNumSongsPlayed() CString Profile::GetProfileDisplayNameFromDir( CString sDir ) { - Profile pro; - pro.LoadGeneralDataFromDir( sDir ); - return pro.GetDisplayName(); + // FIXME! + return ""; } int Profile::GetSongNumTimesPlayed( const Song* pSong ) const @@ -273,73 +273,163 @@ void Profile::IncrementCategoryPlayCount( StepsType st, RankingCategory rc ) // Loading and saving // +#define WARN LOG->Warn("Error parsing file at %s:%d",__FILE__,__LINE__); +#define WARN_AND_RETURN { WARN; return; } +#define WARN_AND_CONTINUE { WARN; continue; } +#define WARN_AND_BREAK { WARN; break; } +#define LOAD_NODE(X) { \ + XNode* X = xml.GetChild(#X); \ + if( X==NULL ) LOG->Warn("Failed to read section " #X); \ + else Load##X##FromNode(X); } +int g_iOnceCtr; +#define FOR_ONCE for(g_iOnceCtr=0;g_iOnceCtr<1;g_iOnceCtr++) + + bool Profile::LoadAllFromDir( CString sDir ) { + CHECKPOINT; + InitAll(); - bool bResult = LoadGeneralDataFromDir( sDir ); - + // Only try to load old score formats if we're allowing unsigned data. if( !PREFSMAN->m_bSignProfileData ) { + LoadProfileDataFromDirSM390a12( sDir ); LoadSongScoresFromDirSM390a12( sDir ); LoadCourseScoresFromDirSM390a12( sDir ); LoadCategoryScoresFromDirSM390a12( sDir ); } + + + // Read editable.xml. This file is never signed. + FOR_ONCE + { + CString fn = sDir + EDITABLE_XML; + + int iBytes = FILEMAN->GetFileSizeInBytes( fn ); + + // + // Don't load unreasonably large editable.xml files. + // + if( iBytes > REASONABLE_EDITABLE_XML_SIZE_BYTES ) + { + LOG->Warn( "The file '%s' is unreasonably large. It won't be loaded.", fn.c_str() ); + break; + } + + + LOG->Trace( "Reading profile data '%s'", fn.c_str() ); + + XNode xml; + if( !xml.LoadFromFile( fn ) ) + { + LOG->Warn( "Couldn't open file '%s' for reading.", fn.c_str() ); + break; + } + + if( xml.name != "Editable" ) + WARN_AND_BREAK; + + LOAD_NODE( EditableData ); + } + - LoadSongScoresFromDir( sDir ); - LoadCourseScoresFromDir( sDir ); - LoadCategoryScoresFromDir( sDir ); - LoadScreenshotDataFromDir( sDir ); - return bResult; + // Read stats.xml + FOR_ONCE + { + CString fn = sDir + STATS_XML; + + LOG->Trace( "Reading profile data '%s'", fn.c_str() ); + + if( PREFSMAN->m_bSignProfileData && !CryptManager::VerifyFile(fn) ) + { + LOG->Warn( "The file '%s' has been tampered with. Its data will be ignored.", fn.c_str() ); + break; + } + + XNode xml; + if( !xml.LoadFromFile( fn ) ) + { + LOG->Warn( "Couldn't open file '%s' for reading.", fn.c_str() ); + break; + } + + if( xml.name != "Stats" ) + WARN_AND_BREAK; + + LOAD_NODE( GeneralData ); + LOAD_NODE( SongScores ); + LOAD_NODE( CourseScores ); + LOAD_NODE( CategoryScores ); + LOAD_NODE( ScreenshotData ); + } + + return true; // FIXME? Investigate what happens if we always return true. } bool Profile::SaveAllToDir( CString sDir ) const { m_sLastMachinePlayed = PREFSMAN->m_sMachineName; + // Save editable.xml + { + CString fn = sDir + EDITABLE_XML; + + XNode xml; + xml.name = "Editable"; + xml.AppendChild( SaveEditableDataCreateNode() ); + if( !xml.SaveToFile(fn) ) + return false; + } + + // Save stats.xml + { + CString fn = sDir + STATS_XML; + + XNode xml; + xml.name = "Stats"; + xml.AppendChild( SaveGeneralDataCreateNode() ); + xml.AppendChild( SaveSongScoresCreateNode() ); + xml.AppendChild( SaveCourseScoresCreateNode() ); + xml.AppendChild( SaveCategoryScoresCreateNode() ); + xml.AppendChild( SaveScreenshotDataCreateNode() ); + if( !xml.SaveToFile(fn) ) + return false; + if( PREFSMAN->m_bSignProfileData ) + CryptManager::SignFile(fn); + } + + // Delete old files after saving new ones so we don't try to load old - // and make duplicate records. - // If the save fails, the delete will fail too... probably :-) - bool bResult = SaveGeneralDataToDir( sDir ); - SaveSongScoresToDir( sDir ); - DeleteSongScoresFromDirSM390a12( sDir ); - SaveCourseScoresToDir( sDir ); - DeleteCourseScoresFromDirSM390a12( sDir ); - SaveCategoryScoresToDir( sDir ); - DeleteCategoryScoresFromDirSM390a12( sDir ); - SaveScreenshotDataToDir( sDir ); + // files the next time and make duplicate records. + if( !PREFSMAN->m_bSignProfileData ) // we tried to read the older formats + { + DeleteProfileDataFromDirSM390a12( sDir ); + DeleteSongScoresFromDirSM390a12( sDir ); + DeleteCourseScoresFromDirSM390a12( sDir ); + DeleteCategoryScoresFromDirSM390a12( sDir ); + } + SaveStatsWebPageToDir( sDir ); - SaveMachinePublicKeyToDir( sDir ); - return bResult; + + return true; } -#define WARN LOG->Warn("Error parsing file '%s' at %s:%d",fn.c_str(),__FILE__,__LINE__); -#define WARN_AND_RETURN { WARN; return; } -#define WARN_AND_CONTINUE { WARN; continue; } -#define CRYPT_VERIFY_FILE \ - if( PREFSMAN->m_bSignProfileData && !CryptManager::VerifyFile(fn) ) { \ - LOG->Warn("Signature check failed for '%s' at %s:%d",fn.c_str(),__FILE__,__LINE__); return; } -#define CRYPT_VERIFY_FILE_BOOL \ - if( PREFSMAN->m_bSignProfileData && !CryptManager::VerifyFile(fn) ) { \ - LOG->Warn("Signature check failed for '%s' at %s:%d",fn.c_str(),__FILE__,__LINE__); return false; } -#define CRYPT_WRITE_SIG if( PREFSMAN->m_bSignProfileData ) { CryptManager::SignFile(fn); } - -bool Profile::LoadGeneralDataFromDir( CString sDir ) +void Profile::LoadProfileDataFromDirSM390a12( CString sDir ) { - CString fn = sDir + PROFILE_INI; + CString fn = sDir + SM_390A12_PROFILE_INI; + InitEditableData(); InitGeneralData(); - CRYPT_VERIFY_FILE_BOOL; - // // read ini // IniFile ini( fn ); if( !ini.ReadFile() ) - return false; + return; - ini.GetValue( "Profile", "DisplayName", m_sName ); + ini.GetValue( "Profile", "DisplayName", m_sDisplayName ); ini.GetValue( "Profile", "LastUsedHighScoreName", m_sLastUsedHighScoreName ); ini.GetValue( "Profile", "UsingProfileDefaultModifiers", m_bUsingProfileDefaultModifiers ); ini.GetValue( "Profile", "DefaultModifiers", m_sDefaultModifiers ); @@ -360,53 +450,135 @@ bool Profile::LoadGeneralDataFromDir( CString sDir ) ini.GetValue( "Profile", "NumSongsPlayedByDifficulty"+Capitalize(DifficultyToString((Difficulty)i)), m_iNumSongsPlayedByDifficulty[i] ); for( i=0; iGetGameDefForGame(GAMEMAN->GetStyleDefForStyle((Style)i)->m_Game)->m_szName)+Capitalize(GAMEMAN->GetStyleDefForStyle((Style)i)->m_szName), m_iNumSongsPlayedByStyle[i] ); - for( i=0; iname = "EditableData"; - bool bResult = ini.WriteFile(); - CRYPT_WRITE_SIG; - return bResult; + pEditableDataNode->AppendChild( "DisplayName", m_sDisplayName ); + pEditableDataNode->AppendChild( "WeightPounds", m_fWeightPounds ); + + return pEditableDataNode; } -void Profile::SaveSongScoresToDir( CString sDir ) const +XNode* Profile::SaveGeneralDataCreateNode() const +{ + XNode* pGeneralDataNode = new XNode; + pGeneralDataNode->name = "GeneralData"; + + pGeneralDataNode->AppendChild( "LastUsedHighScoreName", m_sLastUsedHighScoreName ); + pGeneralDataNode->AppendChild( "UsingProfileDefaultModifiers", m_bUsingProfileDefaultModifiers ); + pGeneralDataNode->AppendChild( "DefaultModifiers", m_sDefaultModifiers ); + pGeneralDataNode->AppendChild( "TotalPlays", m_iTotalPlays ); + pGeneralDataNode->AppendChild( "TotalPlaySeconds", m_iTotalPlaySeconds ); + pGeneralDataNode->AppendChild( "TotalGameplaySeconds", m_iTotalGameplaySeconds ); + pGeneralDataNode->AppendChild( "CurrentCombo", m_iCurrentCombo ); + pGeneralDataNode->AppendChild( "CaloriesBurned", m_fCaloriesBurned ); + pGeneralDataNode->AppendChild( "LastMachinePlayed", m_sLastMachinePlayed ); + + { + XNode* pNumSongsPlayedByPlayMode = pGeneralDataNode->AppendChild("NumSongsPlayedByPlayMode"); + FOREACH_PlayMode( pm ) + pNumSongsPlayedByPlayMode->AppendChild( PlayModeToString(pm), m_iNumSongsPlayedByPlayMode[pm] ); + } + + { + XNode* pNumSongsPlayedByStyle = pGeneralDataNode->AppendChild("NumSongsPlayedByStyle"); + for( int i=0; iGetStyleDefForStyle((Style)i)->m_szName; + pNumSongsPlayedByStyle->AppendChild( sStyle, m_iNumSongsPlayedByStyle[i] ); + } + } + + { + XNode* pNumSongsPlayedByDifficulty = pGeneralDataNode->AppendChild("NumSongsPlayedByDifficulty"); + FOREACH_Difficulty( dc ) + pNumSongsPlayedByDifficulty->AppendChild( DifficultyToString(dc), m_iNumSongsPlayedByDifficulty[dc] ); + } + + { + XNode* pNumSongsPlayedByMeter = pGeneralDataNode->AppendChild("NumSongsPlayedByMeter"); + for( int i=0; iAppendChild( ssprintf("Meter%d",i), m_iNumSongsPlayedByMeter[i] ); + } + + return pGeneralDataNode; +} + +void Profile::LoadEditableDataFromNode( const XNode* pNode ) +{ + ASSERT( pNode->name == "EditableData"); + + pNode->GetChildValue("DisplayName", m_sDisplayName); + pNode->GetChildValue("WeightPounds", m_fWeightPounds); + + // This is data that the user can change, so we have to validate it. + if( m_sDisplayName.GetLength() > 12 ) + m_sDisplayName = m_sDisplayName.Left(12); + // TODO: strip invalid chars? + // TODO: is 12 chars reasonable for all UTF8 strings? + CLAMP( m_fWeightPounds, 0, 500 ); +} + +void Profile::LoadGeneralDataFromNode( const XNode* pNode ) +{ + ASSERT( pNode->name == "GeneralData" ); + + pNode->GetChildValue( "LastUsedHighScoreName", m_sLastUsedHighScoreName ); + pNode->GetChildValue( "UsingProfileDefaultModifiers", m_bUsingProfileDefaultModifiers ); + pNode->GetChildValue( "DefaultModifiers", m_sDefaultModifiers ); + pNode->GetChildValue( "TotalPlays", m_iTotalPlays ); + pNode->GetChildValue( "TotalPlaySeconds", m_iTotalPlaySeconds ); + pNode->GetChildValue( "TotalGameplaySeconds", m_iTotalGameplaySeconds ); + pNode->GetChildValue( "CurrentCombo", m_iCurrentCombo ); + pNode->GetChildValue( "CaloriesBurned", m_fCaloriesBurned ); + pNode->GetChildValue( "LastMachinePlayed", m_sLastMachinePlayed ); + + { + XNode* pNumSongsPlayedByPlayMode = pNode->GetChild("NumSongsPlayedByPlayMode"); + if( pNumSongsPlayedByPlayMode ) + FOREACH_PlayMode( pm ) + pNumSongsPlayedByPlayMode->GetChildValue( PlayModeToString(pm), m_iNumSongsPlayedByPlayMode[pm] ); + } + + { + XNode* pNumSongsPlayedByStyle = pNode->GetChild("NumSongsPlayedByStyle"); + if( pNumSongsPlayedByStyle ) + for( int i=0; iGetStyleDefForStyle((Style)i)->m_szName; + pNumSongsPlayedByStyle->GetChildValue( sStyle, m_iNumSongsPlayedByStyle[i] ); + } + } + + { + XNode* pNumSongsPlayedByDifficulty = pNode->GetChild("NumSongsPlayedByDifficulty"); + if( pNumSongsPlayedByDifficulty ) + FOREACH_Difficulty( dc ) + pNumSongsPlayedByDifficulty->GetChildValue( DifficultyToString(dc), m_iNumSongsPlayedByDifficulty[dc] ); + } + + { + XNode* pNumSongsPlayedByMeter = pNode->GetChild("NumSongsPlayedByMeter"); + if( pNumSongsPlayedByMeter ) + for( int i=0; iGetChildValue( ssprintf("Meter%d",i), m_iNumSongsPlayedByMeter[i] ); + } +} + + +XNode* Profile::SaveSongScoresCreateNode() const { CHECKPOINT; const Profile* pProfile = this; ASSERT( pProfile ); - CString fn = sDir + SONG_SCORES_XML; - - XNode xml; - xml.name = "SongScores"; + XNode* pNode = new XNode; + pNode->name = "SongScores"; const vector &vpSongs = SONGMAN->GetAllSongs(); @@ -419,7 +591,7 @@ void Profile::SaveSongScoresToDir( CString sDir ) const if( pProfile->GetSongNumTimesPlayed(pSong) == 0 ) continue; - LPXNode pSongNode = xml.AppendChild( "Song" ); + LPXNode pSongNode = pNode->AppendChild( "Song" ); pSongNode->AppendChild( "SongDir", pSong->GetSongDir() ); const vector vSteps = pSong->GetAllSteps(); @@ -444,32 +616,15 @@ void Profile::SaveSongScoresToDir( CString sDir ) const } } - xml.SaveToFile( fn ); - CRYPT_WRITE_SIG; + return pNode; } -void Profile::LoadSongScoresFromDir( CString sDir ) +void Profile::LoadSongScoresFromNode( const XNode* pNode ) { - CHECKPOINT; + ASSERT( pNode->name == "SongScores" ); - CString fn = sDir + SONG_SCORES_XML; - if( !IsAFile(fn) ) - return; - - CRYPT_VERIFY_FILE; - - XNode xml; - if( !xml.LoadFromFile( fn ) ) - { - LOG->Warn( "Couldn't open file \"%s\" for reading.", fn.c_str() ); - return; - } - - if( xml.name != "SongScores" ) - WARN_AND_RETURN; - - for( XNodes::iterator song = xml.childs.begin(); - song != xml.childs.end(); + for( XNodes::const_iterator song = pNode->childs.begin(); + song != pNode->childs.end(); song++ ) { if( (*song)->name != "Song" ) @@ -798,18 +953,15 @@ void Profile::LoadCourseScoresFromDirSM390a12( CString sDir ) } -void Profile::SaveCourseScoresToDir( CString sDir ) const +XNode* Profile::SaveCourseScoresCreateNode() const { CHECKPOINT; const Profile* pProfile = this; ASSERT( pProfile ); - CString fn = sDir + COURSE_SCORES_XML; - - - XNode xml; - xml.name = "CourseScores"; + XNode* pNode = new XNode; + pNode->name = "CourseScores"; vector vpCourses; SONGMAN->GetAllCourses( vpCourses, true ); @@ -822,7 +974,7 @@ void Profile::SaveCourseScoresToDir( CString sDir ) const if( pProfile->GetCourseNumTimesPlayed(pCourse) == 0 ) continue; - XNode* pCourseNode = xml.AppendChild( "Course", pCourse->m_bIsAutogen ? pCourse->m_sName : pCourse->m_sPath ); + XNode* pCourseNode = pNode->AppendChild( "Course", pCourse->m_bIsAutogen ? pCourse->m_sName : pCourse->m_sPath ); for( StepsType st=(StepsType)0; stAppendChild( hsl.CreateNode() ); } } - - xml.SaveToFile( fn ); - CRYPT_WRITE_SIG; + + return pNode; } -void Profile::LoadCourseScoresFromDir( CString sDir ) +void Profile::LoadCourseScoresFromNode( const XNode* pNode ) { CHECKPOINT; - CString fn = sDir + COURSE_SCORES_XML; - if( !IsAFile(fn) ) - return; + ASSERT( pNode->name == "CourseScores" ); - CRYPT_VERIFY_FILE; - - XNode xml; - if( !xml.LoadFromFile( fn ) ) - { - LOG->Warn( "Couldn't open file \"%s\" for reading.", fn.c_str() ); - return; - } - - if( xml.name != "CourseScores" ) - WARN_AND_RETURN; - - for( XNodes::iterator course = xml.childs.begin(); - course != xml.childs.end(); + for( XNodes::const_iterator course = pNode->childs.begin(); + course != pNode->childs.end(); course++ ) { if( (*course)->name != "Course" ) @@ -895,17 +1032,15 @@ void Profile::LoadCourseScoresFromDir( CString sDir ) } } -void Profile::SaveCategoryScoresToDir( CString sDir ) const +XNode* Profile::SaveCategoryScoresCreateNode() const { CHECKPOINT; const Profile* pProfile = this; ASSERT( pProfile ); - CString fn = sDir + CATEGORY_SCORES_XML; - - XNode xml; - xml.name = "CategoryScores"; + XNode* pNode = new XNode; + pNode->name = "CategoryScores"; FOREACH_StepsType( st ) { @@ -913,7 +1048,7 @@ void Profile::SaveCategoryScoresToDir( CString sDir ) const if( pProfile->GetCategoryNumTimesPlayed( st ) == 0 ) continue; - XNode* pStepsTypeNode = xml.AppendChild( "StepsType", st ); + XNode* pStepsTypeNode = pNode->AppendChild( "StepsType", st ); FOREACH_RankingCategory( rc ) { @@ -929,32 +1064,17 @@ void Profile::SaveCategoryScoresToDir( CString sDir ) const } } - xml.SaveToFile( fn ); - CRYPT_WRITE_SIG; + return pNode; } -void Profile::LoadCategoryScoresFromDir( CString sDir ) +void Profile::LoadCategoryScoresFromNode( const XNode* pNode ) { CHECKPOINT; - CString fn = sDir + CATEGORY_SCORES_XML; - if( !IsAFile(fn) ) - return; + ASSERT( pNode->name == "CategoryScores" ); - CRYPT_VERIFY_FILE; - - XNode xml; - if( !xml.LoadFromFile( fn ) ) - { - LOG->Warn( "Couldn't open file \"%s\" for reading.", fn.c_str() ); - return; - } - - if( xml.name != "CategoryScores" ) - WARN_AND_RETURN; - - for( XNodes::iterator stepsType = xml.childs.begin(); - stepsType != xml.childs.end(); + for( XNodes::const_iterator stepsType = pNode->childs.begin(); + stepsType != pNode->childs.end(); stepsType++ ) { if( (*stepsType)->name != "StepsType" ) @@ -983,33 +1103,41 @@ void Profile::LoadCategoryScoresFromDir( CString sDir ) } } +void Profile::DeleteProfileDataFromDirSM390a12( CString sDir ) const +{ + CString fn = sDir + SM_390A12_PROFILE_INI; + FILEMAN->Remove( fn ); +} + void Profile::DeleteSongScoresFromDirSM390a12( CString sDir ) const { CString fn = sDir + SM_390A12_SONG_SCORES_DAT; - // FIXME + FILEMAN->Remove( fn ); } void Profile::DeleteCourseScoresFromDirSM390a12( CString sDir ) const { CString fn = sDir + SM_390A12_COURSE_SCORES_DAT; - // FIXME + FILEMAN->Remove( fn ); } void Profile::DeleteCategoryScoresFromDirSM390a12( CString sDir ) const { CString fn = sDir + SM_390A12_CATEGORY_SCORES_DAT; - // FIXME + FILEMAN->Remove( fn ); } void Profile::SaveStatsWebPageToDir( CString sDir ) const { + ASSERT( PROFILEMAN ); + // UGLY... - bool bThisIsMachineProfile = this == PROFILEMAN->GetMachineProfile(); + bool bThisIsMachineProfile = (this == PROFILEMAN->GetMachineProfile()); if( bThisIsMachineProfile ) { SaveMachineHtmlToDir( sDir, this ); -// SavePlayerHtmlToDir( sDir+"temp/", this, PROFILEMAN->GetMachineProfile() ); // remove this when done debugging + SavePlayerHtmlToDir( sDir+"temp/", this, PROFILEMAN->GetMachineProfile() ); // remove this when done debugging } else { @@ -1019,8 +1147,8 @@ void Profile::SaveStatsWebPageToDir( CString sDir ) const void Profile::SaveMachinePublicKeyToDir( CString sDir ) const { - if( IsAFile(CRYPTMAN->GetPublicKeyFileName()) ) - FileCopy( CRYPTMAN->GetPublicKeyFileName(), sDir+"public.key.rsa" ); + if( PREFSMAN->m_bSignProfileData && IsAFile(CRYPTMAN->GetPublicKeyFileName()) ) + FileCopy( CRYPTMAN->GetPublicKeyFileName(), "public.key.rsa" ); } void Profile::AddScreenshot( Screenshot screenshot ) @@ -1028,28 +1156,13 @@ void Profile::AddScreenshot( Screenshot screenshot ) m_vScreenshots.push_back( screenshot ); } -void Profile::LoadScreenshotDataFromDir( CString sDir ) +void Profile::LoadScreenshotDataFromNode( const XNode* pNode ) { CHECKPOINT; - CString fn = sDir + SCREENSHOT_DATA_XML; - if( !IsAFile(fn) ) - return; - - CRYPT_VERIFY_FILE; - - XNode xml; - if( !xml.LoadFromFile( fn ) ) - { - LOG->Warn( "Couldn't open file \"%s\" for reading.", fn.c_str() ); - return; - } - - if( xml.name != "ScreenshotData" ) - WARN_AND_RETURN; - - for( XNodes::iterator screenshot = xml.childs.begin(); - screenshot != xml.childs.end(); + ASSERT( pNode->name == "ScreenshotData" ); + for( XNodes::const_iterator screenshot = pNode->childs.begin(); + screenshot != pNode->childs.end(); screenshot++ ) { if( (*screenshot)->name != "Screenshot" ) @@ -1074,29 +1187,26 @@ void Profile::LoadScreenshotDataFromDir( CString sDir ) } } -void Profile::SaveScreenshotDataToDir( CString sDir ) const +XNode* Profile::SaveScreenshotDataCreateNode() const { CHECKPOINT; const Profile* pProfile = this; ASSERT( pProfile ); - CString fn = sDir + SCREENSHOT_DATA_XML; - - XNode xml; - xml.name = "ScreenshotData"; + XNode* pNode = new XNode; + pNode->name = "ScreenshotData"; for( unsigned i=0; iAppendChild( "Screenshot" ); pScreenshotNode->AppendChild( "FileName", ss.sFileName ); pScreenshotNode->AppendChild( "Signature", ss.sSignature ); pScreenshotNode->AppendChild( ss.highScore.CreateNode() ); } - xml.SaveToFile( fn ); - CRYPT_WRITE_SIG; + return pNode; }