mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	savestates: validate states before load
This commit is contained in:
		
							parent
							
								
									8e8c8fa37a
								
							
						
					
					
						commit
						c79acdd88d
					
				
					 1 changed files with 38 additions and 16 deletions
				
			
		|  | @ -49,6 +49,30 @@ std::string GetSaveStatePath(u64 program_id, u32 slot) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool ValidateSaveState(const CSTHeader& header, SaveStateInfo& info, u64 program_id, | ||||||
|  |                               u32 slot) { | ||||||
|  |     const auto path = GetSaveStatePath(program_id, slot); | ||||||
|  |     if (header.filetype != header_magic_bytes) { | ||||||
|  |         LOG_WARNING(Core, "Invalid save state file {}", path); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     info.time = header.time; | ||||||
|  | 
 | ||||||
|  |     if (header.program_id != program_id) { | ||||||
|  |         LOG_WARNING(Core, "Save state file isn't for the current game {}", path); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     const std::string revision = fmt::format("{:02x}", fmt::join(header.revision, "")); | ||||||
|  |     if (revision == Common::g_scm_rev) { | ||||||
|  |         info.status = SaveStateInfo::ValidationStatus::OK; | ||||||
|  |     } else { | ||||||
|  |         LOG_WARNING(Core, "Save state file {} created from a different revision {}", path, | ||||||
|  |                     revision); | ||||||
|  |         info.status = SaveStateInfo::ValidationStatus::RevisionDismatch; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| std::vector<SaveStateInfo> ListSaveStates(u64 program_id) { | std::vector<SaveStateInfo> ListSaveStates(u64 program_id) { | ||||||
|     std::vector<SaveStateInfo> result; |     std::vector<SaveStateInfo> result; | ||||||
|     for (u32 slot = 1; slot <= SaveStateSlotCount; ++slot) { |     for (u32 slot = 1; slot <= SaveStateSlotCount; ++slot) { | ||||||
|  | @ -74,24 +98,10 @@ std::vector<SaveStateInfo> ListSaveStates(u64 program_id) { | ||||||
|             LOG_ERROR(Core, "Could not read from file {}", path); |             LOG_ERROR(Core, "Could not read from file {}", path); | ||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
|         if (header.filetype != header_magic_bytes) { |         if (!ValidateSaveState(header, info, program_id, slot)) { | ||||||
|             LOG_WARNING(Core, "Invalid save state file {}", path); |  | ||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
|         info.time = header.time; |  | ||||||
| 
 | 
 | ||||||
|         if (header.program_id != program_id) { |  | ||||||
|             LOG_WARNING(Core, "Save state file isn't for the current game {}", path); |  | ||||||
|             continue; |  | ||||||
|         } |  | ||||||
|         const std::string revision = fmt::format("{:02x}", fmt::join(header.revision, "")); |  | ||||||
|         if (revision == Common::g_scm_rev) { |  | ||||||
|             info.status = SaveStateInfo::ValidationStatus::OK; |  | ||||||
|         } else { |  | ||||||
|             LOG_WARNING(Core, "Save state file {} created from a different revision {}", path, |  | ||||||
|                         revision); |  | ||||||
|             info.status = SaveStateInfo::ValidationStatus::RevisionDismatch; |  | ||||||
|         } |  | ||||||
|         result.emplace_back(std::move(info)); |         result.emplace_back(std::move(info)); | ||||||
|     } |     } | ||||||
|     return result; |     return result; | ||||||
|  | @ -146,7 +156,19 @@ void System::LoadState(u32 slot) { | ||||||
|         std::vector<u8> buffer(FileUtil::GetSize(path) - sizeof(CSTHeader)); |         std::vector<u8> buffer(FileUtil::GetSize(path) - sizeof(CSTHeader)); | ||||||
| 
 | 
 | ||||||
|         FileUtil::IOFile file(path, "rb"); |         FileUtil::IOFile file(path, "rb"); | ||||||
|         file.Seek(sizeof(CSTHeader), SEEK_SET); // Skip header
 | 
 | ||||||
|  |         // load header
 | ||||||
|  |         CSTHeader header; | ||||||
|  |         if (file.ReadBytes(&header, sizeof(header)) != sizeof(header)) { | ||||||
|  |             throw std::runtime_error("Could not read from file at " + path); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // validate header
 | ||||||
|  |         SaveStateInfo info; | ||||||
|  |         if (!ValidateSaveState(header, info, title_id, slot)) { | ||||||
|  |             throw std::runtime_error("Invalid savestate"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         if (file.ReadBytes(buffer.data(), buffer.size()) != buffer.size()) { |         if (file.ReadBytes(buffer.data(), buffer.size()) != buffer.size()) { | ||||||
|             throw std::runtime_error("Could not read from file at " + path); |             throw std::runtime_error("Could not read from file at " + path); | ||||||
|         } |         } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue