diff --git a/include/bmp.hpp b/include/bmp.hpp index f2a19ea..6b064eb 100644 --- a/include/bmp.hpp +++ b/include/bmp.hpp @@ -27,4 +27,4 @@ typedef struct __attribute__((__packed__)) { void toDSPixelOrder(u8* store, u8* source); void convertImage(u8* store, u8* source); void convertColors(u16 palette[16], u32 BGR888_palette[16]); -Result loadBmpAsIcon(std::string filename, tNDSBanner* banner); \ No newline at end of file +Result loadBmpAsIcon(std::string filename, tNDSBannerEx* banner); \ No newline at end of file diff --git a/include/nds.h b/include/nds.h index c6b02d7..a5f557d 100644 --- a/include/nds.h +++ b/include/nds.h @@ -131,16 +131,12 @@ typedef struct __DSiHeader { } tDSiHeader; - -#define __NDSHeader ((tNDSHeader *)0x02FFFE00) -#define __DSiHeader ((tDSiHeader *)0x02FFE000) - - /*! \brief the NDS banner format. See gbatek for more information. */ -typedef struct sNDSBanner { + +typedef struct sNDSBannerEx { u16 version; //!< version of the banner. u16 crcv1; //!< 16 bit crc/checksum of the banner. u16 crcv2; //!< 16 bit crc/checksum of the banner. @@ -149,12 +145,21 @@ typedef struct sNDSBanner { u8 reserved[22]; u8 icon[512]; //!< 32*32 icon of the game with 4 bit per pixel. u16 palette[16]; //!< the pallete of the icon. - u16 titles[6][128]; //!< title of the game in 6 different languages. -} tNDSBanner; + u16 titles[16][128]; //!< title of the game in 6 different languages. extra 2+reserved come from extended format + u8 animated_icons[8][512]; // each unique frame has its own icon + u16 animated_palette[8][16]; // each icon has a palette ofc + u16 animated_animation[64]; // the animation instructions +} tNDSBannerEx; + + +#define NDS_BANNER_SIZE_v1 0xA00 +#define NDS_BANNER_SIZE_v2 0xA00 +#define NDS_BANNER_SIZE_v3 0xC00 // does this even exist +#define NDS_BANNER_SIZE_v103 0x23C0 /// this is my stuff vv void _DStoBMPorder(u8* store, u8 *source); void rotateInPlace90(u8 *source,u32 width,u32 height); -void convertIconToBmp(u16* bmp, tNDSBanner* banner ); +void convertIconToBmp(u16* bmp, tNDSBannerEx* banner ); Result LoadIconFromNDS(const char* filename, u16* output); diff --git a/include/settings.hpp b/include/settings.hpp index b433ffb..9161160 100644 --- a/include/settings.hpp +++ b/include/settings.hpp @@ -1,6 +1,6 @@ #pragma once -#define VERSION "v1.4.0" +#define VERSION "v1.4.1" //#define DEBUG 1 #define FORWARDER_DIR std::string("sdmc:/3ds/forwarder") diff --git a/source/bmp.cpp b/source/bmp.cpp index c873eec..6c2fae5 100644 --- a/source/bmp.cpp +++ b/source/bmp.cpp @@ -6,7 +6,7 @@ #include "lang.hpp" Logger bmplogger("BmpHandler"); -Result loadBmpAsIcon(std::string filename, tNDSBanner* banner) { +Result loadBmpAsIcon(std::string filename, tNDSBannerEx* banner) { BMPHeader bmpHeader={0}; std::ifstream f(filename); if (f.fail()) { diff --git a/source/builder.cpp b/source/builder.cpp index cf5690c..c234da1 100644 --- a/source/builder.cpp +++ b/source/builder.cpp @@ -1,4 +1,5 @@ #include <3ds.h> +#include "settings.hpp" #include "builder.hpp" #include #include @@ -13,7 +14,6 @@ #include "cia.h" #include "ticket.h" #include "bmp.hpp" -#include "settings.hpp" #include "lang.hpp" Logger logger("Builder"); @@ -105,9 +105,9 @@ std::string Builder::buildSRL(std::string filename, bool randomTid, std::string //TODO Load nds file tDSiHeader header = {}; // sNDSHeader header={}; - sNDSBanner banner={}; - char animatedIconData[0x1180] = {0}; - char extraTitles[2][0x100] = {0}; + sNDSBannerEx banner={}; + // char animatedIconData[0x1180] = {0}; + // char extraTitles[2][0x100] = {0}; const u8 noAnimation[] = {0x01,0x00,0x00,0x01}; std::string customBannerFilename = filename.substr(0,filename.find_last_of('.'))+".bin"; std::string customIconFilename = filename.substr(0,filename.find_last_of('.'))+".bmp"; @@ -154,55 +154,50 @@ std::string Builder::buildSRL(std::string filename, bool randomTid, std::string f.close(); return ""; } - f.seekg(header.ndshdr.bannerOffset); - f.read((char*)&banner,sizeof(banner)); - if ((banner.version & 0xFF) > 1) { - f.read(extraTitles[0],0x100); - }else{ - memcpy(extraTitles[0],(u8*)&banner.titles[0],0x100); - } - if ((banner.version & 0xFF) > 2) { - f.read(extraTitles[0],0x100); + u16 banner_version=1; + if (!customBanner) { + f.seekg(header.ndshdr.bannerOffset); }else{ - memcpy(extraTitles[1],(u8*)&banner.titles[0],0x100); + f.close(); + f.open(customBannerFilename); } - if ((banner.version & 0x100) > 0) { - f.seekg(header.ndshdr.bannerOffset+0x1240); - f.read(animatedIconData,0x1180); + f.read((char*)&banner_version,2); + f.seekg(0); + switch(banner_version) { + case 0x03: + f.read((char*)&banner,NDS_BANNER_SIZE_v3); + break; + case 0x103: + f.read((char*)&banner,NDS_BANNER_SIZE_v103); + break; + default: + f.read((char*)&banner,NDS_BANNER_SIZE_v1); + break; } - - f.close(); - if (customBanner==true) { - std::ifstream f(customBannerFilename); - f.read((char*)&banner,sizeof(banner)); - if ((banner.version & 0xFF) > 1) { - f.read(extraTitles[0],0x100); - }else{ - memcpy(extraTitles[0],(u8*)&banner.titles[0],0x100); - } - if ((banner.version & 0xFF) > 2) { - f.read(extraTitles[0],0x100); - }else{ - memcpy(extraTitles[1],(u8*)&banner.titles[0],0x100); - } - if ((banner.version & 0x100) > 0) { - f.seekg(0x1240); - f.read(animatedIconData,0x1180); - } - f.close(); - - } - // verify the banner (loaded or not) has valid crc - char* bnr = (char*)&banner; - u16 expectedCRC = crc16Modbus(bnr+0x20,0x820); + + // if ((banner.version & 0xFF) > 1) { + // f.read(extraTitles[0],0x100); + // }else{ + // memcpy(extraTitles[0],(u8*)&banner.titles[0],0x100); + // } + // if ((banner.version & 0xFF) > 2) { + // f.read(extraTitles[0],0x100); + // }else{ + // memcpy(extraTitles[1],(u8*)&banner.titles[0],0x100); + // } + // if ((banner.version & 0x100) > 0) { + // f.seekg(0x1240); + // f.read(animatedIconData,0x1180); + + u16 expectedCRC = crc16Modbus(&(banner.icon),0x820); if (expectedCRC != banner.crcv1) { logger.debug(gLang.parseString("debug_crc",banner.crcv1,expectedCRC)); logger.error(gLang.parseString("builder_invalidBannerCRC","1")); return ""; } if (banner.version > 1) { - expectedCRC = crc16Modbus(bnr+0x20,0x920); + expectedCRC = crc16Modbus(&(banner.icon),0x920); if (expectedCRC != banner.crcv2) { logger.debug(gLang.parseString("debug_crc",banner.crcv2,expectedCRC)); logger.error(gLang.parseString("builder_invalidBannerCRC","2")); @@ -210,7 +205,7 @@ std::string Builder::buildSRL(std::string filename, bool randomTid, std::string } } if (banner.version > 2) { - expectedCRC = crc16Modbus(bnr+0x20,0xA20); + expectedCRC = crc16Modbus(&(banner.icon),0xA20); if (expectedCRC != banner.crcv3) { logger.debug(gLang.parseString("debug_crc",banner.crcv3,expectedCRC)); logger.error(gLang.parseString("builder_invalidBannerCRC","3")); @@ -219,7 +214,7 @@ std::string Builder::buildSRL(std::string filename, bool randomTid, std::string } if ((banner.version & 0x100) > 0) { - expectedCRC = crc16Modbus(animatedIconData,0x1180); + expectedCRC = crc16Modbus(&(banner.animated_icons),0x1180); if (expectedCRC != banner.crcv103) { logger.debug(gLang.parseString("debug_crc",banner.crcv103,expectedCRC)); logger.error(gLang.parseString("builder_invalidBannerCRC","4")); @@ -248,33 +243,36 @@ std::string Builder::buildSRL(std::string filename, bool randomTid, std::string if (!customTitle.empty()) { uint16_t cTitle[0x80] = {0}; utf8_to_utf16(cTitle, (u8*)customTitle.c_str(), 0x80); - for(int i=0;i<6;i++) { + for(int i=0;i<8;i++) { memcpy(banner.titles[i], cTitle, 0x80 * sizeof(uint16_t)); } - for(int i=0;i<2;i++) { - memcpy(extraTitles[i], cTitle, 0x80 * sizeof(uint16_t)); - } + // for(int i=0;i<2;i++) { + // memcpy(extraTitles[i], cTitle, 0x80 * sizeof(uint16_t)); + // } } // Set header // could be 1 command but this is easier to read dsiware.replace(0,0x0C,header.ndshdr.gameTitle,0x0C); dsiware.replace(0x0C,0x04,header.ndshdr.gameCode,0x04); - char emagCode[] = {header.ndshdr.gameCode[0x03],header.ndshdr.gameCode[0x02],header.ndshdr.gameCode[0x01],header.ndshdr.gameCode[0x00]}; - if (extendedHeader) - dsiware.replace(0x230,0x04,emagCode,0x04); + char emagCode[0x04] = {}; + if (!extendedHeader) + memcpyrev(emagCode,header.ndshdr.gameCode,4); + else + memcpy(emagCode,(char*)&header.tid_low,4); + dsiware.replace(0x230,0x04,emagCode,0x04); dsiware.replace(0x10,0x02,header.ndshdr.makercode,0x02); // Set Banner // basic banner info dsiware.replace(this->srlBannerLocation+0x20,0x200,(char*)banner.icon,0x200); // icon dsiware.replace(this->srlBannerLocation+0x220,0x20,(char*)banner.palette,0x20); // palette - dsiware.replace(this->srlBannerLocation+0x240,0x600,(char*)banner.titles,0x600); // titles - dsiware.replace(this->srlBannerLocation+0x840,0x200,(char*)extraTitles,0x200); // titles + dsiware.replace(this->srlBannerLocation+0x240,0x600,(char*)banner.titles,0x800); // titles +// dsiware.replace(this->srlBannerLocation+0x840,0x200,(char*)banner.titles[0x07],0x200); // titles // dsiware.replace(this->srlBannerLocation,sizeof(banner),&banner,sizeof(banner)); // animated banner if ((banner.version & 0x100) > 0) { - dsiware.replace(this->srlBannerLocation + 0x1240,0x1180,animatedIconData,0x1180); + dsiware.replace(this->srlBannerLocation + 0x1240,0x1180,(char*)banner.animated_icons,0x1180); }else{ // fill all icon data with default // then replace animation sequence with static image diff --git a/source/nds.c b/source/nds.c index 66b4b77..7d60328 100644 --- a/source/nds.c +++ b/source/nds.c @@ -33,7 +33,7 @@ void _DStoBMPorder(u8* store, u8 *source) { store[1+x*2]=(tmp[x] >> 4) & 0xF; } } -void convertIconToBmp(u16* bmp, tNDSBanner* banner ) { +void convertIconToBmp(u16* bmp, tNDSBannerEx* banner ) { u8 store[0x400]={0}; _DStoBMPorder(store,banner->icon); rotateInPlace90(store,32,32); @@ -62,12 +62,12 @@ Result LoadIconFromNDS(const char* filename, u16* output) { return -1; } tNDSHeader* header = malloc(sizeof(tNDSHeader)); - tNDSBanner* banner=malloc(sizeof(tNDSBanner)); + tNDSBannerEx* banner=malloc(sizeof(tNDSBannerEx)); fread(header,sizeof(tNDSHeader),1,f); if (header->bannerOffset > 0) { fseek(f,header->bannerOffset,SEEK_SET); - fread(banner,sizeof(tNDSBanner),1,f); + fread(banner,NDS_BANNER_SIZE_v1,1,f); fclose(f); free(header); header=NULL;