From b5f65106cac3128119d4548dab2ebc728392c8e8 Mon Sep 17 00:00:00 2001 From: edo9300 Date: Wed, 13 Feb 2019 20:18:36 +0100 Subject: [PATCH] Added source --- ForwardDuali_8frames.gif | Bin 0 -> 964 bytes Icon.gif | Bin 0 -> 1981 bytes Makefile | 55 ++++ arm7/Makefile | 126 ++++++++++ arm7/source/template.c | 97 ++++++++ arm9/Makefile | 127 ++++++++++ arm9/source/apppatch.cpp | 241 ++++++++++++++++++ arm9/source/apppatch.h | 11 + arm9/source/file_browse.cpp | 223 +++++++++++++++++ arm9/source/file_browse.h | 32 +++ arm9/source/headers.h | 175 +++++++++++++ arm9/source/inifile.cpp | 399 +++++++++++++++++++++++++++++ arm9/source/inifile.h | 69 +++++ arm9/source/main.cpp | 272 ++++++++++++++++++++ arm9/source/maketmd.cpp | 120 +++++++++ arm9/source/menu.cpp | 61 +++++ arm9/source/menu.h | 23 ++ arm9/source/utils.h | 61 +++++ banner.bin | Bin 0 -> 9152 bytes icon/frame_00_delay-0.06s.gif | Bin 0 -> 217 bytes icon/frame_01_delay-0.06s.gif | Bin 0 -> 204 bytes icon/frame_02_delay-0.06s.gif | Bin 0 -> 195 bytes icon/frame_03_delay-0.06s.gif | Bin 0 -> 197 bytes icon/frame_04_delay-0.06s.gif | Bin 0 -> 177 bytes icon/frame_05_delay-0.06s.gif | Bin 0 -> 177 bytes icon/frame_06_delay-0.06s.gif | Bin 0 -> 133 bytes icon/frame_07_delay-0.06s.gif | Bin 0 -> 176 bytes icon/frame_08_delay-0.06s.gif | Bin 0 -> 190 bytes icon/frame_09_delay-0.06s.gif | Bin 0 -> 201 bytes icon/frame_10_delay-0.06s.gif | Bin 0 -> 210 bytes icon/frame_11_delay-0.06s.gif | Bin 0 -> 213 bytes icon/frame_12_delay-0.06s.gif | Bin 0 -> 210 bytes icon/frame_13_delay-0.06s.gif | Bin 0 -> 201 bytes icon/frame_14_delay-0.06s.gif | Bin 0 -> 190 bytes icon/frame_15_delay-0.06s.gif | Bin 0 -> 176 bytes icon/frame_16_delay-0.06s.gif | Bin 0 -> 133 bytes icon/frame_17_delay-0.06s.gif | Bin 0 -> 177 bytes icon/frame_18_delay-0.06s.gif | Bin 0 -> 177 bytes icon/frame_19_delay-0.06s.gif | Bin 0 -> 197 bytes icon/frame_20_delay-0.06s.gif | Bin 0 -> 195 bytes icon/frame_21_delay-0.06s.gif | Bin 0 -> 204 bytes patch_ndsheader_dsiware.py | 457 ++++++++++++++++++++++++++++++++++ title.tmd | Bin 0 -> 520 bytes 43 files changed, 2549 insertions(+) create mode 100644 ForwardDuali_8frames.gif create mode 100644 Icon.gif create mode 100644 Makefile create mode 100644 arm7/Makefile create mode 100644 arm7/source/template.c create mode 100644 arm9/Makefile create mode 100644 arm9/source/apppatch.cpp create mode 100644 arm9/source/apppatch.h create mode 100644 arm9/source/file_browse.cpp create mode 100644 arm9/source/file_browse.h create mode 100644 arm9/source/headers.h create mode 100644 arm9/source/inifile.cpp create mode 100644 arm9/source/inifile.h create mode 100644 arm9/source/main.cpp create mode 100644 arm9/source/maketmd.cpp create mode 100644 arm9/source/menu.cpp create mode 100644 arm9/source/menu.h create mode 100644 arm9/source/utils.h create mode 100644 banner.bin create mode 100644 icon/frame_00_delay-0.06s.gif create mode 100644 icon/frame_01_delay-0.06s.gif create mode 100644 icon/frame_02_delay-0.06s.gif create mode 100644 icon/frame_03_delay-0.06s.gif create mode 100644 icon/frame_04_delay-0.06s.gif create mode 100644 icon/frame_05_delay-0.06s.gif create mode 100644 icon/frame_06_delay-0.06s.gif create mode 100644 icon/frame_07_delay-0.06s.gif create mode 100644 icon/frame_08_delay-0.06s.gif create mode 100644 icon/frame_09_delay-0.06s.gif create mode 100644 icon/frame_10_delay-0.06s.gif create mode 100644 icon/frame_11_delay-0.06s.gif create mode 100644 icon/frame_12_delay-0.06s.gif create mode 100644 icon/frame_13_delay-0.06s.gif create mode 100644 icon/frame_14_delay-0.06s.gif create mode 100644 icon/frame_15_delay-0.06s.gif create mode 100644 icon/frame_16_delay-0.06s.gif create mode 100644 icon/frame_17_delay-0.06s.gif create mode 100644 icon/frame_18_delay-0.06s.gif create mode 100644 icon/frame_19_delay-0.06s.gif create mode 100644 icon/frame_20_delay-0.06s.gif create mode 100644 icon/frame_21_delay-0.06s.gif create mode 100644 patch_ndsheader_dsiware.py create mode 100644 title.tmd diff --git a/ForwardDuali_8frames.gif b/ForwardDuali_8frames.gif new file mode 100644 index 0000000000000000000000000000000000000000..403c9a5509e63012a23aa1ca21ffc19ec7835757 GIT binary patch literal 964 zcmZ?wbhEHbRA5kG_{;zTo}Qj*X=y-)fq{W;s_qR2hI1Ra{{R0EmP98Mf3mQ00tFTS zbNji51UowhxEkphFf#&$bUxpHmc z^*67?xXkCQz5A)QuJ!%h{Oo#b?aIia1}(?#+!hP-3}Ksooryw|yX=joam<)GL3-Yl zM43hXb0(>-Qj}Y}ZvBRho8$x;V9wTIWng9yV~_;8F-yRcbJgC`SC$5Hx35)-Nff12 z7Bx9=J+s=vD0X1A3HR61$z$Viv>qGWb-6XF`W(3EM*7l^oGmvsO%fG)a1! z-${mzJQqIAa9!CYE;|3Uj&AsZH2b()wm}T>g$zy2B`WP5B8Adm>v=(;ro#oao(F8b zjesYM)(nYWt50_vo@d@!!P)eJcg3uYD>--H(Ai#YbIbbPYwdV}A3|cCTQB+TOxic+ zq`)&J#+_P1+@V5@2>);b4deqG7*){V`C7&~LVLr#km-#J&4FRwIe!+@o0sdEG7&DCj_=GxPZrD_0}SeLhBosp2aRW)*Gt1XiC*4z1v(5 zyN?<1U0(L*ygnrKXRee@g}{rBl zLml=h8=Nkj)j6wpd1aT_Lgh1sUKhPAB)nM=rt$z?&jEJ51u(D<3Y6ZQR0vw zpt&_in{k+ULqNDt?y*k_sS<-wY{?Evz9Pj{8Xx3tSM@vR#%}? SRmV_KYb+t6+AAr@U=0BB7HAIu literal 0 HcmV?d00001 diff --git a/Icon.gif b/Icon.gif new file mode 100644 index 0000000000000000000000000000000000000000..208f16f4e1941e028337e3a7dbbaa8568e6c5320 GIT binary patch literal 1981 zcmai!3s6#N7={ms3Eqahg^G?^pb09Ovq0L$B`q?m328)4(G4>yHM%TmmRP2#Dc(xW zER9UTTbfvTS##1#(n_sNlcF?JwEMkw-2>YW%r?!QGjrz5f6lzm_y6Dfek&M$ByxlU z-~hY@)E9%nh>D5=UkC((8`o_J0Q$}w&d$ziKK}RN_!*`@2V8WVHCp2v$fQ%(`Fgq& z^dR68Uj46HRu7hqyupyRkyO1c_8gb2u~&#_Nv*WVWE;8#g@5Fd_<;6!mcm)JS*dS) zU2JBJDqVN&?1iF)4`Sv7&aw+z1&!=_&PwjG;1^ZZ?6^NYWo1Y#sTqBfxIg9PXzbPl z-nhMNev&ISWBVZzG1}ZG8=qsAm%hyN7`(7ZWLugafiBN3$;C(d!aW&jtQ1 z8?O)O0ak!DSR)VVNRhU&dV~pfHl2IzDvyqFW0D-i?)B+4NCDMn=Zn$tx{bZ5kRF)eMLg zSYRy<2~yKitl>I%0}yYf!H25xP3yDdSFT^b#}3D41y(^iha`@+aaW9DI``dGxDEU= z5IZk)JZY&ir_gH(?}K{5KJw+*?MUO0yK8dR8_wfcrjx@0G1W2Mc(*shzbhN=Vmb^x z%HEBb=>QQR&{PAYA%zUp^5`J%dPU%IVVMD3T#0~Gmd<==sAb6a+#G)|c=_u_E*7t! zAbm3C3nefso|$i7c zG)4c}{q{w;i$H7N-d@$2Q!o8S<|g=|U+oI*DW-ExM3U8XsmWuB4I2urWkEkh`vzw$ z&{0<#2?E}FFeq}l7HSMa;Tk9bgbMQyW@UH|9XE(fChQp}iy!i2+faFRp#xKyiiExv z*8qQ%Q)H%{IE{JU!AUD(0*V-DM2K-oh{Kl5v=bjYlDbpuUG|R(in-~zJflCP@@}g# z)duP(m|RFOHa+a?m_vjkOZ=P%X;pxZmJz6BsL@&;XH3C~Xh9D3vQg1?B|LsXe0n%b zHh7|;aZ*BT8(ySPk)aWEk;UNx8kJ93Z)#9s4ip4S4t97UMbU1M^i9koV5q)_3$N|k zT2NS8K!BuLCO&+J_fY?{ji^;|F0&jb`XyGP>0G90Gx^N|T!wqH6Fz=GfOODFipd-~(Nw6+q zPar5xXPBBpGEol-oy0|{Ic+Rc$NIXGtBK(kcQ1&_nrtd}b4iOcZk4T`u;}|rJ{^EM zF_WwZRlf6gXJ7yAcI6l(-;73;kH)t= za*(7CBY{C<$iE;{vV{pF=jnJ7AlP%k_Ajujy*n4eN=kGqT= z>hZA4TO6ipF8=Dx$*z|m4_xE$gTzRe+yIOwQ2+EmYkF6t5FxVL8FWb4{@`9>C_KKL zUG7Y-n4Xfv8nq-RsUq8FmnyoN%K`zNI<&zf#U(MWAa^Ua?NCrryC@vgd_hIwkzDtX zT0%{GGy1+@>(`~iG>nUtclXmS6wOMnklVlILfjl3v7aQoitxbuF^&;%ejY%<;zQu&WNS@Igdkz|)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 diff --git a/arm7/Makefile b/arm7/Makefile new file mode 100644 index 0000000..a6e5bed --- /dev/null +++ b/arm7/Makefile @@ -0,0 +1,126 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=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 +#--------------------------------------------------------------------------------------- diff --git a/arm7/source/template.c b/arm7/source/template.c new file mode 100644 index 0000000..f6d4d0e --- /dev/null +++ b/arm7/source/template.c @@ -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 +#include +#include + +//--------------------------------------------------------------------------------- +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; +} diff --git a/arm9/Makefile b/arm9/Makefile new file mode 100644 index 0000000..1ffeb81 --- /dev/null +++ b/arm9/Makefile @@ -0,0 +1,127 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=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 +#--------------------------------------------------------------------------------------- diff --git a/arm9/source/apppatch.cpp b/arm9/source/apppatch.cpp new file mode 100644 index 0000000..274c821 --- /dev/null +++ b/arm9/source/apppatch.cpp @@ -0,0 +1,241 @@ +#include +#include +#include +#include +#include +#include "apppatch.h" +#include "headers.h" + +class CRC16 { + std::vectorcrc16_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(target)), + std::istreambuf_iterator()); + 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; + } \ No newline at end of file diff --git a/arm9/source/apppatch.h b/arm9/source/apppatch.h new file mode 100644 index 0000000..90bb3fd --- /dev/null +++ b/arm9/source/apppatch.h @@ -0,0 +1,11 @@ +#ifndef APPPATCH_H +#define APPPATCH_H + +#include + +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 \ No newline at end of file diff --git a/arm9/source/file_browse.cpp b/arm9/source/file_browse.cpp new file mode 100644 index 0000000..9c5d096 --- /dev/null +++ b/arm9/source/file_browse.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +#include + +#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 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& dirContents, const vector 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& dirContents) { + vector extensionList; + getDirectoryContents (dirContents, extensionList); +} + +void showDirectoryContents (const vector& 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& extensionList) { + int pressed = 0; + int screenOffset = 0; + int fileOffset = 0; + vector 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); + } + } +} diff --git a/arm9/source/file_browse.h b/arm9/source/file_browse.h new file mode 100644 index 0000000..903b5aa --- /dev/null +++ b/arm9/source/file_browse.h @@ -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 +#include + +std::string browseForFile (const std::vector& extensionList); + + + +#endif //FILE_BROWSE_H diff --git a/arm9/source/headers.h b/arm9/source/headers.h new file mode 100644 index 0000000..dbcf97d --- /dev/null +++ b/arm9/source/headers.h @@ -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<. +*/ + +#include +#include +#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)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& strings,char delimiter) +{ + std::string strValue; + for(size_t ii=0;ii2&&'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;ii0) + { + 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(ii0&&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(ii0&&rBracketPos!=std::string::npos) + { + strSection=strline.substr(1,rBracketPos-1); + if(strSection==Section) + { + while(ii 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 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 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(ndstemplate)), + std::istreambuf_iterator()); + 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; +} diff --git a/arm9/source/maketmd.cpp b/arm9/source/maketmd.cpp new file mode 100644 index 0000000..05f6cde --- /dev/null +++ b/arm9/source/maketmd.cpp @@ -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 +#include +#include + +#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(); +} diff --git a/arm9/source/menu.cpp b/arm9/source/menu.cpp new file mode 100644 index 0000000..182540d --- /dev/null +++ b/arm9/source/menu.cpp @@ -0,0 +1,61 @@ +/*--------------------------------------------------------------------------------- + + Basic template code for starting a DS app + +---------------------------------------------------------------------------------*/ +#include +#include +#include +#include +#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"); + } + if(pressed & KEY_DOWN) { + consoleClear(); + current++; + if(current>=options.size()) + current = 0; + for (int a = 0; a"); + } + 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; +} diff --git a/arm9/source/menu.h b/arm9/source/menu.h new file mode 100644 index 0000000..cb38e90 --- /dev/null +++ b/arm9/source/menu.h @@ -0,0 +1,23 @@ +#ifndef MENU_H +#define MENU_H + +#include +#include + +#define DISPLAY_COLUMNS 32 +#define DISPLAY_ROWS 26 + +class menu{ + private: + std::vector options; + int current; + public: + void AddOption(const std::string& option); + int DoMenu(PrintConsole* screen); + int GetLastSeletedOption(); + +}; + + + +#endif //MENU_H diff --git a/arm9/source/utils.h b/arm9/source/utils.h new file mode 100644 index 0000000..d0cd3e4 --- /dev/null +++ b/arm9/source/utils.h @@ -0,0 +1,61 @@ +#ifndef UTILS_H +#define UTILS_H +#include +#include + +#include +#include + +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 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 \ No newline at end of file diff --git a/banner.bin b/banner.bin new file mode 100644 index 0000000000000000000000000000000000000000..e1a78a7286c83f491b0a7d491d9a541d9f0a667c GIT binary patch literal 9152 zcmeI2v2xTf5Qf);#2JRd7iNG|;dCVpV^_3^q2nE3fQlkB%-q>U9^yJ$I-Y?%2Sd$E z(DSeFB(K(r?@kF6hm`qqE3KqYTG_fp_Ca>>_4k(_-+un0Ez+dS6`G)!Q z9dTO9SXmo=mE7NR=oA6A<@VFT;OF?;a{DQH6O2Wtvn!(WW1@oI(lUGhkp1V!T(U~9 z>5@KEL+|kW1AWBrXY>ZSPo4dMUZM1oUQ$Ib@Uwp@%|ESwy8hGs|G(~k`?sT~8KnrM z2&4$42&4$42&4$42y7pLbUvidi|pCdzMcQlw z7a-~u2>h68FvheaZcu&5E~|e2#%MOr`EKXGiZ@M-;RVnGEJeI0p#wnO;C6ZDPnBGc z>^xC&&Ui!fyu9Y=d_2~*^mr)s@|vgfu9tX2@&@ZKc>`xWGuU!?|Kpkz3EM-4?ZK09 zN15_o3)z~d^HEUIXuxcmrkKy?#bU8wX&&4e+!p$wx(34hx=kb|wo1}R+hBd?h(C?OtI9yU6Ac!pxHcUdrg#gGk?e8C-D8aR#qwQx1m?p-kA6HUexBiOT7Ph zdof-Ra84N7&yUKb-|l(x6aEm>m37bL`MLZJ!s`KMOp+C{cjDuJ5j?J!?+0L1K3}{Z zV7Ow4Da!<3hRWGC-uUz1gueeby&oW1Z0oe?{eYqW?260wCFPXod6pmL_wvL1AiobC N!ahP7e{KKu^anq~aQXlM literal 0 HcmV?d00001 diff --git a/icon/frame_00_delay-0.06s.gif b/icon/frame_00_delay-0.06s.gif new file mode 100644 index 0000000000000000000000000000000000000000..905a446f30d97746fa58ec022f7137ce0b3c3bf6 GIT binary patch literal 217 zcmZ?wbhEHbRA5kG_{6~A>FJr4md3!qaD##2|Ns9$1_UVn=k{|A33hf2a5d61U}gl0 zD*j|)U}N~tpaW6?($2u#?Xm05KZ8@At3@ncpFPT(pwYKjoHJ$CEP++~6n^huOt^0$ zcZ!df=fDC1jvKWO`xkDKu)a3M`?2Pf7Pgs;afj1IleY5YP1nc`JpSaFNT*!Q+^g@Z z|GJz%`}||AS(p3O3MI?t)EWc*1a6adl}@hiCUdPmmI)I(gs1gHip*-C(j~h{Qf%q6 NFJr4md3!qaD##2|Ns9$1_UVn=k{|A33hf2a5d61U}gl0 zD*j|)U}N~tpaW6?($2tK=dtU~KZ8@A+M*V(=dR^Q(CBM?Ffk(|EWT@9ILDciweu7V z-u&UaqZ7IQJM%%cwGDYMn2!~mSthu=hp$WZ)uc{auSvHP!?R`C7Y2UbJgZEp_3cYZ y-LiUj)7dp|g({UjYs(rmOjPOx8kHjILYk^;nmQU}rb>v-m^o|qoVhbO8LR>7!AXt) literal 0 HcmV?d00001 diff --git a/icon/frame_02_delay-0.06s.gif b/icon/frame_02_delay-0.06s.gif new file mode 100644 index 0000000000000000000000000000000000000000..ca2aeb3116b9a53a0bf01820a5c45074b93fb995 GIT binary patch literal 195 zcmZ?wbhEHbRA5kG_{6~A>FJr4md3!qaD##2|Ns9$1_UVn=k{|A33hf2a5d61U}gl0 zD*j|)U}N~tpaW6?($2tK>apw2KZ8@At3@rcb7yiSXf!!(uSt%Y#WJgFbthAa@8leA zCg=Ce7T3;v=RQ?-M9x6qHP7VJ&saH4tyUh%csFyaAM+lq;%?o(*3_lj51D%3T)1Jj p%=XNS`VzMLm+g4vo$jvL*c4tFJr4md3!qaD##2|Ns9$1_UVn=k{|A33hf2a5d61U}gl0 zD*j|)U}N~tpaW6?($2tK?y>96KZ8@At5ua=&&?Nh)aYwE-jEzMi)&Vwb~jTAFUv+t zew+H|^J4QqByV+UP!vo*qA=BU@doj!w(X&Jr=FUUR~wtH(8-&9JfQf)ZkD)Z3EPjR rE?#+GKj`w*>ES;-%IZWKJQSOSTdS%o+kJIqr28jNnL2F>CxbNrH%~=^ literal 0 HcmV?d00001 diff --git a/icon/frame_04_delay-0.06s.gif b/icon/frame_04_delay-0.06s.gif new file mode 100644 index 0000000000000000000000000000000000000000..288f832f65c4fd8d97c05264005d7138e510eb24 GIT binary patch literal 177 zcmZ?wbhEHbRA5kG_{6~A>FJr4md3!qaD##2|Ns9$1_UVn=k{|A33hf2a5d61U}gl0 zD*j|)U}N~tpaW6?($2t~?6K?4KZ8@At7Da3*DU5p&?vbe-lY6;M*1ovH3jB(tB)LZ zxNX4k#QNS@_BA&PtR8bqiWp5@wY)&$hw5^cmm#lJ;H6L6rrRewbbt98Ceqr XhW%?^z7?+9eKFyGLt~Q=CxbNrXQe&J literal 0 HcmV?d00001 diff --git a/icon/frame_05_delay-0.06s.gif b/icon/frame_05_delay-0.06s.gif new file mode 100644 index 0000000000000000000000000000000000000000..288f832f65c4fd8d97c05264005d7138e510eb24 GIT binary patch literal 177 zcmZ?wbhEHbRA5kG_{6~A>FJr4md3!qaD##2|Ns9$1_UVn=k{|A33hf2a5d61U}gl0 zD*j|)U}N~tpaW6?($2t~?6K?4KZ8@At7Da3*DU5p&?vbe-lY6;M*1ovH3jB(tB)LZ zxNX4k#QNS@_BA&PtR8bqiWp5@wY)&$hw5^cmm#lJ;H6L6rrRewbbt98Ceqr XhW%?^z7?+9eKFyGLt~Q=CxbNrXQe&J literal 0 HcmV?d00001 diff --git a/icon/frame_06_delay-0.06s.gif b/icon/frame_06_delay-0.06s.gif new file mode 100644 index 0000000000000000000000000000000000000000..b1e4cfcf30baebdb71948441ccc28968f82f9eff GIT binary patch literal 133 zcmZ?wbhEHbRA5kG_{hMJmX^lA!0`Y7e;}#&pWDwhB-q(8z|~04fSC~_^pk~wjp09o z4v-DhpuoVu|Nli+vWhNis8t+n=qxf31@zViwn`c`3U$7<@g~kt1EP@Alt6 j&8*SRp%+U;RBgR|ia$+pG2S}oz@$xC+wbHuGFSruY{xF~ literal 0 HcmV?d00001 diff --git a/icon/frame_07_delay-0.06s.gif b/icon/frame_07_delay-0.06s.gif new file mode 100644 index 0000000000000000000000000000000000000000..3f5d159abb6da72eea969967ddfd3450d3516e78 GIT binary patch literal 176 zcmZ?wbhEHbRA5kG_{6~A>FJr4md3!qU|?XNo2q+mBiH}`|AAb^|J;7AA;Hd$0j@@R z2F#2gp`R=aYz+SybbxH2W(5WY=A?{Wcm5fi@?4#&lwG)#L*Yc}1#vdzmopMqC8_^f zx6xX9O~v8mw$C@sWqMI9*m_t>Xt|5rT;GSmQg=DoB60#%6?pbE>v{%AOgZemDRQ>n b{G+mr2?p-g&r5%#PLBNbzoC(jlffDQ{Wm>? literal 0 HcmV?d00001 diff --git a/icon/frame_08_delay-0.06s.gif b/icon/frame_08_delay-0.06s.gif new file mode 100644 index 0000000000000000000000000000000000000000..526a84f8e93ecfa98a914d562da4d5f4a8636736 GIT binary patch literal 190 zcmZ?wbhEHbRA5kG_{6~A>FJr4md3!qU|?XNo2q+mBiH}`|AAb^|J;7AA;Hd$0j@@R z2F#2gp`R=aYz+SybbxH2W(5WY=7Nk}cm5fi@?0IN^tyIFM*;`e+|Qkgkw)rLE3}{W zeY~`&pr-rhuH~jT*M$GN*mNxX!UUDFS>75&%jWPc4tefs@SFJr4md3!qU|?XNo2q+mBiH}`|AAb^|J;7AA;Hd$0j@@R z2F#2gp`R=aYz+SybbxH2W(5WY=IV@Hcm5fi@?0%yk)1n}BSE9dX?sm_)GW4HU8`U2 zQ@MRxr!S6S6C@w^T+{^Q=s;WQE_NBTFu69n?#0-cTX)%#EeRv1)DJ zY{jNS4u11*-|yeCH}1IgmzrwkI$kCQ=Jw8xj+WN0{$?{S=_!+@O`kDymM|xSH2`7X BO7{Q& literal 0 HcmV?d00001 diff --git a/icon/frame_10_delay-0.06s.gif b/icon/frame_10_delay-0.06s.gif new file mode 100644 index 0000000000000000000000000000000000000000..dab704071dac0ecd1938f51b8793b450b6aa5d67 GIT binary patch literal 210 zcmV;@04@JVNk%w1VITk?0P+9;Nl8g&W@Z2Y05C8xEoCjvu?qkH{{R30A^!_bMO0Hm zK~P09E-(WD0000X`2+w40RI3i00000AOIi$00V?*y4?OS%1J8~IP0CQ2w*6Vf#8v7 zXjWf}u9y3s@(53DtYtGC;7OP+yvOfCV=)bI8@Uap|)|9EwL27ZBnd4mD~1B;7wjf{4Kgpieyi<5*Lo0%4# MpP-?lqYDWDJHf_M2><{9 literal 0 HcmV?d00001 diff --git a/icon/frame_11_delay-0.06s.gif b/icon/frame_11_delay-0.06s.gif new file mode 100644 index 0000000000000000000000000000000000000000..de1896a22c8ebce9804a7126c8845c048a8d45a1 GIT binary patch literal 213 zcmV;`04o1SNk%w1VITk?0P+9;Nl8g&W@Z2Y05C8xEoCjvu?qkH{{R30A^!_bMO0Hm zK~P09E-(WD0000X`2+w40RI3i00000AOIi$00W0;y4?OS%1NsfIP1;D4PYpaqZbKe znwk)*z99R!uqr!rP2Nqei#&$!7yA%P#$zbB7!sKZ=MQR-)-cJVU@*u&x!xz$dcAPZ z=(Kt~Ahh4^IQ%_e7Y6q{ey_jR&3$}=dVeQ_hk=DHdjJECjdzcZdsJ1El9-o{l~o;{ P85W_Uqok##qX_^zw60Up literal 0 HcmV?d00001 diff --git a/icon/frame_12_delay-0.06s.gif b/icon/frame_12_delay-0.06s.gif new file mode 100644 index 0000000000000000000000000000000000000000..dab704071dac0ecd1938f51b8793b450b6aa5d67 GIT binary patch literal 210 zcmV;@04@JVNk%w1VITk?0P+9;Nl8g&W@Z2Y05C8xEoCjvu?qkH{{R30A^!_bMO0Hm zK~P09E-(WD0000X`2+w40RI3i00000AOIi$00V?*y4?OS%1J8~IP0CQ2w*6Vf#8v7 zXjWf}u9y3s@(53DtYtGC;7OP+yvOfCV=)bI8@Uap|)|9EwL27ZBnd4mD~1B;7wjf{4Kgpieyi<5*Lo0%4# MpP-?lqYDWDJHf_M2><{9 literal 0 HcmV?d00001 diff --git a/icon/frame_13_delay-0.06s.gif b/icon/frame_13_delay-0.06s.gif new file mode 100644 index 0000000000000000000000000000000000000000..7ea94b8fae9af9fe7bea36fdfd799af77f92fab5 GIT binary patch literal 201 zcmZ?wbhEHbRA5kG_{6~A>FJr4md3!qU|?XNo2q+mBiH}`|AAb^|J;7AA;Hd$0j@@R z2F#2gp`R=aYz+SybbxH2W(5WY=IV@Hcm5fi@?0%yk)1n}BSE9dX?sm_)GW4HU8`U2 zQ@MRxr!S6S6C@w^T+{^Q=s;WQE_NBTFu69n?#0-cTX)%#EeRv1)DJ zY{jNS4u11*-|yeCH}1IgmzrwkI$kCQ=Jw8xj+WN0{$?{S=_!+@O`kDymM|xSH2`7X BO7{Q& literal 0 HcmV?d00001 diff --git a/icon/frame_14_delay-0.06s.gif b/icon/frame_14_delay-0.06s.gif new file mode 100644 index 0000000000000000000000000000000000000000..526a84f8e93ecfa98a914d562da4d5f4a8636736 GIT binary patch literal 190 zcmZ?wbhEHbRA5kG_{6~A>FJr4md3!qU|?XNo2q+mBiH}`|AAb^|J;7AA;Hd$0j@@R z2F#2gp`R=aYz+SybbxH2W(5WY=7Nk}cm5fi@?0IN^tyIFM*;`e+|Qkgkw)rLE3}{W zeY~`&pr-rhuH~jT*M$GN*mNxX!UUDFS>75&%jWPc4tefs@SFJr4md3!qU|?XNo2q+mBiH}`|AAb^|J;7AA;Hd$0j@@R z2F#2gp`R=aYz+SybbxH2W(5WY=A?{Wcm5fi@?4#&lwG)#L*Yc}1#vdzmopMqC8_^f zx6xX9O~v8mw$C@sWqMI9*m_t>Xt|5rT;GSmQg=DoB60#%6?pbE>v{%AOgZemDRQ>n b{G+mr2?p-g&r5%#PLBNbzoC(jlffDQ{Wm>? literal 0 HcmV?d00001 diff --git a/icon/frame_16_delay-0.06s.gif b/icon/frame_16_delay-0.06s.gif new file mode 100644 index 0000000000000000000000000000000000000000..b1e4cfcf30baebdb71948441ccc28968f82f9eff GIT binary patch literal 133 zcmZ?wbhEHbRA5kG_{hMJmX^lA!0`Y7e;}#&pWDwhB-q(8z|~04fSC~_^pk~wjp09o z4v-DhpuoVu|Nli+vWhNis8t+n=qxf31@zViwn`c`3U$7<@g~kt1EP@Alt6 j&8*SRp%+U;RBgR|ia$+pG2S}oz@$xC+wbHuGFSruY{xF~ literal 0 HcmV?d00001 diff --git a/icon/frame_17_delay-0.06s.gif b/icon/frame_17_delay-0.06s.gif new file mode 100644 index 0000000000000000000000000000000000000000..288f832f65c4fd8d97c05264005d7138e510eb24 GIT binary patch literal 177 zcmZ?wbhEHbRA5kG_{6~A>FJr4md3!qaD##2|Ns9$1_UVn=k{|A33hf2a5d61U}gl0 zD*j|)U}N~tpaW6?($2t~?6K?4KZ8@At7Da3*DU5p&?vbe-lY6;M*1ovH3jB(tB)LZ zxNX4k#QNS@_BA&PtR8bqiWp5@wY)&$hw5^cmm#lJ;H6L6rrRewbbt98Ceqr XhW%?^z7?+9eKFyGLt~Q=CxbNrXQe&J literal 0 HcmV?d00001 diff --git a/icon/frame_18_delay-0.06s.gif b/icon/frame_18_delay-0.06s.gif new file mode 100644 index 0000000000000000000000000000000000000000..288f832f65c4fd8d97c05264005d7138e510eb24 GIT binary patch literal 177 zcmZ?wbhEHbRA5kG_{6~A>FJr4md3!qaD##2|Ns9$1_UVn=k{|A33hf2a5d61U}gl0 zD*j|)U}N~tpaW6?($2t~?6K?4KZ8@At7Da3*DU5p&?vbe-lY6;M*1ovH3jB(tB)LZ zxNX4k#QNS@_BA&PtR8bqiWp5@wY)&$hw5^cmm#lJ;H6L6rrRewbbt98Ceqr XhW%?^z7?+9eKFyGLt~Q=CxbNrXQe&J literal 0 HcmV?d00001 diff --git a/icon/frame_19_delay-0.06s.gif b/icon/frame_19_delay-0.06s.gif new file mode 100644 index 0000000000000000000000000000000000000000..f754506834e6f95f09b5dba5c275322909cb8238 GIT binary patch literal 197 zcmZ?wbhEHbRA5kG_{6~A>FJr4md3!qaD##2|Ns9$1_UVn=k{|A33hf2a5d61U}gl0 zD*j|)U}N~tpaW6?($2tK?y>96KZ8@At5ua=&&?Nh)aYwE-jEzMi)&Vwb~jTAFUv+t zew+H|^J4QqByV+UP!vo*qA=BU@doj!w(X&Jr=FUUR~wtH(8-&9JfQf)ZkD)Z3EPjR rE?#+GKj`w*>ES;-%IZWKJQSOSTdS%o+kJIqr28jNnL2F>CxbNrH%~=^ literal 0 HcmV?d00001 diff --git a/icon/frame_20_delay-0.06s.gif b/icon/frame_20_delay-0.06s.gif new file mode 100644 index 0000000000000000000000000000000000000000..ca2aeb3116b9a53a0bf01820a5c45074b93fb995 GIT binary patch literal 195 zcmZ?wbhEHbRA5kG_{6~A>FJr4md3!qaD##2|Ns9$1_UVn=k{|A33hf2a5d61U}gl0 zD*j|)U}N~tpaW6?($2tK>apw2KZ8@At3@rcb7yiSXf!!(uSt%Y#WJgFbthAa@8leA zCg=Ce7T3;v=RQ?-M9x6qHP7VJ&saH4tyUh%csFyaAM+lq;%?o(*3_lj51D%3T)1Jj p%=XNS`VzMLm+g4vo$jvL*c4tFJr4md3!qaD##2|Ns9$1_UVn=k{|A33hf2a5d61U}gl0 zD*j|)U}N~tpaW6?($2tK=dtU~KZ8@A+M*V(=dR^Q(CBM?Ffk(|EWT@9ILDciweu7V z-u&UaqZ7IQJM%%cwGDYMn2!~mSthu=hp$WZ)uc{auSvHP!?R`C7Y2UbJgZEp_3cYZ y-LiUj)7dp|g({UjYs(rmOjPOx8kHjILYk^;nmQU}rb>v-m^o|qoVhbO8LR>7!AXt) literal 0 HcmV?d00001 diff --git a/patch_ndsheader_dsiware.py b/patch_ndsheader_dsiware.py new file mode 100644 index 0000000..ad816a5 --- /dev/null +++ b/patch_ndsheader_dsiware.py @@ -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="