From c365617ff737bdb3c06c307159078ca4e5f7e175 Mon Sep 17 00:00:00 2001 From: zeromus Date: Tue, 11 Apr 2017 19:40:31 -0500 Subject: [PATCH] take a stab at fixing the ram/streaming option so that there arent split codepaths everywhere. homebrew that is eligible for DLDI patching now switches entirely to load from memory, because we lack the facilities to patch the DLDI in flight (although we now have a point to hook it into). really, all this code should be torched, but it's less of a mess now. --- desmume/src/NDSSystem.cpp | 138 +++++++++--------- desmume/src/NDSSystem.h | 4 +- desmume/src/ROMReader.cpp | 121 ++++++++++++++- desmume/src/ROMReader.h | 5 +- .../src/addons/slot1_retail_mcrom_debug.cpp | 9 +- desmume/src/frontend/windows/fsnitroView.cpp | 7 +- desmume/src/frontend/windows/main.cpp | 5 - desmume/src/frontend/windows/memView.cpp | 85 ++--------- desmume/src/utils/fsnitro.cpp | 90 ++++++++---- desmume/src/utils/fsnitro.h | 5 +- 10 files changed, 269 insertions(+), 200 deletions(-) diff --git a/desmume/src/NDSSystem.cpp b/desmume/src/NDSSystem.cpp index c1a769373..5601d506d 100644 --- a/desmume/src/NDSSystem.cpp +++ b/desmume/src/NDSSystem.cpp @@ -505,36 +505,45 @@ bool GameInfo::loadROM(std::string fname, u32 type) reader->Read(fROM, &secureArea[0], 0x4000); } - if (CommonSettings.loadToMemory) + //for now, we have to do this, because the DLDI patching requires it + bool loadToMemory = CommonSettings.loadToMemory; + if(isHomebrew()) + loadToMemory = true; + + //convert to an in-memory reader around a pre-read buffer if that's what's requested + if (loadToMemory) { reader->Seek(fROM, headerOffset, SEEK_SET); - romdata = new u8[romsize + 4]; - if (reader->Read(fROM, romdata, romsize) != romsize) + romdataForReader = new u8[romsize]; + if (reader->Read(fROM, romdataForReader, romsize) != romsize) { - delete [] romdata; romdata = NULL; + delete [] romdataForReader; romdataForReader = NULL; romsize = 0; return false; } - if(hasRomBanner()) - { - memcpy(&banner, romdata + header.IconOff, sizeof(RomBanner)); - - banner.version = LE_TO_LOCAL_16(banner.version); - banner.crc16 = LE_TO_LOCAL_16(banner.crc16); - - for(size_t i = 0; i < ARRAY_SIZE(banner.palette); i++) - { - banner.palette[i] = LE_TO_LOCAL_16(banner.palette[i]); - } - } - - _isDSiEnhanced = (LE_TO_LOCAL_32(*(u32*)(romdata + 0x180) == 0x8D898581U) && LE_TO_LOCAL_32(*(u32*)(romdata + 0x184) == 0x8C888480U)); - reader->DeInit(fROM); fROM = NULL; - return true; + reader->DeInit(fROM); + fROM = NULL; + reader = MemROMReaderRead_TrueInit(romdataForReader, romsize); + fROM = reader->Init(NULL); } + + if(hasRomBanner()) + { + reader->Seek(fROM, header.IconOff, SEEK_SET); + reader->Read(fROM, &banner, sizeof(RomBanner)); + + banner.version = LE_TO_LOCAL_16(banner.version); + banner.crc16 = LE_TO_LOCAL_16(banner.crc16); + + for(size_t i = 0; i < ARRAY_SIZE(banner.palette); i++) + { + banner.palette[i] = LE_TO_LOCAL_16(banner.palette[i]); + } + } + _isDSiEnhanced = ((readROM(0x180) == 0x8D898581U) && (readROM(0x184) == 0x8C888480U)); if (hasRomBanner()) { @@ -561,14 +570,15 @@ bool GameInfo::loadROM(std::string fname, u32 type) void GameInfo::closeROM() { - if (fROM) + if (reader) reader->DeInit(fROM); - if (romdata) - delete [] romdata; + if (romdataForReader) + delete [] romdataForReader; fROM = NULL; - romdata = NULL; + reader = NULL; + romdataForReader = NULL; romsize = 0; lastReadPos = 0xFFFFFFFF; } @@ -577,36 +587,10 @@ u32 GameInfo::readROM(u32 pos) { u32 num; u32 data; - if (!romdata) - { - if (lastReadPos != pos) - reader->Seek(fROM, pos + headerOffset, SEEK_SET); - num = reader->Read(fROM, &data, 4); - lastReadPos = (pos + num); - } - else - { - if(pos + 4 <= romsize) - { - //fast path - data = LE_TO_LOCAL_32(*(u32*)(romdata + pos)); - num = 4; - } - else - { - data = 0; - num = 0; - for(int i=0;i<4;i++) - { - if(pos >= romsize) - break; - data |= (romdata[pos]<<(i*8)); - pos++; - num++; - } - } - } - + if (lastReadPos != pos) + reader->Seek(fROM, pos + headerOffset, SEEK_SET); + num = reader->Read(fROM, &data, 4); + lastReadPos = (pos + num); //in case we didn't read enough data, pad the remainder with 0xFF u32 pad = 0; @@ -669,8 +653,16 @@ static int rom_init_path(const char *filename, const char *physicalName, const c return 1; } +struct LastRom { + std::string filename, physicalName, logicalFilename; +} lastRom; + int NDS_LoadROM(const char *filename, const char *physicalName, const char *logicalFilename) { + lastRom.filename = filename; + lastRom.physicalName = physicalName; + lastRom.logicalFilename = logicalFilename; + int ret; char buf[MAX_PATH]; @@ -693,10 +685,15 @@ int NDS_LoadROM(const char *filename, const char *physicalName, const char *logi gameInfo.populate(); - if (CommonSettings.loadToMemory) - gameInfo.crc = crc32(0, (u8*)gameInfo.romdata, gameInfo.romsize); - else - gameInfo.crc = 0; + //run crc over the whole buffer (chunk at a time, to avoid coding a streaming crc + gameInfo.reader->Seek(gameInfo.fROM, 0, SEEK_SET); + gameInfo.crc = 0; + for(;;) { + u8 buf[4096]; + int read = gameInfo.reader->Read(gameInfo.fROM,buf,4096); + if(read == 0) break; + gameInfo.crc = crc32(gameInfo.crc, buf, read); + } gameInfo.chipID = 0xC2; // The Manufacturer ID is defined by JEDEC (C2h = Macronix) if (!gameInfo.isHomebrew()) @@ -720,8 +717,7 @@ int NDS_LoadROM(const char *filename, const char *physicalName, const char *logi } INFO("\nROM game code: %c%c%c%c\n", gameInfo.header.gameCode[0], gameInfo.header.gameCode[1], gameInfo.header.gameCode[2], gameInfo.header.gameCode[3]); - if (gameInfo.crc) - INFO("ROM crc: %08X\n", gameInfo.crc); + INFO("ROM crc: %08X\n", gameInfo.crc); if (!gameInfo.isHomebrew()) { INFO("ROM serial: %s\n", gameInfo.ROMserial); @@ -762,14 +758,11 @@ int NDS_LoadROM(const char *filename, const char *physicalName, const char *logi //for homebrew, try auto-patching DLDI. should be benign if there is no DLDI or if it fails if(gameInfo.isHomebrew()) { - if(!CommonSettings.loadToMemory) - msgbox->warn("Sorry.. right now, you can't use the default (stream rom from disk) with homebrew due to a bug with DLDI-autopatching"); - else if (slot1_GetCurrentType() == NDS_SLOT1_R4) - DLDI::tryPatch((void*)gameInfo.romdata, gameInfo.romsize, 1); - else - if (slot2_GetCurrentType() == NDS_SLOT2_CFLASH) - DLDI::tryPatch((void*)gameInfo.romdata, gameInfo.romsize, 0); - + //note: gameInfo.romdataForReader is safe here because we made sure to load the rom into memory for isHomebrew + if (slot1_GetCurrentType() == NDS_SLOT1_R4) + DLDI::tryPatch((void*)gameInfo.romdataForReader, gameInfo.romsize, 1); + else if (slot2_GetCurrentType() == NDS_SLOT2_CFLASH) + DLDI::tryPatch((void*)gameInfo.romdataForReader, gameInfo.romsize, 0); } if (cheats != NULL) @@ -2510,6 +2503,15 @@ bool NDS_FakeBoot() bool _HACK_DONT_STOPMOVIE = false; void NDS_Reset() { + //reload last paths if needed + if(!gameInfo.reader) + { + LastRom stash = lastRom; + NDS_LoadROM(stash.filename.c_str(), stash.physicalName.c_str(), stash.logicalFilename.c_str()); + //yeah, great. LoadROM calls NDS_Reset. Geeze. + return; + } + PrepareLogfiles(); CommonSettings.gamehacks.apply(); diff --git a/desmume/src/NDSSystem.h b/desmume/src/NDSSystem.h index 7052b4ebd..7b5edda84 100644 --- a/desmume/src/NDSSystem.h +++ b/desmume/src/NDSSystem.h @@ -317,7 +317,7 @@ struct GameInfo { void *fROM; ROMReader_struct *reader; - u8 *romdata; + u8 *romdataForReader; u32 romsize; u32 cardSize; u32 mask; @@ -336,7 +336,7 @@ struct GameInfo const RomBanner& getRomBanner(); GameInfo() : fROM(NULL), - romdata(NULL), + romdataForReader(NULL), crc(0), chipID(0x00000FC2), romsize(0), diff --git a/desmume/src/ROMReader.cpp b/desmume/src/ROMReader.cpp index 778c50e60..5d01bd3ef 100644 --- a/desmume/src/ROMReader.cpp +++ b/desmume/src/ROMReader.cpp @@ -1,6 +1,6 @@ /* Copyright 2007 Guillaume Duhamel - Copyright 2007-2012 DeSmuME team + Copyright 2007-2017 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -55,6 +55,7 @@ void STDROMReaderDeInit(void *); u32 STDROMReaderSize(void *); int STDROMReaderSeek(void *, int, int); int STDROMReaderRead(void *, void *, u32); +int STDROMReaderWrite(void *, void *, u32); ROMReader_struct STDROMReader = { @@ -64,7 +65,8 @@ ROMReader_struct STDROMReader = STDROMReaderDeInit, STDROMReaderSize, STDROMReaderSeek, - STDROMReaderRead + STDROMReaderRead, + STDROMReaderWrite }; void * STDROMReaderInit(const char * filename) @@ -91,7 +93,7 @@ u32 STDROMReaderSize(void * file) { u32 size; - if (!file) return 0 ; + if (!file) return 0; fseek((FILE*)file, 0, SEEK_END); size = ftell((FILE*)file); @@ -102,22 +104,29 @@ u32 STDROMReaderSize(void * file) int STDROMReaderSeek(void * file, int offset, int whence) { - if (!file) return 0 ; + if (!file) return 0; return fseek((FILE*)file, offset, whence); } int STDROMReaderRead(void * file, void * buffer, u32 size) { - if (!file) return 0 ; + if (!file) return 0; return fread(buffer, 1, size, (FILE*)file); } +int STDROMReaderWrite(void *, void *, u32) +{ + //not supported, for now + return 0; +} + #ifdef HAVE_LIBZ void * GZIPROMReaderInit(const char * filename); void GZIPROMReaderDeInit(void *); u32 GZIPROMReaderSize(void *); int GZIPROMReaderSeek(void *, int, int); int GZIPROMReaderRead(void *, void *, u32); +int GZIPROMReaderWrite(void *, void *, u32); ROMReader_struct GZIPROMReader = { @@ -127,7 +136,8 @@ ROMReader_struct GZIPROMReader = GZIPROMReaderDeInit, GZIPROMReaderSize, GZIPROMReaderSeek, - GZIPROMReaderRead + GZIPROMReaderRead, + GZIPROMReaderWrite }; void * GZIPROMReaderInit(const char * filename) @@ -164,6 +174,12 @@ int GZIPROMReaderRead(void * file, void * buffer, u32 size) { return gzread((gzFile)file, buffer, size); } + +int GZIPROMReaderWrite(void *, void *, u32) +{ + //not supported, ever + return 0; +} #endif #ifdef HAVE_LIBZZIP @@ -172,6 +188,7 @@ void ZIPROMReaderDeInit(void *); u32 ZIPROMReaderSize(void *); int ZIPROMReaderSeek(void *, int, int); int ZIPROMReaderRead(void *, void *, u32); +int ZIPROMReaderWrite(void *, void *, u32); ROMReader_struct ZIPROMReader = { @@ -182,6 +199,7 @@ ROMReader_struct ZIPROMReader = ZIPROMReaderSize, ZIPROMReaderSeek, ZIPROMReaderRead + ZIPROMReaderWrite }; void * ZIPROMReaderInit(const char * filename) @@ -230,4 +248,95 @@ int ZIPROMReaderRead(void * file, void * buffer, u32 size) return zzip_read((ZZIP_FILE*)file, buffer, size); #endif } + +int ZIPROMReaderWrite(void *, void *, u32) +{ + //not supported ever + return 0; +} #endif + +struct { + void* buf; + int len; + int pos; +} mem; + +void * MemROMReaderInit(const char * filename) +{ + return NULL; //dummy +} + +void MemROMReaderDeInit(void *) +{ + //nothing to do +} +u32 MemROMReaderSize(void *) +{ + return (u32)mem.len; +} +int MemROMReaderSeek(void * file, int offset, int whence) +{ + switch(whence) { + case SEEK_SET: + mem.pos = offset; + break; + case SEEK_CUR: + mem.pos += offset; + break; + case SEEK_END: + mem.pos = mem.len + offset; + break; + } + return mem.pos; +} + +int MemROMReaderRead(void * file, void * buffer, u32 size) +{ + if(mem.pos<0) return 0; + + int todo = (int)size; + int remain = mem.len - mem.pos; + if(remainrebuildFAT(pathData); } diff --git a/desmume/src/frontend/windows/fsnitroView.cpp b/desmume/src/frontend/windows/fsnitroView.cpp index 27e585aed..b12147a6f 100644 --- a/desmume/src/frontend/windows/fsnitroView.cpp +++ b/desmume/src/frontend/windows/fsnitroView.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2016 DeSmuME team + Copyright (C) 2013-2017 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -91,7 +91,8 @@ void refreshQView(HWND hWnd, u16 id) u32 len = std::min(sizeof(buf), fs->getFileSizeById(id)); u32 start = fs->getStartAddrById(id); - memcpy(&buf[0], &gameInfo.romdata[start], len); + gameInfo.reader->Seek(gameInfo.fROM, start, SEEK_SET); + gameInfo.reader->Read(gameInfo.fROM, &buf[0], len); for (u32 i = 0; i < len; i++) if (buf[i] < 0x20) buf[i] = 0x20; @@ -108,7 +109,7 @@ BOOL CALLBACK ViewFSNitroProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam { case WM_INITDIALOG: { - fs = new FS_NITRO(gameInfo.romdata); + fs = new FS_NITRO(); if (!fs) { diff --git a/desmume/src/frontend/windows/main.cpp b/desmume/src/frontend/windows/main.cpp index eba4dbc4c..346c943f9 100644 --- a/desmume/src/frontend/windows/main.cpp +++ b/desmume/src/frontend/windows/main.cpp @@ -5693,11 +5693,6 @@ DOKEYDOWN: return 0; case ID_TOOLS_VIEWFSNITRO: - if (!CommonSettings.loadToMemory) - { - msgbox->error("Change ROM loading mode to \"Load entirely to RAM\""); - return 0; - } ViewFSNitro->open(); return 0; //========================================================== Tools end diff --git a/desmume/src/frontend/windows/memView.cpp b/desmume/src/frontend/windows/memView.cpp index 5bf31718a..2b78b22ae 100644 --- a/desmume/src/frontend/windows/memView.cpp +++ b/desmume/src/frontend/windows/memView.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2006 yopyop - Copyright (C) 2006-2016 DeSmuME team + Copyright (C) 2006-2017 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -81,10 +81,6 @@ u8 memRead8 (MemRegionType regionType, HWAddressType address) case MEMVIEW_FIRMWARE: value = MMU.fw.data[address]; return value; - case MEMVIEW_ROM: - if (address < gameInfo.romsize) - value = gameInfo.romdata[address]; - return value; case MEMVIEW_FULL: MMU_DumpMemBlock(0, address, 1, &value); return value; @@ -92,69 +88,6 @@ u8 memRead8 (MemRegionType regionType, HWAddressType address) return 0; } -u16 memRead16 (MemRegionType regionType, HWAddressType address) -{ - MemViewRegion& region = s_memoryRegions[regionType]; - if (address < region.hardwareAddress || (address + 1) >= (region.hardwareAddress + region.size)) - { - return 0; - } - - u16 value = 0; - switch (regionType) - { - case MEMVIEW_ARM9: - MMU_DumpMemBlock(ARMCPU_ARM9, address, 2, (u8*)&value); - return value; - case MEMVIEW_ARM7: - MMU_DumpMemBlock(ARMCPU_ARM7, address, 2, (u8*)&value); - return value; - case MEMVIEW_FIRMWARE: - value = *(u16*)(&MMU.fw.data[address]); - return value; - case MEMVIEW_ROM: - if (address < (gameInfo.romsize - 2)) - value = T1ReadWord(gameInfo.romdata, address); - return value; - case MEMVIEW_FULL: - MMU_DumpMemBlock(0, address, 2, (u8*)&value); - return value; - } - return 0; -} - -u32 memRead32 (MemRegionType regionType, HWAddressType address) -{ - MemViewRegion& region = s_memoryRegions[regionType]; - if (address < region.hardwareAddress || (address + 3) >= (region.hardwareAddress + region.size)) - { - return 0; - } - - u32 value = 0; - switch (regionType) - { - case MEMVIEW_ARM9: - MMU_DumpMemBlock(ARMCPU_ARM9, address, 4, (u8*)&value); - return value; - case MEMVIEW_ARM7: - MMU_DumpMemBlock(ARMCPU_ARM7, address, 4, (u8*)&value); - return value; - case MEMVIEW_FIRMWARE: - value = *(u32*)(&MMU.fw.data[address]); - return value; - case MEMVIEW_ROM: - if (address < (gameInfo.romsize - 4)) - value = T1ReadLong(gameInfo.romdata, address); - - return value; - case MEMVIEW_FULL: - MMU_DumpMemBlock(0, address, 4, (u8*)&value); - return value; - } - return 0; -} - void memRead(u8* buffer, MemRegionType regionType, HWAddressType address, size_t size) { switch (regionType) @@ -165,6 +98,10 @@ void memRead(u8* buffer, MemRegionType regionType, HWAddressType address, size_t case MEMVIEW_ARM7: MMU_DumpMemBlock(ARMCPU_ARM7, address, size, buffer); break; + case MEMVIEW_ROM: + gameInfo.reader->Seek(gameInfo.fROM, address, SEEK_SET); + gameInfo.reader->Read(gameInfo.fROM, buffer, size); + break; default: for (size_t i = 0; i < size; i++) { @@ -199,7 +136,8 @@ void memWrite8(MemRegionType regionType, HWAddressType address, u8 value) MMU.fw.data[address] = value; break; case MEMVIEW_ROM: - gameInfo.romdata[address] = value; + gameInfo.reader->Seek(gameInfo.fROM, address, SEEK_SET); + gameInfo.reader->Write(gameInfo.fROM, &value, 1); break; case MEMVIEW_FULL: MMU_write8(ARMCPU_ARM9, address, value); @@ -222,7 +160,8 @@ void memWrite16(MemRegionType regionType, HWAddressType address, u16 value) *((u16*)&MMU.fw.data[address]) = value; break; case MEMVIEW_ROM: - *((u16*)&gameInfo.romdata[address]) = value; + gameInfo.reader->Seek(gameInfo.fROM, address, SEEK_SET); + gameInfo.reader->Write(gameInfo.fROM, &value, 2); break; case MEMVIEW_FULL: MMU_write16(ARMCPU_ARM9, address, value); @@ -245,7 +184,8 @@ void memWrite32(MemRegionType regionType, HWAddressType address, u32 value) *((u32*)&MMU.fw.data[address]) = value; break; case MEMVIEW_ROM: - *((u32*)&gameInfo.romdata[address]) = value; + gameInfo.reader->Seek(gameInfo.fROM, address, SEEK_SET); + gameInfo.reader->Write(gameInfo.fROM, &value, 4); break; case MEMVIEW_FULL: MMU_write32(ARMCPU_ARM9, address, value); @@ -274,8 +214,7 @@ CMemView::CMemView(MemRegionType memRegion, u32 start_address) s_memoryRegions.push_back(s_arm7Region); s_memoryRegions.push_back(s_firmwareRegion); s_memoryRegions.push_back(s_fullRegion); - if (CommonSettings.loadToMemory) - s_memoryRegions.push_back(s_RomRegion); + s_memoryRegions.push_back(s_RomRegion); } PostInitialize(); diff --git a/desmume/src/utils/fsnitro.cpp b/desmume/src/utils/fsnitro.cpp index 2714590e1..e2d0dc319 100644 --- a/desmume/src/utils/fsnitro.cpp +++ b/desmume/src/utils/fsnitro.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2016 DeSmuME team + Copyright (C) 2013-2017 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,8 +22,9 @@ #include "types.h" #include "fsnitro.h" #include "file/file_path.h" +#include "NDSSystem.h" -FS_NITRO::FS_NITRO(u8 *cart_rom) +FS_NITRO::FS_NITRO() { inited = false; numDirs = numFiles = numOverlay7 = numOverlay9 = currentID =0; @@ -32,9 +33,9 @@ FS_NITRO::FS_NITRO(u8 *cart_rom) ovr9 = NULL; ovr7 = NULL; - if (!cart_rom) return; - - rom = cart_rom; + u8 rom[256]; + gameInfo.reader->Seek(gameInfo.fROM, 0, SEEK_SET); + gameInfo.reader->Read(gameInfo.fROM, rom, 256); FNameTblOff = *(u32*)(rom + 0x40); FNameTblSize = *(u32*)(rom + 0x44); @@ -62,7 +63,8 @@ FS_NITRO::FS_NITRO(u8 *cart_rom) if (FATOff < 0x8000) return; if (FATSize == 0) return; - numDirs = *(u16*)(rom + FNameTblOff + 6); + gameInfo.reader->Seek(gameInfo.fROM, FNameTblOff + 6, SEEK_SET); + gameInfo.reader->Read(gameInfo.fROM, &numDirs, 2); numFiles = FATSize / 8; if (numFiles == 0 || numDirs == 0) @@ -140,12 +142,12 @@ bool FS_NITRO::loadFileTables() fnt = new FNT_NITRO[numDirs]; // ========= FAT (File Allocation Table) - u32 *_FAT = (u32*)(rom + FATOff); for (u32 i = 0; i < numFiles; i++) { const u32 ofs = (i * 2); - fat[i].start = *(_FAT + ofs); - fat[i].end = *(_FAT + ofs + 1); + gameInfo.reader->Seek(gameInfo.fROM, FATOff + ofs, SEEK_SET); + gameInfo.reader->Read(gameInfo.fROM, &fat[i].start, 4); + gameInfo.reader->Read(gameInfo.fROM, &fat[i].end, 4); fat[i].size = fat[i].end - fat[i].start; fat[i].sizeFile = fat[i].size; fat[i].isOverlay = false; @@ -154,7 +156,9 @@ bool FS_NITRO::loadFileTables() // ========= Overlays ARM9 if (numOverlay9) { - memcpy(ovr9, (rom + ARM9OverlayOff), ARM9OverlaySize); + gameInfo.reader->Seek(gameInfo.fROM, ARM9OverlayOff, SEEK_SET); + gameInfo.reader->Read(gameInfo.fROM, ovr9, ARM9OverlaySize); + for (u32 i = 0 ; i < numOverlay9; i++) { char buf[129] = {0}; @@ -168,7 +172,9 @@ bool FS_NITRO::loadFileTables() // ========= Overlays ARM7 if (numOverlay7) { - memcpy(ovr7, (rom + ARM7OverlayOff), ARM7OverlaySize); + gameInfo.reader->Seek(gameInfo.fROM, ARM7OverlayOff, SEEK_SET); + gameInfo.reader->Read(gameInfo.fROM, ovr7, ARM7OverlaySize); + for (u32 i = 0 ; i < numOverlay7; i++) { char buf[129] = {0}; @@ -180,23 +186,24 @@ bool FS_NITRO::loadFileTables() } // ========= FNT (File Names Table) - u8 *_FNT = (u8*)(rom + FNameTblOff); + gameInfo.reader->Seek(gameInfo.fROM, FNameTblOff, SEEK_SET); for (u32 i = 0; i < numDirs; i++) { - memcpy(&fnt[i], _FNT, 8); + gameInfo.reader->Read(gameInfo.fROM, &fnt[i], 8); //printf("FNT %04Xh: sub:%08Xh, 1st ID:%04xh, parentID:%04Xh\n", i, fnt[i].offset, fnt[i].firstID, fnt[i].parentID); - _FNT += 8; } // ========= Read file structure - u8 *sub = (u8*)(rom + FNameTblOff + fnt[0].offset); - u8 *_end = (u8*)(rom + FNameTblOff + FNameTblSize - 1); + //u8 *sub = (u8*)(rom + FNameTblOff + fnt[0].offset); + //u8 *_end = (u8*)(rom + FNameTblOff + FNameTblSize - 1); + u32 subptr = FNameTblOff + fnt[0].offset; + u32 _endptr = FNameTblOff + FNameTblSize - 1; u16 fileCount = fnt[0].firstID; u16 fntID = 0xF000; - uintptr_t *store = new uintptr_t[numDirs]; + uintptr_t *store = new u32[numDirs]; if (!store) return false; - memset(store, 0, sizeof(uintptr_t) * numDirs); + memset(store, 0, sizeof(u32) * numDirs); fnt[0].filename = path_default_slash(); fnt[0].parentID = 0xF000; @@ -205,13 +212,17 @@ bool FS_NITRO::loadFileTables() while (true) { - u8 len = (sub[0] & 0x7F); - FNT_TYPES type = getFNTType(sub[0]); + u8 sub; + gameInfo.reader->Seek(gameInfo.fROM, subptr, SEEK_SET); + gameInfo.reader->Read(gameInfo.fROM, &sub, 1); + + u8 len = (sub & 0x7F); + FNT_TYPES type = getFNTType(sub); if (type == FS_END_SUBTABLE) { //printf("********** End Subdir (%04Xh, parent %04X)\n", fntID, fnt[fntID & 0x0FFF].parentID); - sub = (u8*)store[fntID & 0x0FFF]; + subptr = store[fntID & 0x0FFF]; fntID = fnt[fntID & 0x0FFF].parentID; continue; } @@ -220,14 +231,17 @@ bool FS_NITRO::loadFileTables() { //printf("********** Subdir Entry\n"); char buf[129] = {0}; - memcpy(buf, (sub + 1), len); buf[len] = 0; - sub += (len + 1); - fntID = (*(u16*)sub); - sub += 2; + gameInfo.reader->Seek(gameInfo.fROM, subptr + 1, SEEK_SET); + gameInfo.reader->Read(gameInfo.fROM, buf, len); + buf[len] = 0; + subptr += (len + 1); + gameInfo.reader->Seek(gameInfo.fROM, subptr, SEEK_SET); + gameInfo.reader->Read(gameInfo.fROM, &fntID, 2); + subptr += 2; u32 id = (fntID & 0x0FFF); - store[id] = (uintptr_t)sub; - sub = (u8*)(rom + FNameTblOff + fnt[id].offset); + store[id] = subptr; + subptr = FNameTblOff + fnt[id].offset; fnt[id].filename = buf; //printf("FNT %04X: Sub:%08Xh, 1st ID:%04xh, parentID:%04Xh <%s>\n", fntID, fnt[id].offset, fnt[id].firstID, fnt[id].parentID, buf); @@ -238,11 +252,13 @@ bool FS_NITRO::loadFileTables() { //printf("********** File Entry\n"); char buf[129] = {0}; - memcpy(buf, (sub + 1), len); buf[len] = 0; + gameInfo.reader->Seek(gameInfo.fROM, subptr + 1, SEEK_SET); + gameInfo.reader->Read(gameInfo.fROM, buf, len); + buf[len] = 0; fat[fileCount].filename = buf; fat[fileCount].parentID = fntID; //printf("ID:%04Xh, len %03d, type %d, parentID %04X, filename: %s\n", fileCount, len, (u32)type, fntID, fat[fileCount].filename); - sub += (len + 1); + subptr += (len + 1); fileCount++; if (fileCount >= numFiles) break; @@ -272,8 +288,6 @@ bool FS_NITRO::rebuildFAT(u32 addr, u32 size, std::string pathData) const u32 endID = startID + (size / 8); //printf("Start rebuild FAT (start ID:%04Xh)\n", startID); - u8 *romFAT = (u8*)(rom + addr); - for (u32 i = startID; i < endID; i++) { if (i >= numFiles) break; @@ -467,7 +481,19 @@ bool FS_NITRO::extract(u16 id, std::string to) FILE *fp = fopen(to.c_str(), "wb"); if (fp) { - fwrite((rom + fat[id].start), 1, fat[id].size, fp); + u32 remain = fat[id].size; + u32 dstofs = 0; + gameInfo.reader->Seek(gameInfo.fROM, fat[id].start, SEEK_SET); + while(remain>0) { + u8 tmp[4096]; + u32 todo = remain; + if(todo>4096) todo=4096; + int done = gameInfo.reader->Read(gameInfo.fROM, tmp, todo); + if(done != todo) break; //panic + fwrite(tmp, 1, done, fp); + dstofs += done; + remain -= done; + } fclose(fp); return true; } diff --git a/desmume/src/utils/fsnitro.h b/desmume/src/utils/fsnitro.h index 519eb6ca3..724d3f916 100644 --- a/desmume/src/utils/fsnitro.h +++ b/desmume/src/utils/fsnitro.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2016 DeSmuME team + Copyright (C) 2013-2017 DeSmuME team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -118,7 +118,6 @@ private: u32 currentID; - u8 *rom; FAT_NITRO *fat; FNT_NITRO *fnt; OVR_NITRO *ovr9; @@ -131,7 +130,7 @@ private: void destroy(); public: - FS_NITRO(u8 *cart_rom); + FS_NITRO(); ~FS_NITRO(); bool getFileIdByAddr(u32 addr, u16 &id);