/**************************************************************************** * * * Project64 - A Nintendo 64 emulator. * * http://www.pj64-emu.com/ * * Copyright (C) 2012 Project64. All rights reserved. * * * * License: * * GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * * * ****************************************************************************/ #include "stdafx.h" #include "Sram.h" #include #include CSram::CSram(bool ReadOnly) : m_ReadOnly(ReadOnly), m_hFile(NULL) { } CSram::~CSram() { if (m_hFile) { CloseHandle(m_hFile); m_hFile = NULL; } } bool CSram::LoadSram() { CPath FileName; FileName.SetDriveDirectory(g_Settings->LoadStringVal(Directory_NativeSave).c_str()); FileName.SetName(g_Settings->LoadStringVal(Game_GameName).c_str()); FileName.SetExtension("sra"); if (!FileName.DirectoryExists()) { FileName.DirectoryCreate(); } m_hFile = CreateFile(FileName, m_ReadOnly ? GENERIC_READ : GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); if (m_hFile == INVALID_HANDLE_VALUE) { WriteTraceF(TraceError, __FUNCTION__ ": Failed to open (%s), ReadOnly = %d, LastError = %X", (LPCTSTR)FileName, m_ReadOnly, GetLastError()); return false; } SetFilePointer(m_hFile, 0, NULL, FILE_BEGIN); return true; } void CSram::DmaFromSram(uint8_t * dest, int StartOffset, int len) { DWORD dwRead; uint32_t i; uint8_t tmp[4]; if (m_hFile == NULL) { if (!LoadSram()) { return; } } // Fix Dezaemon 3D saves StartOffset = ((StartOffset >> 3) & 0xFFFF8000) | (StartOffset & 0x7FFF); uint32_t Offset = StartOffset & 3; if (Offset == 0) { SetFilePointer(m_hFile, StartOffset, NULL, FILE_BEGIN); ReadFile(m_hFile, dest, len, &dwRead, NULL); } else { SetFilePointer(m_hFile, StartOffset - Offset, NULL, FILE_BEGIN); ReadFile(m_hFile, tmp, 4, &dwRead, NULL); for (i = 0; i < (4 - Offset); i++) { dest[i + Offset] = tmp[i]; } for (i = 4 - Offset; i < len - Offset; i += 4) { ReadFile(m_hFile, tmp, 4, &dwRead, NULL); switch (Offset) { case 1: dest[i + 2] = tmp[0]; dest[i + 3] = tmp[1]; dest[i + 4] = tmp[2]; dest[i - 3] = tmp[3]; break; case 2: dest[i + 4] = tmp[0]; dest[i + 5] = tmp[1]; dest[i - 2] = tmp[2]; dest[i - 1] = tmp[3]; break; case 3: dest[i + 6] = tmp[0]; dest[i - 1] = tmp[1]; dest[i] = tmp[2]; dest[i + 1] = tmp[3]; break; default: break; } } ReadFile(m_hFile, tmp, 4, &dwRead, NULL); switch (Offset) { case 1: dest[i - 3] = tmp[3]; break; case 2: dest[i - 2] = tmp[2]; dest[i - 1] = tmp[3]; break; case 3: dest[i - 1] = tmp[1]; dest[i] = tmp[2]; dest[i + 1] = tmp[3]; break; default: break; } } } void CSram::DmaToSram(uint8_t * Source, int StartOffset, int len) { DWORD dwWritten; uint32_t i; uint8_t tmp[4]; if (m_ReadOnly) { return; } if (m_hFile == NULL) { if (!LoadSram()) { return; } } // Fix Dezaemon 3D saves StartOffset = ((StartOffset >> 3) & 0xFFFF8000) | (StartOffset & 0x7FFF); uint32_t Offset = StartOffset & 3; if (Offset == 0) { SetFilePointer(m_hFile, StartOffset, NULL, FILE_BEGIN); WriteFile(m_hFile, Source, len, &dwWritten, NULL); } else { for (i = 0; i < (4 - Offset); i++) { tmp[i] = Source[i + Offset]; } SetFilePointer(m_hFile, StartOffset - Offset, NULL, FILE_BEGIN); WriteFile(m_hFile, tmp, (4 - Offset), &dwWritten, NULL); SetFilePointer(m_hFile, Offset, NULL, FILE_CURRENT); for (i = 4 - Offset; i < len - Offset; i += 4) { switch (Offset) { case 1: tmp[0] = Source[i + 2]; tmp[1] = Source[i + 3]; tmp[2] = Source[i + 4]; tmp[3] = Source[i - 3]; break; case 2: tmp[0] = Source[i + 4]; tmp[1] = Source[i + 5]; tmp[2] = Source[i - 2]; tmp[3] = Source[i - 1]; break; case 3: tmp[0] = Source[i + 6]; tmp[1] = Source[i - 1]; tmp[2] = Source[i]; tmp[3] = Source[i + 1]; break; default: break; } WriteFile(m_hFile, tmp, 4, &dwWritten, NULL); } switch (Offset) { case 1: tmp[0] = Source[i - 3]; break; case 2: tmp[0] = Source[i - 2]; tmp[0] = Source[i - 1]; break; case 3: tmp[0] = Source[i - 1]; tmp[0] = Source[i]; tmp[0] = Source[i + 1]; break; default: break; } SetFilePointer(m_hFile, 4 - Offset, NULL, FILE_CURRENT); WriteFile(m_hFile, tmp, Offset, &dwWritten, NULL); } FlushFileBuffers(m_hFile); }