/* 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" #if defined(_STORAGE_rpg) #include "rpgprotocol.h" #include "nanddriver.h" #endif #include "language.h" #include "datetime.h" #include "ui.h" #include #include #include using namespace akui; cSaveManager::cSaveManager() { #if defined(_STORAGE_rpg) lockSave(); for( size_t i = 0; i < 64; ++i ) { _saveBlockTable[i] = 0xFFFFFFFF; } #endif } cSaveManager::~cSaveManager() { } #if defined(_STORAGE_rpg) //EEP 指令 //D2 00 00 00 00 00 00 00 // //bit 51 - 48 //48 eep enable //49 eep to nand enable //53 - 50 0001=auto 0000=95040 1000=95640 0100=95512 0010=25pe80 void selectSaveChip( CHIP_TYPE type, bool nandON ) { u8 byte2 = 0; switch( type ) { case CT_NONE: byte2 = 0x00; break; case CT_4K: byte2 = 0x03; // 0000 0011 break; case CT_512K: byte2 = 0x13; // 0001 0011 break; case CT_8M: byte2 = 0x0b; // 0000 1011 break; case CT_AUTO: // auto detect byte2 = 0x07; // 0000 0111 break; default: byte2 = 0x00; }; if( !nandON ) byte2 &= 0xFD; // 1111 1101 u32 cmd[2] = { 0xd2000000 | (byte2 <<16 ), 0x00000000 }; ioRpgSendCommand( cmd, 0, 0, NULL ); } void cSaveManager::lockChips() { selectSaveChip( CT_NONE, false ); } bool cSaveManager::unlockChip(SAVE_TYPE saveType,bool writeToDisk) { CHIP_TYPE chipType=chipTypeFromSaveType(saveType); selectSaveChip(chipType,writeToDisk); if(writeToDisk||CT_AUTO==chipType) { clearSaveBlocks(); u32 nandAddress[64]; if(!assignSaveBlocks(saveType,chipType,nandAddress)) return false; } return true; } void cSaveManager::lockSave() { lockChips(); } bool cSaveManager::unlockSave(SAVE_TYPE saveType,bool writeToDisk) { return unlockChip(saveType,writeToDisk); } #endif 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(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) { NandFast(); int f=open(filename.c_str(),O_WRONLY|O_CREAT|O_TRUNC); if(f<0) { NandFlush(); 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); NandFlush(); 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; } #if defined(_STORAGE_rpg) SAVE_BLOCK_INFO cSaveManager::getBlockInfo( CHIP_TYPE chipType ) { SAVE_BLOCK_INFO ret; switch( chipType ) { case CT_4K: ret.eepPageSize = 16; ret.nandBlockCount = 32; ret.nandPageSize = 16; ret.saveSize = 512; ret.validPageCount = 1; break; case CT_512K: ret.eepPageSize = 128; ret.nandBlockCount = 32; ret.nandPageSize = 2048; ret.saveSize = 65536; ret.validPageCount = 1; break; case CT_8M: ret.eepPageSize = 256; ret.nandBlockCount = 64; ret.nandPageSize = 256; ret.saveSize = 1048576; ret.validPageCount = 64; break; case CT_NONE: default: ret.eepPageSize = 0; ret.nandBlockCount = 0; ret.nandPageSize = 0; ret.saveSize = 0; ret.validPageCount = 0; } return ret; } bool cSaveManager::backupSaveData() { dbg_printf( "SaveManager::backupSaveData()\n" ); CHIP_TYPE autoCT = CT_NONE; bool buildOK = buildSaveBlockTable( &autoCT ); if( !buildOK || CT_NONE == autoCT ) { clearLastInfo(); clearSaveBlocks(); return true; } std::string loadLoadedFile; if( !loadLastInfo( loadLoadedFile ) ) { loadLoadedFile = "fat0:/unknown_savedata_" + datetime().getTimeStampString() + ".nds"; } // update custom savlist if needed DSRomInfo info; info.saveInfo().defaults(); info.MayBeDSRom(loadLoadedFile); if( info.isDSRom() ) { if( ST_UNKNOWN == info.saveInfo().saveType ) { info.saveInfo().saveType = saveTypeFromChipType( autoCT ); updateCustomSaveList( info.saveInfo() ); } } //////////////// u8 slot=info.saveInfo().getSlot(); loadLoadedFile=generateSaveName(loadLoadedFile,slot); NandFast(); FILE * f = fopen( loadLoadedFile.c_str(), "wb" ); if( NULL == f ) { if( (0 == memcmp( "fat1:/", loadLoadedFile.c_str(), 6 ) ) ) { // no sd card, backup to nand flash, and warn user size_t lastSlashPos = loadLoadedFile.find_last_of( '/' ); loadLoadedFile.replace( 0, lastSlashPos + 1, "fat0:/" ); loadLoadedFile.insert( loadLoadedFile.size() - 4, "." + datetime().getTimeStampString() ); f = fopen( loadLoadedFile.c_str(), "wb" ); if( NULL == f ) { NandFlush(); return false; } std::string warningText = formatString( LANG("no sd for save", "text").c_str(), loadLoadedFile.c_str() ); messageBox( NULL, LANG("no sd for save", "title"), warningText, MB_OK ); } else { NandFlush(); return false; } } progressWnd().setTipText( LANG("progress window", "processing save" ) ); progressWnd().show(); progressWnd().setPercent(0); SAVE_BLOCK_INFO bi = getBlockInfo( autoCT ); if(ST_64K==info.saveInfo().saveType&&CT_512K==autoCT) bi.nandBlockCount=4; #define SAVEDATA_BUFFER_SIZE (128 * 1024) u8 * saveDataBuffer = new u8[SAVEDATA_BUFFER_SIZE]; static ALIGN(4) u8 readNandBuffer[2112]; memset( saveDataBuffer, 0x5a, SAVEDATA_BUFFER_SIZE ); u8 * pSaveDataBuffer = saveDataBuffer; u32 written = 0; for( u32 i = 0; i < bi.nandBlockCount; ++i ) { u8 percent = i * 100 / bi.nandBlockCount; if( !(percent & 0x03) ) { progressWnd().setPercent( percent ); } if( _saveBlockTable[i] != 0xFFFFFFFF ) { for( u32 j = 0; j < bi.validPageCount; ++j ) { ioRpgReadNand( _saveBlockTable[i] + j * 2048, readNandBuffer, 2048 ); memcpy( pSaveDataBuffer, readNandBuffer, bi.nandPageSize ); pSaveDataBuffer += bi.nandPageSize; if( pSaveDataBuffer >= saveDataBuffer + SAVEDATA_BUFFER_SIZE ) { written = fwrite( saveDataBuffer, 1, SAVEDATA_BUFFER_SIZE, f ); pSaveDataBuffer = saveDataBuffer; dbg_printf("written %d\n", written); } } } } written = fwrite( saveDataBuffer, 1, pSaveDataBuffer - saveDataBuffer, f ); dbg_printf("written %d\n", written); progressWnd().setPercent( 100 ); progressWnd().hide(); fclose( f ); NandFlush(); clearLastInfo(); clearSaveBlocks(); delete[] saveDataBuffer; return true; } static void checkRedund() { ALIGN(4) u8 cfgPage[528]; dbg_printf( "checkRedund cfgPage\n"); ioRpgReadNand( 0x00000000, cfgPage, 528 ); // read zones count u32 totalZones = 1 << (cfgPage[0x0c] - 10); //wait_press_b(); u32 saveBlockTable[64]; for( size_t i = 0; i < 64; ++i ) saveBlockTable[i] = 0xFFFFFFFF; ALIGN(4) u8 redundData[16]; u8 ctByte = 0x00; u32 saveBlockCountCheck = 0; for( size_t i = 0; i < totalZones * 1024; ++i ) { ioRpgReadNandRedundant( (i << 17) + 512 * 3, redundData ); if( redundData[0] != 0xff && redundData[0] != 0x00 ) dbg_printf("(%02x%02x%02x)", redundData[1],redundData[2],redundData[3] ); if( redundData[0] >= 0x80 && redundData[0] < 0x80 + 64 ) { saveBlockCountCheck++; u8 saveIndex = redundData[3] - 0x80; if( saveBlockTable[saveIndex] != 0xFFFFFFFF ) { dbg_printf("checkRedund() FATAL ERROR: Multi save block assign found\n"); dbg_printf("saveTable[%d] 1=%08x 2=%08x\n", saveIndex, saveBlockTable[saveIndex], (i << 17) ); wait_press_b(); } saveBlockTable[saveIndex] = (i << 17); if( redundData[2] >= 0xc0 && redundData[2] <= 0xc4 && 0 == ctByte ) { ctByte = redundData[2]; } } } if( saveBlockCountCheck != 0 && saveBlockCountCheck != 16 && saveBlockCountCheck != 32 && saveBlockCountCheck != 64 ) { dbg_printf("checkRedund() FATAL ERROR: saveblock COUNT ERROR %d\n", saveBlockCountCheck ); dbg_printf("totalZones %d\n", totalZones ); wait_press_b(); } else { dbg_printf("checkRedund() OK OK OK OK OK OK OK OK OK OK OK %d\n", saveBlockCountCheck ); } } static void clearSaveSram() { progressWnd().setTipText( LANG("progress window", "processing save") ); progressWnd().show(); progressWnd().setPercent( 0 ); // clear sram, fill with 0xff, to keep consist with empty save blocks u32 fillData = 0xFFFFFFFF; for( size_t i = 0;i < 1024 * 1024; i += 4 ) { ioRpgWriteSram( SRAM_SAVEDATA_START + i, &fillData, 4 ); if( !(i % (1024 * 128)) ) { dbg_printf("clear sram %d%s\n", i*100/(1024*1024), "%" ); progressWnd().setPercent( i*100 / (1024 * 1024) ); } } for( size_t i = 0;i < 2048; i += 4 ) { ioRpgWriteSram( SRAM_EEP_BUFFER_START + i, &fillData, 4 ); } progressWnd().setPercent(100); } bool cSaveManager::restoreSaveData( const std::string & romFilename, SAVE_TYPE saveType, u8 slot ) { dbg_printf( "SaveManager::restoreSaveData()\n" ); CHIP_TYPE chipType = chipTypeFromSaveType( saveType ); if( CT_NONE == chipType ) { lockChips(); saveLastInfo( romFilename ); return true; } unlockSave( saveType, true ); checkRedund(); if( ST_UNKNOWN == saveType || ST_AUTO == saveType ) { clearSaveSram(); saveLastInfo( romFilename ); return true; } u32 saveSize = saveSizeFromSaveType( saveType ); std::string saveFilename=generateSaveName(romFilename,slot); // FILE * f = fopen( saveFilename.c_str(), "rb" ); if( NULL == f ) { clearSaveSram(); saveLastInfo( romFilename ); return true; } // clear FLASH if(saveType>=ST_2M&&saveType<=ST_8M ) { switch(saveType) { case ST_2M: saveChipFlashErase(4); break; case ST_4M: saveChipFlashErase(8); break; case ST_8M: saveChipFlashErase(16); break; default: break; } } const u32 blockSize = 512; static ALIGN(4) u8 buffer[blockSize]; u32 readCount = 0; progressWnd().setTipText( LANG("progress window", "processing save") ); progressWnd().show(); progressWnd().setPercent( 0 ); for( u32 i = 0; i < saveSize; i += blockSize ) { u8 percent = i * 100 / saveSize; if( !(percent & 0x07) ) progressWnd().setPercent( percent ); u32 readed = fread( buffer, 1, blockSize, f ); readCount += readed; //if( blockSize != readed ) { // break; //} if( 0 == readed ) break; saveChipWrite( i, buffer, readed, chipType ); } progressWnd().setPercent( 100 ); progressWnd().hide(); fclose( f ); saveLastInfo( romFilename ); return true; } static ALIGN(4) u8 cfgPage[528]; bool cSaveManager::buildSaveBlockTable( CHIP_TYPE * ct ) { // read cfg page // 53 4d 54 44 4d 47 20 00 0e 00 01 06 0d (14) 03 02 dbg_printf( "cfgPage\n"); ioRpgReadNand( 0x00000000, cfgPage, 528 ); for( u32 i = 0; i < 16; ++i ) { dbg_printf("%02x", cfgPage[i] ); } // read zones count u32 totalZones = 1 << (cfgPage[0x0c] - 10); for( size_t i = 0; i < 64; ++i ) _saveBlockTable[i] = 0xFFFFFFFF; // if user turn power off during writting save data(in game or in menu), // the content of save blocks is undefined. Don't write save data to .sav // file if this function returns false ALIGN(4) u8 redundData[16]; u8 ctByte = 0x00; u32 saveBlockCount = 0; for( size_t i = 0; i < totalZones * 1024; ++i ) { ioRpgReadNandRedundant( (i << 17) + 512 * 3, redundData ); if( redundData[0] != 0xff && redundData[0] != 0x00 && redundData[0] != 0xf0 ) dbg_printf("(%02x%02x%02x)", redundData[1],redundData[2],redundData[3] ); if( redundData[0] >= 0x80 && redundData[0] < 0x80 + 64 ) { u8 saveIndex = redundData[3] - 0x80; if( saveIndex < 64 ) { saveBlockCount++; if( _saveBlockTable[saveIndex] != 0xFFFFFFFF ) { dbg_printf("FATAL ERROR: Multi save block assign found\n"); dbg_printf("saveTable[%d] 1=%08x 2=%08x\n", saveIndex, _saveBlockTable[saveIndex], (i << 17) ); wait_press_b(); return false; } _saveBlockTable[saveIndex] = (i << 17); if( redundData[2] >= 0xc0 && redundData[2] <= 0xc4 && 0 == ctByte ) { ctByte = redundData[2]; } } else { dbg_printf("FATAL ERROR: idx err, shouldn't have a %d\n", saveIndex ); dbg_printf("redunt0-4:(%02x%02x%02x%02x%02x)\n", redundData[0], redundData[1], redundData[2],redundData[3], redundData[4] ); dbg_printf("at block: %d\n", i ); wait_press_b(); return false; } } } dbg_printf( "saveBlockCount %d\n", saveBlockCount ); if( 0 != saveBlockCount && saveBlockCount != 16 && saveBlockCount != 32 && saveBlockCount != 64 ) { dbg_printf("FATAL ERROR: Multi save block assign found, saveBlockCount %d\n", saveBlockCount ); wait_press_b(); return false; } *ct = CT_NONE; switch( ctByte ) { case 0xc0: // 40 *ct = CT_4K; break; case 0xc1: // 80 *ct = CT_8M; break; case 0xc2: // 512 *ct = CT_512K; break; case 0xc4: // 640 *ct = CT_512K; break; default: *ct = CT_NONE; } dbg_printf("save mark %02x, type %d\n", ctByte, *ct ); //wait_press_b(); return true; } bool cSaveManager::clearSaveBlocks() { ioRpgReadNand( 0x00000000, cfgPage, 528 ); for( u32 i = 0; i < 16; ++i ) { dbg_printf("%02x", cfgPage[i] ); } // read zones count u32 totalZones = 1 << (cfgPage[0x0c] - 10); dbg_printf("clear save: \n"); ALIGN(4) u8 redundData[16]; for( size_t i = 0; i < totalZones * 1024; ++i ) { ioRpgReadNandRedundant( (i << 17) + 512 * 3, redundData ); if( redundData[0] >= 0x80 && redundData[0] < 0x80 + 64 ) { ioRpgEraseNand( i << 17 ); } } dbg_printf( "end\n" ); // 这个地方是否需要重新建表? return true; } int cSaveManager::CompareIndex(const void* a,const void* b) { return (static_cast(a)->iIndex-static_cast(b)->iIndex); } int cSaveManager::CompareFree(const void* a,const void* b) { return (static_cast(a)->iFree-static_cast(b)->iFree); } bool cSaveManager::assignSaveBlocks(SAVE_TYPE saveType,CHIP_TYPE chipType,u32 nandAddress[64]) { if( CT_NONE == chipType ) { lockChips(); return true; } memset( nandAddress, 0xFF, 64 * 4 ); ioRpgReadNand( 0x00000000, cfgPage, 528 ); for( u32 i = 0; i < 16; ++i ) { dbg_printf("%02x", cfgPage[i] ); } u32 neededBlocks=32; if(saveType==ST_8M) neededBlocks=64; else if(saveType==ST_2M) neededBlocks=16; // read zones count u32 totalZones = 1 << (cfgPage[0x0c] - 10); SZoneInfo zones[totalZones]; memset(zones,0,sizeof(SZoneInfo)*totalZones); u32 totalFreeBlocks=0,totalAllocatedBlocks=0; for(u32 ii=0;ii=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); } NandFlush(); return res; } #if defined(_STORAGE_rpg) || defined(_STORAGE_ak2i) bool cSaveManager::generateProtectionFix(const std::string& romFilename,u32 bytesPerCluster) { bool result=false; std::string fixFilename(romFilename); fixFilename+=".fix"; FILE* check=fopen(fixFilename.c_str(),"rb"); if(check) { fclose(check); return true; } NandFast(); FILE* rom=fopen(romFilename.c_str(),"rb"); if(rom) { fseek(rom,0x8000,SEEK_SET); char buffer[512]; if(fread(buffer,512,1,rom)==1) { FILE* fix=fopen(fixFilename.c_str(),"wb"); if(fix) { for(int ii=0;ii<64;ii++) { if(fwrite(buffer,512,1,fix)!=1) goto error; } if(bytesPerCluster>32768) { if(fwrite(buffer,512,1,fix)!=1) goto error; int counter=bytesPerCluster-32768-512; while(counter>0) { if(fread(buffer,512,1,rom)!=1) goto error; if(fwrite(buffer,512,1,fix)!=1) goto error; counter-=512; } } result=true; error: fclose(fix); } } fclose(rom); } NandFlush(); return result; } #endif 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; } #if defined(_STORAGE_rpg) CHIP_TYPE cSaveManager::chipTypeFromSaveType( SAVE_TYPE saveType ) { if( saveType == ST_NOSAVE ) return CT_NONE; if( saveType <= ST_4K ) return CT_4K; if( saveType <= ST_512K ) return CT_512K; if( saveType <= ST_8M ) return CT_8M; if( ST_AUTO == saveType ) return CT_AUTO; return CT_NONE; } SAVE_TYPE cSaveManager::saveTypeFromChipType( CHIP_TYPE chipType ) { switch( chipType ) { case CT_4K: return ST_4K; case CT_512K: return ST_512K; case CT_8M: return ST_4M; default: return ST_UNKNOWN; } return ST_UNKNOWN; } u32 cSaveManager::saveSizeFromSaveType( SAVE_TYPE saveType ) { switch( saveType ) { case ST_UNKNOWN: return 0; case ST_NOSAVE: return 0; case ST_4K: return 512; case ST_64K: return 8192; case ST_512K: return 65536; case ST_2M: return 262144; case ST_4M: return 524288; case ST_8M: return 1048576; case ST_NEW: return 2097152; default: return 0; }; } #endif 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; }