From 40188fe6694895e0bc82d46814391c31bfc5f3ba Mon Sep 17 00:00:00 2001 From: LiquidFenrir Date: Thu, 27 Apr 2017 22:15:00 +0200 Subject: [PATCH 1/2] this was needed ? --- source/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/main.c b/source/main.c index c62576e..8b2f838 100644 --- a/source/main.c +++ b/source/main.c @@ -107,6 +107,9 @@ int main() { ret = CFG_SetConfigInfoBlk8(CFG_WIFI_SLOT_SIZE, CFG_WIFI_BLKID+selected_slot, wifiblk); if (ret) printf("CFG_GetConfigInfoBlk8\nresult: 0x%08x\n", (unsigned int)ret); + ret = CFG_UpdateConfigNANDSavegame(); + if (ret) printf("CFG_UpdateConfigNANDSavegame\nresult: 0x%08x\n", (unsigned int)ret); + memset(wifiblk, 0x0, CFG_WIFI_SLOT_SIZE); puts("done"); From 4fa4f5bffb88ba834338958038fdcc2ae873b142 Mon Sep 17 00:00:00 2001 From: LiquidFenrir Date: Fri, 7 Jul 2017 00:35:05 +0200 Subject: [PATCH 2/2] huge rewrite, finally working --- LICENSE.txt | 21 +++++ Makefile | 75 ++++++++-------- README.md | 12 +++ app.rsf | 3 +- source/basic.h | 8 ++ source/blocks.c | 23 +++++ source/blocks.h | 71 +++++++++++++++ source/checksum.h | 63 ++++++++++++++ source/crc16.c | 112 ++++++++++++++++++++++++ source/filebrowser/common.h | 16 ++++ source/filebrowser/dir.c | 24 +++++ source/filebrowser/dir.h | 3 + source/filebrowser/draw.c | 46 ++++++++++ source/filebrowser/draw.h | 3 + source/filebrowser/filebrowser.c | 85 ++++++++++++++++++ source/filebrowser/filebrowser.h | 6 ++ source/filebrowser/sort.c | 24 +++++ source/filebrowser/sort.h | 3 + source/main.c | 145 +++++++++++-------------------- source/save.c | 15 ++++ source/save.h | 6 ++ source/stringutils.c | 21 +++++ source/stringutils.h | 5 ++ 23 files changed, 660 insertions(+), 130 deletions(-) create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 source/basic.h create mode 100644 source/blocks.c create mode 100644 source/blocks.h create mode 100644 source/checksum.h create mode 100644 source/crc16.c create mode 100644 source/filebrowser/common.h create mode 100644 source/filebrowser/dir.c create mode 100644 source/filebrowser/dir.h create mode 100644 source/filebrowser/draw.c create mode 100644 source/filebrowser/draw.h create mode 100644 source/filebrowser/filebrowser.c create mode 100644 source/filebrowser/filebrowser.h create mode 100644 source/filebrowser/sort.c create mode 100644 source/filebrowser/sort.h create mode 100644 source/save.c create mode 100644 source/save.h create mode 100644 source/stringutils.c create mode 100644 source/stringutils.h diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..52c4186 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 LiquidFenrir + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile index 88333ce..5454a8b 100644 --- a/Makefile +++ b/Makefile @@ -9,24 +9,25 @@ endif TOPDIR ?= $(CURDIR) include $(DEVKITARM)/3ds_rules -APP_TITLE := WifiManager -APP_DESCRIPTION := wifi slot saving/restore test -APP_AUTHOR := LiquidFenrir +APP_TITLE := WifiManager +APP_DESCRIPTION := Backup and restore your WiFi slots! +APP_AUTHOR := LiquidFenrir -ICON := icon.png +TARGET := $(notdir $(CURDIR)) +OUTDIR := out +BUILD := build +SOURCES := source source/filebrowser +INCLUDES := include -PRODUCT_CODE := CTR-P-WIFI -UNIQUE_ID := 0x05DC9 +ICON := icon.png +ICON_FLAGS := visible,nosavebackups -BANNER_AUDIO := audio.wav -BANNER_IMAGE := banner.png +BANNER_AUDIO := audio.wav +BANNER_IMAGE := banner.png -TARGET := $(notdir $(CURDIR)) -BUILD := build -SOURCES := source -DATA := data -INCLUDES := include -#ROMFS := romfs +RSF_PATH := app.rsf +PRODUCT_CODE := CTR-P-WIFI +UNIQUE_ID := 0x05DC9 #--------------------------------------------------------------------------------- # options for code generation @@ -37,7 +38,7 @@ CFLAGS := -g -Wall -Wextra -O2 -mword-relocations \ -fomit-frame-pointer -ffunction-sections \ $(ARCH) -CFLAGS += $(INCLUDE) -DARM11 -D_3DS -D_GNU_SOURCE +CFLAGS += $(INCLUDE) -DARM11 -D_3DS CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 @@ -60,7 +61,7 @@ LIBDIRS := $(CTRULIB) ifneq ($(BUILD),$(notdir $(CURDIR))) #--------------------------------------------------------------------------------- -export OUTPUT := $(CURDIR)/$(TARGET) +export OUTPUT := $(CURDIR)/$(OUTDIR)/$(TARGET) export TOPDIR := $(CURDIR) export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ @@ -113,39 +114,48 @@ else endif ifeq ($(strip $(NO_SMDH)),) - export _3DSXFLAGS += --smdh=$(CURDIR)/$(TARGET).smdh + export _3DSXFLAGS += --smdh=$(OUTPUT).smdh endif ifneq ($(ROMFS),) export _3DSXFLAGS += --romfs=$(CURDIR)/$(ROMFS) endif -.PHONY: $(BUILD) clean all 3dsx cia +.PHONY: $(BUILD) clean all #--------------------------------------------------------------------------------- +3dsx: $(BUILD) $(OUTPUT).3dsx + +cia : $(BUILD) $(OUTPUT).cia + all: 3dsx cia -3dsx: $(BUILD) -cia : $(OUTPUT).cia $(BUILD): - @[ -d $@ ] || mkdir -p $@ + @mkdir -p $(OUTDIR) + @[ -d "$@" ] || mkdir -p "$@" @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile #--------------------------------------------------------------------------------- clean: @echo clean ... - @rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf + @rm -fr $(BUILD) $(OUTDIR) #--------------------------------------------------------------------------------- -MAKEROM ?= makerom +ifeq ($(strip $(NO_SMDH)),) +$(OUTPUT).3dsx : $(OUTPUT).elf $(OUTPUT).smdh +else +$(OUTPUT).3dsx : $(OUTPUT).elf +endif -$(OUTPUT).cia: $(OUTPUT).elf $(BUILD)/banner.bnr $(BUILD)/icon.icn - $(MAKEROM) -f cia -o $@ -elf $< -rsf $(CURDIR)/app.rsf -target t -exefslogo -banner $(BUILD)/banner.bnr -icon $(BUILD)/icon.icn -DAPP_TITLE="$(APP_TITLE)" -DPRODUCT_CODE="$(PRODUCT_CODE)" -DUNIQUE_ID="$(UNIQUE_ID)" +MAKEROM ?= makerom + +%.cia: $(OUTPUT).elf $(BUILD)/banner.bnr $(BUILD)/icon.icn + $(MAKEROM) -f cia -o "$@" -elf "$(OUTPUT).elf" -rsf "$(RSF_PATH)" -target t -exefslogo -banner "$(BUILD)/banner.bnr" -icon "$(BUILD)/icon.icn" -DAPP_TITLE="$(APP_TITLE)" -DAPP_PRODUCT_CODE="$(PRODUCT_CODE)" -DAPP_UNIQUE_ID="$(UNIQUE_ID)" # Banner -BANNERTOOL ?= bannertool +BANNERTOOL ?= bannertool ifeq ($(suffix $(BANNER_IMAGE)),.cgfx) BANNER_IMAGE_ARG := -ci @@ -159,11 +169,11 @@ else BANNER_AUDIO_ARG := -a endif -$(BUILD)/%.bnr: $(BANNER_IMAGE) $(BANNER_AUDIO) - $(BANNERTOOL) makebanner $(BANNER_IMAGE_ARG) $(BANNER_IMAGE) $(BANNER_AUDIO_ARG) $(BANNER_AUDIO) -o $@ +$(BUILD)/%.bnr : $(BANNER_IMAGE) $(BANNER_AUDIO) + $(BANNERTOOL) makebanner $(BANNER_IMAGE_ARG) "$(BANNER_IMAGE)" $(BANNER_AUDIO_ARG) "$(BANNER_AUDIO)" -o "$@" -$(BUILD)/%.icn: $(ICON) - $(BANNERTOOL) makesmdh -s "$(APP_TITLE)" -l "$(APP_DESCRIPTION)" -p "$(APP_AUTHOR)" -i $(ICON) -f visible,nosavebackups -o $@ +$(BUILD)/%.icn : $(ICON) + $(BANNERTOOL) makesmdh -s "$(APP_TITLE)" -l "$(APP_DESCRIPTION)" -p "$(APP_AUTHOR)" -i "$(ICON)" -f "$(ICON_FLAGS)" -o "$@" #--------------------------------------------------------------------------------- else @@ -173,11 +183,6 @@ DEPENDS := $(OFILES:.o=.d) #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- -ifeq ($(strip $(NO_SMDH)),) -$(OUTPUT).3dsx : $(OUTPUT).elf $(OUTPUT).smdh -else -$(OUTPUT).3dsx : $(OUTPUT).elf -endif $(OUTPUT).elf : $(OFILES) diff --git a/README.md b/README.md new file mode 100644 index 0000000..6eb7277 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# WifiManager + +WifiManager is a simple 3ds homebrew meant to help you backup and restore your console's WiFi slots. +It could prove useful if you travel a lot and need to connect to new wifi networks all the time, or if only 3 slots is really too few for you. + +## CRC + +WifiManager uses `include/checksum.h` and `src/crc16.c` from [libcrc 2.0](https://github.com/lammertb/libcrc/tree/v2.0) by lammertb, licensed under the MIT license, which were modified to remove the functions and data unused by this application. + +# License + +WifiManager is licensed under the MIT license, a copy of which can be found in the `LICENSE.txt` file. diff --git a/app.rsf b/app.rsf index 7132cc1..9933663 100644 --- a/app.rsf +++ b/app.rsf @@ -4,7 +4,7 @@ BasicInfo: Logo : Homebrew TitleInfo: - Category : $(APP_CATEGORY) + Category : Application UniqueId : $(APP_UNIQUE_ID) Option: @@ -231,7 +231,6 @@ AccessControlInfo: - news:s - nwm::EXT - nwm::UDS - - nwm::SOC - ptm:sysm - ptm:u - pxi:dev diff --git a/source/basic.h b/source/basic.h new file mode 100644 index 0000000..8266987 --- /dev/null +++ b/source/basic.h @@ -0,0 +1,8 @@ +#pragma once + +#include <3ds.h> + +#include +#include +#include +#include diff --git a/source/blocks.c b/source/blocks.c new file mode 100644 index 0000000..a71e420 --- /dev/null +++ b/source/blocks.c @@ -0,0 +1,23 @@ +#include "blocks.h" +#include "checksum.h" + +Result getWifiSlot(int selected_slot, wifiBlock * slotData) +{ + Result ret = CFG_GetConfigInfoBlk8(CFG_WIFI_SLOT_SIZE, CFG_WIFI_BLKID+selected_slot, (u8*)slotData); + if (ret) printf("CFG_GetConfigInfoBlk8\nresult: 0x%.8lx\n", ret); + return ret; +} + +Result setWifiSlot(int selected_slot, wifiBlock * slotData) +{ + Result ret = CFG_SetConfigInfoBlk8(CFG_WIFI_SLOT_SIZE, CFG_WIFI_BLKID+selected_slot, (u8*)slotData); + if (ret) printf("CFG_GetConfigInfoBlk8\nresult: 0x%.8lx\n", ret); + return ret; +} + +void fixSlotCRC(wifiBlock * slotData) +{ + printf("Previous CRC-16 checksum: %.4X\n", slotData->checksum); + slotData->checksum = crc_16((u8*)(&(slotData->network)), 0x410); + printf("New CRC-16 checksum: %.4X\n", slotData->checksum); +} diff --git a/source/blocks.h b/source/blocks.h new file mode 100644 index 0000000..07f327a --- /dev/null +++ b/source/blocks.h @@ -0,0 +1,71 @@ +#pragma once + +#include "basic.h" + +#define CFG_WIFI_BLKID (u32 )0x00080000 +#define CFG_WIFI_SLOTS 3 +#define CFG_WIFI_SLOT_SIZE (u32 )0xC00 + +typedef struct { + bool exists; + bool use; + bool second; + u8 padding1; + char SSID[0x20]; + u8 SSID_length; + u8 AP_encryption_type; + u16 padding2; + char password[0x40]; //plaintext, blank for a network set up with WPS + u8 passwordPSK[0x20]; +} networkStruct; + +typedef struct { + bool exists; + u8 padding1; + u16 checksum; //crc-16 of the next 0x410 bytes, with initval 0: https://github.com/lammertb/libcrc/blob/v2.0/src/crc16.c#L43-L76 + //if the network is set "normally", 'use' is 1 + //if the network is set by WPS, 'use' is 0 + //'second' is 0 + //if setting multiple networks with WPS in the same session, only the last set will have this. others will have completely 0x00 except for 'exists' + networkStruct network; + u8 padding2[0x20]; + //completely 0x00 if the network was set "normally", otherwise (set by WPS) normal but 'use' and 'second' are 1 + networkStruct network_WPS; + u8 padding3[0x20C]; + + bool auto_obtain_IP; //defaults to 1 + bool auto_obtain_DNS; //defaults to 1 + u16 padding4; + + u8 IP_address[4]; + u8 gateway_address[4]; + u8 subnet_mask[4]; + + u8 primary_DNS[4]; + u8 secondary_DNS[4]; + + // if setting multiple networks in the same session, only the last set will have these. others will have completely 0x00 + u8 unk1[4]; + u8 IP_to_use[4]; + u8 MAC_address[6]; + u8 channel; + u8 padding5; + + bool use_proxy; //defaults to 0 + bool basic_authentication; //defaults to 0 + u16 port_number; //defaults to 1 + char proxy_address[0x30]; //including ending nullbyte + u8 padding6[0x34]; + char proxy_username[0x20]; //including ending nullbyte + char proxy_password[0x20]; //including ending nullbyte + u16 padding7; + u16 MTU_value; //defaults to 1400, range [576;1500] + + //nothing beyond this point (0x414), but each slot is 0xC00 big... + u8 padding8[0x7EC]; +} wifiBlock; + +Result getWifiSlot(int selected_slot, wifiBlock * slotData); +Result setWifiSlot(int selected_slot, wifiBlock * slotData); + +void fixSlotCRC(wifiBlock * slotData); diff --git a/source/checksum.h b/source/checksum.h new file mode 100644 index 0000000..187bf69 --- /dev/null +++ b/source/checksum.h @@ -0,0 +1,63 @@ +/* + * Library: libcrc + * File: include/checksum.h + * Author: Lammert Bies + * + * This file is licensed under the MIT License as stated below + * + * Copyright (c) 1999-2016 Lammert Bies + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Description + * ----------- + * The headerfile include/checksum.h contains the definitions and prototypes + * for routines that can be used to calculate several kinds of checksums. + */ + +#ifndef DEF_LIBCRC_CHECKSUM_H +#define DEF_LIBCRC_CHECKSUM_H + +#include + +/* + * #define CRC_POLY_xxxx + * + * The constants of the form CRC_POLY_xxxx define the polynomials for some well + * known CRC calculations. + */ + +#define CRC_POLY_16 0xA001 + +/* + * #define CRC_START_xxxx + * + * The constants of the form CRC_START_xxxx define the values that are used for + * initialization of a CRC value for common used calculation methods. + */ + +#define CRC_START_16 0x0000 + +/* + * Prototype list of global functions + */ + +uint16_t crc_16( const unsigned char *input_str, size_t num_bytes ); + +#endif // DEF_LIBCRC_CHECKSUM_H diff --git a/source/crc16.c b/source/crc16.c new file mode 100644 index 0000000..d4c8e5a --- /dev/null +++ b/source/crc16.c @@ -0,0 +1,112 @@ +/* + * Library: libcrc + * File: src/crc16.c + * Author: Lammert Bies + * + * This file is licensed under the MIT License as stated below + * + * Copyright (c) 1999-2016 Lammert Bies + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Description + * ----------- + * The source file src/crc16.c contains routines which calculate the common + * CRC16 cyclic redundancy check values for an incomming byte string. + */ + +#include +#include +#include "checksum.h" + +static void init_crc16_tab( void ); + +static bool crc_tab16_init = false; +static uint16_t crc_tab16[256]; + +/* + * uint16_t crc_16( const unsigned char *input_str, size_t num_bytes ); + * + * The function crc_16() calculates the 16 bits CRC16 in one pass for a byte + * string of which the beginning has been passed to the function. The number of + * bytes to check is also a parameter. The number of the bytes in the string is + * limited by the constant SIZE_MAX. + */ + +uint16_t crc_16( const unsigned char *input_str, size_t num_bytes ) { + + uint16_t crc; + uint16_t tmp; + uint16_t short_c; + const unsigned char *ptr; + size_t a; + + if ( ! crc_tab16_init ) init_crc16_tab(); + + crc = CRC_START_16; + ptr = input_str; + + if ( ptr != NULL ) for (a=0; a> 8) ^ crc_tab16[ tmp & 0xff ]; + + ptr++; + } + + return crc; + +} /* crc_16 */ + +/* + * static void init_crc16_tab( void ); + * + * For optimal performance uses the CRC16 routine a lookup table with values + * that can be used directly in the XOR arithmetic in the algorithm. This + * lookup table is calculated by the init_crc16_tab() routine, the first time + * the CRC function is called. + */ + +static void init_crc16_tab( void ) { + + uint16_t i; + uint16_t j; + uint16_t crc; + uint16_t c; + + for (i=0; i<256; i++) { + + crc = 0; + c = i; + + for (j=0; j<8; j++) { + + if ( (crc ^ c) & 0x0001 ) crc = ( crc >> 1 ) ^ CRC_POLY_16; + else crc = crc >> 1; + + c = c >> 1; + } + + crc_tab16[i] = crc; + } + + crc_tab16_init = true; + +} /* init_crc16_tab */ diff --git a/source/filebrowser/common.h b/source/filebrowser/common.h new file mode 100644 index 0000000..f73fe38 --- /dev/null +++ b/source/filebrowser/common.h @@ -0,0 +1,16 @@ +#pragma once + +#include <3ds.h> +#include +#include +#include +#include +#include + +// according to wikipedia, the max FAT32 path length is 255 UTF-16 characters, so 0xFF * 2 (because the 16 in UTF-16 means 16 bits = 2 bytes) (shifting left of 1 is the same as multiplying by 2) +#define MAX_PATH_LEN (0xFF << 1) + +typedef struct { + char name[MAX_PATH_LEN+1]; + bool isFile; +} dirInfo; diff --git a/source/filebrowser/dir.c b/source/filebrowser/dir.c new file mode 100644 index 0000000..6b83e56 --- /dev/null +++ b/source/filebrowser/dir.c @@ -0,0 +1,24 @@ +#include +#include "dir.h" + +int listdir(char * path, dirInfo * dirInfoArray) +{ + DIR *dir; + struct dirent *ent; + int count = 2; + strncpy(dirInfoArray[0].name, "..", MAX_PATH_LEN); + dirInfoArray[0].isFile = false; + strncpy(dirInfoArray[1].name, ".", MAX_PATH_LEN); + dirInfoArray[1].isFile = true; + + if ((dir = opendir(path)) != NULL) { + while ((ent = readdir(dir)) != NULL) { + strncpy(dirInfoArray[count].name, ent->d_name, MAX_PATH_LEN); + dirInfoArray[count].isFile = (ent->d_type == 8); + count++; + } + closedir (dir); + } + + return count; +} diff --git a/source/filebrowser/dir.h b/source/filebrowser/dir.h new file mode 100644 index 0000000..a85c933 --- /dev/null +++ b/source/filebrowser/dir.h @@ -0,0 +1,3 @@ +#include "common.h" + +int listdir(char * path, dirInfo * dirInfoArray); diff --git a/source/filebrowser/draw.c b/source/filebrowser/draw.c new file mode 100644 index 0000000..b06aa0e --- /dev/null +++ b/source/filebrowser/draw.c @@ -0,0 +1,46 @@ +#include "draw.h" + +//width in characters of the screen you're drawing on. 50 for the top screen, 40 for bottom +#define SCREEN_WIDTH 50 +#define SCREEN_HEIGHT 30 + +#define OFFSET 1 //offset in characters of the file list from the location bar + +#define MAX_ENTRIES_PER_SCREEN (SCREEN_HEIGHT-1-OFFSET*2) + +static int scroll = 0; + +static char uparrow[] = {30, 0}; +static char downarrow[] = {31, 0}; + +void drawDirList(dirInfo * dirInfoArray, char * currentPath, int currentDir, int dirCount) +{ + consoleClear(); + if (strlen(currentPath) <= SCREEN_WIDTH) printf("\x1b[0;0H\x1b[47;30m%s\x1b[0m", currentPath); + else printf("\x1b[0;0H\x1b[47;30m...%s\x1b[0m", ¤tPath[strlen(currentPath)-SCREEN_WIDTH+3]); + + if (currentDir == 0) { + scroll = 0; + } + else if ((dirCount > MAX_ENTRIES_PER_SCREEN) && (currentDir == dirCount-1)) { + scroll = dirCount - MAX_ENTRIES_PER_SCREEN; + } + else if (currentDir >= (MAX_ENTRIES_PER_SCREEN + scroll)) { + scroll++; + } + else if ((currentDir - scroll) < 0) { + scroll--; + } + + if (scroll != 0) printf("\x1b[%i;0H%s", OFFSET+1, uparrow); + + if ((dirCount > MAX_ENTRIES_PER_SCREEN) && scroll != (dirCount - MAX_ENTRIES_PER_SCREEN)) printf("\x1b[%i;0H%s", MAX_ENTRIES_PER_SCREEN+OFFSET, downarrow); + + for (int i = scroll; (i-scroll) < MAX_ENTRIES_PER_SCREEN; i++) { + //selected dir has white background, others have black + int bgcolor = (i == currentDir) ? 47 : 40; + //if it's a file, it has a blue name. otherwise, reverse of background + int txtcolor = (dirInfoArray[i].isFile) ? 36 : ((i == currentDir) ? 30 : 37); + if (dirInfoArray[i].name != NULL) printf("\x1b[%i;2H\x1b[%i;%im%s\x1b[0m", i+OFFSET+1-scroll, bgcolor, txtcolor, dirInfoArray[i].name); + } +} diff --git a/source/filebrowser/draw.h b/source/filebrowser/draw.h new file mode 100644 index 0000000..edfc2fe --- /dev/null +++ b/source/filebrowser/draw.h @@ -0,0 +1,3 @@ +#include "common.h" + +void drawDirList(dirInfo * dirInfoArray, char * currentPath, int currentDir, int dirCount); diff --git a/source/filebrowser/filebrowser.c b/source/filebrowser/filebrowser.c new file mode 100644 index 0000000..04ffe4e --- /dev/null +++ b/source/filebrowser/filebrowser.c @@ -0,0 +1,85 @@ +#include "common.h" +#include "dir.h" +#include "draw.h" +#include "sort.h" + +static char currentPath[MAX_PATH_LEN+1]; //for the ending nullbyte + +static dirInfo dirInfoArray[256]; +static int dirCount = 0; +static int currentDir = 0; + +char * filebrowser(char * startDir) { + chdir(startDir); + + goto change; + + while (aptMainLoop()) { + + //things in there will only run if you do a goto + //otherwise the screen would flicker because of constantly clearing + if (false) { + change: + currentDir = 0; + getcwd(currentPath, MAX_PATH_LEN+1); + dirCount = listdir(currentPath, dirInfoArray); + for (int i = dirCount; i < 256; i++) { + dirInfoArray[i].name[0] = 0; + dirInfoArray[i].isFile = false; + } + sortDirList(&dirInfoArray[2], dirCount-2); + + draw: + if (currentDir > dirCount-1) currentDir = dirCount-1; + if (currentDir < 0) currentDir = 0; + drawDirList(dirInfoArray, currentPath, currentDir, dirCount); + gfxFlushBuffers(); + gfxSwapBuffers(); + gspWaitForVBlank(); + } + + hidScanInput(); + + if (hidKeysDown() & KEY_START) { + break; + } + else if (hidKeysDown() & KEY_A) { + if (dirInfoArray[currentDir].isFile) { + //return the path to the file + char fullPath[MAX_PATH_LEN+1]; + sprintf(fullPath, "%s%s", currentPath, dirInfoArray[currentDir].name); + return strdup(fullPath); + } + else { + chdir(dirInfoArray[currentDir].name); + goto change; + } + } + else if (hidKeysDown() & KEY_B) { + chdir(".."); + goto change; + } + else if (hidKeysDown() & KEY_LEFT) { + currentDir = 0; + goto draw; + } + else if (hidKeysDown() & KEY_RIGHT) { + currentDir = dirCount-1; + goto draw; + } + else if (hidKeysDown() & KEY_UP) { + currentDir--; + goto draw; + } + else if (hidKeysDown() & KEY_DOWN) { + currentDir++; + goto draw; + } + + gfxFlushBuffers(); + gfxSwapBuffers(); + gspWaitForVBlank(); + } + + return NULL; +} diff --git a/source/filebrowser/filebrowser.h b/source/filebrowser/filebrowser.h new file mode 100644 index 0000000..93f6178 --- /dev/null +++ b/source/filebrowser/filebrowser.h @@ -0,0 +1,6 @@ +#ifndef FILEBROWSER_H_ +#define FILEBROWSER_H_ + +char * filebrowser(char * startDir); + +#endif diff --git a/source/filebrowser/sort.c b/source/filebrowser/sort.c new file mode 100644 index 0000000..fdd486f --- /dev/null +++ b/source/filebrowser/sort.c @@ -0,0 +1,24 @@ +#include "sort.h" + +int checkSorted(const void * a, const void * b) +{ + dirInfo * entryA = (dirInfo *)a; + dirInfo * entryB = (dirInfo *)b; + + if ((entryA->isFile && entryB->isFile) || (!entryA->isFile && !entryB->isFile)) { + return strcmp(entryA->name, entryB->name); + } + else if (entryA->isFile) { + return 1; + } + else if (entryB->isFile) { + return -1; + } + + return 0; +} + +void sortDirList(dirInfo * dirInfoArrayArray, int dirCount) +{ + qsort(dirInfoArrayArray, dirCount, sizeof(dirInfo), &checkSorted); +} diff --git a/source/filebrowser/sort.h b/source/filebrowser/sort.h new file mode 100644 index 0000000..d63f267 --- /dev/null +++ b/source/filebrowser/sort.h @@ -0,0 +1,3 @@ +#include "common.h" + +void sortDirList(dirInfo * dirInfoArrayArray, int dirCount); diff --git a/source/main.c b/source/main.c index 8b2f838..0860484 100644 --- a/source/main.c +++ b/source/main.c @@ -1,69 +1,28 @@ -#include <3ds.h> -#include -#include -#include -#include +#include "blocks.h" +#include "save.h" +#include "stringutils.h" +#include "filebrowser/filebrowser.h" -#define WORKDIR "/3ds/WifiManager/" - -#define CFG_WIFI_BLKID (u32 )0x00080000 -#define CFG_WIFI_SLOTS 3 -#define CFG_WIFI_SLOT_SIZE (u32 )0xC00 - -Result ret; - -void loadFileToBuf(u8 * buf, u32 size, const char * path) -{ - printf("Load %s to buf\n", path); - - FILE * fh = fopen(path, "rb"); - - fread(buf, size, 1, fh); - - fclose(fh); - - puts("done"); -} - -void saveBufToFile(u8 * buf, u32 size, const char * path) -{ - printf("Saving buf to %s\n", path); - - FILE * fh = fopen(path, "wb"); - - fwrite(buf, size, 1, fh); - - fclose(fh); - - puts("done"); -} +#define WORKING_DIR "/3ds/WifiManager/" int main() { - chdir(WORKDIR); + chdir(WORKING_DIR); gfxInitDefault(); - consoleInit(GFX_TOP, NULL); + PrintConsole topScreen, bottomScreen; + consoleInit(GFX_TOP, &topScreen); + consoleInit(GFX_BOTTOM, &bottomScreen); - puts("init"); - - ret = cfguInit(); + Result ret = cfguInit(); if (ret) printf("cfguInit\nresult: 0x%08x\n", (unsigned int)ret); - puts("done"); - - puts("mallocing"); - - u8 * wifiblk = malloc(CFG_WIFI_SLOT_SIZE); - memset(wifiblk, 0x0, CFG_WIFI_SLOT_SIZE); - - puts("done"); - - u32 selected_slot = 0; + int selected_slot = 0; puts("Press A to save current slot to file"); puts("Press B to restore current slot from file"); - puts("Press START to quit"); + puts("Press START to quit (reboot)"); + printf("Selected slot: %i\n", selected_slot); while (aptMainLoop()) { @@ -71,60 +30,59 @@ int main() { if (hidKeysDown() & KEY_START) break; else if (hidKeysDown() & KEY_A) - { - puts("getting"); + { + printf("Saving WiFi slot %i...\n", selected_slot); + wifiBlock slotData; + ret = getWifiSlot(selected_slot, &slotData); - ret = CFG_GetConfigInfoBlk8(CFG_WIFI_SLOT_SIZE, CFG_WIFI_BLKID+selected_slot, wifiblk); - if (ret) printf("CFG_GetConfigInfoBlk8\nresult: 0x%08x\n", (unsigned int)ret); - else { - - printf("Slot %lu SSID is '%s' and password is '%s'\n", selected_slot, wifiblk+0x8, wifiblk+0x2C); - - puts("saving"); - - char * filename = NULL; - asprintf(&filename, "wifiblk_%lu.bin", selected_slot); - saveBufToFile(wifiblk, CFG_WIFI_SLOT_SIZE, filename); - free(filename); - memset(wifiblk, 0x0, CFG_WIFI_SLOT_SIZE); - } + char * suffix = "_wifislot.bin"; + char filename[0x20+strlen(suffix)+1]; + strcpy(filename, "Empty slot"); + + if (slotData.network.use) strncpy(filename, slotData.network.SSID, 0x20); + else if (slotData.network_WPS.use) strncpy(filename, slotData.network_WPS.SSID, 0x20); - puts("done"); + strcat(filename, suffix); + cleanPath(filename); + printf("Saving slot to %s%s...", WORKING_DIR, filename); + saveBufToFile((u8*)&slotData, CFG_WIFI_SLOT_SIZE, filename); + printf("Done!\n"); } else if (hidKeysDown() & KEY_B) - { - puts("loading"); - - char * filename = NULL; - asprintf(&filename, "wifiblk_%lu.bin", selected_slot); - loadFileToBuf(wifiblk, CFG_WIFI_SLOT_SIZE, filename); - free(filename); - - printf("Slot %lu SSID is '%s' and password is '%s'\n", selected_slot, wifiblk+0x8, wifiblk+0x2C); + { + printf("Restoring WiFi slot %i...\n", selected_slot); - puts("setting"); + consoleSelect(&topScreen); + char * filepath = filebrowser(WORKING_DIR); + consoleSelect(&bottomScreen); + if (filepath == NULL) { + printf("Cancelling restore...\n"); + continue; + } - ret = CFG_SetConfigInfoBlk8(CFG_WIFI_SLOT_SIZE, CFG_WIFI_BLKID+selected_slot, wifiblk); - if (ret) printf("CFG_GetConfigInfoBlk8\nresult: 0x%08x\n", (unsigned int)ret); + printf("Loading data from:\n%s\nto WiFi slot %i\n", filepath, selected_slot); + wifiBlock slotData; + loadFileToBuf((u8*)&slotData, CFG_WIFI_SLOT_SIZE, filepath); + free(filepath); + fixSlotCRC(&slotData); + ret = setWifiSlot(selected_slot, &slotData); + printf("Saving config savegame...\n"); ret = CFG_UpdateConfigNANDSavegame(); - if (ret) printf("CFG_UpdateConfigNANDSavegame\nresult: 0x%08x\n", (unsigned int)ret); - - memset(wifiblk, 0x0, CFG_WIFI_SLOT_SIZE); - - puts("done"); + if (ret) printf("CFG_UpdateConfigNANDSavegame\nresult: 0x%.8lx\n", ret); + printf("Done!\n"); } else if (hidKeysDown() & KEY_UP) { selected_slot++; if (selected_slot >= CFG_WIFI_SLOTS) selected_slot = CFG_WIFI_SLOTS-1; - printf("Selected slot: %lu\n", selected_slot); + printf("Selected slot: %i\n", selected_slot); } else if (hidKeysDown() & KEY_DOWN) { selected_slot--; - if (selected_slot >= CFG_WIFI_SLOTS) selected_slot = 0; - printf("Selected slot: %lu\n", selected_slot); + if (selected_slot < 0) selected_slot = 0; + printf("Selected slot: %i\n", selected_slot); } gfxFlushBuffers(); @@ -133,9 +91,10 @@ int main() { gspWaitForVBlank(); } - free(wifiblk); - cfguExit(); gfxExit(); + + APT_HardwareResetAsync(); + return 0; } diff --git a/source/save.c b/source/save.c new file mode 100644 index 0000000..b56ee94 --- /dev/null +++ b/source/save.c @@ -0,0 +1,15 @@ +#include "save.h" + +void loadFileToBuf(u8 * buf, u32 size, const char * path) +{ + FILE * fh = fopen(path, "rb"); + fread(buf, size, 1, fh); + fclose(fh); +} + +void saveBufToFile(u8 * buf, u32 size, const char * path) +{ + FILE * fh = fopen(path, "wb"); + fwrite(buf, size, 1, fh); + fclose(fh); +} diff --git a/source/save.h b/source/save.h new file mode 100644 index 0000000..d3358c3 --- /dev/null +++ b/source/save.h @@ -0,0 +1,6 @@ +#pragma once + +#include "basic.h" + +void loadFileToBuf(u8 * buf, u32 size, const char * path); +void saveBufToFile(u8 * buf, u32 size, const char * path); diff --git a/source/stringutils.c b/source/stringutils.c new file mode 100644 index 0000000..2471cac --- /dev/null +++ b/source/stringutils.c @@ -0,0 +1,21 @@ +#include "stringutils.h" + +void cleanPath(char * path) +{ + for (int i = 0; path[i]; i++) { //replace all spaces and fat32 reserved characters in the path with underscores + switch (path[i]) { + case ' ': + case '"': + case '*': + case ':': + case '<': + case '>': + case '?': + case '\\': + case '|': + path[i] = '_'; + default: + break; + } + } +} diff --git a/source/stringutils.h b/source/stringutils.h new file mode 100644 index 0000000..801d322 --- /dev/null +++ b/source/stringutils.h @@ -0,0 +1,5 @@ +#pragma once + +#include "basic.h" + +void cleanPath(char * path);