Added source

This commit is contained in:
edo9300 2019-02-13 20:18:36 +01:00
parent 21f96ca812
commit b5f65106ca
43 changed files with 2549 additions and 0 deletions

BIN
ForwardDuali_8frames.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 964 B

BIN
Icon.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

55
Makefile Normal file
View file

@ -0,0 +1,55 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
export TARGET := $(shell basename $(CURDIR))
export TOPDIR := $(CURDIR)
# specify a directory which contains the nitro filesystem
# this is relative to the Makefile
NITRO_FILES :=
# These set the information text in the nds file
GAME_TITLE := Forwarder Maker
GAME_SUBTITLE1 := Edo9300
#GAME_SUBTITLE2 := http://devitpro.org
include $(DEVKITARM)/ds_rules
.PHONY: checkarm7 checkarm9 clean
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
all: checkarm7 checkarm9 $(TARGET).nds
#---------------------------------------------------------------------------------
checkarm7:
$(MAKE) -C arm7
#---------------------------------------------------------------------------------
checkarm9:
$(MAKE) -C arm9
#---------------------------------------------------------------------------------
$(TARGET).nds : $(NITRO_FILES) arm7/$(TARGET).elf arm9/$(TARGET).elf
ndstool -u 00030004 -g EDO0 -c $(TARGET).nds -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf \
-b $(GAME_ICON) "$(GAME_TITLE);$(GAME_SUBTITLE1);$(GAME_SUBTITLE2)" \
$(_ADDFILES)
#---------------------------------------------------------------------------------
arm7/$(TARGET).elf:
$(MAKE) -C arm7
#---------------------------------------------------------------------------------
arm9/$(TARGET).elf:
$(MAKE) -C arm9
#---------------------------------------------------------------------------------
clean:
$(MAKE) -C arm9 clean
$(MAKE) -C arm7 clean
rm -f $(TARGET).nds $(TARGET).arm7 $(TARGET).arm9

126
arm7/Makefile Normal file
View file

@ -0,0 +1,126 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/ds_rules
#---------------------------------------------------------------------------------
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
# DATA is a list of directories containing binary files
# all directories are relative to this makefile
#---------------------------------------------------------------------------------
BUILD := build
SOURCES := source
INCLUDES := include build
DATA :=
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -mthumb-interwork
CFLAGS := -g -Wall -O2\
-mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\
-ffast-math \
$(ARCH)
CFLAGS += $(INCLUDE) -DARM7
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -fno-rtti
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=ds_arm7.specs -g $(ARCH) -Wl,--nmagic -Wl,-Map,$(notdir $*).map
LIBS := -ldswifi7 -lmm7 -lnds7
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBNDS)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export ARM7ELF := $(CURDIR)/$(TARGET).elf
export DEPSDIR := $(CURDIR)/$(BUILD)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) *.elf
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(ARM7ELF) : $(OFILES)
@echo linking $(notdir $@)
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

97
arm7/source/template.c Normal file
View file

@ -0,0 +1,97 @@
/*---------------------------------------------------------------------------------
default ARM7 core
Copyright (C) 2005 - 2010
Michael Noland (joat)
Jason Rogers (dovoto)
Dave Murphy (WinterMute)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
---------------------------------------------------------------------------------*/
#include <nds.h>
#include <dswifi7.h>
#include <maxmod7.h>
//---------------------------------------------------------------------------------
void VblankHandler(void) {
//---------------------------------------------------------------------------------
Wifi_Update();
}
//---------------------------------------------------------------------------------
void VcountHandler() {
//---------------------------------------------------------------------------------
inputGetAndSend();
}
volatile bool exitflag = false;
//---------------------------------------------------------------------------------
void powerButtonCB() {
//---------------------------------------------------------------------------------
exitflag = true;
}
//---------------------------------------------------------------------------------
int main() {
//---------------------------------------------------------------------------------
// clear sound registers
dmaFillWords(0, (void*)0x04000400, 0x100);
REG_SOUNDCNT |= SOUND_ENABLE;
writePowerManagement(PM_CONTROL_REG, ( readPowerManagement(PM_CONTROL_REG) & ~PM_SOUND_MUTE ) | PM_SOUND_AMP );
powerOn(POWER_SOUND);
readUserSettings();
ledBlink(0);
irqInit();
// Start the RTC tracking IRQ
initClockIRQ();
fifoInit();
mmInstall(FIFO_MAXMOD);
SetYtrigger(80);
installWifiFIFO();
installSoundFIFO();
installSystemFIFO();
irqSet(IRQ_VCOUNT, VcountHandler);
irqSet(IRQ_VBLANK, VblankHandler);
irqEnable( IRQ_VBLANK | IRQ_VCOUNT | IRQ_NETWORK);
setPowerButtonCB(powerButtonCB);
// Keep the ARM7 mostly idle
while (!exitflag) {
if ( 0 == (REG_KEYINPUT & (KEY_SELECT | KEY_START | KEY_L | KEY_R))) {
exitflag = true;
}
swiWaitForVBlank();
}
return 0;
}

127
arm9/Makefile Normal file
View file

@ -0,0 +1,127 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/ds_rules
#---------------------------------------------------------------------------------
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
# DATA is a list of directories containing binary files
# all directories are relative to this makefile
#---------------------------------------------------------------------------------
BUILD := build
SOURCES := source
INCLUDES := include
DATA :=
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -mthumb -mthumb-interwork
CFLAGS := -g -Wall -O2\
-march=armv5te -mtune=arm946e-s -fomit-frame-pointer\
-ffast-math \
$(ARCH)
CFLAGS += $(INCLUDE) -DARM9
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH) -march=armv5te -mtune=arm946e-s
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS := -lfat -lnds9
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBNDS)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export ARM9ELF := $(CURDIR)/$(TARGET).elf
export DEPSDIR := $(CURDIR)/$(BUILD)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) *.elf *.nds* *.bin
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(ARM9ELF) : $(OFILES)
@echo linking $(notdir $@)
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPSDIR)/*.d
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

241
arm9/source/apppatch.cpp Normal file
View file

@ -0,0 +1,241 @@
#include <fstream>
#include <vector>
#include <cstring>
#include <nds.h>
#include <cstdio>
#include "apppatch.h"
#include "headers.h"
class CRC16 {
std::vector<uint16_t>crc16_tab;
uint16_t crc16_constant = 0xA001;
bool mdflag;
public:
CRC16(bool modbus_flag = false) {
// initialize the precalculated tables
if(crc16_tab.empty()) {
init_crc16();
}
mdflag = modbus_flag;
}
uint16_t calculate(std::string input_data) {
uint16_t crc_value = mdflag ? 0xffff : 0x0000;
for(auto c : input_data) {
uint16_t tmp = crc_value ^ c;
uint16_t rotated = crc_value >> 8;
crc_value = rotated ^ crc16_tab[(tmp & 0x00ff)];
}
return crc_value;
}
void init_crc16() {
for(int i = 0; i < 256; i++) {
uint16_t crc = i;
for(int j = 0; j < 8; j++) {
if(crc & 0x0001)
crc = (crc >> 1) ^ crc16_constant;
else
crc = crc >> 1;
}
crc16_tab.push_back(crc);
}
}
};
int32_t GetBanerSize(uint16_t banner_type) {
switch(banner_type) {
case NDS_BANNER_VER_ZH: {
return NDS_BANNER_SIZE_ZH;
break;
}
case NDS_BANNER_VER_ZH_KO: {
return NDS_BANNER_SIZE_ZH_KO;
break;
}
case NDS_BANNER_VER_DSi: {
return NDS_BANNER_SIZE_DSi;
break;
}
default:
return NDS_BANNER_SIZE_ORIGINAL;
}
}
void ReplaceBanner(const std::string& target, const std::string& input, const std::string& output) {
std::string destination = target;
std::ifstream infile(input, std::ifstream::binary);
if(!output.empty()) {
std::ifstream src(target, std::ios::binary);
std::ofstream dst(output, std::ios::binary);
dst << src.rdbuf();
src.close();
dst.close();
destination = output;
}
SrlHeader isrlheader;
infile.read((char*)&isrlheader, sizeof(SrlHeader));
TwlHeader itwlheader = { 0 };
if(isrlheader.rom_header_size >= 0x300) {
infile.read((char*)&itwlheader, sizeof(SrlHeader));
}
infile.seekg(0, infile.beg);
infile.seekg(isrlheader.banner_offset, infile.beg);
int16_t ibanner_type = 0;
infile.read((char*)&ibanner_type, sizeof(int16_t));
infile.seekg(isrlheader.banner_offset, infile.beg);
sNDSBannerExt ibanner;
infile.read((char*)&ibanner, GetBanerSize(ibanner_type));
std::fstream trfile(destination, std::fstream::binary | std::fstream::out | std::fstream::in);
SrlHeader tsrlheader;
trfile.read((char*)&tsrlheader, sizeof(SrlHeader));
TwlHeader ttwlheader;
trfile.read((char*)&ttwlheader, sizeof(SrlHeader));
trfile.seekg(tsrlheader.banner_offset, trfile.beg);
int16_t tbanner_type = 0;
trfile.read((char*)&tbanner_type, sizeof(int16_t));
trfile.seekg(tsrlheader.banner_offset, trfile.beg);
{
int32_t diff = GetBanerSize(ibanner_type) - GetBanerSize(tbanner_type);
std::ofstream tmp("tmp.nds", std::ios::binary);
trfile.seekg(0, trfile.beg);
std::string tmpstr;
tmpstr.resize(tsrlheader.banner_offset);
trfile.read(&tmpstr[0], tsrlheader.banner_offset);
tmp.write(&tmpstr[0], tsrlheader.banner_offset);
tmp.write((char*)&ibanner, GetBanerSize(ibanner_type));
int32_t start = tsrlheader.banner_offset + GetBanerSize(tbanner_type);
trfile.seekg(0, trfile.end);
int32_t length = trfile.tellg();
trfile.seekg(0, trfile.beg);
trfile.seekg(start);
tmpstr.clear();
tmpstr.resize(length - start);
trfile.read(&tmpstr[0], length - start);
tmp.write(&tmpstr[0], length - start);
tmp.close();
trfile.close();
remove(destination.c_str());
rename("tmp.nds", destination.c_str());
trfile.open(destination, std::fstream::binary | std::fstream::out | std::fstream::in);
tsrlheader.application_end_offset += diff;
ttwlheader.dsi9_rom_offset += diff;
ttwlheader.dsi7_rom_offset += diff;
ttwlheader.total_rom_size += diff;
}
tsrlheader.gamecode[0] = isrlheader.gamecode[0];
tsrlheader.gamecode[1] = isrlheader.gamecode[1];
tsrlheader.gamecode[2] = isrlheader.gamecode[2];
tsrlheader.gamecode[3] = isrlheader.gamecode[3];
ttwlheader.tid_low = tsrlheader.gamecode[3] | (tsrlheader.gamecode[2] << 8) | (tsrlheader.gamecode[1] << 16) | (tsrlheader.gamecode[0] << 24);
trfile.seekg(0, trfile.beg);
trfile.write((char*)&tsrlheader, sizeof(tsrlheader));
trfile.write((char*)&ttwlheader, sizeof(ttwlheader));
trfile.close();
infile.close();
}
/*
Straight port of ahezard's python script to patch the header for dsiwares apps
*/
void Patch(const std::string& name, bool backup) {
if(backup) {
//make a backup of the nds
std::ifstream src(name, std::ios::binary);
std::ofstream dst((name + ".orig.nds"), std::ios::binary);
dst << src.rdbuf();
src.close();
dst.close();
}
std::fstream infile(name, std::fstream::binary | std::fstream::out | std::fstream::in);
infile.seekg(0, infile.beg);
SrlHeader header;
infile.read((char*)&header, sizeof(SrlHeader));
header.dsi_flags = 0x01;
header.nds_region = 0x00;
header.unitcode = 0x03;
CRC16 crc(true);
std::string aa;
aa.resize(0x15E);
memcpy(&aa[0], (char*)&header, 0x15E);
auto headercrc = crc.calculate(aa);
header.header_crc = headercrc;
TwlHeader header2;
infile.read((char*)&header2, sizeof(TwlHeader));
header2.access_control = 0x00000138;
header2.scfg_ext_mask = 0x80040000;
memset(header2.offset_0x1BC, 0, sizeof(header2.offset_0x1BC));
header2.appflags = 0;
SrlSignedHeader header3 = { 0 };
if(header.rom_header_size >= 0x1100) {
infile.read((char*)&header3, sizeof(SrlSignedHeader));
}
infile.seekg(0x4000, infile.beg);
memset(header3.hmac_arm7, 0xff, sizeof(header3.hmac_arm7));
memset(header3.hmac_arm7i, 0xff, sizeof(header3.hmac_arm7i));
memset(header3.hmac_arm9, 0xff, sizeof(header3.hmac_arm9));
memset(header3.hmac_arm9i, 0xff, sizeof(header3.hmac_arm9i));
memset(header3.hmac_arm9_no_secure, 0xff, sizeof(header3.hmac_arm9_no_secure));
memset(header3.hmac_icon_title, 0xff, sizeof(header3.hmac_icon_title));
memset(header3.hmac_digest_master, 0xff, sizeof(header3.hmac_digest_master));
memset(header3.rsa_signature, 0xff, sizeof(header3.rsa_signature));
auto arm9FooterAddr = header.arm9_rom_offset + header.arm9_size;
bool writefooter = false;
ARM9Footer footer;
infile.seekg(arm9FooterAddr, infile.beg);
infile.read((char*)&footer, sizeof(ARM9Footer));
if(footer.nitrocode != 0xDEC00621) {
footer.nitrocode = 0xDEC00621;
footer.versionInfo = 0xad8;
footer.reserved = 0;
writefooter = true;
}
infile.seekg(0, infile.beg);
infile.write((char*)&header, sizeof(SrlHeader));
infile.write((char*)&header2, sizeof(TwlHeader));
infile.write((char*)&header3, 0xC80);
std::string dummy;
dummy.resize(16 * 8);
std::fill_n(&dummy[0], 16 * 8, 0xff);
infile.write(&dummy[0], 16 * 8);
if(writefooter) {
infile.seekg(arm9FooterAddr, infile.beg);
infile.write((char*)&footer, sizeof(ARM9Footer));
}
infile.close();
}
int PathStringReplace(std::string path) {
std::fstream target("sd:/MakeForwarder/banner.nds", std::fstream::binary | std::fstream::out | std::fstream::in);
if(!target.is_open())
return 255;
std::string str((std::istreambuf_iterator<char>(target)),
std::istreambuf_iterator<char>());
std::size_t found = str.find("sd:/kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk");
if(found == std::string::npos)
return 5;
target.seekg(found + 4, target.beg);
target.write(&path[0], path.size());
target.put('\0');
return 0;
}

11
arm9/source/apppatch.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef APPPATCH_H
#define APPPATCH_H
#include <string>
void ReplaceBanner(const std::string& target, const std::string& input, const std::string& output);
void Patch(const std::string& name, bool backup);
void MakeTmd(const std::string& target, const std::string& destination = "");
int PathStringReplace(std::string path);
#endif //APPPATCH_H

223
arm9/source/file_browse.cpp Normal file
View file

@ -0,0 +1,223 @@
/*-----------------------------------------------------------------
Copyright (C) 2005 - 2017
Michael "Chishm" Chisholm
Dave "WinterMute" Murphy
Claudio "sverx"
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
------------------------------------------------------------------*/
#include "file_browse.h"
#include <vector>
#include <algorithm>
#include <unistd.h>
#include <string>
#include <cstdio>
#include <dirent.h>
#include <unistd.h>
#include <nds.h>
#define SCREEN_COLS 32
#define ENTRIES_PER_SCREEN 22
#define ENTRIES_START_ROW 2
#define ENTRY_PAGE_LENGTH 10
using namespace std;
struct DirEntry {
string name;
bool isDirectory;
} ;
bool nameEndsWith (const string& name, const vector<string> extensionList) {
if (name.size() == 0) return false;
if (extensionList.size() == 0) return true;
for (int i = 0; i < (int)extensionList.size(); i++) {
const string ext = extensionList.at(i);
if ( strcasecmp (name.c_str() + name.size() - ext.size(), ext.c_str()) == 0) return true;
}
return false;
}
bool dirEntryPredicate (const DirEntry& lhs, const DirEntry& rhs) {
if (!lhs.isDirectory && rhs.isDirectory) {
return false;
}
if (lhs.isDirectory && !rhs.isDirectory) {
return true;
}
return strcasecmp(lhs.name.c_str(), rhs.name.c_str()) < 0;
}
void getDirectoryContents (vector<DirEntry>& dirContents, const vector<string> extensionList) {
struct stat st;
dirContents.clear();
DIR *pdir = opendir (".");
if (pdir == NULL) {
iprintf ("Unable to open the directory.\n");
} else {
while(true) {
DirEntry dirEntry;
struct dirent* pent = readdir(pdir);
if(pent == NULL) break;
stat(pent->d_name, &st);
dirEntry.name = pent->d_name;
dirEntry.isDirectory = (st.st_mode & S_IFDIR) ? true : false;
if (dirEntry.name.compare(".") != 0 && (dirEntry.isDirectory || nameEndsWith(dirEntry.name, extensionList))) {
dirContents.push_back (dirEntry);
}
}
closedir(pdir);
}
sort(dirContents.begin(), dirContents.end(), dirEntryPredicate);
}
void getDirectoryContents (vector<DirEntry>& dirContents) {
vector<string> extensionList;
getDirectoryContents (dirContents, extensionList);
}
void showDirectoryContents (const vector<DirEntry>& dirContents, int startRow) {
char path[PATH_MAX];
getcwd(path, PATH_MAX);
// Clear the screen
iprintf ("\x1b[2J");
// Print the path
if (strlen(path) < SCREEN_COLS) {
iprintf ("%s", path);
} else {
iprintf ("%s", path + strlen(path) - SCREEN_COLS);
}
// Move to 2nd row
iprintf ("\x1b[1;0H");
// Print line of dashes
iprintf ("--------------------------------");
// Print directory listing
for (int i = 0; i < ((int)dirContents.size() - startRow) && i < ENTRIES_PER_SCREEN; i++) {
const DirEntry* entry = &dirContents.at(i + startRow);
char entryName[SCREEN_COLS + 1];
// Set row
iprintf ("\x1b[%d;0H", i + ENTRIES_START_ROW);
if (entry->isDirectory) {
strncpy (entryName, entry->name.c_str(), SCREEN_COLS);
entryName[SCREEN_COLS - 3] = '\0';
iprintf (" [%s]", entryName);
} else {
strncpy (entryName, entry->name.c_str(), SCREEN_COLS);
entryName[SCREEN_COLS - 1] = '\0';
iprintf (" %s", entryName);
}
}
}
string browseForFile (const vector<string>& extensionList) {
int pressed = 0;
int screenOffset = 0;
int fileOffset = 0;
vector<DirEntry> dirContents;
getDirectoryContents (dirContents, extensionList);
showDirectoryContents (dirContents, screenOffset);
while (true) {
// Clear old cursors
for (int i = ENTRIES_START_ROW; i < ENTRIES_PER_SCREEN + ENTRIES_START_ROW; i++) {
iprintf ("\x1b[%d;0H ", i);
}
// Show cursor
iprintf ("\x1b[%d;0H*", fileOffset - screenOffset + ENTRIES_START_ROW);
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
do {
scanKeys();
pressed = keysDownRepeat();
swiWaitForVBlank();
} while (!pressed);
if (pressed & KEY_UP) fileOffset -= 1;
if (pressed & KEY_DOWN) fileOffset += 1;
if (pressed & KEY_LEFT) fileOffset -= ENTRY_PAGE_LENGTH;
if (pressed & KEY_RIGHT) fileOffset += ENTRY_PAGE_LENGTH;
if (fileOffset < 0) fileOffset = dirContents.size() - 1; // Wrap around to bottom of list
if (fileOffset > ((int)dirContents.size() - 1)) fileOffset = 0; // Wrap around to top of list
// Scroll screen if needed
if (fileOffset < screenOffset) {
screenOffset = fileOffset;
showDirectoryContents (dirContents, screenOffset);
}
if (fileOffset > screenOffset + ENTRIES_PER_SCREEN - 1) {
screenOffset = fileOffset - ENTRIES_PER_SCREEN + 1;
showDirectoryContents (dirContents, screenOffset);
}
if (pressed & KEY_A) {
DirEntry* entry = &dirContents.at(fileOffset);
if (entry->isDirectory) {
iprintf("Entering directory\n");
// Enter selected directory
chdir (entry->name.c_str());
getDirectoryContents (dirContents, extensionList);
screenOffset = 0;
fileOffset = 0;
showDirectoryContents (dirContents, screenOffset);
} else {
// Clear the screen
iprintf ("\x1b[2J");
// Return the chosen file
char cwd[PATH_MAX];
getcwd(cwd, PATH_MAX);
std::string full_path;
full_path.resize(sizeof(cwd)+entry->name.size()+10);
sprintf(&full_path[0], "%s%s", cwd, entry->name.c_str());
return full_path;
}
}
if (pressed & KEY_B) {
// Go up a directory
chdir ("..");
getDirectoryContents (dirContents, extensionList);
screenOffset = 0;
fileOffset = 0;
showDirectoryContents (dirContents, screenOffset);
}
}
}

32
arm9/source/file_browse.h Normal file
View file

@ -0,0 +1,32 @@
/*-----------------------------------------------------------------
Copyright (C) 2005 - 2017
Michael "Chishm" Chisholm
Dave "WinterMute" Murphy
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
------------------------------------------------------------------*/
#ifndef FILE_BROWSE_H
#define FILE_BROWSE_H
#include <string>
#include <vector>
std::string browseForFile (const std::vector<std::string>& extensionList);
#endif //FILE_BROWSE_H

175
arm9/source/headers.h Normal file
View file

@ -0,0 +1,175 @@
#ifndef HEADERS
#define HEADERS
struct SrlHeader {
int8_t title[0xC];
int8_t gamecode[0x4];
int8_t makercode[2];
uint8_t unitcode; // product code. 0=NDS, 2=NDS+DSi, 3=DSi
uint8_t devicetype; // device code. 0 = normal
uint8_t devicecap; // device size. (1<<n Mbit)
uint8_t reserved1[0x7]; // 0x015..0x01D
uint8_t dsi_flags;
uint8_t nds_region;
uint8_t romversion;
uint8_t reserved2; // 0x01F
uint32_t arm9_rom_offset; // points to libsyscall and rest of ARM9 binary
uint32_t arm9_entry_address;
uint32_t arm9_ram_address;
uint32_t arm9_size;
uint32_t arm7_rom_offset;
uint32_t arm7_entry_address;
uint32_t arm7_ram_address;
uint32_t arm7_size;
uint32_t fnt_offset;
uint32_t fnt_size;
uint32_t fat_offset;
uint32_t fat_size;
uint32_t arm9_overlay_offset;
uint32_t arm9_overlay_size;
uint32_t arm7_overlay_offset;
uint32_t arm7_overlay_size;
uint32_t rom_control_info1; // 0x00416657 for OneTimePROM
uint32_t rom_control_info2; // 0x081808F8 for OneTimePROM
uint32_t banner_offset;
uint16_t secure_area_crc;
uint16_t rom_control_info3; // 0x0D7E for OneTimePROM
uint32_t offset_0x70; // magic1 (64 bit encrypted magic code to disable LFSR)
uint32_t offset_0x74; // magic2
uint32_t offset_0x78; // unique ID for homebrew
uint32_t offset_0x7C; // unique ID for homebrew
uint32_t application_end_offset; // rom size
uint32_t rom_header_size;
uint32_t offset_0x88; // reserved... ?
uint32_t offset_0x8C;
// reserved
uint32_t offset_0x90;
uint32_t offset_0x94;
uint32_t offset_0x98;
uint32_t offset_0x9C;
uint32_t offset_0xA0;
uint32_t offset_0xA4;
uint32_t offset_0xA8;
uint32_t offset_0xAC;
uint32_t offset_0xB0;
uint32_t offset_0xB4;
uint32_t offset_0xB8;
uint32_t offset_0xBC;
uint8_t logo[156]; // character data
uint16_t logo_crc;
uint16_t header_crc;
// 0x160..0x17F reserved
uint32_t debug_rom_offset;
uint32_t debug_size;
uint32_t debug_ram_address;
uint32_t offset_0x16C;
uint8_t zero[0x10];
};
struct TwlHeader {
// DSi extended stuff below
uint8_t global_mbk_setting[5][4];
uint32_t arm9_mbk_setting[3];
uint32_t arm7_mbk_setting[3];
uint32_t mbk9_wramcnt_setting;
uint32_t region_flags;
uint32_t access_control;
uint32_t scfg_ext_mask;
uint8_t offset_0x1BC[3];
uint8_t appflags;
uint32_t dsi9_rom_offset;
uint32_t offset_0x1C4;
uint32_t dsi9_ram_address;
uint32_t dsi9_size;
uint32_t dsi7_rom_offset;
uint32_t offset_0x1D4;
uint32_t dsi7_ram_address;
uint32_t dsi7_size;
uint32_t digest_ntr_start;
uint32_t digest_ntr_size;
uint32_t digest_twl_start;
uint32_t digest_twl_size;
uint32_t sector_hashtable_start;
uint32_t sector_hashtable_size;
uint32_t block_hashtable_start;
uint32_t block_hashtable_size;
uint32_t digest_sector_size;
uint32_t digest_block_sectorcount;
uint32_t banner_size;
uint32_t offset_0x20C;
uint32_t total_rom_size;
uint32_t offset_0x214;
uint32_t offset_0x218;
uint32_t offset_0x21C;
uint32_t modcrypt1_start;
uint32_t modcrypt1_size;
uint32_t modcrypt2_start;
uint32_t modcrypt2_size;
uint32_t tid_low;
uint32_t tid_high;
uint32_t public_sav_size;
uint32_t private_sav_size;
uint8_t reserved3[176];
uint8_t age_ratings[0x10];
};
struct SrlSignedHeader {
uint8_t hmac_arm9[20];
uint8_t hmac_arm7[20];
uint8_t hmac_digest_master[20];
uint8_t hmac_icon_title[20];
uint8_t hmac_arm9i[20];
uint8_t hmac_arm7i[20];
uint8_t reserved4[40];
uint8_t hmac_arm9_no_secure[20];
uint8_t reserved5[2636];
uint8_t debug_args[0x180];
uint8_t rsa_signature[0x80];
};
struct ARM9Footer {
uint32_t nitrocode;
uint32_t versionInfo;
uint32_t reserved;
};
struct sNDSBannerExt {
uint16_t version; //!< version of the banner.
uint16_t crc[4]; //!< CRC-16s of the banner.
uint8_t reserved[22];
uint8_t icon[512]; //!< 32*32 icon of the game with 4 bit per pixel.
uint16_t palette[16]; //!< the palette of the icon.
uint16_t titles[8][128]; //!< title of the game in 8 different languages.
// [0xA40] Reserved space, possibly for other titles.
uint8_t reserved2[0x800];
// DSi-specific.
uint8_t dsi_icon[8][512]; //!< DSi animated icon frame data.
uint16_t dsi_palette[8][16]; //!< Palette for each DSi icon frame.
uint16_t dsi_seq[64]; //!< DSi animated icon sequence.
};
// sNDSBanner version.
enum sNDSBannerVersion {
NDS_BANNER_VER_ORIGINAL = 0x0001,
NDS_BANNER_VER_ZH = 0x0002,
NDS_BANNER_VER_ZH_KO = 0x0003,
NDS_BANNER_VER_DSi = 0x0103,
};
// sNDSBanner sizes.
enum sNDSBannerSize {
NDS_BANNER_SIZE_ORIGINAL = 0x0840,
NDS_BANNER_SIZE_ZH = 0x0940,
NDS_BANNER_SIZE_ZH_KO = 0x0A40,
NDS_BANNER_SIZE_DSi = 0x23C0,
};
#endif

399
arm9/source/inifile.cpp Normal file
View file

@ -0,0 +1,399 @@
/*
inifile.cpp
Copyright (C) 2007 Acekard, www.acekard.com
Copyright (C) 2007-2009 somebody
Copyright (C) 2009 yellow wood goblin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cstdio>
#include <cstdlib>
#include "inifile.h"
//#include "stringtool.h"
static bool freadLine(FILE* f,std::string& str)
{
str.clear();
__read:
char p=0;
size_t readed=fread(&p,1,1,f);
if(0==readed)
{
str="";
return false;
}
if('\n'==p||'\r'==p)
{
str="";
return true;
}
while(p!='\n'&&p!='\r'&&readed)
{
str+=p;
readed=fread(&p,1,1,f);
}
if(str.empty()||""==str)
{
goto __read;
}
return true;
}
static void trimString(std::string& str)
{
size_t first=str.find_first_not_of(" \t"),last;
if(first==str.npos)
{
str="";
}
else
{
last=str.find_last_not_of(" \t");
if(first>0||(last+1)<str.length()) str=str.substr(first,last-first+1);
}
}
CIniFile::CIniFile()
{
m_bLastResult=false;
m_bModified=false;
m_bReadOnly=false;
}
CIniFile::CIniFile(const std::string& filename)
{
m_sFileName=filename;
m_bLastResult=false;
m_bModified=false;
m_bReadOnly=false;
m_bHasHandle=false;
LoadIniFile(m_sFileName);
}
CIniFile::~CIniFile()
{
if(m_FileContainer.size()>0)
{
m_FileContainer.clear();
}
}
void CIniFile::SetString(const std::string& Section,const std::string& Item,const std::string& Value)
{
if(GetFileString(Section,Item)!=Value)
{
SetFileString(Section,Item,Value);
m_bModified=true;
}
}
/*void CIniFile::SetInt(const std::string& Section,const std::string& Item,int Value)
{
std::string strtemp=formatString("%d",Value);
if(GetFileString(Section,Item)!=strtemp)
{
SetFileString(Section,Item,strtemp);
m_bModified=true;
}
}*/
std::string CIniFile::GetString(const std::string& Section,const std::string& Item)
{
return GetFileString(Section,Item);
}
std::string CIniFile::GetString(const std::string& Section,const std::string& Item,const std::string& DefaultValue)
{
std::string temp=GetString(Section,Item);
if(!m_bLastResult)
{
SetString(Section,Item,DefaultValue);
temp=DefaultValue;
}
return temp;
}
void CIniFile::GetStringVector(const std::string& Section,const std::string& Item,std::vector< std::string >& strings,char delimiter)
{
std::string strValue=GetFileString(Section,Item);
strings.clear();
size_t pos;
while((pos=strValue.find(delimiter),strValue.npos!=pos))
{
const std::string string=strValue.substr(0,pos);
if(string.length())
{
strings.push_back(string);
}
strValue=strValue.substr(pos+1,strValue.npos);
}
if(strValue.length())
{
strings.push_back(strValue);
}
}
void CIniFile::SetStringVector(const std::string& Section,const std::string& Item,std::vector<std::string>& strings,char delimiter)
{
std::string strValue;
for(size_t ii=0;ii<strings.size();++ii)
{
if(ii) strValue+=delimiter;
strValue+=strings[ii];
}
SetString(Section,Item,strValue);
}
/*int CIniFile::GetInt(const std::string& Section,const std::string& Item)
{
std::string value=GetFileString(Section,Item);
if(value.size()>2&&'0'==value[0]&&('x'==value[1]||'X'==value[1]))
return strtol(value.c_str(),NULL,16);
else
return strtol(value.c_str(),NULL,10);
}
int CIniFile::GetInt(const std::string& Section,const std::string& Item,int DefaultValue)
{
int temp;
temp=GetInt(Section,Item);
if(!m_bLastResult)
{
SetInt(Section,Item,DefaultValue);
temp=DefaultValue;
}
return temp;
}*/
bool CIniFile::LoadIniFile(const std::string& FileName)
{
//dbg_printf("load %s\n",FileName.c_str());
if(FileName!="") m_sFileName=FileName;
FILE* f=fopen(FileName.c_str(),"rb");
if(NULL==f) return false;
m_bHasHandle = true;
//check for utf8 bom.
char bom[3];
if(fread(bom,3,1,f)==1&&bom[0]==0xef&&bom[1]==0xbb&&bom[2]==0xbf) ;
else fseek(f,0,SEEK_SET);
std::string strline("");
m_FileContainer.clear();
while(freadLine(f,strline))
{
trimString(strline);
if(strline!=""&&';'!=strline[0]&&'/'!=strline[0]&&'!'!=strline[0]) m_FileContainer.push_back(strline);
}
fclose(f);
m_bLastResult=false;
m_bModified=false;
return true;
}
bool CIniFile::SaveIniFileModified(const std::string& FileName)
{
if(m_bModified==true)
{
return SaveIniFile(FileName);
}
return true;
}
bool CIniFile::HasFileHandle()
{
return m_bHasHandle;
}
bool CIniFile::SaveIniFile(const std::string& FileName)
{
if(FileName!="")
m_sFileName=FileName;
FILE* f=fopen(m_sFileName.c_str(),"wb");
if(NULL==f)
{
return false;
}
for(size_t ii=0;ii<m_FileContainer.size();ii++)
{
std::string& strline=m_FileContainer[ii];
size_t notSpace=strline.find_first_not_of(' ');
strline=strline.substr(notSpace);
if(strline.find('[')==0&&ii>0)
{
if(!m_FileContainer[ii-1].empty()&&m_FileContainer[ii-1]!="")
fwrite("\r\n",1,2,f);
}
if(!strline.empty()&&strline!="")
{
fwrite(strline.c_str(),1,strline.length(),f);
fwrite("\r\n",1,2,f);
}
}
fclose(f);
m_bModified=false;
return true;
}
std::string CIniFile::GetFileString(const std::string& Section,const std::string& Item)
{
std::string strline;
std::string strSection;
std::string strItem;
std::string strValue;
size_t ii=0;
size_t iFileLines=m_FileContainer.size();
if(m_bReadOnly)
{
cSectionCache::iterator it=m_Cache.find(Section);
if((it!=m_Cache.end())) ii=it->second;
}
m_bLastResult=false;
if(iFileLines>=0)
{
while(ii<iFileLines)
{
strline=m_FileContainer[ii++];
size_t rBracketPos=0;
if('['==strline[0]) rBracketPos=strline.find(']');
if(rBracketPos>0&&rBracketPos!=std::string::npos)
{
strSection=strline.substr(1,rBracketPos-1);
if(m_bReadOnly) m_Cache.insert(std::make_pair(strSection,ii-1));
if(strSection==Section)
{
while(ii<iFileLines)
{
strline=m_FileContainer[ii++];
size_t equalsignPos=strline.find('=');
if(equalsignPos!=strline.npos)
{
size_t last=equalsignPos?strline.find_last_not_of(" \t",equalsignPos-1):strline.npos;
if(last==strline.npos) strItem="";
else strItem=strline.substr(0,last+1);
if(strItem==Item)
{
size_t first=strline.find_first_not_of(" \t",equalsignPos+1);
if(first==strline.npos) strValue="";
else strValue=strline.substr(first);
m_bLastResult=true;
return strValue;
}
}
else if('['==strline[0])
{
break;
}
}
break;
}
}
}
}
return std::string("");
}
void CIniFile::SetFileString(const std::string& Section,const std::string& Item,const std::string& Value)
{
std::string strline;
std::string strSection;
std::string strItem;
if(m_bReadOnly) return;
size_t ii=0;
size_t iFileLines=m_FileContainer.size();
while(ii<iFileLines)
{
strline=m_FileContainer[ii++];
size_t rBracketPos=0;
if('['==strline[0]) rBracketPos=strline.find(']');
if(rBracketPos>0&&rBracketPos!=std::string::npos)
{
strSection=strline.substr(1,rBracketPos-1);
if(strSection==Section)
{
while(ii<iFileLines)
{
strline=m_FileContainer[ii++];
size_t equalsignPos=strline.find('=');
if(equalsignPos!=strline.npos)
{
size_t last=equalsignPos?strline.find_last_not_of(" \t",equalsignPos-1):strline.npos;
if(last==strline.npos) strItem="";
else strItem=strline.substr(0,last+1);
if(Item==strItem)
{
ReplaceLine(ii-1,Item+" = "+Value);
return;
}
}
else if('['==strline[0])
{
InsertLine(ii-1,Item+" = "+Value);
return;
}
}
InsertLine(ii,Item+" = "+Value);
return;
}
}
}
InsertLine(ii,"["+Section+"]");
InsertLine(ii+1,Item+" = "+Value);
return;
}
bool CIniFile::InsertLine(size_t line,const std::string& str)
{
m_FileContainer.insert(m_FileContainer.begin()+line,str);
return true;
}
bool CIniFile::ReplaceLine(size_t line,const std::string& str)
{
m_FileContainer[line]=str;
return true;
}

69
arm9/source/inifile.h Normal file
View file

@ -0,0 +1,69 @@
/*
inifile.h
Copyright (C) 2007 Acekard, www.acekard.com
Copyright (C) 2007-2009 somebody
Copyright (C) 2009-2010 yellow wood goblin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _INIFILE_H_
#define _INIFILE_H_
#include <string>
#include <vector>
#include <map>
class CIniFile
{
public:
CIniFile();
CIniFile(const std::string& filename);
virtual ~CIniFile();
public:
bool LoadIniFile(const std::string& FileName);
bool SaveIniFile(const std::string& FileName);
bool SaveIniFileModified(const std::string& FileName);
bool HasFileHandle();
std::string GetString(const std::string& Section,const std::string& Item,const std::string& DefaultValue);
void SetString(const std::string& Section,const std::string& Item,const std::string& Value);
int GetInt(const std::string& Section,const std::string& Item,int DefaultValue);
void SetInt(const std::string& Section,const std::string& Item,int Value);
void GetStringVector(const std::string& Section,const std::string& Item,std::vector<std::string>& strings,char delimiter=',');
void SetStringVector(const std::string& Section,const std::string& Item,std::vector<std::string>& strings,char delimiter=',');
protected:
std::string m_sFileName;
typedef std::vector<std::string> cStringArray;
cStringArray m_FileContainer;
bool m_bLastResult;
bool m_bModified;
bool m_bReadOnly;
bool m_bHasHandle;
typedef std::map<std::string,size_t> cSectionCache;
cSectionCache m_Cache;
bool InsertLine(size_t line,const std::string& str);
bool ReplaceLine(size_t line,const std::string& str);
void SetFileString(const std::string& Section,const std::string& Item,const std::string& Value);
std::string GetFileString(const std::string& Section,const std::string& Item);
std::string GetString(const std::string& Section,const std::string& Item);
int GetInt(const std::string& Section,const std::string& Item);
};
#endif // _INIFILE_H_

272
arm9/source/main.cpp Normal file
View file

@ -0,0 +1,272 @@
/*---------------------------------------------------------------------------------
Basic template code for starting a DS app
---------------------------------------------------------------------------------*/
#include <nds.h>
#include <cstdio>
#include <fstream>
#include <vector>
#include <unistd.h>
#include <fat.h>
#include "file_browse.h"
#include "headers.h"
#include "utils.h"
#include "menu.h"
#include "inifile.h"
#include "apppatch.h"
CIniFile bootsrtapconfig;
CIniFile bootstrap_template;
PrintConsole upperScreen;
PrintConsole lowerScreen;
void WriteMessage(std::string text, bool clear = false, PrintConsole* screen = nullptr) {
if(screen)
consoleSelect(screen);
if(clear)
consoleClear();
if(text.size() <= DISPLAY_COLUMNS) {
iprintf(text.c_str());
return;
}
std::vector<std::string> words;
std::string temp;
for(int i = 0; i < (int)text.size(); i++) {
if(text[i] == ' ' || text[i] == '\n') {
words.push_back(temp);
temp.clear();
if(text[i] == '\n')
words.push_back("\n");
} else
temp += text[i];
}
if(temp.size())
words.push_back(temp);
int column = 0;
for(auto word : words) {
if(word.size() == 1 && word[0] == '\n') {
if(column != DISPLAY_COLUMNS)
iprintf("\n");
column = 0;
return;
}
int chkval = column + (int)word.size();
if(column)
chkval++;
if(chkval <= DISPLAY_COLUMNS) {
if(column) {
iprintf(" ");
column++;
}
iprintf(word.c_str());
column += (int)word.size();
} else {
if(column != DISPLAY_COLUMNS)
iprintf("\n");
column = (int)word.size();
iprintf(word.c_str());
}
}
}
menu yesno;
void displayInit() {
lowerScreen = *consoleDemoInit();
videoSetMode(MODE_0_2D);
vramSetBankA(VRAM_A_MAIN_BG);
consoleInit(&upperScreen, 3, BgType_Text4bpp, BgSize_T_256x256, 31, 0, true, true);
}
bool fileExists(const std::string& file) {
struct stat buf;
return (stat(file.c_str(), &buf) == 0);
}
std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) {
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
}
return str;
}
void stop (void) {
//---------------------------------------------------------------------------------
while (1) {
swiWaitForVBlank();
}
}
void wait (void) {
//---------------------------------------------------------------------------------
while (1) {
swiWaitForVBlank();
scanKeys();
int pressed = keysDown();
if(pressed & KEY_A) break;
}
}
const char* GetErrorString(int code) {
switch(code){
case 1:
return "fatInitDefault failed!";
case 2:
return "The MakeForwarder folder is missing!";
case 3:
return "Template.nds is missing from the MakeForwarder folder!";
case 4:
return "Error when reading the template.nds file, make sure to have the correct one!";
case 5:
return "Couldn't open the target rom, or the rom is not a valid target!";
default:
return "";
}
}
void PrintError(int errorcode, bool halt = false) {
consoleSetWindow(&upperScreen, 0, 3, DISPLAY_COLUMNS, 23);
consoleSelect(&upperScreen);
WriteMessage(GetErrorString(errorcode), true);
if (halt)
stop();
else {
WriteMessage("Press A to continue", false);
wait();
consoleClear();
}
}
std::string GetHexid(std::string file, int* chk) {
std::ifstream infile(file, std::ifstream::binary);
infile.seekg(0xc);
if(infile.tellg()!=0xc) {
*chk = 1;
return "";
}
std::string gameid;
gameid.resize(4);
infile.read(&gameid[0], 4);
infile.close();
return string_to_hex(gameid);
}
void CreateForwarder() {
std::vector<std::string> extensionList={".nds"};
WriteMessage("Select the target rom", true, &upperScreen);
consoleSelect(&lowerScreen);
std::string file = browseForFile(extensionList);
chdir("sd:/");
int chk = 0;
std::string gameidhex = GetHexid(file, &chk);
if (chk){
PrintError(5);
return;
}
std::string folderpath("sd:/title/00030004/" + gameidhex);
if(fileExists(folderpath + "/content/00000000.app")) {
WriteMessage("A DsiWare with the same id already exists, do you want to overwrite it?", true, &upperScreen);
int ret = yesno.DoMenu(&lowerScreen);
consoleSelect(&upperScreen);
consoleClear();
if(ret)
return;
}
WriteMessage("Creating forwarder", true, &lowerScreen);
ReplaceBanner("sd:/MakeForwarder/template.nds", file, "sd:/MakeForwarder/banner.nds");
Patch("sd:/MakeForwarder/banner.nds", false);
MakeTmd("sd:/MakeForwarder/banner.nds", "sd:/MakeForwarder/title.tmd");
chk = PathStringReplace("title/00030004/" + gameidhex + "/data/");
if(chk) {
PrintError(chk);
remove("sd:/MakeForwarder/banner.nds");
remove("sd:/MakeForwarder/title.tmd");
return;
}
if(CreatePath("title/00030004/" + gameidhex + "/data", "sd:/") && CreatePath("title/00030004/" + gameidhex + "/content", "sd:/")) {
Movefile("sd:/MakeForwarder/banner.nds", folderpath + "/content/00000000.app");
Movefile("sd:/MakeForwarder/title.tmd", folderpath + "/content/title.tmd");
if(bootstrap_template.HasFileHandle()) {
bootsrtapconfig.SaveIniFile((folderpath + "/data/config.ini").c_str());
bootstrap_template.SetString( "NDS-BOOTSTRAP", "NDS_PATH", file.c_str());
std::string savePath = ReplaceAll(file, ".nds", ".sav");
bootstrap_template.SetString( "NDS-BOOTSTRAP", "SAV_PATH", savePath.c_str());
bootstrap_template.SaveIniFile((folderpath + "/data/bootstrap.ini").c_str());
}
}
}
void SetBootstrap() {
std::vector<std::string> extensionList={".nds"};
WriteMessage("Select the target bootstrap file to be used", true, &upperScreen);
consoleSelect(&lowerScreen);
std::string file = browseForFile(extensionList);
chdir("sd:/");
size_t found = file.find_last_of("/");
std::string bootstrappath=file.substr(0,found+1);
std::string bootstrapversion=file.substr(found+1);
bootsrtapconfig.SetString( "NDS-FORWARDER", "BOOTSTRAP_PATH", bootstrappath.c_str());
bootsrtapconfig.SetString( "NDS-FORWARDER", "BOOTSTRAP_VERSION", bootstrapversion.c_str());
bootstrap_template.LoadIniFile((bootstrappath+"nds-bootstrap.ini").c_str());
}
void CheckResources() {
if (!fileExists("sd:/MakeForwarder"))
PrintError(2, true);
if (!fileExists("sd:/MakeForwarder/template.nds"))
PrintError(3, true);
std::ifstream ndstemplate("sd:/MakeForwarder/template.nds", std::ifstream::binary);
std::string str((std::istreambuf_iterator<char>(ndstemplate)),
std::istreambuf_iterator<char>());
std::size_t found = str.find("sd:/kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk");
if(found == std::string::npos)
PrintError(4, true);
}
int main() {
displayInit();
consoleSetWindow(&upperScreen, 0, 0, DISPLAY_COLUMNS, 3);
WriteMessage("Forwarder maker by edo9300 v1.0", true, &upperScreen);
consoleSetWindow(&upperScreen, 0, 3, DISPLAY_COLUMNS, 23);
if (!fatInitDefault())
PrintError(1, true);
CheckResources();
menu mainmenu;
mainmenu.AddOption("Create Forwarder");
mainmenu.AddOption("Set target bootstrap");
yesno.AddOption("Yes");
yesno.AddOption("No");
while(1){
swiWaitForVBlank();
WriteMessage("Use the option \"Set target bootstrap\" to avoid configuring the created forwarders at startup", true, &upperScreen);
int ret = mainmenu.DoMenu(&lowerScreen);
if (ret==0)
CreateForwarder();
else if (ret==1)
SetBootstrap();
else
break;
}
stop();
return 0;
}

120
arm9/source/maketmd.cpp Normal file
View file

@ -0,0 +1,120 @@
/*---------------------------------------------------------------------------------
maketmd.cpp -- TMD Creator for DSiWare Homebrew
Copyright (C) 2018
Przemyslaw Skryjomski (Tuxality)
Big thanks to:
Apache Thunder
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
---------------------------------------------------------------------------------*/
#include <fstream>
#include <cstring>
#include <nds/sha1.h>
#define TMD_SIZE 0x208
#define SHA_BUFFER_SIZE 0x200
#define SHA1_DIGEST_SIZE 0x14
void MakeTmd(const std::string& target, const std::string& destination) {
uint8_t tmd[TMD_SIZE] = { 0 };
std::fstream app(target, std::ios::in | std::ios::binary);
{
app.seekg(0x234, app.beg);
uint32_t value;
app.read((char*)&value, 4);
value = __bswap32(value);
memcpy(tmd + 0x18C, &value, 4);
}
// Phase 2 - offset 0x190 (Title ID, second part)
{
// We can take this also from 0x230, but reversed
app.seekg(0x0C, app.beg);
app.read((char*)&tmd[0x190], 4);
}
// Phase 3 - offset 0x198 (Group ID = '01')
{
app.seekg(0x10, app.beg);
app.read((char*)&tmd[0x198], 2);
}
// Phase 4 - offset 0x1AA (fill-in 0x80 value, 0x10 times)
{
for(size_t i = 0; i<0x10; i++) {
tmd[0x1AA + i] = 0x80;
}
}
// Phase 5 - offset 0x1DE (number of contents = 1)
{
tmd[0x1DE] = 0x00;
tmd[0x1DF] = 0x01;
}
// Phase 6 - offset 0x1EA (type of content = 1)
{
tmd[0x1EA] = 0x00;
tmd[0x1EB] = 0x01;
}
// Phase 7 - offset, 0x1EC (file size, 8B)
{
app.seekg(0, app.end);
uint32_t size = app.tellg();
size = __bswap32(size);
// We only use 4B for size as for now
memcpy((tmd + 0x1F0), &size, sizeof(uint32_t));
}
// Phase 8 - offset, 0x1F4 (SHA1 sum, 20B)
{
app.seekg(0, app.beg);
uint8_t buffer[SHA_BUFFER_SIZE] = { 0 };
uint32_t buffer_read = 0;
swiSHA1context_t ctx;
swiSHA1Init(&ctx);
do {
app.read((char*)&buffer[0], SHA_BUFFER_SIZE);
buffer_read = app.gcount();
swiSHA1Update(&ctx, buffer, buffer_read);
} while(buffer_read == SHA_BUFFER_SIZE);
swiSHA1Final(buffer, &ctx);
// Store SHA1 sum
memcpy((tmd + 0x1F4), buffer, SHA1_DIGEST_SIZE);
}
std::ofstream temptmd(destination.empty() ? "title.tmd" : destination, std::fstream::binary);
temptmd.write((const char*)tmd, TMD_SIZE);
temptmd.close();
}

61
arm9/source/menu.cpp Normal file
View file

@ -0,0 +1,61 @@
/*---------------------------------------------------------------------------------
Basic template code for starting a DS app
---------------------------------------------------------------------------------*/
#include <nds.h>
#include <cstdio>
#include <vector>
#include <string>
#include "menu.h"
void menu::AddOption(const std::string& option){
options.push_back(option);
}
int menu::DoMenu(PrintConsole* screen){
consoleSelect(screen);
current = 0;
consoleClear();
consoleSetWindow(screen, 1, 0, DISPLAY_COLUMNS-1, DISPLAY_ROWS);
for(auto option : options)
iprintf((option+"\n").c_str());
consoleSetWindow(screen, 0, 0, 1, DISPLAY_ROWS);
iprintf(">");
while (true){
swiWaitForVBlank();
scanKeys();
int pressed = keysDownRepeat();
if(pressed & KEY_UP) {
consoleClear();
current--;
if(current<0)
current = options.size() - 1;
for (int a = 0; a<current; a++)
iprintf("\n");
iprintf(">");
}
if(pressed & KEY_DOWN) {
consoleClear();
current++;
if(current>=options.size())
current = 0;
for (int a = 0; a<current; a++)
iprintf("\n");
iprintf(">");
}
if(pressed & KEY_A) {
consoleSetWindow(screen, 0, 0, DISPLAY_COLUMNS, DISPLAY_ROWS);
consoleClear();
return current;
}
if(pressed & KEY_START) {
consoleSetWindow(screen, 0, 0, DISPLAY_COLUMNS, DISPLAY_ROWS);
consoleClear();
current = -1;
return current;
}
}
}
int menu::GetLastSeletedOption(){
return current;
}

23
arm9/source/menu.h Normal file
View file

@ -0,0 +1,23 @@
#ifndef MENU_H
#define MENU_H
#include <string>
#include <vector>
#define DISPLAY_COLUMNS 32
#define DISPLAY_ROWS 26
class menu{
private:
std::vector<std::string> options;
int current;
public:
void AddOption(const std::string& option);
int DoMenu(PrintConsole* screen);
int GetLastSeletedOption();
};
#endif //MENU_H

61
arm9/source/utils.h Normal file
View file

@ -0,0 +1,61 @@
#ifndef UTILS_H
#define UTILS_H
#include <fstream>
#include <vector>
#include <errno.h>
#include <sys/stat.h>
std::string string_to_hex(const std::string& input) {
static const char* const lut = "0123456789ABCDEF";
size_t len = input.length();
std::string output;
output.reserve(2 * len);
for(size_t i = 0; i < len; ++i) {
const unsigned char c = input[i];
output.push_back(lut[c >> 4]);
output.push_back(lut[c & 15]);
}
return output;
}
bool Makedirectory(const std::string& path) {
return !mkdir((const char *)path.c_str(), 0777) || errno == EEXIST;
}
bool Movefile(const std::string& source, const std::string& destination) {
std::ifstream src(source, std::ios::binary);
if(!src.is_open())
return false;
std::ofstream dst(destination, std::ios::binary);
if(!dst.is_open())
return false;
dst << src.rdbuf();
src.close();
remove(source.c_str());
return true;
}
bool CreatePath(const std::string& path, const std::string& workingdir = "") {
std::vector<std::string> folders;
std::string temp;
for(int i = 0; i < (int)path.size(); i++) {
if(path[i] == '/') {
folders.push_back(temp);
temp.clear();
} else
temp += path[i];
}
if(!temp.empty())
folders.push_back(temp);
temp.clear();
for(auto folder : folders) {
if(temp.empty() && !workingdir.empty())
temp = workingdir + "/" + folder;
else
temp += "/" + folder;
if(!Makedirectory(temp))
return false;
}
return true;
}
#endif

BIN
banner.bin Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

457
patch_ndsheader_dsiware.py Normal file
View file

@ -0,0 +1,457 @@
# -*- coding: utf8 -*-
# Patch an .nds (works with homebrew and ds demo only) to make it ready for make_cia
#
# 2016-02-28, Ahezard
#
# inspired by
# Apache Thunder .nds edited files and comments
# https://github.com/Relys/Project_CTR/blob/master/makerom/srl.h
# https://dsibrew.org/wiki/DSi_Cartridge_Header
# if the header size of the input nds file is 0x200 (homebrew)
# the header size of the output nds file will be patched to 0x4000 (normal ds/dsi header), 0x3E00 offset
from struct import *
from collections import namedtuple
from collections import OrderedDict
from pprint import pprint
import os, sys
import binascii
import argparse
parser = argparse.ArgumentParser(description='Patch an nds in order to be ready cia conversion via make_cia --srl=.')
parser.add_argument('file', metavar='file.nds', type=file, help='nds file to patch')
parser.add_argument('--verbose', help='verbose mode', action="store_true")
parser.add_argument('--out', help='output file [optionnal]')
parser.add_argument('--read', help='print only the header content, do not patch', action="store_true")
parser.add_argument('--extract', help='extract the content of the rom : header.bin,arm9.bin,arm7.bin,icon.bin,arm9i.bin,arm7i.bin, do not patch', action="store_true") #Not yet implemented
parser.add_argument('--title', help='Game title')
parser.add_argument('--code', help='Game code')
parser.add_argument('--maker', help='Maker code')
parser.add_argument('--mode', help='target mode, default mode is ds [ds|dsi|dsinogba]')
parser.add_argument('--arm9', type=file, help='swap the ds arm9 binary by the one provided')
parser.add_argument('--arm7', type=file, help='swap the ds arm7 binary by the one provided')
parser.add_argument('--arm9EntryAddress', help='arm9 ram address of the binary provided')
parser.add_argument('--arm7EntryAddress', help='arm7 ram address of the binary provided')
parser.add_argument('--arm9i', type=file, help='add a dsi arm9i binary to the file, not needed for homebrew so far')
parser.add_argument('--arm7i', type=file, help='add a dsi arm7i binary to the file, not needed for homebrew so far')
parser.add_argument('--digest-block', type=file, help='dsi digest block table') #Not yet implemented
parser.add_argument('--digest-sector', type=file, help='dsi digest sector table') #Not yet implemented
args = parser.parse_args()
if args.mode is None:
args.mode = "dsi"
#
# CRC16 MODULE
#
# includes CRC16 and CRC16 MODBUS
#
from ctypes import c_ushort
# from https://github.com/cristianav/PyCRC/blob/master/demo.py
class CRC16(object):
crc16_tab = []
# The CRC's are computed using polynomials. Here is the most used
# coefficient for CRC16
crc16_constant = 0xA001 # 40961
def __init__(self, modbus_flag=False):
# initialize the precalculated tables
if not len(self.crc16_tab):
self.init_crc16()
self.mdflag = bool(modbus_flag)
def calculate(self, input_data=None):
try:
is_string = isinstance(input_data, str)
is_bytes = isinstance(input_data, (bytes, bytearray))
if not is_string and not is_bytes:
raise Exception("Please provide a string or a byte sequence "
"as argument for calculation.")
crc_value = 0x0000 if not self.mdflag else 0xffff
for c in input_data:
d = ord(c) if is_string else c
tmp = crc_value ^ d
rotated = crc_value >> 8
crc_value = rotated ^ self.crc16_tab[(tmp & 0x00ff)]
return crc_value
except Exception as e:
print("EXCEPTION(calculate): {}".format(e))
def init_crc16(self):
"""The algorithm uses tables with precalculated values"""
for i in range(0, 256):
crc = c_ushort(i).value
for j in range(0, 8):
if crc & 0x0001:
crc = c_ushort(crc >> 1).value ^ self.crc16_constant
else:
crc = c_ushort(crc >> 1).value
self.crc16_tab.append(crc)
def getSize(fileobject):
current = fileobject.tell()
fileobject.seek(0,2) # move the cursor to the end of the file
size = fileobject.tell()
fileobject.seek(current,0)
return size
def skipUntilAddress(f_in,f_out, caddr, taddr):
chunk = f_in.read(taddr-caddr)
f_out.write(chunk)
def writeBlankuntilAddress(f_out, caddr, taddr):
f_out.write("\x00"*(taddr-caddr))
fname=args.file.name
args.file.close()
if not args.read:
print "Patching file : "+fname
else:
print "Reading header of file : "+fname
#offset of 0x4600 created
# File size compute
file = open(fname, 'rb')
fsize=getSize(file)
file.close()
#CRC header compute "CRC-16 (Modbus)"
file = open(fname, 'rb')
#0x15E from https://github.com/devkitPro/ndstool/ ... source/header.cpp
hdr = file.read(0x15E)
hdrCrc=CRC16(modbus_flag=True).calculate(hdr)
if args.verbose:
print("{:10s} {:20X}".format('HDR CRC-16 ModBus', hdrCrc))
#print "origin header cr c"+hdr[0x15E:0x15F]
#filew = open(fname+".hdr", "wb")
#filew.write(hdr);
#filew.close()
file.close()
if args.arm9 is not None:
arm9Fname=args.arm9.name
args.arm9.close()
arm9File = open(arm9Fname, 'rb')
arm9FileSize=getSize(arm9File)
dataArm9=arm9File.read(arm9FileSize)
arm9File.close()
if args.arm7 is not None:
arm7Fname=args.arm7.name
args.arm7.close()
arm7File = open(arm7Fname, 'rb')
arm7FileSize=getSize(arm7File)
dataArm7=arm7File.read(arm7FileSize)
arm7File.close()
filer = open(fname, 'rb')
data = filer.read(0x180)
caddr=0x180
#DS Data 180 bytes
SrlHeader = namedtuple('SrlHeader',
"gameTitle "
"gameCode "
"makerCode "
"unitCode "
"encryptionSeedSelect "
"deviceCapacity "
"reserved0 "
"dsiflags "
"romVersion "
"internalFlag "
"arm9RomOffset "
"arm9EntryAddress "
"arm9RamAddress "
"arm9Size "
"arm7RomOffset "
"arm7EntryAddress "
"arm7RamAddress "
"arm7Size "
"fntOffset "
"fntSize "
"fatOffset "
"fatSize "
"arm9OverlayOffset "
"arm9OverlaySize "
"arm7OverlayOffset "
"arm7OverlaySize "
"normalCardControlRegSettings "
"secureCardControlRegSettings "
"icon_bannerOffset "
"secureAreaCrc "
"secure_transfer_timeout "
"arm9Autoload "
"arm7Autoload "
"secureDisable "
"ntrRomSize "
"headerSize "
"reserved1 "
"nintendoLogo "
"nintendoLogoCrc "
"headerCrc "
"debugReserved ")
srlHeaderFormat='<12s4s2scbb7s2sbcIIIIIIIIIIIIIIIIIIIHHII8sII56s156s2sH32s'
srlHeader=SrlHeader._make(unpack_from(srlHeaderFormat, data))
if args.verbose:
print "origin header crc "+hex(srlHeader.headerCrc)
print "origin secure crc "+hex(srlHeader.secureAreaCrc)
#SecureArea CRC compute "CRC-16 (Modbus)"
file = open(fname, 'rb')
#0x15E from https://github.com/devkitPro/ndstool/ ... source/header.cpp
file.read(0x200)
sec = file.read(0x4000)
secCrc=CRC16(modbus_flag=True).calculate(sec)
if args.verbose:
print("{:10s} {:20X}".format('SEC CRC-16 ModBus', secCrc))
file.close()
if srlHeader.arm7EntryAddress>0x2400000 and not args.read and args.arm7 is None:
print "WARNING: .nds arm7EntryAddress greater than 0x2400000 will not boot as cia"
print "you need to recompile or swap the arm7 binary with a precompiled one with --arm7 and --arm7EntryAddress"
if "dsi" in args.mode :
srlHeaderPatched=srlHeader._replace(
dsiflags= '\x01\x00', #disable modcrypt but enable twl
unitCode= '\x03',
)
data1=pack(*[srlHeaderFormat]+srlHeaderPatched._asdict().values())
newHdrCrc=CRC16(modbus_flag=True).calculate(data1[0:0x15E])
srlHeaderPatched=srlHeaderPatched._replace(headerCrc=newHdrCrc)
if args.verbose:
print "new header crc "+hex(newHdrCrc)
if not args.read :
if args.verbose:
pprint(dict(srlHeaderPatched._asdict()))
else:
pprint(dict(srlHeader._asdict()))
data1=pack(*[srlHeaderFormat]+srlHeaderPatched._asdict().values())
arm9isize=0
arm7isize=0
#TWL Only Data 384 bytes
SrlTwlExtHeader = namedtuple('SrlTwlExtHeader',
"MBK_1_5_Settings "
"MBK_6_8_Settings_ARM9 "
"MBK_6_8_Settings_ARM7 "
"global_MBK_9_Setting "
"regionFlags "
"accessControl "
"arm7ScfgExtMask "
"reserved_flags "
"arm9iRomOffset "
"reserved2 "
"arm9iLoadAddress "
"arm9iSize "
"arm7iRomOffset "
"struct_param_baseAddress "
"arm7iLoadAddress "
"arm7iSize "
"digest_ntrRegionOffset "
"digest_ntrRegionSize "
"digest_twlRegionOffset "
"digest_twlRegionSize "
"digestSectorHashtableOffset "
"digestSectorHashtableSize "
"digest_blockHashtableOffset "
"digest_blockHashtableSize "
"digestSectorSize "
"digest_blockSectorcount "
"iconSize " #usually 0x23C0 or 2112 in homebrew
"unknown1 "
"twlRomSize "
"unknown2 "
"modcryptArea1Offset "
"modcryptArea1Size "
"modcryptArea2Offset "
"modcryptArea2Size "
"title_id "
"pubSaveDataSize "
"privSaveDataSize "
"reserved4 "
"parentalControl ")
srlTwlExtHeaderFormat="<20s12s12s4s4sIIII4sIIIIIIIIIIIIIIIII4sI12sIIII8sII176s16s"
if srlHeader.headerSize<0x300:
#homebrew
srlTwlExtHeader=SrlTwlExtHeader._make(unpack_from(srlTwlExtHeaderFormat, "\x00" * (0x300-0x180)))
else:
data = filer.read(0x300-0x180)
srlTwlExtHeader=SrlTwlExtHeader._make(unpack_from(srlTwlExtHeaderFormat, data))
caddr=0x300
#pprint(dict(srlTwlExtHeader._asdict()))
if not args.read:
# Fix srlTwlExtHeader
if "dsi" in args.mode:
arm7iRomOffset=srlHeaderPatched.arm7RomOffset
arm9iRomOffset=srlHeaderPatched.arm9RomOffset
arm7isize=srlHeaderPatched.arm7Size
arm9isize=srlHeaderPatched.arm9Size
totaldsisize=0
arm7iname = None
arm9iname = None
if args.arm9i is not None:
arm9iname = args.arm9i.name
arm9isize = getSize(args.arm9i)
arm9iRomOffset=srlHeaderPatched.ntrRomSize
if args.verbose:
print "arm9isize : "+hex(arm9isize)
print "arm9ioffset : "+hex(srlHeaderPatched.ntrRomSize)
args.arm9i.close()
totaldsisize=arm9isize
if args.arm7i is not None:
arm7iname = args.arm7i.name
arm7isize = getSize(args.arm7i)
arm7iRomOffset=srlHeaderPatched.ntrRomSize+arm9isize
if args.verbose:
print "arm7isize : "+hex(arm7isize)
print "arm9ioffset : "+hex(srlHeaderPatched.ntrRomSize+arm9isize)
args.arm7i.close()
totaldsisize=arm9isize+arm7isize
srlTwlExtHeader=srlTwlExtHeader._replace(
accessControl= 0x00000138,
arm7ScfgExtMask= 0x80040000,
reserved_flags= 0x00000000
)
if args.verbose or args.read:
pprint(dict(srlTwlExtHeader._asdict()))
data2=pack(*[srlTwlExtHeaderFormat]+srlTwlExtHeader._asdict().values())
#TWL and Signed NTR 3328 bytes
SrlSignedHeader = namedtuple('SrlSignedHeader',
"arm9WithSecAreaSha1Hmac "
"arm7Sha1Hmac "
"digestMasterSha1Hmac "
"bannerSha1Hmac "
"arm9iSha1Hmac "
"arm7iSha1Hmac "
"reserved5 "
"arm9Sha1Hmac "
"reserved6 "
"reserved7 "
"signature "
)
srlSignedHeaderFormat="<20s20s20s20s20s20s40s20s2636s384s128s"
if srlHeader.headerSize<0x1100:
#homebrew
srlSignedHeader=SrlSignedHeader._make(unpack_from(srlSignedHeaderFormat, "\x00" * (3328)))
else:
data = filer.read(3328)
srlSignedHeader=SrlSignedHeader._make(unpack_from(srlSignedHeaderFormat, data))
caddr=0x300+3328
filer.read(0x4000-caddr)
caddr=0x4000
#pprint(dict(srlSignedHeader._asdict()))
# Fix srlSignedHeader
if not args.read:
srlSignedHeader=srlSignedHeader._replace(
arm7Sha1Hmac= '\xff'*20,
arm9WithSecAreaSha1Hmac= '\xff'*20,
bannerSha1Hmac= '\xff'*20,
signature= '\xff'*128
)
if "dsi" in args.mode :
srlSignedHeader=srlSignedHeader._replace(
arm7Sha1Hmac= '\xff'*20,
arm7iSha1Hmac= '\xff'*20,
arm9Sha1Hmac= '\xff'*20,
arm9WithSecAreaSha1Hmac= '\xff'*20,
arm9iSha1Hmac= '\xff'*20,
bannerSha1Hmac= '\xff'*20,
digestMasterSha1Hmac= '\xff'*20,
signature= '\xff'*128
)
if args.verbose or args.read:
pprint(dict(srlSignedHeader._asdict()))
data3=pack(*[srlSignedHeaderFormat]+srlSignedHeader._asdict().values())
# ARM9 footer
# from https://github.com/devkitPro/ndstool/ ... source/header.cpp
# ARM9 footer size = 3*4
ARM9Footer = namedtuple('ARM9Footer',
"nitrocode " #0xDEC00621
"versionInfo "
"reserved "
)
ARM9FooterFormat="<III"
file = open(fname, 'rb')
arm9FooterAddr=srlHeader.arm9RomOffset + srlHeader.arm9Size
file.read(arm9FooterAddr)
data=file.read(12)
arm9Footer=ARM9Footer._make(unpack_from(ARM9FooterFormat, data))
if args.verbose:
print "footer addr "+hex(arm9FooterAddr)
if arm9Footer.nitrocode == 0xDEC00621:
if args.verbose or args.read:
print "ARM9 footer found."
print "no patch needed"
print "nitrocode "+hex(arm9Footer.nitrocode)
print "versionInfo "+hex(arm9Footer.versionInfo)
print "reserved "+hex(arm9Footer.reserved)
print "\n"
else:
if args.verbose or args.read:
print "ARM9 footer not found.\n"
arm9FooterPatched=arm9Footer._replace(
nitrocode= 0xDEC00621,
versionInfo= 0xad8,
reserved= 0
)
data4=pack(*[ARM9FooterFormat]+arm9FooterPatched._asdict().values())
file.close()
if not args.read:
# write the file
if args.out is not None:
filew = open(args.out, "wb")
else:
filew = open(fname+".tmp", "wb")
filew.write(data1)
filew.write(data2)
filew.write(data3[0:0xC80])
filew.write('\xff'*16*8)
writeBlankuntilAddress(filew,0x1000,0x4000)
if arm9Footer.nitrocode != 0xDEC00621:
# patch ARM9 footer
skipUntilAddress(filer,filew,caddr,arm9FooterAddr)
filew.write(data4)
filer.read(12)
caddr=arm9FooterAddr+12
skipUntilAddress(filer,filew,caddr,srlTwlExtHeader.twlRomSize)
filew.close()
filer.close()
if args.out is None:
if os.path.exists(fname+".orig.nds"):
os.remove(fname+".orig.nds")
os.rename(fname,fname+".orig.nds")
os.rename(fname+".tmp",fname)
print "file patched"

BIN
title.tmd Normal file

Binary file not shown.