/* ======================================================================================= Name :SaveMngr.cpp Author :Vincent Lhullier Date :11/07/97 Description :manage save of data before modification Create a copy of GameData tree with all file that would be modified. That will allow someone to recuperate previous version if save generate some problem in data. ======================================================================================= Modification -> Author : Date : Description : ======================================================================================= */ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ #include "stdafx.h" #ifdef ACTIVE_EDITOR #include #include "SaveMngr.h" #include "acp_base.h" #include "itf/CPAProj.hpp" #include "DPT.h" #include "SCR.h" /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /* ======================================================================================= STRUCTURE ======================================================================================= */ typedef struct SAVE_tdstFile_ { char *szName; char cNew; } SAVE_tdstFile; /* ======================================================================================= GLOBALS ======================================================================================= */ /* * indicate next number of version to use to save files * Warning : to be valid you must call SAVE_fn_vAnalyseCurrentUsedVersion before using * this number */ static long SAVE_g_lNextVersionNumber; static BOOL SAVE_g_bContinue; static BOOL SAVE_g_bGenerateIsActive = 2; static char SAVE_g_szDirName[ _MAX_PATH ]; static SAVE_tdstFile *SAVE_gs_d_stFile; static long SAVE_gs_lNumberOfFiles; static char *SAVE_g_szGameData; static long SAVE_g_lGameDataLength; /* ======================================================================================= ======================================================================================= FUNCTIONS ======================================================================================= ======================================================================================= */ /* ======================================================================================= Directory Functions ======================================================================================= */ /* ---------------------------------------------------------------------------------------- Don't call this function directly, it is used by SAVE_fn_bDeleteTree Description : delete recursively a directory Returns (BOOL ) true if success ---------------------------------------------------------------------------------------- */ BOOL fn_bDeleteTree( void ) { WIN32_FIND_DATA stFindData; HANDLE hFind; char *p_szEndDirName; p_szEndDirName = SAVE_g_szDirName + strlen( SAVE_g_szDirName ); strcpy( p_szEndDirName, "\\*.*" ); if( (hFind = FindFirstFile(SAVE_g_szDirName, &stFindData )) == INVALID_HANDLE_VALUE) return TRUE; *p_szEndDirName = 0; do { *p_szEndDirName = '\\'; strcpy( p_szEndDirName + 1, stFindData.cFileName ); if ( stFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { if ( *stFindData.cFileName != '.') { if ( !fn_bDeleteTree() ) return FALSE; } } else { if (_access( SAVE_g_szDirName, 2) == -1 ) _chmod( SAVE_g_szDirName, _S_IWRITE ); if ( !DeleteFile( SAVE_g_szDirName ) ) return FALSE; } *p_szEndDirName = 0; } while(FindNextFile( hFind, &stFindData )); FindClose( hFind ); return RemoveDirectory( SAVE_g_szDirName ); } /* ---------------------------------------------------------------------------------------- Description : delete completely a directory szDirName -> name of dir to delete Returns (BOOL ) true if success ---------------------------------------------------------------------------------------- */ BOOL SAVE_fn_bDeleteTree( char *szDirName ) { strcpy( SAVE_g_szDirName, szDirName ); return fn_bDeleteTree(); } /* ---------------------------------------------------------------------------------------- Description : create a directory szDirName -> name of directory Returns (BOOL ) true if sucess ---------------------------------------------------------------------------------------- */ BOOL SAVE_fn_bCreateDirectory( char *szDirName ) { if ( (!CreateDirectory( szDirName, NULL )) && (GetLastError() != ERROR_ALREADY_EXISTS) ) { char *p_szCur; p_szCur = strchr( szDirName, '\\'); while (p_szCur != NULL) { *p_szCur = 0; if ((!CreateDirectory (szDirName, NULL)) && (GetLastError() != ERROR_ALREADY_EXISTS) ) { char szMessage[ 512 ]; sprintf( szMessage, "Can't create local path %s", szDirName ); SAVE_fn_vErrorMessage( szMessage ); return FALSE; } *p_szCur++ = '\\'; p_szCur = strchr( p_szCur, '\\'); }; if ((!CreateDirectory (szDirName, NULL)) && (GetLastError() != ERROR_ALREADY_EXISTS) ) { char szMessage[ 512 ]; sprintf( szMessage, "Can't create local path %s", szDirName ); SAVE_fn_vErrorMessage( szMessage ); return FALSE; } } return TRUE; } /* ======================================================================================= Error functions ======================================================================================= */ /* ---------------------------------------------------------------------------------------- Description : display an error message _szMessage -> message to display ---------------------------------------------------------------------------------------- */ void SAVE_fn_vErrorMessage( char *_szMessage ) { char szError[1024]; char *p_szError = szError; p_szError += sprintf( p_szError, "Error saving current version before saving new data\n" ); p_szError += sprintf( p_szError, "You will not be able to get local previous version\n" ); p_szError += sprintf( p_szError, "---------------------------------------------------\n" ); p_szError += sprintf( p_szError, "%s\n\n", _szMessage ); p_szError += sprintf( p_szError, " Save anyway ?" ); SAVE_g_bContinue = AfxMessageBox( szError, MB_ICONSTOP | MB_YESNO ); } /* ======================================================================================= Version functions ======================================================================================= */ /* ---------------------------------------------------------------------------------------- Description : _szSavedDirectoryName -> name of directory from which function extract version number Returns (long ) version number if it's a valid directory, -1 else ---------------------------------------------------------------------------------------- */ long SAVE_fn_lGetVersionNumberFromDirExt( char *_szSavedDirectoryName ) { char *p_szExt; long lVersionNumber = -1; p_szExt = strchr( _szSavedDirectoryName, '.' ); if (p_szExt != NULL) { if ( strlen( ++p_szExt ) == 3) { lVersionNumber = 0; while (*p_szExt != 0) { if ( !isdigit (*p_szExt) ) return -1; lVersionNumber = lVersionNumber * 10 + (*p_szExt++ - '0'); } } } return lVersionNumber; } /* ---------------------------------------------------------------------------------------- Description : return name of directory used to store data for a given version lVersion -> version number szVersionDirName -> to put dir name (assumed to be long enough ) ---------------------------------------------------------------------------------------- */ void SAVE_fn_vGetVersionDirName( long _lVersion, char *_szVersionDirName ) { sprintf( _szVersionDirName, "%s.%03d", fn_szGetGameDataPath(), _lVersion ); } /* ---------------------------------------------------------------------------------------- Description : delete a version directory _lVersion -> number of version Returns (BOOL ) true if success ---------------------------------------------------------------------------------------- */ BOOL SAVE_fn_bDeleteVersion( long _lVersion ) { char szVersionName[ _MAX_PATH ]; SAVE_fn_vGetVersionDirName( _lVersion, szVersionName ); if (!SAVE_fn_bDeleteTree( szVersionName )) { char szMessage[100]; sprintf( szMessage, "Can't delete old %s version directory", szVersionName ); SAVE_fn_vErrorMessage( szMessage ); return FALSE; } return TRUE; } /* ---------------------------------------------------------------------------------------- Description : rename a version _lOldVersion -> old version number _lNewVersion -> new version number Returns (BOOL ) ---------------------------------------------------------------------------------------- */ BOOL SAVE_fn_bRenameVersion( long _lOldVersion, long _lNewVersion ) { char szOldVersion[ _MAX_PATH ]; char szNewVersion[ _MAX_PATH ]; SAVE_fn_vGetVersionDirName( _lOldVersion, szOldVersion ); SAVE_fn_vGetVersionDirName( _lNewVersion, szNewVersion ); if ( !MoveFile( szOldVersion, szNewVersion) ) { char szMessage[100]; sprintf( szMessage, "Can't rename old %s version to new version %s ", szOldVersion, szNewVersion ); SAVE_fn_vErrorMessage( szMessage ); return FALSE; } return TRUE; } /* ---------------------------------------------------------------------------------------- Description : analyse the current version that are on disk a_cVersion -> array of 1000 char that will be filled each case is a flag that indicate if a version number is used or not return (long) number of used version ---------------------------------------------------------------------------------------- */ long SAVE_fn_lGetUsedVersion( char *a_cVersion ) { WIN32_FIND_DATA stFindData; HANDLE hFind; char szFilter[ _MAX_PATH ]; long lNumberOfVersions = 0; long lVersion; /* * set all version as unused */ memset ( a_cVersion , 0, 1000 ); sprintf( szFilter, "%s.*", fn_szGetGameDataPath() ); if( (hFind = FindFirstFile(szFilter, &stFindData )) == INVALID_HANDLE_VALUE) return 0; do { if ( stFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { lVersion = SAVE_fn_lGetVersionNumberFromDirExt( stFindData.cFileName ); if (lVersion != -1) { a_cVersion[ lVersion ] = 1; lNumberOfVersions++ ; } } } while(FindNextFile( hFind, &stFindData )); FindClose( hFind ); return lNumberOfVersions; } /* ---------------------------------------------------------------------------------------- Description : analyse the current version that are on disk ---------------------------------------------------------------------------------------- */ BOOL SAVE_fn_bAnalyseCurrentUsedVersion( void ) { char a_cVersion[1000]; long lNumberOfVersions; long lVersion; long lVersionIndex; long lLastUnusedVersion = -1; /* * get used versions */ lNumberOfVersions = SAVE_fn_lGetUsedVersion( a_cVersion ); if (lNumberOfVersions == 0) { SAVE_g_lNextVersionNumber = 0; return TRUE; } /* * check for hole in version number */ lVersion = 0; for (lVersionIndex = 0; lVersion < lNumberOfVersions; lVersionIndex ++) { if (a_cVersion[ lVersionIndex ]) { lVersion ++; } else { lLastUnusedVersion = lVersionIndex; } } if (lLastUnusedVersion == -1) { SAVE_g_lNextVersionNumber = lNumberOfVersions; } else { for (lVersionIndex = 0; lVersionIndex < lLastUnusedVersion; lVersionIndex++) { if (a_cVersion[ lVersionIndex ]) { if (!SAVE_fn_bDeleteVersion( lVersionIndex )) { return FALSE; } } } lVersion = 0; for (lVersionIndex = lLastUnusedVersion + 1; a_cVersion[ lVersionIndex ]; lVersionIndex ++) { if (!SAVE_fn_bRenameVersion( lVersionIndex, lVersion ++ )) { return FALSE; } } SAVE_g_lNextVersionNumber = lVersion; } return TRUE; } /* ======================================================================================= modified File functions ======================================================================================= */ /* ---------------------------------------------------------------------------------------- Description : Add Gamedata dir behind name if not already here and check if file exist szFile -> name to check Returns (BOOL ) true if file exist ---------------------------------------------------------------------------------------- */ BOOL SAVE_fn_bGetGameDataFile( char *szFile ) { if (strnicmp( szFile, SAVE_g_szGameData, SAVE_g_lGameDataLength ) != 0) { memmove( szFile + SAVE_g_lGameDataLength + 1, szFile, strlen( szFile )); memcpy ( szFile, SAVE_g_szGameData, SAVE_g_lGameDataLength ); *(szFile + SAVE_g_lGameDataLength) = '\\'; } return ( _access( szFile, 0) == 0); } /* ---------------------------------------------------------------------------------------- Description : add file in array of file to save. check if file doesn't still exist szFile -> name to add ---------------------------------------------------------------------------------------- */ void SAVE_fn_vAddFile( char *_szFile, char _cNew ) { long lFile; /* * check if file doesn't till exist in list */ for (lFile = 0; lFile < SAVE_gs_lNumberOfFiles; lFile++) { if (stricmp( _szFile, SAVE_gs_d_stFile[ lFile ].szName ) == 0 ) return; } /* * Add file */ SAVE_gs_d_stFile[ SAVE_gs_lNumberOfFiles ].szName = (char *) malloc( strlen( _szFile ) + 1 ); strcpy( SAVE_gs_d_stFile[ SAVE_gs_lNumberOfFiles ].szName, _szFile ); SAVE_gs_d_stFile[ SAVE_gs_lNumberOfFiles ].cNew = _cNew; SAVE_gs_lNumberOfFiles++; } /* ---------------------------------------------------------------------------------------- Description : delete file list ---------------------------------------------------------------------------------------- */ void SAVE_fn_vFreeFileList( void ) { long lFile; if ( SAVE_gs_d_stFile != NULL) { for (lFile = 0; lFile < SAVE_gs_lNumberOfFiles; lFile++) free ( SAVE_gs_d_stFile[ lFile ].szName ); free ( SAVE_gs_d_stFile ); SAVE_gs_d_stFile = NULL; } } /* ---------------------------------------------------------------------------------------- Description : read all notification to buil list of files that would be modified return (long ) : number of file in list ---------------------------------------------------------------------------------------- */ long SAVE_fn_lGetNotifiedFileList( void ) { unsigned int uiPos; SCR_tdst_Ntfy_Description *p_stNtfy; char szFile[ _MAX_PATH ]; char *p_szEndFile; long lNbMaxFiles; /* * get number max of files and allocate array to store filenames */ lNbMaxFiles = SCR_g_st_Ntfy_Array.uiNumValues; SAVE_gs_lNumberOfFiles = 0; SAVE_gs_d_stFile = (SAVE_tdstFile *) malloc( (lNbMaxFiles + 1) * sizeof( SAVE_tdstFile ) ); /* * add eventually modification file */ strcpy( szFile, "modiflst.txt" ); SAVE_fn_vAddFile( szFile, SAVE_fn_bGetGameDataFile( szFile ) ? 0 : 1 ); /* * parse all notifications */ for (uiPos = 0; uiPos < (unsigned short) lNbMaxFiles; uiPos ++) { SCR_M_DyAr_GetNextElement(SCR_tdst_Ntfy_Description, uiPos, p_stNtfy, SCR_g_st_Ntfy_Array); if (p_stNtfy == NULL) break; strcpy( szFile, p_stNtfy->a_szSectionName ); p_szEndFile = strchr( szFile, '^' ); if (p_szEndFile != NULL) *p_szEndFile = 0; SAVE_fn_vAddFile( szFile, SAVE_fn_bGetGameDataFile( szFile ) ? 0 : 1 ); } return SAVE_gs_lNumberOfFiles; } /* ---------------------------------------------------------------------------------------- Description : create new tree with saved file ---------------------------------------------------------------------------------------- */ BOOL SAVE_fn_bCreateNewVersion( void ) { /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ long lFile; char szNewFile[ _MAX_PATH ]; char *p_szNewFile; char *p_szEndPath; FILE *hpFile; /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ SAVE_fn_vGetVersionDirName( SAVE_g_lNextVersionNumber, szNewFile ); p_szNewFile = szNewFile + strlen( szNewFile ); *p_szNewFile++ = '\\'; /* * copy file that exist and are going to be modified */ for (lFile = 0; lFile < SAVE_gs_lNumberOfFiles; lFile ++) { if ( SAVE_gs_d_stFile[lFile].cNew == 0) { strcpy( p_szNewFile, SAVE_gs_d_stFile[ lFile ].szName + SAVE_g_lGameDataLength + 1 ); p_szEndPath = strrchr( szNewFile, '\\' ); *p_szEndPath = 0; if ( !SAVE_fn_bCreateDirectory( szNewFile ) ) return FALSE; *p_szEndPath = '\\'; if ( !CopyFile( SAVE_gs_d_stFile[ lFile ].szName, szNewFile, FALSE ) ) { //char szMessage[ 512 ]; //sprintf( szMessage, "Can't copy %s to %s", SAVE_g_d_szFile[ lFile ], szNewFile ); return FALSE; } } } /* * create a file with all file that are going to be created */ strcpy( p_szNewFile, "delete.lst" ); if ((hpFile = fopen( szNewFile, "wt" )) == NULL) return FALSE; for (lFile = 0; lFile < SAVE_gs_lNumberOfFiles; lFile ++) { if ( SAVE_gs_d_stFile[lFile].cNew ) fprintf( hpFile, "%s\n", SAVE_gs_d_stFile[ lFile ].szName + SAVE_g_lGameDataLength + 1 ); } fclose( hpFile ); return TRUE; } /* ======================================================================================= principal function ======================================================================================= */ /* ---------------------------------------------------------------------------------------- Description : make a copy of file that will be deleted. ---------------------------------------------------------------------------------------- */ BOOL SAVE_fn_bGenerateACopyOfFilesBeforeModification( void ) { SAVE_g_bContinue = TRUE; if (SAVE_g_bGenerateIsActive == 2) { CString csFileName; csFileName = M_GetMainApp()->m_csEditorDataPath + C_szInterfaceIniFile; SAVE_g_bGenerateIsActive = GetPrivateProfileInt ("SecuritySave", "Active", 1, (char*)(LPCSTR) csFileName); } if ( !SAVE_g_bGenerateIsActive ) return TRUE; if (SCR_g_st_Ntfy_Array.uiNumValues == 0) return TRUE; /* * init */ SAVE_g_szGameData = fn_szGetGameDataPath(); SAVE_g_lGameDataLength = strlen( SAVE_g_szGameData ); if (SAVE_fn_bAnalyseCurrentUsedVersion()) { if (SAVE_fn_lGetNotifiedFileList()) { SAVE_fn_bCreateNewVersion(); SAVE_fn_vFreeFileList(); } } return SAVE_g_bContinue; } #endif /*ACTIVE_EDITOR*/