diff --git a/Source/Project64-core/N64System/N64RomClass.cpp b/Source/Project64-core/N64System/N64RomClass.cpp index cd818f0c2..6ddb6c6e6 100644 --- a/Source/Project64-core/N64System/N64RomClass.cpp +++ b/Source/Project64-core/N64System/N64RomClass.cpp @@ -14,19 +14,17 @@ #include #include #include -#include +#include +#include +#include -CN64Rom::CN64Rom() +CN64Rom::CN64Rom() : +m_ROMImage(NULL), +m_ROMImageBase(NULL), +m_ErrorMsg(EMPTY_STRING), +m_Country(UnknownCountry), +m_CicChip(CIC_UNKNOWN) { - m_hRomFile = NULL; - m_hRomFileMapping = NULL; - m_ROMImage = NULL; - m_ErrorMsg = EMPTY_STRING; - m_RomName = ""; - m_FileName = ""; - m_MD5 = ""; - m_Country = UnknownCountry; - m_CicChip = CIC_UNKNOWN; } CN64Rom::~CN64Rom() @@ -34,82 +32,104 @@ CN64Rom::~CN64Rom() UnallocateRomImage(); } +bool CN64Rom::AllocateRomImage(uint32_t RomFileSize) +{ + WriteTrace(TraceN64System, TraceDebug, "Allocating memory for rom"); + std::auto_ptr ImageBase(new uint8_t[RomFileSize + 0x1000]); + if (ImageBase.get() == NULL) + { + SetError(MSG_MEM_ALLOC_ERROR); + WriteTrace(TraceN64System, TraceError, "Failed to allocate memory for rom (size: 0x%X)", RomFileSize); + return false; + } + uint8_t * Image = (uint8_t *)(((uint64_t)ImageBase.get() + 0xFFF) & ~0xFFF); // start at begining of memory page + WriteTrace(TraceN64System, TraceDebug, "Allocated rom memory (%p)", Image); + + //save information about the rom loaded + m_ROMImageBase = ImageBase.release(); + m_ROMImage = Image; + m_RomFileSize = RomFileSize; + return true; +} + bool CN64Rom::AllocateAndLoadN64Image(const char * FileLoc, bool LoadBootCodeOnly) { - //Try to open the target file - HANDLE hFile = CreateFile(FileLoc, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, - NULL); - if (hFile == INVALID_HANDLE_VALUE) { return false; } - - //Read the first 4 bytes and make sure it is a valid n64 image - DWORD dwRead; uint8_t Test[4]; - - SetFilePointer(hFile, 0, 0, FILE_BEGIN); - ReadFile(hFile, Test, 4, &dwRead, NULL); - if (!IsValidRomImage(Test)) + WriteTrace(TraceN64System, TraceDebug, "Trying to open %s", FileLoc); + if (!m_RomFile.Open(FileLoc, CFileBase::modeRead)) { - CloseHandle(hFile); + WriteTrace(TraceN64System, TraceError, "Failed to open %s", FileLoc); return false; } - //Get the size of the rom and try to allocate the memory needed. - DWORD RomFileSize = GetFileSize(hFile, NULL); - //if loading boot code then just load the first 0x1000 bytes - if (LoadBootCodeOnly) { RomFileSize = 0x1000; } - - uint8_t * Image = (uint8_t *)VirtualAlloc(NULL, RomFileSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - if (Image == NULL) + //Read the first 4 bytes and make sure it is a valid n64 image + uint8_t Test[4]; + m_RomFile.SeekToBegin(); + if (m_RomFile.Read(Test, sizeof(Test)) != sizeof(Test)) { - SetError(MSG_MEM_ALLOC_ERROR); - CloseHandle(hFile); + m_RomFile.Close(); + WriteTrace(TraceN64System, TraceError, "Failed to read ident bytes"); + return false; + } + if (!IsValidRomImage(Test)) + { + m_RomFile.Close(); + WriteTrace(TraceN64System, TraceError, "invalid image file %X %X %X %X", Test[0], Test[1], Test[2], Test[3]); + return false; + } + uint32_t RomFileSize = m_RomFile.GetLength(); + WriteTrace(TraceN64System, TraceDebug, "Successfully Opened, size: 0x%X", RomFileSize); + + //if loading boot code then just load the first 0x1000 bytes + if (LoadBootCodeOnly) + { + WriteTrace(TraceN64System, TraceDebug, "loading boot code, so loading the first 0x1000 bytes", RomFileSize); + RomFileSize = 0x1000; + } + + if (!AllocateRomImage(RomFileSize)) + { + m_RomFile.Close(); return false; } //Load the n64 rom to the allocated memory g_Notify->DisplayMessage(5, MSG_LOADING); - SetFilePointer(hFile, 0, 0, FILE_BEGIN); + m_RomFile.SeekToBegin(); - DWORD count, TotalRead = 0; + uint32_t count, TotalRead = 0; for (count = 0; count < (int)RomFileSize; count += ReadFromRomSection) { - DWORD dwToRead = RomFileSize - count; + uint32_t dwToRead = RomFileSize - count; if (dwToRead > ReadFromRomSection) { dwToRead = ReadFromRomSection; } - if (!ReadFile(hFile, &Image[count], dwToRead, &dwRead, NULL)) + if (m_RomFile.Read(&m_ROMImage[count], dwToRead) != dwToRead) { - VirtualFree(Image, 0, MEM_RELEASE); - CloseHandle(hFile); + m_RomFile.Close(); SetError(MSG_FAIL_IMAGE); + WriteTrace(TraceN64System, TraceError, "Failed to read file (TotalRead: 0x%X)", TotalRead); return false; } - TotalRead += dwRead; + TotalRead += dwToRead; //Show Message of how much % wise of the rom has been loaded g_Notify->DisplayMessage(0, stdstr_f("%s: %.2f%c", GS(MSG_LOADED), ((float)TotalRead / (float)RomFileSize) * 100.0f, '%').c_str()); } - dwRead = TotalRead; - if (RomFileSize != dwRead) + if (RomFileSize != TotalRead) { - VirtualFree(Image, 0, MEM_RELEASE); - CloseHandle(hFile); + m_RomFile.Close(); SetError(MSG_FAIL_IMAGE); + WriteTrace(TraceN64System, TraceError, "Expected to read: 0x%X, read: 0x%X", TotalRead, RomFileSize); return false; } - //save information about the rom loaded - m_hRomFile = hFile; - m_ROMImage = Image; - m_RomFileSize = RomFileSize; - g_Notify->DisplayMessage(5, MSG_BYTESWAP); ByteSwapRom(); //Protect the memory so that it can not be written to. DWORD OldProtect; VirtualProtect(m_ROMImage, m_RomFileSize, PAGE_READONLY, &OldProtect); - + ProtectMemory(m_ROMImage, m_RomFileSize, MEM_READONLY); return true; } @@ -148,34 +168,32 @@ bool CN64Rom::AllocateAndLoadZipImage(const char * FileLoc, bool LoadBootCodeOnl if (IsValidRomImage(Test)) { //Get the size of the rom and try to allocate the memory needed. - DWORD RomFileSize = info.uncompressed_size; + uint32_t RomFileSize = info.uncompressed_size; if (LoadBootCodeOnly) { RomFileSize = 0x1000; } - uint8_t * Image = (uint8_t *)VirtualAlloc(NULL, RomFileSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - if (Image == NULL) + + if (!AllocateRomImage(RomFileSize)) { - SetError(MSG_MEM_ALLOC_ERROR); - unzCloseCurrentFile(file); - break; + m_RomFile.Close(); + return false; } //Load the n64 rom to the allocated memory g_Notify->DisplayMessage(5, MSG_LOADING); - memcpy(Image, Test, 4); + memcpy(m_ROMImage, Test, 4); - DWORD dwRead, count, TotalRead = 0; + uint32_t dwRead, count, TotalRead = 0; for (count = 4; count < (int)RomFileSize; count += ReadFromRomSection) { - DWORD dwToRead = RomFileSize - count; + uint32_t dwToRead = RomFileSize - count; if (dwToRead > ReadFromRomSection) { dwToRead = ReadFromRomSection; } - dwRead = unzReadCurrentFile(file, &Image[count], dwToRead); + dwRead = unzReadCurrentFile(file, &m_ROMImage[count], dwToRead); if (dwRead == 0) { SetError(MSG_FAIL_ZIP); - VirtualFree(Image, 0, MEM_RELEASE); unzCloseCurrentFile(file); break; } @@ -188,26 +206,18 @@ bool CN64Rom::AllocateAndLoadZipImage(const char * FileLoc, bool LoadBootCodeOnl if (RomFileSize != dwRead) { - VirtualFree(Image, 0, MEM_RELEASE); unzCloseCurrentFile(file); SetError(MSG_FAIL_ZIP); g_Notify->DisplayMessage(1, ""); break; } - - //save information about the rom loaded - m_hRomFile = NULL; - m_ROMImage = Image; - m_RomFileSize = RomFileSize; FoundRom = true; g_Notify->DisplayMessage(5, MSG_BYTESWAP); ByteSwapRom(); //Protect the memory so that it can not be written to. - DWORD OldProtect; - VirtualProtect(m_ROMImage, m_RomFileSize, PAGE_READONLY, &OldProtect); - g_Notify->DisplayMessage(1, ""); + ProtectMemory(m_ROMImage, m_RomFileSize, MEM_READONLY); } unzCloseCurrentFile(file); @@ -223,9 +233,9 @@ bool CN64Rom::AllocateAndLoadZipImage(const char * FileLoc, bool LoadBootCodeOnl void CN64Rom::ByteSwapRom() { - DWORD count; + uint32_t count; - switch (*((DWORD *)&m_ROMImage[0])) + switch (*((uint32_t *)&m_ROMImage[0])) { case 0x12408037: for (count = 0; count < m_RomFileSize; count += 4) @@ -268,7 +278,7 @@ void CN64Rom::CalculateCicChip() for (int count = 0x40; count < 0x1000; count += 4) { - CRC += *(DWORD *)(m_ROMImage + count); + CRC += *(uint32_t *)(m_ROMImage + count); } switch (CRC) { case 0x000000D0027FDF31: m_CicChip = CIC_NUS_6101; break; @@ -290,10 +300,10 @@ void CN64Rom::CalculateCicChip() void CN64Rom::CalculateRomCrc() { - DWORD t0, t2, t3, t4, t5; - DWORD a0, a1, a2, a3; - DWORD s0; - DWORD v0, v1; + uint32_t t0, t2, t3, t4, t5; + uint32_t a0, a1, a2, a3; + uint32_t s0; + uint32_t v0, v1; // CIC_NUS_6101 at=0x5D588B65 , s6=0x3F // CIC_NUS_6102 at=0x5D588B65 , s6=0x3F @@ -315,8 +325,7 @@ void CN64Rom::CalculateRomCrc() return; } - DWORD OldProtect; - VirtualProtect(m_ROMImage, m_RomFileSize, PAGE_READWRITE, &OldProtect); + ProtectMemory(m_ROMImage, m_RomFileSize, MEM_READWRITE); v1 = 0; t0 = 0; @@ -331,7 +340,7 @@ void CN64Rom::CalculateRomCrc() for (t0 = 0; t0 < 0x00100000; t0 += 4) { - v0 = *(DWORD *)(m_ROMImage + t0 + 0x1000); + v0 = *(uint32_t *)(m_ROMImage + t0 + 0x1000); v1 = a3 + v0; a1 = v1; @@ -350,7 +359,7 @@ void CN64Rom::CalculateRomCrc() if (m_CicChip == CIC_NUS_6105) { - t4 = (v0 ^ (*(DWORD *)(m_ROMImage + (0xFF & t0) + 0x750))) + t4; + t4 = (v0 ^ (*(uint32_t *)(m_ROMImage + (0xFF & t0) + 0x750))) + t4; } else t4 = (v0 ^ s0) + t4; } @@ -370,10 +379,10 @@ void CN64Rom::CalculateRomCrc() s0 = s0 ^ a2 ^ t4; } - *(DWORD *)(m_ROMImage + 0x10) = a3; - *(DWORD *)(m_ROMImage + 0x14) = s0; + *(uint32_t *)(m_ROMImage + 0x10) = a3; + *(uint32_t *)(m_ROMImage + 0x14) = s0; - VirtualProtect(m_ROMImage, m_RomFileSize, PAGE_READONLY, &OldProtect); + ProtectMemory(m_ROMImage, m_RomFileSize, MEM_READONLY); } CICChip CN64Rom::CicChipID() @@ -383,10 +392,10 @@ CICChip CN64Rom::CicChipID() bool CN64Rom::IsValidRomImage(uint8_t Test[4]) { - if (*((DWORD *)&Test[0]) == 0x40123780) { return true; } - if (*((DWORD *)&Test[0]) == 0x12408037) { return true; } - if (*((DWORD *)&Test[0]) == 0x80371240) { return true; } - if (*((DWORD *)&Test[0]) == 0x40072780) { return true; } //64DD IPL + if (*((uint32_t *)&Test[0]) == 0x40123780) { return true; } + if (*((uint32_t *)&Test[0]) == 0x12408037) { return true; } + if (*((uint32_t *)&Test[0]) == 0x80371240) { return true; } + if (*((uint32_t *)&Test[0]) == 0x40072780) { return true; } //64DD IPL return false; } @@ -400,22 +409,20 @@ bool CN64Rom::LoadN64Image(const char * FileLoc, bool LoadBootCodeOnly) UnallocateRomImage(); m_ErrorMsg = EMPTY_STRING; - char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT]; - _splitpath(FileLoc, drive, dir, fname, ext); + stdstr ext = CPath(FileLoc).GetExtension(); bool Loaded7zFile = false; - if (strstr(FileLoc, "?") != NULL || strcmp(ext, ".7z") == 0) + if (strstr(FileLoc, "?") != NULL || _stricmp(ext.c_str(), "7z") == 0) { - char FullPath[MAX_PATH + 100]; - strcpy(FullPath, FileLoc); + stdstr FullPath = FileLoc; //this should be a 7zip file - char * SubFile = strstr(FullPath, "?"); + char * SubFile = strstr(const_cast(FullPath.c_str()), "?"); if (SubFile == NULL) { //Pop up a dialog and select file //allocate memory for sub name and copy selected file name to var - //return false; //remove once dialog is done + return false; //remove once dialog is done } else { @@ -423,7 +430,7 @@ bool CN64Rom::LoadN64Image(const char * FileLoc, bool LoadBootCodeOnly) SubFile += 1; } - C7zip ZipFile(FullPath); + C7zip ZipFile(FullPath.c_str()); ZipFile.SetNotificationCallback((C7zip::LP7ZNOTIFICATION)NotificationCB, this); for (int i = 0; i < ZipFile.NumFiles(); i++) { @@ -444,44 +451,33 @@ bool CN64Rom::LoadN64Image(const char * FileLoc, bool LoadBootCodeOnly) } //Get the size of the rom and try to allocate the memory needed. - DWORD RomFileSize = (DWORD)f->Size; + uint32_t RomFileSize = (uint32_t)f->Size; //if loading boot code then just load the first 0x1000 bytes if (LoadBootCodeOnly) { RomFileSize = 0x1000; } - uint8_t * Image = (uint8_t *)VirtualAlloc(NULL, RomFileSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - if (Image == NULL) + if (!AllocateRomImage(RomFileSize)) { - SetError(MSG_MEM_ALLOC_ERROR); return false; } //Load the n64 rom to the allocated memory g_Notify->DisplayMessage(5, MSG_LOADING); - if (!ZipFile.GetFile(i, Image, RomFileSize)) + if (!ZipFile.GetFile(i, m_ROMImage, RomFileSize)) { - VirtualFree(Image, 0, MEM_RELEASE); SetError(MSG_FAIL_IMAGE); return false; } - if (!IsValidRomImage(Image)) + if (!IsValidRomImage(m_ROMImage)) { - VirtualFree(Image, 0, MEM_RELEASE); SetError(MSG_FAIL_IMAGE); return false; } - - //save information about the rom loaded - m_ROMImage = Image; - m_RomFileSize = RomFileSize; - g_Notify->DisplayMessage(5, MSG_BYTESWAP); ByteSwapRom(); //Protect the memory so that it can not be written to. - DWORD OldProtect; - VirtualProtect(m_ROMImage, m_RomFileSize, PAGE_READONLY, &OldProtect); - + ProtectMemory(m_ROMImage, m_RomFileSize, MEM_READONLY); Loaded7zFile = true; break; } @@ -501,52 +497,10 @@ bool CN64Rom::LoadN64Image(const char * FileLoc, bool LoadBootCodeOnly) { return false; } - - //other wise treat if normal file and open the passed file - HANDLE hFile = CreateFile(FileLoc, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); - if (hFile == INVALID_HANDLE_VALUE) { SetError(MSG_FAIL_OPEN_IMAGE); return false; } - - //Create a file map - HANDLE hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); - if (hFileMapping == NULL) + if (!AllocateAndLoadN64Image(FileLoc, LoadBootCodeOnly)) { - CloseHandle(hFile); - SetError(MSG_FAIL_OPEN_IMAGE); return false; } - - //Map the file to a memory pointer .. ie a way of pretending to load the rom - //loose the bonus of being able to flip it on the fly tho. - uint8_t * Image = (PBYTE)MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0); - if (Image == NULL) - { - CloseHandle(hFileMapping); - CloseHandle(hFile); - SetError(MSG_FAIL_OPEN_IMAGE); - return false; - } - - if (!IsValidRomImage(Image)) - { - UnmapViewOfFile(Image); - CloseHandle(hFileMapping); - CloseHandle(hFile); - SetError(MSG_FAIL_IMAGE); - return false; - } - - if (*((DWORD *)Image) == 0x80371240) - { - m_hRomFile = hFile; - m_hRomFileMapping = hFileMapping; - m_ROMImage = Image; - m_RomFileSize = GetFileSize(hFile, NULL); - } - else - { - if (!AllocateAndLoadN64Image(FileLoc, LoadBootCodeOnly)) { return false; } - } } } @@ -582,9 +536,7 @@ bool CN64Rom::LoadN64Image(const char * FileLoc, bool LoadBootCodeOnly) RomName[20] = '\0'; if (strlen(RomName) == 0) { - char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT]; - _splitpath(FileLoc, drive, dir, fname, ext); - strcpy(RomName, fname); + strcpy(RomName, CPath(FileLoc).GetName().c_str()); } //remove all /,\,: from the string @@ -596,6 +548,7 @@ bool CN64Rom::LoadN64Image(const char * FileLoc, bool LoadBootCodeOnly) case ':': RomName[count] = ';'; break; } } + WriteTrace(TraceN64System, TraceDebug, "RomName %s", RomName); m_RomName = RomName; m_FileName = FileLoc; @@ -605,10 +558,12 @@ bool CN64Rom::LoadN64Image(const char * FileLoc, bool LoadBootCodeOnly) { //Calculate files MD5 m_MD5 = MD5((const unsigned char *)m_ROMImage, m_RomFileSize).hex_digest(); + WriteTrace(TraceN64System, TraceDebug, "MD5: %s", m_MD5.c_str()); } m_Country = (Country)m_ROMImage[0x3D]; - m_RomIdent.Format("%08X-%08X-C:%X", *(DWORD *)(&m_ROMImage[0x10]), *(DWORD *)(&m_ROMImage[0x14]), m_ROMImage[0x3D]); + m_RomIdent.Format("%08X-%08X-C:%X", *(uint32_t *)(&m_ROMImage[0x10]), *(uint32_t *)(&m_ROMImage[0x14]), m_ROMImage[0x3D]); + WriteTrace(TraceN64System, TraceDebug, "Ident: %s", m_RomIdent.c_str()); CalculateCicChip(); if (!LoadBootCodeOnly && g_Rom == this) @@ -660,24 +615,14 @@ void CN64Rom::SetError(LanguageStringID ErrorMsg) void CN64Rom::UnallocateRomImage() { - if (m_hRomFileMapping) - { - UnmapViewOfFile(m_ROMImage); - CloseHandle(m_hRomFileMapping); - m_ROMImage = NULL; - m_hRomFileMapping = NULL; - } - if (m_hRomFile) - { - CloseHandle(m_hRomFile); - m_hRomFile = NULL; - } + m_RomFile.Close(); //if this value is still set then the image was not created a map //file but created with VirtualAllocate - if (m_ROMImage) + if (m_ROMImageBase) { - VirtualFree(m_ROMImage, 0, MEM_RELEASE); - m_ROMImage = NULL; + delete[] m_ROMImageBase; + m_ROMImageBase = NULL; } + m_ROMImage = NULL; } \ No newline at end of file diff --git a/Source/Project64-core/N64System/N64RomClass.h b/Source/Project64-core/N64System/N64RomClass.h index b30d9ac22..6e10a0709 100644 --- a/Source/Project64-core/N64System/N64RomClass.h +++ b/Source/Project64-core/N64System/N64RomClass.h @@ -16,26 +16,6 @@ class CN64Rom : protected CDebugSettings { - //constant values - enum { ReadFromRomSection = 0x400000 }; - - //class variables - void * m_hRomFile, *m_hRomFileMapping; - uint8_t * m_ROMImage; - uint32_t m_RomFileSize; - Country m_Country; - CICChip m_CicChip; - LanguageStringID m_ErrorMsg; - stdstr m_RomName, m_FileName, m_MD5, m_RomIdent; - - bool AllocateAndLoadN64Image(const char * FileLoc, bool LoadBootCodeOnly); - bool AllocateAndLoadZipImage(const char * FileLoc, bool LoadBootCodeOnly); - void ByteSwapRom(); - void SetError(LanguageStringID ErrorMsg); - static void NotificationCB(const char * Status, CN64Rom * _this); - void CalculateCicChip(); - void CalculateRomCrc(); - public: CN64Rom(); ~CN64Rom(); @@ -55,4 +35,28 @@ public: //Get a message id for the reason that you failed to load the rom LanguageStringID GetError() const { return m_ErrorMsg; } + +private: + bool AllocateRomImage(uint32_t RomFileSize); + bool AllocateAndLoadN64Image(const char * FileLoc, bool LoadBootCodeOnly); + bool AllocateAndLoadZipImage(const char * FileLoc, bool LoadBootCodeOnly); + void ByteSwapRom(); + void SetError(LanguageStringID ErrorMsg); + static void NotificationCB(const char * Status, CN64Rom * _this); + void CalculateCicChip(); + void CalculateRomCrc(); + + //constant values + enum { ReadFromRomSection = 0x400000 }; + + //class variables + CFile m_RomFile; + void *m_hRomFileMapping; + uint8_t * m_ROMImage; + uint8_t * m_ROMImageBase; + uint32_t m_RomFileSize; + Country m_Country; + CICChip m_CicChip; + LanguageStringID m_ErrorMsg; + stdstr m_RomName, m_FileName, m_MD5, m_RomIdent; };