Add nxlink support (#27)
* Add nxlink support * use libnx nro.h * make sure path doesn't overflow * convert indentation to spaces
This commit is contained in:
parent
e684bb1b71
commit
ebced71ec3
@ -53,7 +53,7 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
|||||||
ASFLAGS := -g $(ARCH)
|
ASFLAGS := -g $(ARCH)
|
||||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||||
|
|
||||||
LIBS := -lnx -lm
|
LIBS := -lnx -lm -lz
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# list of directories containing libraries, this must be the top level containing
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
@ -4,6 +4,10 @@ ifeq ($(strip $(HOST_OS)),Darwin)
|
|||||||
BIN2S_FLAGS := --apple-llvm
|
BIN2S_FLAGS := --apple-llvm
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring MINGW,$(HOST_OS)))
|
||||||
|
EXTRA_CFLAGS="-D__USE_MINGW_ANSI_STDIO"
|
||||||
|
EXTRA_LDFLAGS="-lws2_32"
|
||||||
|
endif
|
||||||
|
|
||||||
# canned command sequence for binary data
|
# canned command sequence for binary data
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
@ -18,11 +22,12 @@ test : pc_main/main.cpp pc_main/pc_launch.c \
|
|||||||
common/menu.c common/font.c common/language.c common/launch.c \
|
common/menu.c common/font.c common/language.c common/launch.c \
|
||||||
common/menu-entry.c common/menu-list.c common/message-box.c common/text.c \
|
common/menu-entry.c common/menu-list.c common/message-box.c common/text.c \
|
||||||
common/nanojpeg.c common/ui.c common/math.c common/theme.c \
|
common/nanojpeg.c common/ui.c common/math.c common/theme.c \
|
||||||
|
common/netloader.c \
|
||||||
build_pc/tahoma24.o build_pc/tahoma12.o build_pc/interuimedium20.o build_pc/interuimedium30.o \
|
build_pc/tahoma24.o build_pc/tahoma12.o build_pc/interuimedium20.o build_pc/interuimedium30.o \
|
||||||
build_pc/interuiregular14.o build_pc/interuiregular18.o \
|
build_pc/interuiregular14.o build_pc/interuiregular18.o \
|
||||||
build_pc/invalid_icon.bin.o build_pc/folder_icon.bin.o \
|
build_pc/invalid_icon.bin.o build_pc/folder_icon.bin.o \
|
||||||
build_pc/button_a_light.bin.o build_pc/button_a_dark.bin.o build_pc/button_b_light.bin.o build_pc/button_b_dark.bin.o build_pc/hbmenu_logo_light.bin.o build_pc/hbmenu_logo_dark.bin.o
|
build_pc/button_a_light.bin.o build_pc/button_a_dark.bin.o build_pc/button_b_light.bin.o build_pc/button_b_dark.bin.o build_pc/hbmenu_logo_light.bin.o build_pc/hbmenu_logo_dark.bin.o
|
||||||
gcc -Wall -O2 -g0 -DVERSION=\"$(APP_VERSION)\" $^ -lsfml-graphics -lsfml-window -lsfml-system -lstdc++ -lm -I. -Ibuild_pc -o $@
|
gcc -Wall -O2 -g -DVERSION=\"$(APP_VERSION)\" $(EXTRA_CFLAGS) $^ -lsfml-graphics -lsfml-window -lsfml-system -lstdc++ -lm -lz $(EXTRA_LDFLAGS) -I. -I$(DEVKITPRO)/libnx/include -Ibuild_pc -g -o $@
|
||||||
|
|
||||||
build_pc/tahoma12.o : data/tahoma12.nxfnt
|
build_pc/tahoma12.o : data/tahoma12.nxfnt
|
||||||
mkdir -p $(dir $@)
|
mkdir -p $(dir $@)
|
||||||
|
@ -23,6 +23,16 @@ typedef uint8_t u8;
|
|||||||
typedef uint32_t u32;
|
typedef uint32_t u32;
|
||||||
typedef uint64_t u64;
|
typedef uint64_t u64;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define DIRECTORY_SEPARATOR_CHAR '\\'
|
||||||
|
static const char DIRECTORY_SEPARATOR[] = "\\";
|
||||||
|
#else
|
||||||
|
#define DIRECTORY_SEPARATOR_CHAR '/'
|
||||||
|
static const char DIRECTORY_SEPARATOR[] = "/";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define M_TAU (2*M_PI)
|
#define M_TAU (2*M_PI)
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
@ -44,7 +54,7 @@ typedef union {
|
|||||||
|
|
||||||
// when building for pc we need to include nro.h separately
|
// when building for pc we need to include nro.h separately
|
||||||
#ifndef __SWITCH__
|
#ifndef __SWITCH__
|
||||||
#include "nro.h"
|
#include <switch/nro.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void menuStartup();
|
void menuStartup();
|
||||||
|
@ -4,6 +4,6 @@
|
|||||||
|
|
||||||
float approxSin(float x);
|
float approxSin(float x);
|
||||||
|
|
||||||
inline float clamp(float x, float min, float max) {
|
static inline float clamp(float x, float min, float max) {
|
||||||
return fmin(fmax(x, min), max);
|
return fmin(fmax(x, min), max);
|
||||||
}
|
}
|
@ -1,9 +1,16 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "netloader.h"
|
||||||
|
|
||||||
#include "invalid_icon_bin.h"
|
#include "invalid_icon_bin.h"
|
||||||
#include "folder_icon_bin.h"
|
#include "folder_icon_bin.h"
|
||||||
|
|
||||||
|
char rootPath[PATH_MAX];
|
||||||
|
|
||||||
|
char *menuGetRootPath() {
|
||||||
|
return rootPath;
|
||||||
|
}
|
||||||
|
|
||||||
void launchMenuEntryTask(menuEntry_s* arg)
|
void launchMenuEntryTask(menuEntry_s* arg)
|
||||||
{
|
{
|
||||||
menuEntry_s* me = arg;
|
menuEntry_s* me = arg;
|
||||||
@ -14,7 +21,29 @@ void launchMenuEntryTask(menuEntry_s* arg)
|
|||||||
launchMenuEntry(me);
|
launchMenuEntry(me);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum
|
||||||
|
{
|
||||||
|
HBMENU_DEFAULT,
|
||||||
|
HBMENU_NETLOADER_ACTIVE,
|
||||||
|
HBMENU_NETLOADER_ERROR,
|
||||||
|
HBMENU_NETLOADER_SUCCESS,
|
||||||
|
} hbmenu_state = HBMENU_DEFAULT;
|
||||||
|
|
||||||
|
void launchMenuNetloaderTask() {
|
||||||
|
if(hbmenu_state == HBMENU_DEFAULT)
|
||||||
|
if(netloader_activate() == 0) hbmenu_state = HBMENU_NETLOADER_ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void launchMenuBackTask()
|
||||||
|
{
|
||||||
|
if(hbmenu_state == HBMENU_NETLOADER_ACTIVE) {
|
||||||
|
netloader_deactivate();
|
||||||
|
hbmenu_state = HBMENU_DEFAULT;
|
||||||
|
} else {
|
||||||
|
menuScan("..");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//Draws an RGB888 or RGBA8888 image.
|
//Draws an RGB888 or RGBA8888 image.
|
||||||
static void drawImage(int x, int y, int width, int height, const uint8_t *image, ImageMode mode) {
|
static void drawImage(int x, int y, int width, int height, const uint8_t *image, ImageMode mode) {
|
||||||
@ -219,15 +248,16 @@ void computeFrontGradient(color_t baseColor, int height) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void menuStartup() {
|
void menuStartup() {
|
||||||
const char *path;
|
|
||||||
|
|
||||||
#ifdef __SWITCH__
|
#ifdef __SWITCH__
|
||||||
path = "sdmc:/switch";
|
strcpy(rootPath,"sdmc:");
|
||||||
#else
|
#else
|
||||||
path = "switch";
|
getcwd(rootPath, PATH_MAX);
|
||||||
#endif
|
#endif
|
||||||
|
sprintf(rootPath,"%s%s%s" , rootPath, DIRECTORY_SEPARATOR, "switch" );
|
||||||
|
|
||||||
menuScan(path);
|
menuScan(rootPath);
|
||||||
|
|
||||||
folder_icon_small = downscaleImg(folder_icon_bin, 256, 256, 140, 140, IMAGE_MODE_RGB24);
|
folder_icon_small = downscaleImg(folder_icon_bin, 256, 256, 140, 140, IMAGE_MODE_RGB24);
|
||||||
invalid_icon_small = downscaleImg(invalid_icon_bin, 256, 256, 140, 140, IMAGE_MODE_RGB24);
|
invalid_icon_small = downscaleImg(invalid_icon_bin, 256, 256, 140, 140, IMAGE_MODE_RGB24);
|
||||||
@ -352,9 +382,23 @@ void menuLoop() {
|
|||||||
|
|
||||||
//drawTime();
|
//drawTime();
|
||||||
|
|
||||||
if (menu->nEntries==0)
|
if (menu->nEntries==0 || hbmenu_state == HBMENU_NETLOADER_ACTIVE)
|
||||||
{
|
{
|
||||||
|
if (hbmenu_state == HBMENU_NETLOADER_ACTIVE) {
|
||||||
|
menuEntry_s me;
|
||||||
|
menuEntryInit(&me,ENTRY_TYPE_FILE);
|
||||||
|
|
||||||
|
int netloader_result = netloader_loop(&me);
|
||||||
|
if( netloader_result != 0) {
|
||||||
|
hbmenu_state = HBMENU_DEFAULT;
|
||||||
|
if (netloader_result == 1) {
|
||||||
|
menuCreateMsgBox(240,240, textGetString(StrId_Loading));
|
||||||
|
launchMenuEntryTask(&me);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
DrawText(interuiregular14, 64, 128, themeCurrent.textColor, textGetString(StrId_NoAppsFound_Msg));
|
DrawText(interuiregular14, 64, 128, themeCurrent.textColor, textGetString(StrId_NoAppsFound_Msg));
|
||||||
|
}
|
||||||
drawBackBtn(menu, true);
|
drawBackBtn(menu, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#else
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#undef DrawText
|
||||||
|
#undef MessageBox
|
||||||
|
#endif
|
||||||
|
|
||||||
#define ENTRY_NAMELENGTH 0x200
|
#define ENTRY_NAMELENGTH 0x200
|
||||||
#define ENTRY_AUTHORLENGTH 0x100
|
#define ENTRY_AUTHORLENGTH 0x100
|
||||||
#define ENTRY_VERLENGTH 0x10
|
#define ENTRY_VERLENGTH 0x10
|
||||||
@ -27,6 +37,7 @@ typedef struct
|
|||||||
{
|
{
|
||||||
char* dst;
|
char* dst;
|
||||||
uint32_t buf[ENTRY_ARGBUFSIZE/sizeof(uint32_t)];
|
uint32_t buf[ENTRY_ARGBUFSIZE/sizeof(uint32_t)];
|
||||||
|
struct in_addr nxlink_host;
|
||||||
} argData_s;
|
} argData_s;
|
||||||
|
|
||||||
struct menuEntry_s_tag
|
struct menuEntry_s_tag
|
||||||
@ -58,6 +69,10 @@ typedef enum
|
|||||||
|
|
||||||
double menuTimer;
|
double menuTimer;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
void menuCreateMsgBox(int width, int height, const char *text);
|
void menuCreateMsgBox(int width, int height, const char *text);
|
||||||
void menuCloseMsgBox();
|
void menuCloseMsgBox();
|
||||||
bool menuIsMsgBoxOpen();
|
bool menuIsMsgBoxOpen();
|
||||||
@ -74,6 +89,16 @@ void menuEntryParseNacp(menuEntry_s* me);
|
|||||||
menu_s* menuGetCurrent(void);
|
menu_s* menuGetCurrent(void);
|
||||||
int menuScan(const char* target);
|
int menuScan(const char* target);
|
||||||
|
|
||||||
|
void launchMenuEntryTask(menuEntry_s* arg);
|
||||||
|
void launchMenuBackTask();
|
||||||
|
void launchMenuNetloaderTask();
|
||||||
|
char *menuGetRootPath();
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline char* getExtension(const char* str)
|
static inline char* getExtension(const char* str)
|
||||||
{
|
{
|
||||||
const char* p;
|
const char* p;
|
||||||
|
575
common/netloader.c
Normal file
575
common/netloader.c
Normal file
@ -0,0 +1,575 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#ifndef __WIN32__
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
typedef int socklen_t;
|
||||||
|
typedef uint32_t in_addr_t;
|
||||||
|
|
||||||
|
#undef DrawText
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "netloader.h"
|
||||||
|
|
||||||
|
#include <switch/runtime/nxlink.h>
|
||||||
|
|
||||||
|
// having trouble with non blocking sockets & udp on switch currently
|
||||||
|
#ifndef __SWITCH__
|
||||||
|
#define PING_ENABLED 1
|
||||||
|
#else
|
||||||
|
#define PING_ENABLED 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ZLIB_CHUNK (16 * 1024)
|
||||||
|
#define FILE_BUFFER_SIZE (128*1024)
|
||||||
|
|
||||||
|
static int netloader_listenfd = -1;
|
||||||
|
static int netloader_datafd = -1;
|
||||||
|
#if PING_ENABLED
|
||||||
|
static int netloader_udpfd = -1;
|
||||||
|
#endif
|
||||||
|
unsigned char in[ZLIB_CHUNK];
|
||||||
|
unsigned char out[ZLIB_CHUNK];
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
static void netloader_error(const char *func, int err) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
char errortext[1024];
|
||||||
|
|
||||||
|
sprintf(errortext, "%s: err=%d\n %s\n", func, err, strerror(errno));
|
||||||
|
|
||||||
|
menuCreateMsgBox(640,480, errortext);
|
||||||
|
|
||||||
|
netloader_deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
static void netloader_socket_error(const char *func) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
int errcode;
|
||||||
|
#ifdef __WIN32__
|
||||||
|
errcode = WSAGetLastError();
|
||||||
|
#else
|
||||||
|
errcode = errno;
|
||||||
|
#endif
|
||||||
|
netloader_error(func,errcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
void shutdownSocket(int socket) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
#ifdef __WIN32__
|
||||||
|
shutdown (socket, SD_SEND);
|
||||||
|
closesocket (socket);
|
||||||
|
#else
|
||||||
|
close(socket);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char DIRECTORY_THIS[] = ".";
|
||||||
|
static const char DIRECTORY_PARENT[] = "..";
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
static bool isDirectorySeparator(int c) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
return c == DIRECTORY_SEPARATOR_CHAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
static void sanitisePath(char *path) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
char *tmpPath = strdup(path);
|
||||||
|
tmpPath[0] = 0;
|
||||||
|
|
||||||
|
char *dirStart = path;
|
||||||
|
char *curPath = tmpPath;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
while(dirStart[0]) {
|
||||||
|
if (dirStart[0] == '/') dirStart[0] =DIRECTORY_SEPARATOR_CHAR;
|
||||||
|
dirStart++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
dirStart = path;
|
||||||
|
|
||||||
|
while(isDirectorySeparator(dirStart[0])) dirStart++;
|
||||||
|
|
||||||
|
|
||||||
|
do {
|
||||||
|
char *dirEnd = strchr(dirStart, DIRECTORY_SEPARATOR_CHAR);
|
||||||
|
if (dirEnd) {
|
||||||
|
dirEnd++;
|
||||||
|
if(!strncmp(DIRECTORY_PARENT,dirStart,strlen(DIRECTORY_PARENT))) {
|
||||||
|
/* move back one directory */
|
||||||
|
size_t pathlen = strlen(tmpPath);
|
||||||
|
if(tmpPath[pathlen-1] == DIRECTORY_SEPARATOR_CHAR) tmpPath[pathlen-1] = 0;
|
||||||
|
char *prev = strrchr(tmpPath,DIRECTORY_SEPARATOR_CHAR);
|
||||||
|
if (prev) {
|
||||||
|
curPath = prev + 1;
|
||||||
|
} else {
|
||||||
|
curPath = tmpPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dirStart = dirEnd;
|
||||||
|
} else if (!strncmp(DIRECTORY_THIS,dirStart,strlen(DIRECTORY_THIS))) {
|
||||||
|
/* strip this entry */
|
||||||
|
dirStart = dirEnd;
|
||||||
|
} else {
|
||||||
|
size_t dirSize = dirEnd - dirStart;
|
||||||
|
strncpy(curPath,dirStart,dirSize);
|
||||||
|
curPath[dirSize] = 0;
|
||||||
|
curPath += dirSize;
|
||||||
|
dirStart += dirSize;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strcpy(curPath,dirStart);
|
||||||
|
dirStart += strlen(dirStart);
|
||||||
|
}
|
||||||
|
} while(dirStart[0]);
|
||||||
|
|
||||||
|
strcpy(path, tmpPath);
|
||||||
|
free(tmpPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
static int set_socket_nonblocking(int sock) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef __WIN32__
|
||||||
|
int flags = fcntl(sock, F_GETFL);
|
||||||
|
|
||||||
|
if(flags == -1) return -1;
|
||||||
|
|
||||||
|
int rc = fcntl(sock, F_SETFL, flags | O_NONBLOCK);
|
||||||
|
|
||||||
|
if(rc != 0) return -1;
|
||||||
|
|
||||||
|
#else
|
||||||
|
u_long opt = 1;
|
||||||
|
ioctlsocket(sock, FIONBIO, &opt);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
static int recvall(int sock, void *buffer, int size, int flags) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
int len, sizeleft = size;
|
||||||
|
|
||||||
|
while (sizeleft) {
|
||||||
|
|
||||||
|
len = recv(sock,buffer,sizeleft,flags);
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
size = 0;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (len != -1) {
|
||||||
|
sizeleft -=len;
|
||||||
|
buffer +=len;
|
||||||
|
} else {
|
||||||
|
#ifdef _WIN32
|
||||||
|
int errcode = WSAGetLastError();
|
||||||
|
if (errcode != WSAEWOULDBLOCK) {
|
||||||
|
netloader_error("win socket error",errcode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if ( errno != EWOULDBLOCK && errno != EAGAIN) {
|
||||||
|
perror(NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
static int decompress(int sock, FILE *fh, size_t filesize) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
int ret;
|
||||||
|
unsigned have;
|
||||||
|
z_stream strm;
|
||||||
|
size_t chunksize;
|
||||||
|
|
||||||
|
/* allocate inflate state */
|
||||||
|
strm.zalloc = Z_NULL;
|
||||||
|
strm.zfree = Z_NULL;
|
||||||
|
strm.opaque = Z_NULL;
|
||||||
|
strm.avail_in = 0;
|
||||||
|
strm.next_in = Z_NULL;
|
||||||
|
ret = inflateInit(&strm);
|
||||||
|
if (ret != Z_OK) {
|
||||||
|
netloader_error("inflateInit failed.",ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t total = 0;
|
||||||
|
/* decompress until deflate stream ends or end of file */
|
||||||
|
do {
|
||||||
|
|
||||||
|
int len = recvall(sock, &chunksize, 4, 0);
|
||||||
|
|
||||||
|
if (len != 4) {
|
||||||
|
(void)inflateEnd(&strm);
|
||||||
|
netloader_error("Error getting chunk size",len);
|
||||||
|
return Z_DATA_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
strm.avail_in = recvall(sock,in,chunksize,0);
|
||||||
|
|
||||||
|
if (strm.avail_in == 0) {
|
||||||
|
(void)inflateEnd(&strm);
|
||||||
|
netloader_error("remote closed socket.",0);
|
||||||
|
return Z_DATA_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
strm.next_in = in;
|
||||||
|
|
||||||
|
/* run inflate() on input until output buffer not full */
|
||||||
|
do {
|
||||||
|
strm.avail_out = ZLIB_CHUNK;
|
||||||
|
strm.next_out = out;
|
||||||
|
ret = inflate(&strm, Z_NO_FLUSH);
|
||||||
|
|
||||||
|
switch (ret) {
|
||||||
|
|
||||||
|
case Z_NEED_DICT:
|
||||||
|
ret = Z_DATA_ERROR; /* and fall through */
|
||||||
|
|
||||||
|
case Z_DATA_ERROR:
|
||||||
|
case Z_MEM_ERROR:
|
||||||
|
case Z_STREAM_ERROR:
|
||||||
|
(void)inflateEnd(&strm);
|
||||||
|
netloader_error("inflate error",ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
have = ZLIB_CHUNK - strm.avail_out;
|
||||||
|
|
||||||
|
if (fwrite(out, 1, have, fh) != have || ferror(fh)) {
|
||||||
|
(void)inflateEnd(&strm);
|
||||||
|
netloader_error("file write error",0);
|
||||||
|
return Z_ERRNO;
|
||||||
|
}
|
||||||
|
|
||||||
|
total += have;
|
||||||
|
//printf("%zu (%zd%%)",total, (100 * total) / filesize);
|
||||||
|
} while (strm.avail_out == 0);
|
||||||
|
|
||||||
|
/* done when inflate() says it's done */
|
||||||
|
} while (ret != Z_STREAM_END);
|
||||||
|
|
||||||
|
/* clean up and return */
|
||||||
|
(void)inflateEnd(&strm);
|
||||||
|
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
int loadnro(menuEntry_s *me, int sock, struct in_addr remote) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
int len, namelen, filelen;
|
||||||
|
char filename[PATH_MAX+1];
|
||||||
|
len = recvall(sock, &namelen, 4, 0);
|
||||||
|
|
||||||
|
if (len != 4) {
|
||||||
|
netloader_error("Error getting name length", errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (namelen >= sizeof(filename)-1) {
|
||||||
|
netloader_error("Filename length is too large",errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = recvall(sock, filename, namelen, 0);
|
||||||
|
|
||||||
|
if (len != namelen) {
|
||||||
|
netloader_error("Error getting filename", errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
filename[namelen] = 0;
|
||||||
|
|
||||||
|
len = recvall(sock, &filelen, 4, 0);
|
||||||
|
|
||||||
|
if (len != 4) {
|
||||||
|
netloader_error("Error getting file length",errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int response = 0;
|
||||||
|
|
||||||
|
sanitisePath(filename);
|
||||||
|
|
||||||
|
snprintf(me->path, PATH_MAX, "%s%s%s", menuGetRootPath(), DIRECTORY_SEPARATOR, filename);
|
||||||
|
// make sure it's terminated
|
||||||
|
me->path[PATH_MAX] = 0;
|
||||||
|
|
||||||
|
argData_s* ad = &me->args;
|
||||||
|
ad->dst = (char*)&ad->buf[1];
|
||||||
|
ad->nxlink_host = remote;
|
||||||
|
|
||||||
|
launchAddArg(ad, me->path);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
int fd = open(me->path,O_CREAT|O_WRONLY, ACCESSPERMS);
|
||||||
|
|
||||||
|
if (fd < 0) {
|
||||||
|
response = -1;
|
||||||
|
netloader_error("open", errno);
|
||||||
|
} else {
|
||||||
|
if (ftruncate(fd,filelen) == -1) {
|
||||||
|
response = -2;
|
||||||
|
netloader_error("ftruncate",errno);
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FILE *file = NULL;
|
||||||
|
|
||||||
|
if (response == 0) file = fopen(me->path,"wb");
|
||||||
|
|
||||||
|
if(NULL == file) {
|
||||||
|
perror("file");
|
||||||
|
response = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
send(sock,(char *)&response,sizeof(response),0);
|
||||||
|
|
||||||
|
if (response == 0 ) {
|
||||||
|
|
||||||
|
//char *writebuffer=malloc(FILE_BUFFER_SIZE);
|
||||||
|
//setvbuf(file,writebuffer,_IOFBF, FILE_BUFFER_SIZE);
|
||||||
|
|
||||||
|
//printf("transferring %s\n%d bytes.\n", filename, filelen);
|
||||||
|
|
||||||
|
if (decompress(sock,file,filelen)==Z_OK) {
|
||||||
|
int netloaded_cmdlen = 0;
|
||||||
|
send(sock,(char *)&response,sizeof(response),0);
|
||||||
|
//printf("\ntransferring command line\n");
|
||||||
|
len = recvall(sock,(char*)&netloaded_cmdlen,4,0);
|
||||||
|
|
||||||
|
len = recvall(sock,me->args.dst, netloaded_cmdlen,0);
|
||||||
|
|
||||||
|
while(netloaded_cmdlen) {
|
||||||
|
size_t len = strlen(me->args.dst) + 1;
|
||||||
|
ad->dst += len;
|
||||||
|
ad->buf[0]++;
|
||||||
|
netloaded_cmdlen -= len;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
response = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free(writebuffer);
|
||||||
|
fflush(file);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
int netloader_activate(void) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
struct sockaddr_in serv_addr;
|
||||||
|
|
||||||
|
#ifdef __SWITCH__
|
||||||
|
socketInitializeDefault();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __WIN32__
|
||||||
|
WSADATA wsa_data;
|
||||||
|
if (WSAStartup (MAKEWORD(2,2), &wsa_data)) {
|
||||||
|
netloader_error("WSAStartup failed\n",1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
memset(&serv_addr, '0', sizeof(serv_addr));
|
||||||
|
serv_addr.sin_family = AF_INET;
|
||||||
|
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
serv_addr.sin_port = htons(NXLINK_SERVER_PORT);
|
||||||
|
|
||||||
|
#if PING_ENABLED
|
||||||
|
// create udp socket for broadcast ping
|
||||||
|
netloader_udpfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (netloader_udpfd < 0)
|
||||||
|
{
|
||||||
|
netloader_socket_error("udp socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bind(netloader_udpfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) {
|
||||||
|
netloader_socket_error("bind udp socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set_socket_nonblocking(netloader_udpfd) == -1)
|
||||||
|
{
|
||||||
|
netloader_socket_error("listen fcntl");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// create listening socket on all addresses on NXLINK_SERVER_PORT
|
||||||
|
|
||||||
|
netloader_listenfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if(netloader_listenfd < 0)
|
||||||
|
{
|
||||||
|
netloader_socket_error("socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rc = bind(netloader_listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
|
||||||
|
if(rc != 0)
|
||||||
|
{
|
||||||
|
netloader_socket_error("bind");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set_socket_nonblocking(netloader_listenfd) == -1)
|
||||||
|
{
|
||||||
|
netloader_socket_error("listen fcntl");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = listen(netloader_listenfd, 10);
|
||||||
|
if(rc != 0)
|
||||||
|
{
|
||||||
|
netloader_socket_error("listen");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
int netloader_deactivate(void) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
// close all remaining sockets and allow mainloop to return to main menu
|
||||||
|
if(netloader_listenfd >= 0)
|
||||||
|
{
|
||||||
|
shutdownSocket(netloader_listenfd);
|
||||||
|
netloader_listenfd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(netloader_datafd >= 0)
|
||||||
|
{
|
||||||
|
shutdownSocket(netloader_datafd);
|
||||||
|
netloader_datafd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if PING_ENABLED
|
||||||
|
if(netloader_udpfd >= 0)
|
||||||
|
{
|
||||||
|
shutdownSocket(netloader_udpfd);
|
||||||
|
netloader_udpfd = -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __SWITCH__
|
||||||
|
socketExit();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __WIN32__
|
||||||
|
WSACleanup ();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
int netloader_loop(menuEntry_s *me) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
struct sockaddr_in sa_remote;
|
||||||
|
|
||||||
|
#if PING_ENABLED
|
||||||
|
char recvbuf[256];
|
||||||
|
socklen_t fromlen = sizeof(sa_remote);
|
||||||
|
|
||||||
|
int len = recvfrom(netloader_udpfd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr*) &sa_remote, &fromlen);
|
||||||
|
|
||||||
|
if (len!=-1) {
|
||||||
|
if (strncmp(recvbuf,"nxboot",strlen("nxboot")) == 0) {
|
||||||
|
sa_remote.sin_family=AF_INET;
|
||||||
|
sa_remote.sin_port=htons(NXLINK_CLIENT_PORT);
|
||||||
|
sendto(netloader_udpfd, "bootnx", strlen("bootnx"), 0, (struct sockaddr*) &sa_remote,sizeof(sa_remote));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if(netloader_listenfd >= 0 && netloader_datafd < 0) {
|
||||||
|
socklen_t addrlen = sizeof(sa_remote);
|
||||||
|
netloader_datafd = accept(netloader_listenfd, (struct sockaddr*)&sa_remote, &addrlen);
|
||||||
|
if(netloader_datafd < 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
int errcode = WSAGetLastError();
|
||||||
|
if (errcode != WSAEWOULDBLOCK) {
|
||||||
|
netloader_error("accept", errcode);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if ( errno != EWOULDBLOCK && errno != EAGAIN) {
|
||||||
|
netloader_error("accept", errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
close(netloader_listenfd);
|
||||||
|
netloader_listenfd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(netloader_datafd >= 0)
|
||||||
|
{
|
||||||
|
int result = loadnro(me, netloader_datafd,sa_remote.sin_addr);
|
||||||
|
netloader_deactivate();
|
||||||
|
if (result== 0) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
5
common/netloader.h
Normal file
5
common/netloader.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
int netloader_activate(void);
|
||||||
|
int netloader_deactivate(void);
|
||||||
|
int netloader_loop( menuEntry_s *me;);
|
54
common/nro.h
54
common/nro.h
@ -1,54 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file nro.h
|
|
||||||
* @brief NRO headers.
|
|
||||||
* @copyright libnx Authors
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#define NROHEADER_MAGIC 0x304f524e
|
|
||||||
|
|
||||||
#define NROASSETHEADER_MAGIC 0x54455341
|
|
||||||
#define NROASSETHEADER_VERSION 0
|
|
||||||
|
|
||||||
/// Entry for each segment in the codebin.
|
|
||||||
typedef struct {
|
|
||||||
u32 file_off;
|
|
||||||
u32 size;
|
|
||||||
} NroSegment;
|
|
||||||
|
|
||||||
/// Offset 0x0 in the NRO.
|
|
||||||
typedef struct {
|
|
||||||
u32 unused;
|
|
||||||
u32 mod_offset;
|
|
||||||
u8 padding[8];
|
|
||||||
} NroStart;
|
|
||||||
|
|
||||||
/// This follows NroStart, the actual nro-header.
|
|
||||||
typedef struct {
|
|
||||||
u32 magic;
|
|
||||||
u32 unk1;
|
|
||||||
u32 size;
|
|
||||||
u32 unk2;
|
|
||||||
NroSegment segments[3];
|
|
||||||
u32 bss_size;
|
|
||||||
u32 unk3;
|
|
||||||
u8 build_id[0x20];
|
|
||||||
u8 padding[0x20];
|
|
||||||
} NroHeader;
|
|
||||||
|
|
||||||
/// Custom asset section.
|
|
||||||
typedef struct {
|
|
||||||
u64 offset;
|
|
||||||
u64 size;
|
|
||||||
} NroAssetSection;
|
|
||||||
|
|
||||||
/// Custom asset header.
|
|
||||||
typedef struct {
|
|
||||||
u32 magic;
|
|
||||||
u32 version;
|
|
||||||
NroAssetSection icon;
|
|
||||||
NroAssetSection nacp;
|
|
||||||
NroAssetSection romfs;
|
|
||||||
} NroAssetHeader;
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
|||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include "../common/common.h"
|
#include "../common/common.h"
|
||||||
|
|
||||||
static char argBuf[ENTRY_ARGBUFSIZE];
|
static char argBuf[ENTRY_ARGBUFSIZE];
|
||||||
|
|
||||||
static void init_args(char *dst, size_t dst_maxsize, u32 *in_args, size_t size)
|
static char *init_args(char *dst, size_t dst_maxsize, u32 *in_args, size_t size)
|
||||||
{
|
{
|
||||||
size_t tmplen;
|
size_t tmplen;
|
||||||
u32 argi;
|
u32 argi;
|
||||||
@ -36,6 +38,7 @@ static void init_args(char *dst, size_t dst_maxsize, u32 *in_args, size_t size)
|
|||||||
dst_maxsize--;
|
dst_maxsize--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool init(void)
|
static bool init(void)
|
||||||
@ -53,8 +56,19 @@ static void launchFile(const char* path, argData_s* args)
|
|||||||
/*if (strncmp(path, "sdmc:/",6) == 0)
|
/*if (strncmp(path, "sdmc:/",6) == 0)
|
||||||
path += 5;*/
|
path += 5;*/
|
||||||
memset(argBuf, 0, sizeof(argBuf));
|
memset(argBuf, 0, sizeof(argBuf));
|
||||||
|
|
||||||
|
uint32_t remote = args->nxlink_host.s_addr;
|
||||||
|
|
||||||
|
if (remote) {
|
||||||
|
char nxlinked[17];
|
||||||
|
sprintf(nxlinked,"%08" PRIx32 "_NXLINK_",remote);
|
||||||
|
launchAddArg(args, nxlinked);
|
||||||
|
}
|
||||||
|
|
||||||
init_args(argBuf, sizeof(argBuf)-1, args->buf, sizeof(args->buf));
|
init_args(argBuf, sizeof(argBuf)-1, args->buf, sizeof(args->buf));
|
||||||
|
|
||||||
Result rc = envSetNextLoad(path, argBuf);
|
Result rc = envSetNextLoad(path, argBuf);
|
||||||
|
|
||||||
if(R_FAILED(rc)) fatalSimple(rc);//TODO: How should failing be handled?
|
if(R_FAILED(rc)) fatalSimple(rc);//TODO: How should failing be handled?
|
||||||
uiExitLoop();
|
uiExitLoop();
|
||||||
}
|
}
|
||||||
|
@ -82,15 +82,17 @@ int main(int argc, char **argv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void launchMenuEntryTask(menuEntry_s* arg);
|
|
||||||
|
|
||||||
//This is implemented here due to the hid code.
|
//This is implemented here due to the hid code.
|
||||||
bool menuUpdate(void) {
|
bool menuUpdate(void) {
|
||||||
bool exitflag = 0;
|
bool exitflag = 0;
|
||||||
menu_s* menu = menuGetCurrent();
|
menu_s* menu = menuGetCurrent();
|
||||||
u32 down = hidKeysDown(CONTROLLER_P1_AUTO);
|
u32 down = hidKeysDown(CONTROLLER_P1_AUTO);
|
||||||
|
|
||||||
if (down & KEY_A)
|
if (down & KEY_Y)
|
||||||
|
{
|
||||||
|
launchMenuNetloaderTask();
|
||||||
|
}
|
||||||
|
else if (down & KEY_A)
|
||||||
{
|
{
|
||||||
if (menuIsMsgBoxOpen()) {
|
if (menuIsMsgBoxOpen()) {
|
||||||
menuCloseMsgBox();
|
menuCloseMsgBox();
|
||||||
@ -106,11 +108,7 @@ bool menuUpdate(void) {
|
|||||||
}
|
}
|
||||||
else if (down & KEY_B)
|
else if (down & KEY_B)
|
||||||
{
|
{
|
||||||
if (strcmp( menu->dirname, "sdmc:/") != 0)
|
launchMenuBackTask();
|
||||||
{
|
|
||||||
//workerSchedule(changeDirTask, "..");
|
|
||||||
menuScan("..");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (down & KEY_PLUS)
|
else if (down & KEY_PLUS)
|
||||||
{
|
{
|
||||||
|
@ -53,8 +53,6 @@ int main()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void launchMenuEntryTask(menuEntry_s* arg);
|
|
||||||
|
|
||||||
extern "C" bool menuUpdate(void) {
|
extern "C" bool menuUpdate(void) {
|
||||||
//This is implemented here due to the hid code.
|
//This is implemented here due to the hid code.
|
||||||
menu_s* menu = menuGetCurrent();
|
menu_s* menu = menuGetCurrent();
|
||||||
@ -63,10 +61,18 @@ extern "C" bool menuUpdate(void) {
|
|||||||
int new_esc_state = sf::Keyboard::isKeyPressed(sf::Keyboard::Escape);
|
int new_esc_state = sf::Keyboard::isKeyPressed(sf::Keyboard::Escape);
|
||||||
static int return_state = 0;
|
static int return_state = 0;
|
||||||
int new_return_state = sf::Keyboard::isKeyPressed(sf::Keyboard::Return);
|
int new_return_state = sf::Keyboard::isKeyPressed(sf::Keyboard::Return);
|
||||||
|
static int y_state = 0;
|
||||||
|
int new_y_state = sf::Keyboard::isKeyPressed(sf::Keyboard::Y);
|
||||||
|
|
||||||
|
if(!new_y_state && y_state)
|
||||||
|
{
|
||||||
|
launchMenuNetloaderTask();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (!new_esc_state && esc_state)
|
if (!new_esc_state && esc_state)
|
||||||
{
|
{
|
||||||
menuScan("..");
|
launchMenuBackTask();
|
||||||
}
|
}
|
||||||
else if (!new_return_state && return_state)
|
else if (!new_return_state && return_state)
|
||||||
{
|
{
|
||||||
@ -106,6 +112,7 @@ extern "C" bool menuUpdate(void) {
|
|||||||
|
|
||||||
esc_state = new_esc_state;
|
esc_state = new_esc_state;
|
||||||
return_state = new_return_state;
|
return_state = new_return_state;
|
||||||
|
y_state = new_y_state;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user