mirror of
https://github.com/coderkei/akmenu-next.git
synced 2025-06-18 08:55:46 -04:00

- Added DSiWare detection - Start INI Work for DSiWare. PUB and PRV save creation not added yet. - Only modify VRAM if running on a flashcart (resolved Giana Sisters DS regression) - Remove Card DMA configuration to align with nds-bootstrap removing it as a configurable value - Show a message to the user if using akmenu-next for the first time
257 lines
7.5 KiB
C++
257 lines
7.5 KiB
C++
/*
|
||
dsrom.cpp
|
||
Copyright (C) 2007 Acekard, www.acekard.com
|
||
Copyright (C) 2007-2009 somebody
|
||
Copyright (C) 2009 yellow wood goblin
|
||
|
||
SPDX-License-Identifier: GPL-3.0-or-later
|
||
*/
|
||
|
||
#include "dsrom.h"
|
||
#include "dbgtool.h"
|
||
#include "fileicons.h"
|
||
#include "gamecode.h"
|
||
#include "gbarom_banner_bin.h"
|
||
#include "icon_bg_bin.h"
|
||
#include "icons.h"
|
||
#include "nds_banner_bin.h"
|
||
#include "unknown_nds_banner_bin.h"
|
||
|
||
DSRomInfo& DSRomInfo::operator=(const DSRomInfo& src) {
|
||
memcpy(&_banner, &src._banner, sizeof(_banner));
|
||
memcpy(&_saveInfo, &src._saveInfo, sizeof(_saveInfo));
|
||
_isDSRom = src._isDSRom;
|
||
_isHomebrew = src._isHomebrew;
|
||
_isGbaRom = src._isGbaRom;
|
||
_fileName = src._fileName;
|
||
_romVersion = src._romVersion;
|
||
_extIcon = src._extIcon;
|
||
return *this;
|
||
}
|
||
|
||
bool DSRomInfo::loadDSRomInfo(const std::string& filename, bool loadBanner) {
|
||
_isDSRom = EFalse;
|
||
_isHomebrew = EFalse;
|
||
FILE* f = fopen(filename.c_str(), "rb");
|
||
if (NULL == f) // 锟斤拷锟侥硷拷失锟斤拷
|
||
{
|
||
return false;
|
||
}
|
||
|
||
tNDSHeader header;
|
||
if (512 != fread(&header, 1, 512, f)) // 锟斤拷锟侥硷拷头失锟斤拷
|
||
{
|
||
dbg_printf("read rom header fail\n");
|
||
memcpy(&_banner, unknown_nds_banner_bin, sizeof(_banner));
|
||
fclose(f);
|
||
return false;
|
||
}
|
||
|
||
if (header.unitCode == 0x03) {
|
||
_isDSiWare = ETrue;
|
||
}
|
||
|
||
///////// ROM Header /////////
|
||
u16 crc = swiCRC16(0xFFFF, &header, 0x15E);
|
||
if (crc != header.headerCRC16) // 锟侥硷拷头 CRC 锟斤拷锟襟,诧拷锟斤拷nds锟斤拷戏
|
||
{
|
||
dbg_printf("%s rom header crc error\n", filename.c_str());
|
||
memcpy(&_banner, unknown_nds_banner_bin, sizeof(_banner));
|
||
fclose(f);
|
||
return true;
|
||
} else {
|
||
_isDSRom = ETrue;
|
||
if ((u32)(header.arm7destination) >= 0x037F8000 ||
|
||
0x23232323 == gamecode(header.gameCode)) { // 23->'#'
|
||
_isHomebrew = ETrue;
|
||
}
|
||
}
|
||
|
||
///////// saveInfo /////////
|
||
memcpy(_saveInfo.gameTitle, header.gameTitle, 12);
|
||
memcpy(_saveInfo.gameCode, header.gameCode, 4);
|
||
_saveInfo.gameCRC = header.headerCRC16;
|
||
saveManager().updateSaveInfoByInfo(_saveInfo);
|
||
_romVersion = header.romversion;
|
||
|
||
// dbg_printf( "save type %d\n", _saveInfo.saveType );
|
||
|
||
///////// banner /////////
|
||
if (header.bannerOffset != 0) {
|
||
fseek(f, header.bannerOffset, SEEK_SET);
|
||
tNDSBanner banner;
|
||
u32 readed = fread(&banner, 1, 0x840, f);
|
||
if (sizeof(tNDSBanner) != readed) {
|
||
memcpy(&_banner, nds_banner_bin, sizeof(_banner));
|
||
} else {
|
||
crc = swiCRC16(0xffff, banner.icon, 0x840 - 32);
|
||
|
||
if (crc != banner.crc) {
|
||
dbg_printf("banner crc error, %04x/%04x\n", banner.crc, crc);
|
||
memcpy(&_banner, nds_banner_bin, sizeof(_banner));
|
||
} else {
|
||
memcpy(&_banner, &banner, sizeof(_banner));
|
||
}
|
||
}
|
||
} else {
|
||
// dbg_printf( "%s has no banner\n", filename );
|
||
memcpy(&_banner, nds_banner_bin, sizeof(_banner));
|
||
}
|
||
|
||
fclose(f);
|
||
return true;
|
||
}
|
||
|
||
void DSRomInfo::drawDSRomIcon(u8 x, u8 y, GRAPHICS_ENGINE engine) {
|
||
if (_extIcon >= 0) {
|
||
fileIcons().Draw(_extIcon, x, y, engine);
|
||
return;
|
||
}
|
||
load();
|
||
bool skiptransparent = false;
|
||
switch (_saveInfo.getIcon()) {
|
||
case SAVE_INFO_EX_ICON_TRANSPARENT:
|
||
break;
|
||
case SAVE_INFO_EX_ICON_AS_IS:
|
||
skiptransparent = true;
|
||
break;
|
||
case SAVE_INFO_EX_ICON_FIRMWARE:
|
||
gdi().maskBlt(icon_bg_bin, x, y, 32, 32, engine);
|
||
break;
|
||
}
|
||
for (int tile = 0; tile < 16; ++tile) {
|
||
for (int pixel = 0; pixel < 32; ++pixel) {
|
||
u8 a_byte = _banner.icon[(tile << 5) + pixel];
|
||
|
||
// int px = (tile & 3) * 8 + (2 * pixel & 7);
|
||
// int py = (tile / 4) * 8 + (2 * pixel / 8);
|
||
int px = ((tile & 3) << 3) + ((pixel << 1) & 7);
|
||
int py = ((tile >> 2) << 3) + (pixel >> 2);
|
||
|
||
u8 idx1 = (a_byte & 0xf0) >> 4;
|
||
if (skiptransparent || 0 != idx1) {
|
||
gdi().setPenColor(_banner.palette[idx1], engine);
|
||
gdi().drawPixel(px + 1 + x, py + y, engine);
|
||
}
|
||
|
||
u8 idx2 = (a_byte & 0x0f);
|
||
if (skiptransparent || 0 != idx2) {
|
||
gdi().setPenColor(_banner.palette[idx2], engine);
|
||
gdi().drawPixel(px + x, py + y, engine);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void DSRomInfo::drawDSRomIconMem(void* mem) {
|
||
if (_extIcon >= 0) {
|
||
fileIcons().DrawMem(_extIcon, mem);
|
||
return;
|
||
}
|
||
load();
|
||
u16* pmem = (u16*)mem;
|
||
bool skiptransparent = false;
|
||
switch (_saveInfo.getIcon()) {
|
||
case SAVE_INFO_EX_ICON_TRANSPARENT:
|
||
break;
|
||
case SAVE_INFO_EX_ICON_AS_IS:
|
||
skiptransparent = true;
|
||
break;
|
||
case SAVE_INFO_EX_ICON_FIRMWARE:
|
||
cIcons::maskBlt((const u16*)icon_bg_bin, pmem);
|
||
break;
|
||
}
|
||
for (int tile = 0; tile < 16; ++tile) {
|
||
for (int pixel = 0; pixel < 32; ++pixel) {
|
||
u8 a_byte = _banner.icon[(tile << 5) + pixel];
|
||
|
||
// int px = (tile & 3) * 8 + (2 * pixel & 7);
|
||
// int py = (tile / 4) * 8 + (2 * pixel / 8);
|
||
int px = ((tile & 3) << 3) + ((pixel << 1) & 7);
|
||
int py = ((tile >> 2) << 3) + (pixel >> 2);
|
||
|
||
u8 idx1 = (a_byte & 0xf0) >> 4;
|
||
if (skiptransparent || 0 != idx1) {
|
||
pmem[py * 32 + px + 1] = _banner.palette[idx1] | BIT(15);
|
||
// gdi().setPenColor( _banner.palette[idx1] );
|
||
// gdi().drawPixel( px+1+x, py+y, engine );
|
||
}
|
||
|
||
u8 idx2 = (a_byte & 0x0f);
|
||
if (skiptransparent || 0 != idx2) {
|
||
pmem[py * 32 + px] = _banner.palette[idx2] | BIT(15);
|
||
// gdi().setPenColor( _banner.palette[idx2] );
|
||
// gdi().drawPixel( px+x, py+y, engine );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
bool DSRomInfo::loadGbaRomInfo(const std::string& filename) {
|
||
_isGbaRom = EFalse;
|
||
FILE* gbaFile = fopen(filename.c_str(), "rb");
|
||
if (gbaFile) {
|
||
sGBAHeader header;
|
||
fread(&header, 1, sizeof(header), gbaFile);
|
||
fclose(gbaFile);
|
||
if (header.is96h == 0x96) {
|
||
_isGbaRom = ETrue;
|
||
memcpy(_saveInfo.gameCode, header.gamecode, 4);
|
||
_romVersion = header.version;
|
||
memcpy(&_banner, gbarom_banner_bin, sizeof(tNDSBanner));
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
void DSRomInfo::load(void) {
|
||
if (_isDSRom == EMayBe) loadDSRomInfo(_fileName, true);
|
||
if (_isGbaRom == EMayBe) loadGbaRomInfo(_fileName);
|
||
if (_isDSiWare == EMayBe) loadDSRomInfo(_fileName, true);
|
||
}
|
||
|
||
tNDSBanner& DSRomInfo::banner(void) {
|
||
load();
|
||
return _banner;
|
||
}
|
||
|
||
SAVE_INFO_EX& DSRomInfo::saveInfo(void) {
|
||
load();
|
||
return _saveInfo;
|
||
}
|
||
|
||
u8 DSRomInfo::version(void) {
|
||
load();
|
||
return _romVersion;
|
||
}
|
||
|
||
bool DSRomInfo::isDSRom(void) {
|
||
load();
|
||
return (_isDSRom == ETrue) ? true : false;
|
||
}
|
||
|
||
bool DSRomInfo::isDSiWare(void) {
|
||
load();
|
||
return (_isDSiWare == ETrue) ? true : false;
|
||
}
|
||
|
||
bool DSRomInfo::isHomebrew(void) {
|
||
load();
|
||
return (_isHomebrew == ETrue) ? true : false;
|
||
}
|
||
|
||
bool DSRomInfo::isGbaRom(void) {
|
||
load();
|
||
return (_isGbaRom == ETrue) ? true : false;
|
||
}
|
||
|
||
void DSRomInfo::setExtIcon(const std::string& aValue) {
|
||
_extIcon = fileIcons().Icon(aValue);
|
||
};
|
||
|
||
void DSRomInfo::setBanner(const std::string& anExtIcon, const u8* aBanner) {
|
||
setExtIcon(anExtIcon);
|
||
memcpy(&banner(), aBanner, sizeof(tNDSBanner));
|
||
}
|