diff --git a/Makefile b/Makefile
index 963ebee..e60d301 100644
--- a/Makefile
+++ b/Makefile
@@ -22,6 +22,7 @@ SOURCES := source \
source/fs \
source/utils \
source/language \
+ source/network \
source/system \
source/kernel
INCLUDES := include \
@@ -106,12 +107,14 @@ install:
@mkdir -p $(INCLUDEDIR)/utils/
@mkdir -p $(INCLUDEDIR)/kernel/
@mkdir -p $(INCLUDEDIR)/system/
+ @mkdir -p $(INCLUDEDIR)/network/
@mkdir -p $(INCLUDEDIR)/language/
@mkdir -p $(INCLUDEDIR)/fs/
@cp source/utils/*.h $(INCLUDEDIR)/utils/
@cp source/utils/*.hpp $(INCLUDEDIR)/utils/
@cp source/system/*.h $(INCLUDEDIR)/system/
@cp source/language/*.h $(INCLUDEDIR)/language/
+ @cp source/network/*.h $(INCLUDEDIR)/network/
@cp source/fs/*.h $(INCLUDEDIR)/fs/
@cp source/fs/*.hpp $(INCLUDEDIR)/fs/
@cp source/kernel/*.h $(INCLUDEDIR)/kernel/
diff --git a/source/network/FileDownloader.cpp b/source/network/FileDownloader.cpp
new file mode 100644
index 0000000..c179628
--- /dev/null
+++ b/source/network/FileDownloader.cpp
@@ -0,0 +1,185 @@
+/****************************************************************************
+ * Copyright (C) 2016 Dimok
+ * Modified by Maschell, 2018
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ ****************************************************************************/
+#include
+#include
+#include "FileDownloader.h"
+#include
+#include "utils/logger.h"
+#include "utils/utils.h"
+
+
+bool FileDownloader::getFile(const std::string & downloadUrl, std::string & fileBuffer, ProgressCallback callback, void *arg) {
+ curl_private_data_t private_data;
+ private_data.progressCallback = callback;
+ private_data.progressArg = arg;
+ private_data.buffer = 0;
+ private_data.filesize = 0;
+ private_data.file = 0;
+
+ bool result = internalGetFile(downloadUrl, &private_data);
+
+ if(private_data.filesize > 0 && private_data.buffer) {
+ fileBuffer.resize(private_data.filesize);
+ memcpy(&fileBuffer[0], private_data.buffer, private_data.filesize);
+ }
+
+ if(private_data.buffer) {
+ free(private_data.buffer);
+ }
+
+ return result;
+}
+
+bool FileDownloader::getFile(const std::string & downloadUrl, const std::string & outputPath, ProgressCallback callback, void *arg) {
+ curl_private_data_t private_data;
+ private_data.progressCallback = callback;
+ private_data.progressArg = arg;
+ private_data.buffer = 0;
+ private_data.filesize = 0;
+
+ s32 res = open(outputPath.c_str(), O_CREAT | O_TRUNC | O_WRONLY);
+ close(res);
+
+ private_data.file = new CFile(outputPath.c_str(), CFile::WriteOnly);
+
+ if(!private_data.file->isOpen()) {
+ delete private_data.file;
+ DEBUG_FUNCTION_LINE("Can not write to file %s\n", outputPath.c_str());
+ return false;
+ }
+
+ bool result = internalGetFile(downloadUrl, &private_data);
+
+ private_data.file->close();
+ delete private_data.file;
+ return result;
+}
+
+bool FileDownloader::internalGetFile(const std::string & downloadUrl, curl_private_data_t * private_data) {
+ bool result = false;
+ int resp = 404;
+ int ret = -1;
+ CURL * curl = n_curl_easy_init();
+ if(!curl) {
+ return false;
+ }
+
+ int ssl_context = -1;
+
+ std::string prefix = "https";
+ if(strncmp(downloadUrl.c_str(), prefix.c_str(), prefix.size()) == 0) {
+ DEBUG_FUNCTION_LINE("Needs a SSL context\n");
+ ssl_context = NSSLCreateContext(0);
+ if(ssl_context < 0) {
+ DEBUG_FUNCTION_LINE("Failed to create SSL Context\n");
+ goto exit_error;
+ }
+
+ // Add all existing certs
+ for(int i = 100; i<106; i++) {
+ NSSLAddServerPKI(ssl_context,i);
+ }
+
+ for(int i = 1001; i<1034; i++) {
+ NSSLAddServerPKI(ssl_context,i);
+ }
+ n_curl_easy_setopt(curl, CURLOPT_GSSAPI_DELEGATION, ssl_context); // Is CURLOPT_NSSL_CONTEXT on the Wii U
+ }
+
+ n_curl_easy_setopt(curl, CURLOPT_URL, downloadUrl.c_str());
+ n_curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, FileDownloader::curlCallback);
+ n_curl_easy_setopt(curl, CURLOPT_WRITEDATA, private_data);
+ n_curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+
+ //n_curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
+
+ if(private_data->progressCallback) {
+ n_curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, FileDownloader::curlProgressCallback);
+ n_curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, private_data);
+ n_curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
+ }
+
+ ret = n_curl_easy_perform(curl);
+ if(ret) {
+ DEBUG_FUNCTION_LINE("n_curl_easy_perform ret %i\n", ret);
+ goto exit_error;
+ }
+
+ if(!private_data->filesize) {
+ DEBUG_FUNCTION_LINE("file length is 0\n");
+ goto exit_error;
+ }
+
+ n_curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &resp);
+
+ if(resp != 200) {
+ DEBUG_FUNCTION_LINE("response != 200\n");
+ goto exit_error;
+ }
+
+ result = true;
+
+exit_error:
+ if(ssl_context >= 0) {
+ NSSLDestroyContext(ssl_context);
+ }
+
+ n_curl_easy_cleanup(curl);
+ return result;
+}
+
+int FileDownloader::curlCallback(void *buffer, int size, int nmemb, void *userp) {
+ curl_private_data_t *private_data = (curl_private_data_t *)userp;
+ int read_len = size*nmemb;
+
+ if(private_data->file) {
+ int res = private_data->file->write((u8*)buffer, read_len);
+ private_data->filesize += res;
+ return res;
+ } else {
+ if(!private_data->buffer) {
+ private_data->buffer = (u8*) malloc(read_len);
+ } else {
+ u8 *tmp = (u8*) realloc(private_data->buffer, private_data->filesize + read_len);
+ if(!tmp) {
+ free(private_data->buffer);
+ private_data->buffer = NULL;
+ } else {
+ private_data->buffer = tmp;
+ }
+ }
+
+ if(!private_data->buffer) {
+ private_data->filesize = 0;
+ return -1;
+ }
+
+ memcpy(private_data->buffer + private_data->filesize, buffer, read_len);
+ private_data->filesize += read_len;
+ return read_len;
+ }
+}
+
+int FileDownloader::curlProgressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) {
+ curl_private_data_t *private_data = (curl_private_data_t *)clientp;
+ if(private_data->progressCallback) {
+ private_data->progressCallback(private_data->progressArg, (u32)dlnow, (u32)dltotal);
+ }
+ return 0;
+}
+
diff --git a/source/network/FileDownloader.h b/source/network/FileDownloader.h
new file mode 100644
index 0000000..ab897f9
--- /dev/null
+++ b/source/network/FileDownloader.h
@@ -0,0 +1,46 @@
+/****************************************************************************
+ * Copyright (C) 2016 Dimok
+ * Modified by Maschell, 2018
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ ****************************************************************************/
+#ifndef _FILE_DOWNLOADER_H
+#define _FILE_DOWNLOADER_H
+
+#include
+#include "fs/CFile.hpp"
+
+class FileDownloader
+{
+public:
+ typedef void (*ProgressCallback)(void *arg, u32 done, u32 total);
+
+ static bool getFile(const std::string & downloadUrl, std::string & fileBuffer, ProgressCallback callback = 0, void *arg = 0);
+ static bool getFile(const std::string & downloadUrl, const std::string & outputPath, ProgressCallback callback = 0, void *arg = 0);
+private:
+ typedef struct
+ {
+ ProgressCallback progressCallback;
+ void *progressArg;
+ CFile * file;
+ u8 *buffer;
+ u32 filesize;
+ } curl_private_data_t;
+
+ static bool internalGetFile(const std::string & downloadUrl, curl_private_data_t * private_data);
+ static int curlCallback(void *buffer, int size, int nmemb, void *userp);
+ static int curlProgressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
+};
+
+#endif // _FILE_DOWNLOADER_H