/* savemngr.cpp Copyright (C) 2007 Acekard, www.acekard.com Copyright (C) 2007-2009 somebody Copyright (C) 2009 yellow wood goblin This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ //� #include "savemngr.h" #include "inifile.h" #include "dsrom.h" #include "dbgtool.h" #include "systemfilenames.h" #include "progresswnd.h" #include "language.h" #include "datetime.h" #include "ui.h" #include #include #include using namespace akui; cSaveManager::cSaveManager() { } cSaveManager::~cSaveManager() { } static bool loadSaveList(const std::string& filename,std::vector& buffer) { u8* data=NULL; FILE* f=fopen(filename.c_str(),"rb"); if(NULL==f) { dbg_printf("fopen %s fail\n",filename.c_str()); return false; } bool res=false; do { u32 saveCount=0; SAVE_INFO_EX_HEADER header={SAVE_INFO_EX_HEADER_MAGIC,sizeof(SAVE_INFO),saveCount,0}; if(1!=fread(&header,sizeof(header),1,f)) break; if(header.marker!=SAVE_INFO_EX_HEADER_MAGIC) break; data=new u8[header.itemSize*header.itemCount]; u32 copiedSize=std::min((unsigned int)header.itemSize,sizeof(SAVE_INFO_EX)); if(header.itemCount!=fread(data,header.itemSize,header.itemCount,f)) break; buffer.resize(header.itemCount); for(u32 ii=0;ii& buffer) { FILE* f=fopen(filename.c_str(),"rb"); if(NULL==f) { dbg_printf("fopen %s fail\n",filename.c_str()); return false; } fseek(f,0,SEEK_END); u32 filesize=ftell(f); if(0==filesize||0!=(filesize%19)) { dbg_printf("%s size error %d\n", filename.c_str(), filesize ); fclose(f); f=NULL; return false; } u32 saveCount=filesize/19; buffer.resize(saveCount); fseek(f,0,SEEK_SET); u32 readed=fread(&buffer[0],1,filesize,f); if(filesize!=readed) { dbg_printf("%s read length error %d\n",filename.c_str(),readed); fclose(f); f=NULL; return false; } fclose(f); return true; } bool cSaveManager::importSaveList( const std::string & customFile, const std::string & officialFile ) { loadSaveList(customFile,_customSaveList); loadOfficialSaveList(officialFile,_saveList); return true; } bool cSaveManager::exportCustomSaveList(const std::string& filename) { int f=open(filename.c_str(),O_WRONLY|O_CREAT|O_TRUNC); if(f<0) { dbg_printf("fopen %s fail\n",filename.c_str()); return false; } bool res=false; do { u32 count=_customSaveList.size(); SAVE_INFO_EX_HEADER header={SAVE_INFO_EX_HEADER_MAGIC,sizeof(SAVE_INFO_EX),count,0}; //libelm hack lseek(f,sizeof(header)+sizeof(SAVE_INFO_EX)*count,SEEK_SET); lseek(f,0,SEEK_SET); // ssize_t written=write(f,&header,sizeof(header)); if(written!=sizeof(header)) { dbg_printf("%s write length error %d\n",filename.c_str(),written); break; } written=write(f,&_customSaveList[0],sizeof(SAVE_INFO_EX)*count); if(static_cast(sizeof(SAVE_INFO_EX)*count)!=written) { dbg_printf("%s write length error %d\n",filename.c_str(),written); break; } res=true; } while(false); close(f); return res; } void cSaveManager::updateCustomSaveList( const SAVE_INFO_EX & aSaveInfo ) { size_t i = 0; for( i = 0; i < _customSaveList.size(); ++i ) { if( 0 == memcmp( &_customSaveList[i], &aSaveInfo, SAVE_INFO_EX_COMPARE_SIZE ) ) { _customSaveList[i] = aSaveInfo; break; } } if( i == _customSaveList.size() ) _customSaveList.push_back( aSaveInfo ); exportCustomSaveList( SFN_CUSTOM_SAVELIST ); } bool cSaveManager::saveLastInfo( const std::string & romFilename ) { CIniFile f; f.SetString( "Save Info", "lastLoaded", romFilename ); if( !f.SaveIniFile( SFN_LAST_SAVEINFO ) ) return false; return true; } bool cSaveManager::loadLastInfo( std::string & lastLoadedFilename ) { CIniFile f; if( !f.LoadIniFile( SFN_LAST_SAVEINFO ) ) { lastLoadedFilename = ""; return false; } lastLoadedFilename = f.GetString( "Save Info", "lastLoaded", "" ); if( "" == lastLoadedFilename ) return false; return true; } bool cSaveManager::clearLastInfo() { std::string loadLoadedFile; if(loadLastInfo(loadLoadedFile)) { return saveLastInfo(""); } return true; } bool cSaveManager::initializeSaveFile(const std::string& romFilename,u8 slot,u32 size) { bool res=false; std::string saveFilename=generateSaveName(romFilename,slot); int f=open(saveFilename.c_str(),O_WRONLY|O_CREAT); if(f>=0) { off_t filesize=lseek(f,0,SEEK_END); if(filesize>=0) { if((u32)filesize>=size) { write(f,NULL,0); //update time stamp res=true; } else { progressWnd().setTipText(LANG("progress window","processing save")); progressWnd().show(); progressWnd().setPercent(0); u32 tail=size-filesize; const u32 bufferSize=128*1024; u32 ii=0; u8* buffer=new u8[bufferSize]; memset(buffer,0,bufferSize); res=true; while(tail>0) { ssize_t writtenSize=(tail>bufferSize)?bufferSize:tail; if(write(f,buffer,writtenSize)!=writtenSize) { res=false; break; } tail-=writtenSize; ii++; if(0==ii%8) progressWnd().setPercent((lseek(f,0,SEEK_END))*100/size); } progressWnd().setPercent(100); progressWnd().hide(); } } close(f); } return res; } std::string cSaveManager::generateSaveName(const std::string& romFilename,u8 slot) { std::string saveFilename(romFilename); if(gs().saveExt&&saveFilename.length()>3) { size_t nameLength=saveFilename.length()-4; if(saveFilename[nameLength]=='.') saveFilename=saveFilename.substr(0,nameLength); } if(slot) { saveFilename+="."; saveFilename+=(slot+'0'); } saveFilename+=".sav"; return saveFilename; } SAVE_TYPE cSaveManager::getSaveTypeByFile( const std::string & romFilename ) { return ST_UNKNOWN; } void cSaveManager::updateSaveInfoByInfo( SAVE_INFO_EX & gameInfo ) { size_t saveCount = _customSaveList.size(); for( size_t i = 0; i < saveCount; ++i ) { if( 0 == memcmp( &gameInfo, &_customSaveList[i], SAVE_INFO_EX_COMPARE_SIZE ) ) { gameInfo=_customSaveList[i]; return; } } gameInfo.defaults(); saveCount=_saveList.size(); for(size_t ii=0;iiST_UNKNOWN&&saveType<=ST_8M) gameInfo.saveType=_saveList[ii].saveType; return; } } return; } DISPLAY_SAVE_TYPE cSaveManager::SaveTypeToDisplaySaveType(SAVE_TYPE aSaveType) { switch(aSaveType) { case ST_UNKNOWN: return D_ST_UNKNOWN; case ST_NOSAVE: return D_ST_NOSAVE; case ST_4K: return D_ST_4K; case ST_64K: return D_ST_64K; case ST_512K: return D_ST_512K; case ST_2M: return D_ST_2M; case ST_4M: return D_ST_4M; case ST_8M: return D_ST_8M; case ST_NEW: return D_ST_UNKNOWN; case ST_AUTO: return D_ST_UNKNOWN; case ST_1M: return D_ST_1M; case ST_16M: return D_ST_16M; case ST_32M: return D_ST_32M; case ST_64M: return D_ST_64M; default: return D_ST_UNKNOWN; } } SAVE_TYPE cSaveManager::DisplaySaveTypeToSaveType(DISPLAY_SAVE_TYPE aSaveType) { switch(aSaveType) { case D_ST_UNKNOWN: return ST_UNKNOWN; case D_ST_NOSAVE: return ST_NOSAVE; case D_ST_4K: return ST_4K; case D_ST_64K: return ST_64K; case D_ST_512K: return ST_512K; case D_ST_1M: return ST_1M; case D_ST_2M: return ST_2M; case D_ST_4M: return ST_4M; case D_ST_8M: return ST_8M; case D_ST_16M: return ST_16M; case D_ST_32M: return ST_32M; case D_ST_64M: return ST_64M; } return ST_UNKNOWN; }