mirror of
https://github.com/J-D-K/JKSV.git
synced 2026-03-21 17:24:37 -05:00
Fix config loading, early drive code, threaded file read/write
This commit is contained in:
parent
2fbfe5b62e
commit
c29688ea97
2
Makefile
2
Makefile
|
|
@ -38,7 +38,7 @@ INCLUDES := inc inc/ui inc/fs
|
|||
EXEFS_SRC := exefs_src
|
||||
APP_TITLE := JKSV
|
||||
APP_AUTHOR := JK
|
||||
APP_VERSION := 11.15.2021
|
||||
APP_VERSION := 11.28.2021
|
||||
ROMFS := romfs
|
||||
ICON := icon.jpg
|
||||
|
||||
|
|
|
|||
|
|
@ -34,4 +34,5 @@ namespace cfg
|
|||
extern std::vector<uint64_t> blacklist;
|
||||
extern std::vector<uint64_t> favorites;
|
||||
extern uint8_t sortType;
|
||||
extern std::string driveClientID, driveClientSecret, driveRefreshToken, driveAuthCode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,35 @@
|
|||
#ifndef CURLFUNCS_H
|
||||
#define CURLFUNCS_H
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
std::string getJSONURL(std::vector<std::string> *headers, const std::string& _url);
|
||||
bool getBinURL(std::vector<uint8_t> *out, const std::string& _url);
|
||||
#define HEADER_ERROR "ERROR"
|
||||
|
||||
#endif // CURLFUNCS_H
|
||||
namespace curlFuncs
|
||||
{
|
||||
typedef struct
|
||||
{
|
||||
FILE *f;
|
||||
uint64_t *o;
|
||||
} curlUpArgs;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
std::string path;
|
||||
unsigned int size;
|
||||
uint64_t *o;
|
||||
} curlDlArgs;
|
||||
|
||||
size_t writeDataString(const char *buff, size_t sz, size_t cnt, void *u);
|
||||
size_t writeHeaders(const char *buff, size_t sz, size_t cnt, void *u);
|
||||
size_t readDataFile(char *buff, size_t sz, size_t cnt, void *u);
|
||||
size_t readDataBuffer(char *buff, size_t sz, size_t cnt, void *u);
|
||||
size_t writeDataFile(const char *buff, size_t sz, size_t cnt, void *u);
|
||||
size_t writeDataBuffer(const char *buff, size_t sz, size_t cnt, void *u);
|
||||
|
||||
std::string getHeader(const std::string& _name, std::vector<std::string> *h);
|
||||
|
||||
//Shortcuts/legacy
|
||||
std::string getJSONURL(std::vector<std::string> *headers, const std::string& url);
|
||||
bool getBinURL(std::vector<uint8_t> *out, const std::string& url);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,13 +8,11 @@
|
|||
#include "gfx.h"
|
||||
|
||||
#define BLD_MON 11
|
||||
#define BLD_DAY 15
|
||||
#define BLD_DAY 28
|
||||
#define BLD_YEAR 2021
|
||||
|
||||
namespace data
|
||||
{
|
||||
extern bool forceMount;
|
||||
|
||||
//Loads user + title info
|
||||
void init();
|
||||
void exit();
|
||||
|
|
|
|||
5
inc/fs.h
5
inc/fs.h
|
|
@ -8,9 +8,12 @@
|
|||
#include "fs/dir.h"
|
||||
#include "fs/zip.h"
|
||||
#include "fs/fsfile.h"
|
||||
#include "fs/drive.h"
|
||||
#include "ui/miscui.h"
|
||||
|
||||
#define BUFF_SIZE 0xC0000
|
||||
#define BUFF_SIZE 0x8000
|
||||
#define ZIP_BUFF_SIZE 0x10000
|
||||
#define TRANSFER_BUFFER_LIMIT 0xA00000
|
||||
|
||||
namespace fs
|
||||
{
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ namespace fs
|
|||
std::string getItemExt(int index) const { return item[index].getExt(); }
|
||||
bool isDir(int index) const { return item[index].isDir(); }
|
||||
unsigned getCount() const { return item.size(); }
|
||||
fs::dirItem *getDirItemAt(unsigned int _ind) { return &item[_ind]; }
|
||||
|
||||
private:
|
||||
std::string path;
|
||||
|
|
|
|||
10
inc/fs/drive.h
Normal file
10
inc/fs/drive.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "../gd.h"
|
||||
|
||||
namespace fs
|
||||
{
|
||||
extern drive::gd *gDrive;
|
||||
void driveInit();
|
||||
void driveExit();
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "data.h"
|
||||
#include "ui.h"
|
||||
#include "miscui.h"
|
||||
#include "type.h"
|
||||
|
||||
namespace fs
|
||||
|
|
|
|||
70
inc/gd.h
Normal file
70
inc/gd.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#pragma once
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <json-c/json.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "curlfuncs.h"
|
||||
|
||||
#define HEADER_CONTENT_TYPE_APP_JSON "Content-Type: application/json; charset=UTF-8"
|
||||
#define HEADER_AUTHORIZATION "Authorization: Bearer "
|
||||
|
||||
#define MIMETYPE_FOLDER "application/vnd.google-apps.folder"
|
||||
|
||||
namespace drive
|
||||
{
|
||||
typedef struct
|
||||
{
|
||||
std::string name, id, mimeType;
|
||||
unsigned int size;
|
||||
std::vector<std::string> parents;
|
||||
} gdDirItem;
|
||||
|
||||
class gd
|
||||
{
|
||||
public:
|
||||
gd(const std::string& _clientID, const std::string& _secretID, const std::string& _authCode, const std::string& _rToken);
|
||||
|
||||
void exhangeAuthCode(const std::string& _authCode);
|
||||
bool hasToken() { return token.empty() == false; }
|
||||
void refreshToken();
|
||||
bool tokenIsValid();
|
||||
//Drive query parameters are appened to the default
|
||||
void loadDriveList(const std::string& _qParams);
|
||||
|
||||
void debugWriteList();
|
||||
|
||||
bool createDir(const std::string& _dirName);
|
||||
bool dirExists(const std::string& _dirName);
|
||||
void setRootDir(const std::string& _dirID)
|
||||
{
|
||||
rootDir = _dirID;
|
||||
parentDir = _dirID;
|
||||
loadDriveList("");
|
||||
}
|
||||
void returnToRoot(){ parentDir = rootDir; loadDriveList(""); }
|
||||
void chDir(const std::string& _dirID) { parentDir = _dirID; loadDriveList(""); }
|
||||
|
||||
bool fileExists(const std::string& _filename);
|
||||
void uploadFile(const std::string& _filename, curlFuncs::curlUpArgs *_upload);
|
||||
void updateFile(const std::string& _fileID, curlFuncs::curlUpArgs *_upload);
|
||||
void downloadFile(const std::string& _fileID, curlFuncs::curlDlArgs *_download);
|
||||
void deleteFile(const std::string& _fileID);
|
||||
|
||||
std::string getClientID() const { return clientID; }
|
||||
std::string getClientSecret() const { return secretID; }
|
||||
std::string getRefreshToken() const { return rToken; }
|
||||
std::string getFileID(const std::string& name);
|
||||
|
||||
size_t getDriveListCount() const { return driveList.size(); }
|
||||
drive::gdDirItem *getDirItemAt(unsigned int _ind) { return &driveList[_ind]; }
|
||||
|
||||
private:
|
||||
std::vector<gdDirItem> driveList;
|
||||
std::string clientID, secretID, token, rToken;
|
||||
std::string rootDir = "", parentDir = "";
|
||||
};
|
||||
}
|
||||
1
inc/ui.h
1
inc/ui.h
|
|
@ -15,6 +15,7 @@
|
|||
#include "ui/sldpanel.h"
|
||||
#include "ui/usr.h"
|
||||
#include "ui/ttl.h"
|
||||
#include "ui/fld.h"
|
||||
#include "ui/sett.h"
|
||||
#include "ui/ext.h"
|
||||
#include "ui/fm.h"
|
||||
|
|
|
|||
19
inc/ui/fld.h
Normal file
19
inc/ui/fld.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "ui.h"
|
||||
#include "dir.h"
|
||||
|
||||
namespace ui
|
||||
{
|
||||
//extern ui::menu *fldMenu;
|
||||
extern ui::slideOutPanel *fldPanel;
|
||||
//extern fs::dirList *fldList;
|
||||
|
||||
void fldInit();
|
||||
void fldExit();
|
||||
void fldUpdate();
|
||||
|
||||
//Populate to open menu, refresh for updating after actions
|
||||
void fldPopulateMenu();
|
||||
void fldRefreshMenu(bool _updateDrive);
|
||||
}
|
||||
|
|
@ -4,9 +4,8 @@ namespace ui
|
|||
{
|
||||
void ttlInit();
|
||||
void ttlExit();
|
||||
void ttlSetActive(int usr);
|
||||
void ttlSetActive(int usr, bool _set, bool _showSel);
|
||||
void ttlRefresh();
|
||||
void populateFldMenu();
|
||||
|
||||
//JIC for func ptr
|
||||
void ttlReset();
|
||||
|
|
|
|||
39
inc/util.h
39
inc/util.h
|
|
@ -1,5 +1,4 @@
|
|||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
#pragma once
|
||||
|
||||
#include "data.h"
|
||||
#include "ui.h"
|
||||
|
|
@ -37,6 +36,37 @@ namespace util
|
|||
CPU_SPEED_1785MHz = 1785000000
|
||||
} cpuSpds;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GPU_SPEED_0MHz = 0,
|
||||
GPU_SPEED_76MHz = 76800000,
|
||||
GPU_SPEED_153MHz = 153600000,
|
||||
GPU_SPEED_203MHz = 230400000,
|
||||
GPU_SPEED_307MHz = 307200000, //Handheld 1
|
||||
GPU_SPEED_384MHz = 384000000, //Handheld 2
|
||||
GPU_SPEED_460MHz = 460800000,
|
||||
GPU_SPEED_537MHz = 537600000,
|
||||
GPU_SPEED_614MHz = 614400000,
|
||||
GPU_SPEED_768MHz = 768000000, //Docked
|
||||
GPU_SPEED_844MHz = 844800000,
|
||||
GPU_SPEED_921MHZ = 921600000
|
||||
} gpuSpds;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RAM_SPEED_0MHz = 0,
|
||||
RAM_SPEED_40MHz = 40800000,
|
||||
RAM_SPEED_68MHz = 68000000,
|
||||
RAM_SPEED_102MHz = 102000000,
|
||||
RAM_SPEED_204MHz = 204000000,
|
||||
RAM_SPEED_408MHz = 408000000,
|
||||
RAM_SPEED_665MHz = 665600000,
|
||||
RAM_SPEED_800MHz = 800000000,
|
||||
RAM_SPEED_1065MHz = 1065600000,
|
||||
RAM_SPEED_1331MHz = 1331200000,
|
||||
RAM_SPEED_1600MHz = 1600000000
|
||||
} ramSpds;
|
||||
|
||||
//Returns string with date S+ time
|
||||
std::string getDateTime(int fmt);
|
||||
|
||||
|
|
@ -112,7 +142,8 @@ namespace util
|
|||
|
||||
Result accountDeleteUser(AccountUid *uid);
|
||||
|
||||
void setCPU(uint32_t hz);
|
||||
void sysBoost();
|
||||
void sysNormal();
|
||||
|
||||
void checkForUpdate(void *a);
|
||||
}
|
||||
#endif // UTIL_H
|
||||
|
|
|
|||
41
src/cfg.cpp
41
src/cfg.cpp
|
|
@ -14,13 +14,16 @@ std::vector<uint64_t> cfg::blacklist;
|
|||
std::vector<uint64_t> cfg::favorites;
|
||||
static std::unordered_map<uint64_t, std::string> pathDefs;
|
||||
uint8_t cfg::sortType;
|
||||
std::string cfg::driveClientID, cfg::driveClientSecret, cfg::driveRefreshToken, cfg::driveAuthCode;
|
||||
|
||||
const char *cfgPath = "sdmc:/config/JKSV/JKSV.cfg", *titleDefPath = "sdmc:/config/JKSV/titleDefs.txt", *workDirLegacy = "sdmc:/switch/jksv_dir.txt";
|
||||
static std::unordered_map<std::string, unsigned> cfgStrings =
|
||||
{
|
||||
{"workDir", 0}, {"includeDeviceSaves", 1}, {"autoBackup", 2}, {"overclock", 3}, {"holdToDelete", 4}, {"holdToRestore", 5},
|
||||
{"holdToOverwrite", 6}, {"forceMount", 7}, {"accountSystemSaves", 8}, {"allowSystemSaveWrite", 9}, {"directFSCommands", 10},
|
||||
{"exportToZIP", 11}, {"languageOverride", 12}, {"enableTrashBin", 13}, {"titleSortType", 14}, {"animationScale", 15},
|
||||
{"favorite", 16}, {"blacklist", 17}, {"autoName", 18}
|
||||
{"favorite", 16}, {"blacklist", 17}, {"autoName", 18}, {"driveClientID", 19}, {"driveClientSecret", 20}, {"driveRefreshToken", 21},
|
||||
{"driveAuthCode", 22}
|
||||
};
|
||||
|
||||
const std::string _true_ = "true", _false_ = "false";
|
||||
|
|
@ -102,12 +105,13 @@ bool cfg::isDefined(const uint64_t& tid)
|
|||
|
||||
void cfg::pathDefAdd(const uint64_t& tid, const std::string& newPath)
|
||||
{
|
||||
std::string oldSafe = data::titles[tid].safeTitle;
|
||||
data::titleInfo *t = data::getTitleInfoByTID(tid);
|
||||
std::string oldSafe = t->safeTitle;
|
||||
std::string tmp = util::safeString(newPath);
|
||||
if(!tmp.empty())
|
||||
{
|
||||
pathDefs[tid] = tmp;
|
||||
data::titles[tid].safeTitle = tmp;
|
||||
t->safeTitle = tmp;
|
||||
|
||||
std::string oldOutput = fs::getWorkDir() + oldSafe;
|
||||
std::string newOutput = fs::getWorkDir() + tmp;
|
||||
|
|
@ -302,7 +306,10 @@ void cfg::loadConfig()
|
|||
fs::dataFile cfgRead(cfgPath);
|
||||
while(cfgRead.readNextLine(true))
|
||||
{
|
||||
switch(cfgStrings[cfgRead.getName()])
|
||||
std::string varName = cfgRead.getName();
|
||||
if(cfgStrings.find(varName) != cfgStrings.end())
|
||||
{
|
||||
switch(cfgStrings[varName])
|
||||
{
|
||||
case 0:
|
||||
fs::setWorkDir(cfgRead.getNextValueStr());
|
||||
|
|
@ -397,12 +404,29 @@ void cfg::loadConfig()
|
|||
cfg::config["autoName"] = textToBool(cfgRead.getNextValueStr());
|
||||
break;
|
||||
|
||||
case 19:
|
||||
cfg::driveClientID = cfgRead.getNextValueStr();
|
||||
break;
|
||||
|
||||
case 20:
|
||||
cfg::driveClientSecret = cfgRead.getNextValueStr();
|
||||
break;
|
||||
|
||||
case 21:
|
||||
cfg::driveRefreshToken = cfgRead.getNextValueStr();
|
||||
break;
|
||||
|
||||
case 22:
|
||||
cfg::driveAuthCode = cfgRead.getNextValueStr();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void savePathDefs()
|
||||
{
|
||||
|
|
@ -433,6 +457,15 @@ void cfg::saveConfig()
|
|||
fprintf(cfgOut, "titleSortType = %s\n", sortTypeText().c_str());
|
||||
fprintf(cfgOut, "animationScale = %f\n", ui::animScale);
|
||||
|
||||
if(!cfg::driveClientID.empty())
|
||||
fprintf(cfgOut, "driveClientID = %s\n", cfg::driveClientID.c_str());
|
||||
|
||||
if(!cfg::driveClientSecret.empty())
|
||||
fprintf(cfgOut, "driveClientSecret = %s\n", cfg::driveClientSecret.c_str());
|
||||
|
||||
if(!cfg::driveRefreshToken.empty())
|
||||
fprintf(cfgOut, "driveRefreshToken = %s\n", cfg::driveRefreshToken.c_str());
|
||||
|
||||
if(!cfg::favorites.empty())
|
||||
{
|
||||
fprintf(cfgOut, "\n#favorites\n");
|
||||
|
|
|
|||
|
|
@ -2,21 +2,54 @@
|
|||
#include <vector>
|
||||
#include <curl/curl.h>
|
||||
|
||||
size_t writeDataString(const char *buff, size_t sz, size_t cnt, void *u)
|
||||
#include "curlfuncs.h"
|
||||
#include "util.h"
|
||||
|
||||
size_t curlFuncs::writeDataString(const char *buff, size_t sz, size_t cnt, void *u)
|
||||
{
|
||||
std::string *str = (std::string *)u;
|
||||
str->append(buff, 0, sz * cnt);
|
||||
return sz * cnt;
|
||||
}
|
||||
|
||||
size_t writeDataHead(const char *buff, size_t sz, size_t cnt, void *u)
|
||||
size_t curlFuncs::writeHeaders(const char *buff, size_t sz, size_t cnt, void *u)
|
||||
{
|
||||
std::vector<std::string> *headers = (std::vector<std::string> *)u;
|
||||
headers->push_back(buff);
|
||||
return sz * cnt;
|
||||
}
|
||||
|
||||
std::string getJSONURL(std::vector<std::string> *headers, const std::string& _url)
|
||||
size_t curlFuncs::readDataFile(char *buff, size_t sz, size_t cnt, void *u)
|
||||
{
|
||||
curlFuncs::curlUpArgs*in = (curlFuncs::curlUpArgs *)u;
|
||||
|
||||
size_t ret = fread(buff, sz, cnt, in->f);
|
||||
|
||||
if(in->o)
|
||||
*in->o = ftell(in->f);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string curlFuncs::getHeader(const std::string& name, std::vector<std::string> *h)
|
||||
{
|
||||
std::string ret = HEADER_ERROR;
|
||||
for (unsigned i = 0; i < h->size(); i++)
|
||||
{
|
||||
std::string curHeader = h->at(i);
|
||||
size_t colonPos = curHeader.find_first_of(':');
|
||||
if (curHeader.substr(0, colonPos) == name)
|
||||
{
|
||||
ret = curHeader.substr(colonPos + 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
util::stripChar('\n', ret);
|
||||
util::stripChar('\r', ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string curlFuncs::getJSONURL(std::vector<std::string> *headers, const std::string& _url)
|
||||
{
|
||||
std::string ret;
|
||||
CURL *handle = curl_easy_init();
|
||||
|
|
@ -29,7 +62,7 @@ std::string getJSONURL(std::vector<std::string> *headers, const std::string& _ur
|
|||
curl_easy_setopt(handle, CURLOPT_TIMEOUT, 15);
|
||||
if(headers)
|
||||
{
|
||||
curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, writeDataHead);
|
||||
curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, writeHeaders);
|
||||
curl_easy_setopt(handle, CURLOPT_HEADERDATA, headers);
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +82,7 @@ size_t writeDataBin(uint8_t *buff, size_t sz, size_t cnt, void *u)
|
|||
return sizeIn;
|
||||
}
|
||||
|
||||
bool getBinURL(std::vector<uint8_t> *out, const std::string& _url)
|
||||
bool curlFuncs::getBinURL(std::vector<uint8_t> *out, const std::string& _url)
|
||||
{
|
||||
bool ret = false;
|
||||
CURL *handle = curl_easy_init();
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ SetLanguage data::sysLang;
|
|||
//For other save types
|
||||
static bool sysBCATPushed = false, tempPushed = false;
|
||||
std::unordered_map<uint64_t, data::titleInfo> data::titles;
|
||||
static SDL_Texture *iconMask;
|
||||
|
||||
//Sorts titles by sortType
|
||||
static struct
|
||||
|
|
@ -355,9 +354,6 @@ void data::sortUserTitles()
|
|||
|
||||
void data::init()
|
||||
{
|
||||
if(cfg::config["ovrClk"])
|
||||
util::setCPU(util::CPU_SPEED_1224MHz);
|
||||
|
||||
data::loadUsersTitles(true);
|
||||
}
|
||||
|
||||
|
|
@ -366,11 +362,6 @@ void data::exit()
|
|||
for(data::user& u : data::users) u.delIcon();
|
||||
for(auto& tinfo : titles)
|
||||
SDL_DestroyTexture(tinfo.second.icon);
|
||||
|
||||
SDL_DestroyTexture(iconMask);
|
||||
|
||||
if(cfg::config["ovrClk"])
|
||||
util::setCPU(util::CPU_SPEED_1020MHz);
|
||||
}
|
||||
|
||||
void data::setUserIndex(unsigned _sUser)
|
||||
|
|
|
|||
|
|
@ -431,7 +431,7 @@ void fs::createNewBackup(void *a)
|
|||
path += "/";
|
||||
fs::copyDirToDirThreaded("sv:/", path);
|
||||
}
|
||||
ui::populateFldMenu();
|
||||
ui::fldRefreshMenu(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -537,7 +537,7 @@ void fs::restoreBackup(void *a)
|
|||
}
|
||||
}
|
||||
if(cfg::config["autoBack"])
|
||||
ui::populateFldMenu();
|
||||
ui::fldRefreshMenu(false);
|
||||
|
||||
delete restore;
|
||||
t->finished = true;
|
||||
|
|
@ -572,7 +572,7 @@ void fs::deleteBackup(void *a)
|
|||
fs::delfile(*deletePath);
|
||||
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupDeleted", 0), backupName.c_str());
|
||||
}
|
||||
ui::populateFldMenu();
|
||||
ui::fldRefreshMenu(false);
|
||||
delete deletePath;
|
||||
t->finished = true;
|
||||
}
|
||||
|
|
|
|||
41
src/fs/drive.cpp
Normal file
41
src/fs/drive.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#include "drive.h"
|
||||
#include "cfg.h"
|
||||
#include "ui.h"
|
||||
|
||||
drive::gd *fs::gDrive = NULL;
|
||||
|
||||
void fs::driveInit()
|
||||
{
|
||||
if(!cfg::driveClientID.empty() && !cfg::driveClientSecret.empty())
|
||||
{
|
||||
fs::gDrive = new drive::gd(cfg::driveClientID, cfg::driveClientSecret, cfg::driveAuthCode, cfg::driveRefreshToken);
|
||||
if(!fs::gDrive->hasToken())
|
||||
{
|
||||
delete fs::gDrive;
|
||||
fs::gDrive = NULL;
|
||||
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popDriveFailed", 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
fs::gDrive->loadDriveList("name = 'JKSV'");
|
||||
|
||||
if(!fs::gDrive->dirExists("JKSV"))
|
||||
fs::gDrive->createDir("JKSV");
|
||||
|
||||
std::string jksvID = fs::gDrive->getFileID("JKSV");
|
||||
fs::gDrive->setRootDir(jksvID);
|
||||
|
||||
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popDriveStarted", 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fs::driveExit()
|
||||
{
|
||||
if(fs::gDrive)
|
||||
{
|
||||
//Need to save for config if first run
|
||||
cfg::driveRefreshToken = fs::gDrive->getRefreshToken();
|
||||
delete gDrive;
|
||||
}
|
||||
}
|
||||
213
src/fs/file.cpp
213
src/fs/file.cpp
|
|
@ -5,6 +5,8 @@
|
|||
#include <switch.h>
|
||||
#include <unistd.h>
|
||||
#include <cstdarg>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "fs.h"
|
||||
|
|
@ -16,6 +18,69 @@
|
|||
|
||||
static std::string wd = "sdmc:/JKSV/";
|
||||
|
||||
typedef struct
|
||||
{
|
||||
std::mutex bufferLock;
|
||||
std::condition_variable cond;
|
||||
std::vector<uint8_t> sharedBuffer;
|
||||
std::string dst, dev;
|
||||
bool bufferIsFull = false;
|
||||
unsigned int filesize = 0, writeLimit = 0;
|
||||
} fileCpyThreadArgs;
|
||||
|
||||
static void writeFile_t(void *a)
|
||||
{
|
||||
fileCpyThreadArgs *in = (fileCpyThreadArgs *)a;
|
||||
size_t written = 0;
|
||||
std::vector<uint8_t> localBuffer;
|
||||
FILE *out = fopen(in->dst.c_str(), "wb");
|
||||
while(written < in->filesize)
|
||||
{
|
||||
std::unique_lock<std::mutex> buffLock(in->bufferLock);
|
||||
in->cond.wait(buffLock, [in]{ return in->bufferIsFull;});
|
||||
localBuffer.clear();
|
||||
localBuffer.assign(in->sharedBuffer.begin(), in->sharedBuffer.end());
|
||||
in->sharedBuffer.clear();
|
||||
in->bufferIsFull = false;
|
||||
buffLock.unlock();
|
||||
in->cond.notify_one();
|
||||
|
||||
written += fwrite(localBuffer.data(), 1, localBuffer.size(), out);
|
||||
}
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
static void writeFileCommit_t(void *a)
|
||||
{
|
||||
fileCpyThreadArgs *in = (fileCpyThreadArgs *)a;
|
||||
size_t written = 0, journalCount = 0;
|
||||
std::vector<uint8_t> localBuffer;
|
||||
FILE *out = fopen(in->dst.c_str(), "wb");
|
||||
|
||||
while(written < in->filesize)
|
||||
{
|
||||
std::unique_lock<std::mutex> buffLock(in->bufferLock);
|
||||
in->cond.wait(buffLock, [in]{ return in->bufferIsFull; });
|
||||
localBuffer.clear();
|
||||
localBuffer.assign(in->sharedBuffer.begin(), in->sharedBuffer.end());
|
||||
in->sharedBuffer.clear();
|
||||
in->bufferIsFull = false;
|
||||
buffLock.unlock();
|
||||
in->cond.notify_one();
|
||||
|
||||
written += fwrite(localBuffer.data(), 1, localBuffer.size(), out);
|
||||
journalCount += written;
|
||||
if(journalCount >= in->writeLimit)
|
||||
{
|
||||
journalCount = 0;
|
||||
fclose(out);
|
||||
fs::commitToDevice(in->dev.c_str());
|
||||
out = fopen(in->dst.c_str(), "ab");
|
||||
}
|
||||
}
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
fs::copyArgs *fs::copyArgsCreate(const std::string& src, const std::string& dst, const std::string& dev, zipFile z, unzFile unz, bool _cleanup, bool _trimZipPath, uint8_t _trimPlaces)
|
||||
{
|
||||
copyArgs *ret = new copyArgs;
|
||||
|
|
@ -122,63 +187,54 @@ int fs::dataFile::getNextValueInt()
|
|||
void fs::copyFile(const std::string& src, const std::string& dst, threadInfo *t)
|
||||
{
|
||||
fs::copyArgs *c = NULL;
|
||||
size_t filesize = fs::fsize(src);
|
||||
if(t)
|
||||
{
|
||||
c = (fs::copyArgs *)t->argPtr;
|
||||
c->offset = 0;
|
||||
c->prog->setMax(fs::fsize(src));
|
||||
c->prog->setMax(filesize);
|
||||
c->prog->update(0);
|
||||
}
|
||||
|
||||
if(cfg::config["directFsCmd"])
|
||||
{
|
||||
FSFILE *fsrc = fsfopen(src.c_str(), FsOpenMode_Read);
|
||||
FSFILE *fdst = fsfopen(dst.c_str(), FsOpenMode_Write);
|
||||
|
||||
if(!fsrc || !fdst)
|
||||
{
|
||||
fsfclose(fsrc);
|
||||
fsfclose(fdst);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *buff = new uint8_t[BUFF_SIZE];
|
||||
size_t readIn = 0;
|
||||
while((readIn = fsfread(buff, 1, BUFF_SIZE, fsrc)) > 0)
|
||||
{
|
||||
fsfwrite(buff, 1, readIn, fdst);
|
||||
if(c)
|
||||
c->offset += readIn;
|
||||
}
|
||||
fsfclose(fsrc);
|
||||
fsfclose(fdst);
|
||||
delete[] buff;
|
||||
}
|
||||
else
|
||||
{
|
||||
FILE *fsrc = fopen(src.c_str(), "rb");
|
||||
FILE *fdst = fopen(dst.c_str(), "wb");
|
||||
|
||||
if(!fsrc || !fdst)
|
||||
if(!fsrc)
|
||||
{
|
||||
fclose(fsrc);
|
||||
fclose(fdst);
|
||||
return;
|
||||
}
|
||||
|
||||
fileCpyThreadArgs thrdArgs;
|
||||
thrdArgs.dst = dst;
|
||||
thrdArgs.filesize = filesize;
|
||||
|
||||
uint8_t *buff = new uint8_t[BUFF_SIZE];
|
||||
std::vector<uint8_t> transferBuffer;
|
||||
Thread writeThread;
|
||||
threadCreate(&writeThread, writeFile_t, &thrdArgs, NULL, 0x8000, 0x2B, 2);
|
||||
threadStart(&writeThread);
|
||||
size_t readIn = 0;
|
||||
while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0)
|
||||
{
|
||||
fwrite(buff, 1, readIn, fdst);
|
||||
transferBuffer.insert(transferBuffer.end(), buff, buff + readIn);
|
||||
if(c)
|
||||
c->offset += readIn;
|
||||
|
||||
if(transferBuffer.size() > TRANSFER_BUFFER_LIMIT || readIn < BUFF_SIZE)
|
||||
{
|
||||
std::unique_lock<std::mutex> buffLock(thrdArgs.bufferLock);
|
||||
thrdArgs.cond.wait(buffLock, [&thrdArgs]{ return thrdArgs.bufferIsFull == false; });
|
||||
thrdArgs.sharedBuffer.assign(transferBuffer.begin(), transferBuffer.end());
|
||||
transferBuffer.clear();
|
||||
thrdArgs.bufferIsFull = true;
|
||||
buffLock.unlock();
|
||||
thrdArgs.cond.notify_one();
|
||||
}
|
||||
}
|
||||
threadWaitForExit(&writeThread);
|
||||
threadClose(&writeThread);
|
||||
fclose(fsrc);
|
||||
fclose(fdst);
|
||||
delete[] buff;
|
||||
}
|
||||
}
|
||||
|
||||
static void copyFileThreaded_t(void *a)
|
||||
{
|
||||
|
|
@ -202,89 +258,60 @@ void fs::copyFileThreaded(const std::string& src, const std::string& dst)
|
|||
void fs::copyFileCommit(const std::string& src, const std::string& dst, const std::string& dev, threadInfo *t)
|
||||
{
|
||||
fs::copyArgs *c = NULL;
|
||||
size_t filesize = fs::fsize(src);
|
||||
if(t)
|
||||
{
|
||||
c = (fs::copyArgs *)t->argPtr;
|
||||
c->offset = 0;
|
||||
c->prog->setMax(fs::fsize(src));
|
||||
c->prog->setMax(filesize);
|
||||
c->prog->update(0);
|
||||
}
|
||||
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
uint64_t journ = fs::getJournalSize(utinfo);
|
||||
if(cfg::config["directFsCmd"])
|
||||
{
|
||||
FSFILE *fsrc = fsfopen(src.c_str(), FsOpenMode_Read);
|
||||
FSFILE *fdst = fsfopen(dst.c_str(), FsOpenMode_Write);
|
||||
|
||||
if(!fsrc || !fdst)
|
||||
{
|
||||
fsfclose(fsrc);
|
||||
fsfclose(fdst);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *buff = new uint8_t[BUFF_SIZE];
|
||||
size_t readIn = 0, writeCount = 0;
|
||||
while((readIn = fsfread(buff, 1, BUFF_SIZE, fsrc)) > 0)
|
||||
{
|
||||
fsfwrite(buff, 1, readIn, fdst);
|
||||
writeCount += readIn;
|
||||
if(c)
|
||||
c->offset += readIn;
|
||||
|
||||
if(writeCount >= (journ - 0x100000))
|
||||
{
|
||||
writeCount = 0;
|
||||
fsfclose(fdst);
|
||||
if(!fs::commitToDevice(dev.c_str()))
|
||||
break;
|
||||
|
||||
fdst = fsfopen(dst.c_str(), FsOpenMode_Write | FsOpenMode_Append);
|
||||
}
|
||||
}
|
||||
fsfclose(fsrc);
|
||||
fsfclose(fdst);
|
||||
fs::commitToDevice(dev);
|
||||
delete[] buff;
|
||||
}
|
||||
else
|
||||
{
|
||||
FILE *fsrc = fopen(src.c_str(), "rb");
|
||||
FILE *fdst = fopen(dst.c_str(), "wb");
|
||||
|
||||
if(!fsrc || !fdst)
|
||||
if(!fsrc)
|
||||
{
|
||||
fclose(fsrc);
|
||||
fclose(fdst);
|
||||
return;
|
||||
}
|
||||
|
||||
fileCpyThreadArgs thrdArgs;
|
||||
thrdArgs.dst = dst;
|
||||
thrdArgs.dev = dev;
|
||||
thrdArgs.filesize = filesize;
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
uint64_t journalSpace = fs::getJournalSize(utinfo);
|
||||
thrdArgs.writeLimit = (journalSpace - 0x100000) < TRANSFER_BUFFER_LIMIT ? journalSpace - 0x100000 : TRANSFER_BUFFER_LIMIT;
|
||||
|
||||
Thread writeThread;
|
||||
threadCreate(&writeThread, writeFileCommit_t, &thrdArgs, NULL, 0x8000, 0x2B, 2);
|
||||
|
||||
uint8_t *buff = new uint8_t[BUFF_SIZE];
|
||||
size_t readIn = 0, writeCount = 0;
|
||||
size_t readIn = 0;
|
||||
std::vector<uint8_t> transferBuffer;
|
||||
threadStart(&writeThread);
|
||||
while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0)
|
||||
{
|
||||
fwrite(buff, 1, readIn, fdst);
|
||||
writeCount += readIn;
|
||||
transferBuffer.insert(transferBuffer.end(), buff, buff + readIn);
|
||||
if(c)
|
||||
c->offset += readIn;
|
||||
|
||||
if(writeCount >= (journ - 0x100000))
|
||||
if(transferBuffer.size() >= thrdArgs.writeLimit || readIn < BUFF_SIZE)
|
||||
{
|
||||
writeCount = 0;
|
||||
fclose(fdst);
|
||||
if(!fs::commitToDevice(dev))
|
||||
break;
|
||||
std::unique_lock<std::mutex> buffLock(thrdArgs.bufferLock);
|
||||
thrdArgs.cond.wait(buffLock, [&thrdArgs]{ return thrdArgs.bufferIsFull == false; });
|
||||
thrdArgs.sharedBuffer.assign(transferBuffer.begin(), transferBuffer.end());
|
||||
transferBuffer.clear();
|
||||
thrdArgs.bufferIsFull = true;
|
||||
buffLock.unlock();
|
||||
thrdArgs.cond.notify_one();
|
||||
}
|
||||
}
|
||||
threadWaitForExit(&writeThread);
|
||||
threadClose(&writeThread);
|
||||
|
||||
fdst = fopen(dst.c_str(), "ab");
|
||||
}
|
||||
}
|
||||
fclose(fsrc);
|
||||
fclose(fdst);
|
||||
fs::commitToDevice(dev);
|
||||
delete[] buff;
|
||||
}
|
||||
}
|
||||
|
||||
static void copyFileCommit_t(void *a)
|
||||
{
|
||||
|
|
|
|||
100
src/fs/zip.cpp
100
src/fs/zip.cpp
|
|
@ -1,8 +1,57 @@
|
|||
#include <switch.h>
|
||||
#include <time.h>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <condition_variable>
|
||||
|
||||
#include "fs.h"
|
||||
#include "util.h"
|
||||
#include "cfg.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
std::mutex buffLock;
|
||||
std::condition_variable cond;
|
||||
std::vector<uint8_t> sharedBuffer;
|
||||
std::string dst, dev;
|
||||
bool bufferIsFull = false;
|
||||
unzFile unz;
|
||||
unsigned int fileSize, writeLimit = 0;
|
||||
} unzThrdArgs;
|
||||
|
||||
static void writeFileFromZip_t(void *a)
|
||||
{
|
||||
unzThrdArgs *in = (unzThrdArgs *)a;
|
||||
std::vector<uint8_t> localBuffer;
|
||||
unsigned int written = 0, journalCount = 0;
|
||||
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
uint64_t journalSpace = fs::getJournalSize(utinfo);
|
||||
|
||||
FILE *out = fopen(in->dst.c_str(), "wb");
|
||||
while(written < in->fileSize)
|
||||
{
|
||||
std::unique_lock<std::mutex> buffLock(in->buffLock);
|
||||
in->cond.wait(buffLock, [in]{ return in->bufferIsFull; });
|
||||
localBuffer.clear();
|
||||
localBuffer.assign(in->sharedBuffer.begin(), in->sharedBuffer.end());
|
||||
in->sharedBuffer.clear();
|
||||
in->bufferIsFull = false;
|
||||
buffLock.unlock();
|
||||
in->cond.notify_one();
|
||||
|
||||
written += fwrite(localBuffer.data(), 1, localBuffer.size(), out);
|
||||
journalCount += written;
|
||||
if(journalCount >= in->writeLimit)
|
||||
{
|
||||
journalCount = 0;
|
||||
fclose(out);
|
||||
fs::commitToDevice(in->dev);
|
||||
out = fopen(in->dst.c_str(), "ab");
|
||||
}
|
||||
}
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
void fs::copyDirToZip(const std::string& src, zipFile dst, bool trimPath, int trimPlaces, threadInfo *t)
|
||||
{
|
||||
|
|
@ -56,8 +105,8 @@ void fs::copyDirToZip(const std::string& src, zipFile dst, bool trimPath, int tr
|
|||
|
||||
FILE *fsrc = fopen(fullSrc.c_str(), "rb");
|
||||
size_t readIn = 0;
|
||||
uint8_t *buff = new uint8_t[BUFF_SIZE];
|
||||
while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0)
|
||||
uint8_t *buff = new uint8_t[ZIP_BUFF_SIZE];
|
||||
while((readIn = fread(buff, 1, ZIP_BUFF_SIZE, fsrc)) > 0)
|
||||
{
|
||||
zipWriteInFileInZip(dst, buff, readIn);
|
||||
if(c)
|
||||
|
|
@ -74,7 +123,17 @@ void copyDirToZip_t(void *a)
|
|||
{
|
||||
threadInfo *t = (threadInfo *)a;
|
||||
fs::copyArgs *c = (fs::copyArgs *)t->argPtr;
|
||||
if(cfg::config["ovrClk"])
|
||||
{
|
||||
util::sysBoost();
|
||||
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popCPUBoostEnabled", 0));
|
||||
}
|
||||
|
||||
fs::copyDirToZip(c->src, c->z, c->trimZipPath, c->trimZipPlaces, t);
|
||||
|
||||
if(cfg::config["ovrClk"])
|
||||
util::sysNormal();
|
||||
|
||||
if(c->cleanup)
|
||||
{
|
||||
zipClose(c->z, NULL);
|
||||
|
|
@ -119,23 +178,36 @@ void fs::copyZipToDir(unzFile src, const std::string& dst, const std::string& de
|
|||
std::string fullDst = dst + filename;
|
||||
fs::mkDirRec(fullDst.substr(0, fullDst.find_last_of('/') + 1));
|
||||
|
||||
FILE *fdst = fopen(fullDst.c_str(), "wb");
|
||||
unzThrdArgs unzThrd;
|
||||
unzThrd.dst = fullDst;
|
||||
unzThrd.fileSize = info.uncompressed_size;
|
||||
unzThrd.dev = dev;
|
||||
unzThrd.writeLimit = (journalSize - 0x100000) < TRANSFER_BUFFER_LIMIT ? (journalSize - 0x100000) : TRANSFER_BUFFER_LIMIT;
|
||||
|
||||
Thread writeThread;
|
||||
threadCreate(&writeThread, writeFileFromZip_t, &unzThrd, NULL, 0x8000, 0x2B, 2);
|
||||
threadStart(&writeThread);
|
||||
|
||||
std::vector<uint8_t> transferBuffer;
|
||||
while((readIn = unzReadCurrentFile(src, buff, BUFF_SIZE)) > 0)
|
||||
{
|
||||
c->offset += readIn;
|
||||
writeCount += readIn;
|
||||
fwrite(buff, 1, readIn, fdst);
|
||||
if(writeCount >= journalSize - 0x100000)
|
||||
{
|
||||
writeCount = 0;
|
||||
fclose(fdst);
|
||||
if(!fs::commitToDevice(dev))
|
||||
break;
|
||||
transferBuffer.insert(transferBuffer.end(), buff, buff + readIn);
|
||||
|
||||
fdst = fopen(fullDst.c_str(), "ab");
|
||||
if(c)
|
||||
c->offset += readIn;
|
||||
|
||||
if(transferBuffer.size() >= unzThrd.writeLimit || readIn < BUFF_SIZE)
|
||||
{
|
||||
std::unique_lock<std::mutex> buffLock(unzThrd.buffLock);
|
||||
unzThrd.cond.wait(buffLock, [&unzThrd]{ return unzThrd.bufferIsFull == false; });
|
||||
unzThrd.sharedBuffer.assign(transferBuffer.begin(), transferBuffer.end());
|
||||
transferBuffer.clear();
|
||||
unzThrd.bufferIsFull = true;
|
||||
unzThrd.cond.notify_one();
|
||||
}
|
||||
}
|
||||
fclose(fdst);
|
||||
threadWaitForExit(&writeThread);
|
||||
threadClose(&writeThread);
|
||||
fs::commitToDevice(dev);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
654
src/gd.cpp
Normal file
654
src/gd.cpp
Normal file
|
|
@ -0,0 +1,654 @@
|
|||
#include <stdio.h>
|
||||
#include <curl/curl.h>
|
||||
#include <json-c/json.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
#include "gd.h"
|
||||
#include "fs.h"
|
||||
#include "curlfuncs.h"
|
||||
#include "util.h"
|
||||
|
||||
/*
|
||||
Google Drive code for JKSV.
|
||||
Still major WIP
|
||||
*/
|
||||
|
||||
#define DRIVE_UPLOAD_BUFFER_SIZE 0x8000
|
||||
#define DRIVE_DOWNLOAD_BUFFER_SIZE 0xA00000
|
||||
|
||||
#define tokenURL "https://oauth2.googleapis.com/token"
|
||||
#define tokenCheckURL "https://oauth2.googleapis.com/tokeninfo"
|
||||
#define driveURL "https://www.googleapis.com/drive/v3/files"
|
||||
#define driveUploadURL "https://www.googleapis.com/upload/drive/v3/files"
|
||||
#define userAgent "JKSV"
|
||||
|
||||
std::vector<uint8_t> downloadBuffer;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
curlFuncs::curlDlArgs *cfa;
|
||||
std::mutex dataLock;
|
||||
std::condition_variable cond;
|
||||
std::vector<uint8_t> sharedBuffer;
|
||||
bool bufferFull = false;
|
||||
unsigned int downloaded = 0;
|
||||
} dlWriteThreadStruct;
|
||||
|
||||
static inline void writeDriveError(const std::string& _function, const std::string& _message)
|
||||
{
|
||||
fs::logWrite("Drive/%s: %s\n", _function.c_str(), _message.c_str());
|
||||
}
|
||||
|
||||
static inline void writeCurlError(const std::string& _function, int _cerror)
|
||||
{
|
||||
fs::logWrite("Drive/%s: CURL returned error %i\n", _function.c_str(), _cerror);
|
||||
}
|
||||
|
||||
static void writeThread_t(void *a)
|
||||
{
|
||||
dlWriteThreadStruct *in = (dlWriteThreadStruct *)a;
|
||||
std::vector<uint8_t> localBuff;
|
||||
int written = 0;
|
||||
|
||||
FILE *out = fopen(in->cfa->path.c_str(), "wb");
|
||||
|
||||
while(written < in->cfa->size)
|
||||
{
|
||||
std::unique_lock<std::mutex> dataLock(in->dataLock);
|
||||
in->cond.wait(dataLock, [in]{ return in->bufferFull; });
|
||||
localBuff.clear();
|
||||
localBuff.assign(in->sharedBuffer.begin(), in->sharedBuffer.end());
|
||||
in->sharedBuffer.clear();
|
||||
in->bufferFull = false;
|
||||
dataLock.unlock();
|
||||
in->cond.notify_one();
|
||||
|
||||
written += fwrite(localBuff.data(), 1, localBuff.size(), out);
|
||||
}
|
||||
fclose(out);
|
||||
downloadBuffer.clear();
|
||||
}
|
||||
|
||||
static size_t writeDataBufferThreaded(uint8_t *buff, size_t sz, size_t cnt, void *u)
|
||||
{
|
||||
dlWriteThreadStruct *in = (dlWriteThreadStruct *)u;
|
||||
downloadBuffer.insert(downloadBuffer.end(), buff, buff + (sz * cnt));
|
||||
in->downloaded += sz * cnt;
|
||||
|
||||
if(in->downloaded == in->cfa->size || (downloadBuffer.size() >= DRIVE_DOWNLOAD_BUFFER_SIZE))
|
||||
{
|
||||
std::unique_lock<std::mutex> dataLock(in->dataLock);
|
||||
in->cond.wait(dataLock, [in]{ return in->bufferFull == false; });
|
||||
in->sharedBuffer.assign(downloadBuffer.begin(), downloadBuffer.end());
|
||||
downloadBuffer.clear();
|
||||
in->bufferFull = true;
|
||||
dataLock.unlock();
|
||||
in->cond.notify_one();
|
||||
}
|
||||
|
||||
if(in->cfa->o)
|
||||
*in->cfa->o = in->downloaded;
|
||||
|
||||
return sz * cnt;
|
||||
}
|
||||
|
||||
drive::gd::gd(const std::string &_clientID, const std::string& _secretID, const std::string& _authCode, const std::string& _rToken)
|
||||
{
|
||||
clientID = _clientID;
|
||||
secretID = _secretID;
|
||||
rToken = _rToken;
|
||||
|
||||
if(!_authCode.empty())
|
||||
exhangeAuthCode(_authCode);
|
||||
else if(!rToken.empty())
|
||||
refreshToken();
|
||||
else
|
||||
writeDriveError("gd::gd", "Missing data needed to init Google Drive.\n");
|
||||
}
|
||||
|
||||
void drive::gd::exhangeAuthCode(const std::string& _authCode)
|
||||
{
|
||||
// Header
|
||||
curl_slist *postHeader = NULL;
|
||||
postHeader = curl_slist_append(postHeader, HEADER_CONTENT_TYPE_APP_JSON);
|
||||
|
||||
// Post json
|
||||
std::string *postJson = new std::string;
|
||||
json_object *post = json_object_new_object();
|
||||
json_object *clientIDString = json_object_new_string(clientID.c_str());
|
||||
json_object *secretIDString = json_object_new_string(secretID.c_str());
|
||||
json_object *authCodeString = json_object_new_string(_authCode.c_str());
|
||||
json_object *redirectUriString = json_object_new_string("urn:ietf:wg:oauth:2.0:oob");
|
||||
json_object *grantTypeString = json_object_new_string("authorization_code");
|
||||
json_object_object_add(post, "client_id", clientIDString);
|
||||
json_object_object_add(post, "client_secret", secretIDString);
|
||||
json_object_object_add(post, "code", authCodeString);
|
||||
json_object_object_add(post, "redirect_uri", redirectUriString);
|
||||
json_object_object_add(post, "grant_type", grantTypeString);
|
||||
postJson->assign(json_object_to_json_string_ext(post, JSON_C_TO_STRING_NOSLASHESCAPE));
|
||||
|
||||
// Curl Request
|
||||
std::string *jsonResp = new std::string;
|
||||
CURL *curl = curl_easy_init();
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, postHeader);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, tokenURL);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlFuncs::writeDataString);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, jsonResp);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postJson->c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, postJson->length());
|
||||
|
||||
int error = curl_easy_perform(curl);
|
||||
|
||||
json_object *respParse = json_tokener_parse(jsonResp->c_str());
|
||||
if (error == CURLE_OK)
|
||||
{
|
||||
json_object *accessToken = json_object_object_get(respParse, "access_token");
|
||||
json_object *refreshToken = json_object_object_get(respParse, "refresh_token");
|
||||
|
||||
if(accessToken && refreshToken)
|
||||
{
|
||||
token = json_object_get_string(accessToken);
|
||||
rToken = json_object_get_string(refreshToken);
|
||||
}
|
||||
else
|
||||
writeDriveError("exchangeAuthCode", "Error exchanging code for token.");
|
||||
}
|
||||
else
|
||||
writeCurlError("exchangeAuthCode", error);
|
||||
|
||||
delete postJson;
|
||||
delete jsonResp;
|
||||
json_object_put(post);
|
||||
json_object_put(respParse);
|
||||
curl_slist_free_all(postHeader);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
void drive::gd::refreshToken()
|
||||
{
|
||||
// Header
|
||||
curl_slist *header = NULL;
|
||||
header = curl_slist_append(header, HEADER_CONTENT_TYPE_APP_JSON);
|
||||
|
||||
// Post Json
|
||||
std::string *jsonPost = new std::string;
|
||||
json_object *post = json_object_new_object();
|
||||
json_object *clientIDString = json_object_new_string(clientID.c_str());
|
||||
json_object *secretIDString = json_object_new_string(secretID.c_str());
|
||||
json_object *refreshTokenString = json_object_new_string(rToken.c_str());
|
||||
json_object *grantTypeString = json_object_new_string("refresh_token");
|
||||
json_object_object_add(post, "client_id", clientIDString);
|
||||
json_object_object_add(post, "client_secret", secretIDString);
|
||||
json_object_object_add(post, "refresh_token", refreshTokenString);
|
||||
json_object_object_add(post, "grant_type", grantTypeString);
|
||||
jsonPost->assign(json_object_to_json_string(post));
|
||||
|
||||
// Curl
|
||||
std::string *jsonResp = new std::string;
|
||||
CURL *curl = curl_easy_init();
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, tokenURL);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlFuncs::writeDataString);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, jsonResp);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonPost->c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, jsonPost->length());
|
||||
int error = curl_easy_perform(curl);
|
||||
|
||||
json_object *parse = json_tokener_parse(jsonResp->c_str());
|
||||
if (error == CURLE_OK)
|
||||
{
|
||||
json_object *accessToken;
|
||||
json_object_object_get_ex(parse, "access_token", &accessToken);
|
||||
if(accessToken)
|
||||
token = json_object_get_string(accessToken);
|
||||
else
|
||||
writeDriveError("refreshToken", "Error refreshing token.");
|
||||
}
|
||||
|
||||
delete jsonPost;
|
||||
delete jsonResp;
|
||||
json_object_put(post);
|
||||
json_object_put(parse);
|
||||
curl_slist_free_all(header);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
bool drive::gd::tokenIsValid()
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
std::string url = tokenCheckURL;
|
||||
url.append("?access_token=" + token);
|
||||
|
||||
CURL *curl = curl_easy_init();
|
||||
std::string *jsonResp = new std::string;
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlFuncs::writeDataString);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, jsonResp);
|
||||
|
||||
int error = curl_easy_perform(curl);
|
||||
json_object *parse = json_tokener_parse(jsonResp->c_str());
|
||||
if (error == CURLE_OK)
|
||||
{
|
||||
json_object *checkError;
|
||||
json_object_object_get_ex(parse, "error", &checkError);
|
||||
if(!checkError)
|
||||
ret = true;
|
||||
}
|
||||
|
||||
delete jsonResp;
|
||||
json_object_put(parse);
|
||||
curl_easy_cleanup(curl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void drive::gd::loadDriveList(const std::string& _qParams)
|
||||
{
|
||||
if(!tokenIsValid())
|
||||
refreshToken();
|
||||
|
||||
// Request url with specific fields needed.
|
||||
std::string url = driveURL, queryParams = "trashed=false and 'me' in owners ";
|
||||
//These are always used
|
||||
url.append("?fields=files(name,id,mimeType,size,parents)&q=");
|
||||
if(!parentDir.empty())
|
||||
queryParams.append("and '" + parentDir + "' in parents ");
|
||||
if(!_qParams.empty())
|
||||
queryParams.append("and " + _qParams);
|
||||
|
||||
// Headers needed
|
||||
curl_slist *postHeaders = NULL;
|
||||
postHeaders = curl_slist_append(postHeaders, std::string(HEADER_AUTHORIZATION + token).c_str());
|
||||
|
||||
// Curl request
|
||||
std::string *jsonResp = new std::string;
|
||||
CURL *curl = curl_easy_init();
|
||||
|
||||
//I don't understand why this needs a CURL handle...
|
||||
char *urlAppend = curl_easy_escape(curl, queryParams.c_str(), queryParams.length());
|
||||
url.append(urlAppend);
|
||||
curl_free(urlAppend);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "");
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, postHeaders);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlFuncs::writeDataString);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, jsonResp);
|
||||
|
||||
int error = curl_easy_perform(curl);
|
||||
|
||||
json_object *parse = json_tokener_parse(jsonResp->c_str());
|
||||
if (error == CURLE_OK)
|
||||
{
|
||||
driveList.clear();
|
||||
json_object *fileArray;
|
||||
json_object_object_get_ex(parse, "files", &fileArray);
|
||||
if(fileArray)
|
||||
{
|
||||
size_t count = json_object_array_length(fileArray);
|
||||
driveList.reserve(count);
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
{
|
||||
json_object *idString, *nameString, *mimeTypeString, *size, *parentArray;
|
||||
json_object *curFile = json_object_array_get_idx(fileArray, i);
|
||||
json_object_object_get_ex(curFile, "id", &idString);
|
||||
json_object_object_get_ex(curFile, "name", &nameString);
|
||||
json_object_object_get_ex(curFile, "mimeType", &mimeTypeString);
|
||||
json_object_object_get_ex(curFile, "size", &size);
|
||||
json_object_object_get_ex(curFile, "parents", &parentArray);
|
||||
|
||||
drive::gdDirItem newDirItem;
|
||||
newDirItem.name = json_object_get_string(nameString);
|
||||
newDirItem.id = json_object_get_string(idString);
|
||||
newDirItem.mimeType = json_object_get_string(mimeTypeString);
|
||||
newDirItem.size = json_object_get_int(size);
|
||||
|
||||
if (parentArray)
|
||||
{
|
||||
size_t parentCount = json_object_array_length(parentArray);
|
||||
for (unsigned j = 0; j < parentCount; j++)
|
||||
{
|
||||
json_object *parent = json_object_array_get_idx(parentArray, j);
|
||||
newDirItem.parents.push_back(json_object_get_string(parent));
|
||||
}
|
||||
}
|
||||
driveList.push_back(newDirItem);
|
||||
}
|
||||
}
|
||||
else
|
||||
writeDriveError("updateList", "Error obtaining drive listing.");
|
||||
}
|
||||
else
|
||||
writeCurlError("updateList", error);
|
||||
|
||||
delete jsonResp;
|
||||
json_object_put(parse);
|
||||
curl_slist_free_all(postHeaders);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
void drive::gd::debugWriteList()
|
||||
{
|
||||
fs::logWrite("Parent: %s\n", parentDir.c_str());
|
||||
for(auto& di : driveList)
|
||||
{
|
||||
fs::logWrite("%s\n\t%s\n", di.name.c_str(), di.id.c_str());
|
||||
if(!di.parents.empty())
|
||||
fs::logWrite("\t%s\n", di.parents[0].c_str());
|
||||
}
|
||||
}
|
||||
|
||||
bool drive::gd::createDir(const std::string& _dirName)
|
||||
{
|
||||
if(!tokenIsValid())
|
||||
refreshToken();
|
||||
|
||||
bool ret = true;
|
||||
|
||||
// Headers to use
|
||||
curl_slist *postHeaders = NULL;
|
||||
postHeaders = curl_slist_append(postHeaders, std::string(HEADER_AUTHORIZATION + token).c_str());
|
||||
postHeaders = curl_slist_append(postHeaders, HEADER_CONTENT_TYPE_APP_JSON);
|
||||
|
||||
// JSON To Post
|
||||
std::string *jsonPost = new std::string;
|
||||
json_object *post = json_object_new_object();
|
||||
json_object *nameString = json_object_new_string(_dirName.c_str());
|
||||
json_object *mimeTypeString = json_object_new_string(MIMETYPE_FOLDER);
|
||||
json_object_object_add(post, "name", nameString);
|
||||
json_object_object_add(post, "mimeType", mimeTypeString);
|
||||
if (!parentDir.empty())
|
||||
{
|
||||
json_object *parentsArray = json_object_new_array();
|
||||
json_object *parentString = json_object_new_string(parentDir.c_str());
|
||||
json_object_array_add(parentsArray, parentString);
|
||||
json_object_object_add(post, "parents", parentsArray);
|
||||
}
|
||||
jsonPost->assign(json_object_to_json_string_ext(post, JSON_C_TO_STRING_NOSLASHESCAPE));
|
||||
|
||||
// Curl Request
|
||||
std::string *jsonResp = new std::string;
|
||||
CURL *curl = curl_easy_init();
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, postHeaders);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, driveURL);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlFuncs::writeDataString);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, jsonResp);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonPost->c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, jsonPost->length());
|
||||
int error = curl_easy_perform(curl);
|
||||
|
||||
json_object *respParse = json_tokener_parse(jsonResp->c_str()), *checkError;
|
||||
json_object_object_get_ex(respParse, "error", &checkError);
|
||||
if (error == CURLE_OK && !checkError)
|
||||
{
|
||||
//Append it to list
|
||||
json_object *id;
|
||||
json_object_object_get_ex(respParse, "id", &id);
|
||||
|
||||
drive::gdDirItem newDir;
|
||||
newDir.name = _dirName;
|
||||
newDir.id = json_object_get_string(id);
|
||||
newDir.mimeType = MIMETYPE_FOLDER;
|
||||
newDir.size = 0;
|
||||
driveList.push_back(newDir);
|
||||
}
|
||||
else
|
||||
ret = false;
|
||||
|
||||
delete jsonPost;
|
||||
delete jsonResp;
|
||||
json_object_put(post);
|
||||
json_object_put(respParse);
|
||||
curl_slist_free_all(postHeaders);
|
||||
curl_easy_cleanup(curl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool drive::gd::dirExists(const std::string& _dirName)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
for(unsigned i = 0; i < driveList.size(); i++)
|
||||
{
|
||||
if(driveList[i].name == _dirName && driveList[i].mimeType == MIMETYPE_FOLDER)
|
||||
{
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool drive::gd::fileExists(const std::string& _filename)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
for(unsigned i = 0; i < driveList.size(); i++)
|
||||
{
|
||||
if(driveList[i].name == _filename && driveList[i].mimeType != MIMETYPE_FOLDER)
|
||||
{
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void drive::gd::uploadFile(const std::string& _filename, curlFuncs::curlUpArgs *_upload)
|
||||
{
|
||||
if(!tokenIsValid())
|
||||
refreshToken();
|
||||
|
||||
std::string url = driveUploadURL;
|
||||
url.append("?uploadType=resumable");
|
||||
|
||||
// Headers
|
||||
curl_slist *postHeaders = NULL;
|
||||
postHeaders = curl_slist_append(postHeaders, std::string(HEADER_AUTHORIZATION + token).c_str());
|
||||
postHeaders = curl_slist_append(postHeaders, HEADER_CONTENT_TYPE_APP_JSON);
|
||||
|
||||
// Post JSON
|
||||
std::string *jsonPost = new std::string;
|
||||
json_object *post = json_object_new_object();
|
||||
json_object *nameString = json_object_new_string(_filename.c_str());
|
||||
json_object_object_add(post, "name", nameString);
|
||||
if (!parentDir.empty())
|
||||
{
|
||||
json_object *parentArray = json_object_new_array();
|
||||
json_object *parentString = json_object_new_string(parentDir.c_str());
|
||||
json_object_array_add(parentArray, parentString);
|
||||
json_object_object_add(post, "parents", parentArray);
|
||||
}
|
||||
jsonPost->assign(json_object_to_json_string_ext(post, JSON_C_TO_STRING_NOSLASHESCAPE));
|
||||
|
||||
// Curl upload request
|
||||
std::string *jsonResp = new std::string;
|
||||
std::vector<std::string> *headers = new std::vector<std::string>;
|
||||
CURL *curl = curl_easy_init();
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, postHeaders);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curlFuncs::writeHeaders);
|
||||
curl_easy_setopt(curl, CURLOPT_HEADERDATA, headers);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonPost->c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, jsonPost->length());
|
||||
|
||||
int error = curl_easy_perform(curl);
|
||||
std::string location = curlFuncs::getHeader("Location", headers);
|
||||
if (error == CURLE_OK && location != HEADER_ERROR)
|
||||
{
|
||||
CURL *curlUp = curl_easy_init();
|
||||
curl_easy_setopt(curlUp, CURLOPT_PUT, 1);
|
||||
curl_easy_setopt(curlUp, CURLOPT_URL, location.c_str());
|
||||
curl_easy_setopt(curlUp, CURLOPT_WRITEFUNCTION, curlFuncs::writeDataString);
|
||||
curl_easy_setopt(curlUp, CURLOPT_WRITEDATA, jsonResp);
|
||||
curl_easy_setopt(curlUp, CURLOPT_READFUNCTION, curlFuncs::readDataFile);
|
||||
curl_easy_setopt(curlUp, CURLOPT_READDATA, _upload);
|
||||
curl_easy_setopt(curlUp, CURLOPT_UPLOAD_BUFFERSIZE, DRIVE_UPLOAD_BUFFER_SIZE);
|
||||
curl_easy_setopt(curlUp, CURLOPT_UPLOAD, 1);
|
||||
curl_easy_perform(curlUp);
|
||||
curl_easy_cleanup(curlUp);
|
||||
|
||||
json_object *parse = json_tokener_parse(jsonResp->c_str()), *id, *name, *mimeType;
|
||||
json_object_object_get_ex(parse, "id", &id);
|
||||
json_object_object_get_ex(parse, "name", &name);
|
||||
json_object_object_get_ex(parse, "mimeType", &mimeType);
|
||||
|
||||
if(name && id && mimeType)
|
||||
{
|
||||
drive::gdDirItem uploadData;
|
||||
uploadData.id = json_object_get_string(id);
|
||||
uploadData.name = json_object_get_string(name);
|
||||
uploadData.mimeType = json_object_get_string(mimeType);
|
||||
uploadData.size = *_upload->o;//should be safe to use
|
||||
uploadData.parents.push_back(parentDir);
|
||||
driveList.push_back(uploadData);
|
||||
}
|
||||
}
|
||||
else
|
||||
writeCurlError("uploadFile", error);
|
||||
|
||||
delete jsonPost;
|
||||
delete jsonResp;
|
||||
delete headers;
|
||||
json_object_put(post);
|
||||
curl_slist_free_all(postHeaders);
|
||||
}
|
||||
|
||||
void drive::gd::updateFile(const std::string& _fileID, curlFuncs::curlUpArgs *_upload)
|
||||
{
|
||||
if(!tokenIsValid())
|
||||
refreshToken();
|
||||
|
||||
//URL
|
||||
std::string url = driveUploadURL;
|
||||
url.append("/" + _fileID);
|
||||
url.append("?uploadType=resumable");
|
||||
|
||||
//Header
|
||||
curl_slist *patchHeader = NULL;
|
||||
patchHeader = curl_slist_append(patchHeader, std::string(HEADER_AUTHORIZATION + token).c_str());
|
||||
|
||||
//Curl
|
||||
std::string *jsonResp = new std::string;
|
||||
std::vector<std::string> *headers = new std::vector<std::string>;
|
||||
CURL *curl = curl_easy_init();
|
||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, patchHeader);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlFuncs::writeDataString);
|
||||
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curlFuncs::writeHeaders);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, jsonResp);
|
||||
curl_easy_setopt(curl, CURLOPT_HEADERDATA, headers);
|
||||
|
||||
int error = curl_easy_perform(curl);
|
||||
std::string location = curlFuncs::getHeader("Location", headers);
|
||||
if(error == CURLE_OK && location != HEADER_ERROR)
|
||||
{
|
||||
CURL *curlPatch = curl_easy_init();
|
||||
curl_easy_setopt(curlPatch, CURLOPT_PUT, 1);
|
||||
curl_easy_setopt(curlPatch, CURLOPT_URL, location.c_str());
|
||||
curl_easy_setopt(curlPatch, CURLOPT_READFUNCTION, curlFuncs::readDataFile);
|
||||
curl_easy_setopt(curlPatch, CURLOPT_READDATA, _upload);
|
||||
curl_easy_setopt(curlPatch, CURLOPT_UPLOAD_BUFFERSIZE, DRIVE_UPLOAD_BUFFER_SIZE);
|
||||
curl_easy_setopt(curlPatch, CURLOPT_UPLOAD, 1);
|
||||
curl_easy_perform(curlPatch);
|
||||
curl_easy_cleanup(curlPatch);
|
||||
}
|
||||
|
||||
delete jsonResp;
|
||||
delete headers;
|
||||
curl_slist_free_all(patchHeader);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
void drive::gd::downloadFile(const std::string& _fileID, curlFuncs::curlDlArgs *_download)
|
||||
{
|
||||
if(!tokenIsValid())
|
||||
refreshToken();
|
||||
|
||||
//URL
|
||||
std::string url = driveURL;
|
||||
url.append("/" + _fileID);
|
||||
url.append("?alt=media");
|
||||
|
||||
//Headers
|
||||
curl_slist *getHeaders = NULL;
|
||||
getHeaders = curl_slist_append(getHeaders, std::string(HEADER_AUTHORIZATION + token).c_str());
|
||||
|
||||
//Downloading is threaded because it's too slow otherwise
|
||||
dlWriteThreadStruct dlWrite;
|
||||
dlWrite.cfa = _download;
|
||||
|
||||
Thread writeThread;
|
||||
threadCreate(&writeThread, writeThread_t, &dlWrite, NULL, 0x8000, 0x2B, 2);
|
||||
|
||||
//Curl
|
||||
CURL *curl = curl_easy_init();
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, getHeaders);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeDataBufferThreaded);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &dlWrite);
|
||||
threadStart(&writeThread);
|
||||
int error = curl_easy_perform(curl);
|
||||
|
||||
threadWaitForExit(&writeThread);
|
||||
threadClose(&writeThread);
|
||||
|
||||
curl_slist_free_all(getHeaders);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
void drive::gd::deleteFile(const std::string& _fileID)
|
||||
{
|
||||
if(!tokenIsValid())
|
||||
refreshToken();
|
||||
|
||||
//URL
|
||||
std::string url = driveURL;
|
||||
url.append("/" + _fileID);
|
||||
|
||||
//Header
|
||||
curl_slist *delHeaders = NULL;
|
||||
delHeaders = curl_slist_append(delHeaders, std::string(HEADER_AUTHORIZATION + token).c_str());
|
||||
|
||||
//Curl
|
||||
CURL *curl = curl_easy_init();
|
||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, delHeaders);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
int error = curl_easy_perform(curl);
|
||||
|
||||
curl_slist_free_all(delHeaders);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
std::string drive::gd::getFileID(const std::string& _name)
|
||||
{
|
||||
for(unsigned i = 0; i < driveList.size(); i++)
|
||||
{
|
||||
if(driveList[i].name == _name)
|
||||
return driveList[i].id;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
#include <switch.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "gfx.h"
|
||||
#include "file.h"
|
||||
|
|
@ -49,8 +50,14 @@ int main(int argc, const char *argv[])
|
|||
ui::init();
|
||||
romfsExit();
|
||||
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
//Drive needs config read
|
||||
fs::driveInit();
|
||||
|
||||
while(ui::runApp()){ }
|
||||
|
||||
fs::driveExit();
|
||||
curl_global_cleanup();
|
||||
cfg::saveConfig();
|
||||
ui::exit();
|
||||
data::exit();
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ void ui::init()
|
|||
ui::settInit();
|
||||
ui::extInit();
|
||||
ui::fmInit();
|
||||
ui::fldInit();
|
||||
|
||||
popMessages = new ui::popMessageMngr;
|
||||
threadMngr = new ui::threadProcMngr;
|
||||
|
|
@ -165,6 +166,7 @@ void ui::exit()
|
|||
ui::settExit();
|
||||
ui::extExit();
|
||||
ui::fmExit();
|
||||
ui::fldExit();
|
||||
|
||||
delete popMessages;
|
||||
delete threadMngr;
|
||||
|
|
@ -312,7 +314,7 @@ void ui::toTTL(void *a)
|
|||
if(u->titleInfo.size() > 0)
|
||||
{
|
||||
ui::changeState(TTL_SEL);
|
||||
ui::ttlSetActive(curUserIndex);
|
||||
ui::ttlSetActive(curUserIndex, true, true);
|
||||
ui::usrMenu->setActive(false);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ static void extMenuPackJKSVZip_t(void *a)
|
|||
t->status->setStatus(ui::getUICString("threadStatusPackingJKSV", 0));
|
||||
if(cfg::config["ovrClk"])
|
||||
{
|
||||
util::setCPU(util::CPU_SPEED_1785MHz);
|
||||
util::sysBoost();
|
||||
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popCPUBoostEnabled", 0));
|
||||
}
|
||||
|
||||
|
|
@ -164,7 +164,7 @@ static void extMenuPackJKSVZip_t(void *a)
|
|||
zipClose(zip, NULL);
|
||||
}
|
||||
if(cfg::config["ovrClk"])
|
||||
util::setCPU(util::CPU_SPEED_1224MHz);
|
||||
util::sysNormal();
|
||||
|
||||
delete jksv;
|
||||
delete c;
|
||||
|
|
|
|||
374
src/ui/fld.cpp
Normal file
374
src/ui/fld.cpp
Normal file
|
|
@ -0,0 +1,374 @@
|
|||
#include <switch.h>
|
||||
|
||||
#include "ui.h"
|
||||
#include "fs.h"
|
||||
#include "util.h"
|
||||
#include "cfg.h"
|
||||
|
||||
static ui::menu *fldMenu = NULL;
|
||||
ui::slideOutPanel *ui::fldPanel = NULL;
|
||||
static fs::dirList *fldList = NULL;
|
||||
static SDL_Texture *fldBuffer;
|
||||
static unsigned int fldGuideWidth = 0;
|
||||
static Mutex fldLock = 0;
|
||||
|
||||
static void fldMenuCallback(void *a)
|
||||
{
|
||||
switch(ui::padKeysDown())
|
||||
{
|
||||
case HidNpadButton_B:
|
||||
if(fs::gDrive)
|
||||
fs::gDrive->returnToRoot();
|
||||
|
||||
fs::unmountSave();
|
||||
fs::freePathFilters();
|
||||
fldMenu->setActive(false);
|
||||
ui::fldPanel->closePanel();
|
||||
unsigned cusr = data::getCurrentUserIndex();
|
||||
ui::ttlSetActive(cusr, true, true);
|
||||
ui::updateInput();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void fldPanelDraw(void *a)
|
||||
{
|
||||
mutexLock(&fldLock);
|
||||
SDL_Texture *target = (SDL_Texture *)a;
|
||||
gfx::clearTarget(fldBuffer, &ui::slidePanelColor);
|
||||
fldMenu->draw(fldBuffer, &ui::txtCont, true);
|
||||
gfx::texDraw(target, fldBuffer, 0, 0);
|
||||
gfx::drawLine(target, &ui::divClr, 10, 648, fldGuideWidth + 54, 648);
|
||||
gfx::drawTextf(target, 18, 32, 673, &ui::txtCont, ui::getUICString("helpFolder", 0));
|
||||
mutexUnlock(&fldLock);
|
||||
}
|
||||
|
||||
static void fldFuncCancel(void *a)
|
||||
{
|
||||
std::string *del = (std::string *)a;
|
||||
delete del;
|
||||
}
|
||||
|
||||
static void fldFuncOverwrite(void *a)
|
||||
{
|
||||
fs::dirItem *in = (fs::dirItem *)a;
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
std::string *send = new std::string;
|
||||
send->assign(util::generatePathByTID(utinfo->tid) + in->getItm());
|
||||
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdOver"], fs::overwriteBackup, fldFuncCancel, send, ui::getUICString("confirmOverwrite", 0), in->getItm().c_str());
|
||||
ui::confirm(conf);
|
||||
}
|
||||
|
||||
static void fldFuncDelete(void *a)
|
||||
{
|
||||
fs::dirItem *in = (fs::dirItem *)a;
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
std::string *send = new std::string;
|
||||
send->assign(util::generatePathByTID(utinfo->tid) + in->getItm());
|
||||
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], fs::deleteBackup, fldFuncCancel, send, ui::getUICString("confirmDelete", 0), in->getItm().c_str());
|
||||
ui::confirm(conf);
|
||||
}
|
||||
|
||||
static void fldFuncRestore(void *a)
|
||||
{
|
||||
fs::dirItem *in = (fs::dirItem *)a;
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
std::string *send = new std::string;
|
||||
send->assign(util::generatePathByTID(utinfo->tid) + in->getItm());
|
||||
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdRest"], fs::restoreBackup, fldFuncCancel, send, ui::getUICString("confirmRestore", 0), in->getItm().c_str());
|
||||
ui::confirm(conf);
|
||||
}
|
||||
|
||||
static void fldFuncUpload_t(void *a)
|
||||
{
|
||||
threadInfo *t = (threadInfo *)a;
|
||||
fs::dirItem *di = (fs::dirItem *)t->argPtr;
|
||||
fsSetPriority(FsPriority_Realtime);
|
||||
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
data::titleInfo *tinfo = data::getTitleInfoByTID(utinfo->tid);
|
||||
std::string path, tmpZip, filename;//Final path to upload from
|
||||
|
||||
if(cfg::config["ovrClk"])
|
||||
util::sysBoost();
|
||||
|
||||
//Zip first then upload if folder based backup
|
||||
if(di->isDir())
|
||||
{
|
||||
t->status->setStatus(ui::getUICString("threadStatusCompressingSaveForUpload", 0), di->getItm().c_str());
|
||||
filename = di->getItm() + ".zip";
|
||||
tmpZip = util::generatePathByTID(utinfo->tid) + di->getItm() + ".zip";
|
||||
std::string fldPath = util::generatePathByTID(utinfo->tid) + di->getItm() + "/";
|
||||
|
||||
int zipTrim = util::getTotalPlacesInPath(fs::getWorkDir()) + 2;//Trim path down to save root
|
||||
zipFile tmp = zipOpen64(tmpZip.c_str(), 0);
|
||||
fs::copyDirToZip(fldPath, tmp, true, zipTrim, NULL);
|
||||
zipClose(tmp, NULL);
|
||||
path = tmpZip;
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = di->getItm();
|
||||
path = util::generatePathByTID(utinfo->tid) + di->getItm();
|
||||
}
|
||||
|
||||
//Change thread stuff so upload status can be shown
|
||||
t->status->setStatus(ui::getUICString("threadStatusUploadingFile", 0), di->getItm().c_str());
|
||||
fs::copyArgs *cpyArgs = fs::copyArgsCreate("", "", "", NULL, NULL, false, false, 0);
|
||||
cpyArgs->prog->setMax(fs::fsize(path));
|
||||
cpyArgs->prog->update(0);
|
||||
t->argPtr = cpyArgs;
|
||||
t->drawFunc = fs::fileDrawFunc;
|
||||
|
||||
//curlDlArgs
|
||||
curlFuncs::curlUpArgs upload;
|
||||
upload.f = fopen(path.c_str(), "rb");
|
||||
upload.o = &cpyArgs->offset;
|
||||
|
||||
if(fs::gDrive->fileExists(filename))
|
||||
{
|
||||
std::string id = fs::gDrive->getFileID(filename);
|
||||
fs::gDrive->updateFile(id, &upload);
|
||||
}
|
||||
else
|
||||
fs::gDrive->uploadFile(filename, &upload);
|
||||
|
||||
fclose(upload.f);
|
||||
|
||||
if(!tmpZip.empty())
|
||||
fs::delfile(tmpZip);
|
||||
|
||||
fs::copyArgsDestroy(cpyArgs);
|
||||
t->drawFunc = NULL;
|
||||
|
||||
if(cfg::config["ovrClk"])
|
||||
util::sysNormal();
|
||||
|
||||
ui::fldRefreshMenu(false);
|
||||
|
||||
t->finished = true;
|
||||
}
|
||||
|
||||
static void fldFuncUpload(void *a)
|
||||
{
|
||||
if(fs::gDrive)
|
||||
ui::newThread(fldFuncUpload_t, a, NULL);
|
||||
else
|
||||
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popDriveNotActive", 0));
|
||||
}
|
||||
|
||||
static void fldFuncDownload_t(void *a)
|
||||
{
|
||||
threadInfo *t = (threadInfo *)a;
|
||||
drive::gdDirItem *in = (drive::gdDirItem *)t->argPtr;
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
data::titleInfo *tinfo = data::getTitleInfoByTID(utinfo->tid);
|
||||
std::string targetPath = util::generatePathByTID(utinfo->tid) + in->name;
|
||||
t->status->setStatus(ui::getUICString("threadStatusDownloadingFile", 0), in->name.c_str());
|
||||
|
||||
if(cfg::config["ovrClk"])
|
||||
util::sysBoost();
|
||||
|
||||
if(fs::fileExists(targetPath))
|
||||
fs::delfile(targetPath);
|
||||
|
||||
//Use this for progress bar
|
||||
fs::copyArgs *cpy = fs::copyArgsCreate("", "", "", NULL, NULL, false, false, 0);
|
||||
cpy->prog->setMax(in->size);
|
||||
cpy->prog->update(0);
|
||||
t->argPtr = cpy;
|
||||
t->drawFunc = fs::fileDrawFunc;
|
||||
|
||||
//DL struct
|
||||
curlFuncs::curlDlArgs dlFile;
|
||||
dlFile.path = targetPath;
|
||||
dlFile.size = in->size;
|
||||
dlFile.o = &cpy->offset;
|
||||
|
||||
fs::gDrive->downloadFile(in->id, &dlFile);
|
||||
|
||||
//fclose(dlFile.f);
|
||||
|
||||
fs::copyArgsDestroy(cpy);
|
||||
t->drawFunc = NULL;
|
||||
|
||||
if(cfg::config["ovrClk"])
|
||||
util::sysNormal();
|
||||
|
||||
ui::fldRefreshMenu(false);
|
||||
|
||||
t->finished = true;
|
||||
}
|
||||
|
||||
static void fldFuncDownload(void *a)
|
||||
{
|
||||
drive::gdDirItem *in = (drive::gdDirItem *)a;
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
data::titleInfo *tinfo = data::getTitleInfoByTID(utinfo->tid);
|
||||
std::string testPath = util::generatePathByTID(utinfo->tid) + in->name;
|
||||
if(fs::fileExists(testPath))
|
||||
{
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdOver"], fldFuncDownload_t, NULL, a, ui::getUICString("confirmDriveOverwrite", 0));
|
||||
ui::confirm(conf);
|
||||
}
|
||||
else
|
||||
ui::newThread(fldFuncDownload_t, a, NULL);
|
||||
|
||||
}
|
||||
|
||||
static void fldFuncDriveDelete_t(void *a)
|
||||
{
|
||||
threadInfo *t = (threadInfo *)a;
|
||||
drive::gdDirItem *gdi = (drive::gdDirItem *)t->argPtr;
|
||||
t->status->setStatus(ui::getUICString("threadStatusDeletingFile", 0));
|
||||
fs::gDrive->deleteFile(gdi->id);
|
||||
ui::fldRefreshMenu(true);
|
||||
t->finished = true;
|
||||
}
|
||||
|
||||
static void fldFuncDriveDelete(void *a)
|
||||
{
|
||||
drive::gdDirItem *in = (drive::gdDirItem *)a;
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], fldFuncDriveDelete_t, NULL, a, ui::getUICString("confirmDelete", 0), in->name.c_str());
|
||||
ui::confirm(conf);
|
||||
}
|
||||
|
||||
//TODO
|
||||
static void fldFuncDriveRestore_t(void *a)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void fldFuncDriveRestore(void *a)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ui::fldInit()
|
||||
{
|
||||
fldGuideWidth = gfx::getTextWidth(ui::getUICString("helpFolder", 0), 18);
|
||||
|
||||
fldMenu = new ui::menu(10, 8, fldGuideWidth + 44, 20, 6);
|
||||
fldMenu->setCallback(fldMenuCallback, NULL);
|
||||
fldMenu->setActive(false);
|
||||
|
||||
ui::fldPanel = new ui::slideOutPanel(fldGuideWidth + 64, 720, 0, ui::SLD_RIGHT, fldPanelDraw);
|
||||
fldBuffer = SDL_CreateTexture(gfx::render, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET, fldGuideWidth + 64, 647);
|
||||
ui::registerPanel(fldPanel);
|
||||
|
||||
fldList = new fs::dirList;
|
||||
}
|
||||
|
||||
void ui::fldExit()
|
||||
{
|
||||
delete ui::fldPanel;
|
||||
delete fldMenu;
|
||||
delete fldList;
|
||||
SDL_DestroyTexture(fldBuffer);
|
||||
}
|
||||
|
||||
void ui::fldUpdate()
|
||||
{
|
||||
fldMenu->update();
|
||||
}
|
||||
|
||||
void ui::fldPopulateMenu()
|
||||
{
|
||||
mutexLock(&fldLock);
|
||||
|
||||
fldMenu->reset();
|
||||
|
||||
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
|
||||
data::titleInfo *t = data::getTitleInfoByTID(d->tid);
|
||||
util::createTitleDirectoryByTID(d->tid);
|
||||
std::string targetDir = util::generatePathByTID(d->tid);
|
||||
|
||||
fldList->reassign(targetDir);
|
||||
if(fs::gDrive)
|
||||
{
|
||||
if(!fs::gDrive->dirExists(t->title))
|
||||
fs::gDrive->createDir(t->title);
|
||||
|
||||
std::string dirID = fs::gDrive->getFileID(t->title);
|
||||
fs::gDrive->chDir(dirID);
|
||||
}
|
||||
|
||||
fs::loadPathFilters(d->tid);
|
||||
|
||||
fldMenu->addOpt(NULL, ui::getUICString("folderMenuNew", 0));
|
||||
fldMenu->optAddButtonEvent(0, HidNpadButton_A, fs::createNewBackup, NULL);
|
||||
|
||||
unsigned fldInd = 1;
|
||||
if(fs::gDrive && fs::gDrive->getDriveListCount() > 0)
|
||||
{
|
||||
for(unsigned i = 0; i < fs::gDrive->getDriveListCount(); i++, fldInd++)
|
||||
{
|
||||
drive::gdDirItem *gdi = fs::gDrive->getDirItemAt(i);
|
||||
fldMenu->addOpt(NULL, "[GD] " + gdi->name);
|
||||
|
||||
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_A, fldFuncDownload, gdi);
|
||||
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_X, fldFuncDriveDelete, gdi);
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < fldList->getCount(); i++, fldInd++)
|
||||
{
|
||||
fs::dirItem *di = fldList->getDirItemAt(i);
|
||||
fldMenu->addOpt(NULL, di->getItm());
|
||||
|
||||
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_A, fldFuncOverwrite, di);
|
||||
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_X, fldFuncDelete, di);
|
||||
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_Y, fldFuncRestore, di);
|
||||
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_ZR, fldFuncUpload, di);
|
||||
}
|
||||
fldMenu->setActive(true);
|
||||
ui::fldPanel->openPanel();
|
||||
|
||||
mutexUnlock(&fldLock);
|
||||
}
|
||||
|
||||
void ui::fldRefreshMenu(bool _updateDrive)
|
||||
{
|
||||
mutexLock(&fldLock);
|
||||
|
||||
fldMenu->reset();
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
data::titleInfo *tinfo = data::getTitleInfoByTID(utinfo->tid);
|
||||
std::string targetDir = util::generatePathByTID(utinfo->tid);
|
||||
|
||||
fldList->reassign(targetDir);
|
||||
if(_updateDrive && fs::gDrive)
|
||||
fs::gDrive->loadDriveList("");
|
||||
|
||||
fldMenu->addOpt(NULL, ui::getUIString("folderMenuNew", 0));
|
||||
fldMenu->optAddButtonEvent(0, HidNpadButton_A, fs::createNewBackup, NULL);
|
||||
|
||||
unsigned fldInd = 1;
|
||||
if(fs::gDrive && fs::gDrive->getDriveListCount() > 0)
|
||||
{
|
||||
for(unsigned i = 0; i < fs::gDrive->getDriveListCount(); i++, fldInd++)
|
||||
{
|
||||
drive::gdDirItem *gdi = fs::gDrive->getDirItemAt(i);
|
||||
fldMenu->addOpt(NULL, "[GD] " + gdi->name);
|
||||
|
||||
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_A, fldFuncDownload, gdi);
|
||||
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_X, fldFuncDriveDelete, gdi);
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < fldList->getCount(); i++, fldInd++)
|
||||
{
|
||||
fs::dirItem *di = fldList->getDirItemAt(i);
|
||||
fldMenu->addOpt(NULL, di->getItm());
|
||||
|
||||
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_A, fldFuncOverwrite, di);
|
||||
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_X, fldFuncDelete, di);
|
||||
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_Y, fldFuncRestore, di);
|
||||
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_ZR, fldFuncUpload, di);
|
||||
}
|
||||
|
||||
mutexUnlock(&fldLock);
|
||||
}
|
||||
131
src/ui/ttl.cpp
131
src/ui/ttl.cpp
|
|
@ -6,14 +6,11 @@
|
|||
#include "util.h"
|
||||
#include "cfg.h"
|
||||
|
||||
static int ttlHelpX = 0, fldHelpWidth = 0;
|
||||
static int ttlHelpX = 0;
|
||||
static std::vector<ui::titleview *> ttlViews;
|
||||
static ui::menu *ttlOpts, *fldMenu;
|
||||
static ui::menu *ttlOpts;
|
||||
ui::slideOutPanel *ui::ttlOptsPanel;
|
||||
static ui::slideOutPanel *infoPanel, *fldPanel;//There's no reason to have a separate folder section
|
||||
static fs::dirList *fldList;
|
||||
static std::string infoPanelString;
|
||||
static SDL_Texture *fldBuffer;//This is so folder menu doesn't draw over guide
|
||||
static ui::slideOutPanel *infoPanel;
|
||||
static Mutex ttlViewLock = 0;
|
||||
|
||||
void ui::ttlRefresh()
|
||||
|
|
@ -24,77 +21,6 @@ void ui::ttlRefresh()
|
|||
mutexUnlock(&ttlViewLock);
|
||||
}
|
||||
|
||||
static void fldFuncCancel(void *a)
|
||||
{
|
||||
std::string *del = (std::string *)a;
|
||||
delete del;
|
||||
}
|
||||
|
||||
static void fldFuncOverwrite(void *a)
|
||||
{
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
int sel = fldMenu->getSelected() - 1;//Skip 'New'
|
||||
std::string itm = fldList->getItem(sel);
|
||||
std::string *send = new std::string;
|
||||
send->assign(util::generatePathByTID(utinfo->tid) + itm);
|
||||
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdOver"], fs::overwriteBackup, fldFuncCancel, send, ui::getUICString("confirmOverwrite", 0), itm.c_str());
|
||||
ui::confirm(conf);
|
||||
}
|
||||
|
||||
static void fldFuncDelete(void *a)
|
||||
{
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
int sel = fldMenu->getSelected() - 1;//Skip 'New'
|
||||
std::string itm = fldList->getItem(sel);
|
||||
std::string *send = new std::string;
|
||||
send->assign(util::generatePathByTID(utinfo->tid) + itm);
|
||||
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], fs::deleteBackup, fldFuncCancel, send, ui::getUICString("confirmDelete", 0), itm.c_str());
|
||||
ui::confirm(conf);
|
||||
}
|
||||
|
||||
static void fldFuncRestore(void *a)
|
||||
{
|
||||
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
|
||||
int sel = fldMenu->getSelected() - 1;//Skip 'New'
|
||||
std::string itm = fldList->getItem(sel);
|
||||
std::string *send = new std::string;
|
||||
send->assign(util::generatePathByTID(utinfo->tid) + itm);
|
||||
|
||||
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdRest"], fs::restoreBackup, fldFuncCancel, send, ui::getUICString("confirmRestore", 0), itm.c_str());
|
||||
ui::confirm(conf);
|
||||
}
|
||||
|
||||
void ui::populateFldMenu()
|
||||
{
|
||||
fldMenu->reset();
|
||||
|
||||
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
|
||||
util::createTitleDirectoryByTID(d->tid);
|
||||
std::string targetDir = util::generatePathByTID(d->tid);
|
||||
|
||||
fldList->reassign(targetDir);
|
||||
|
||||
char filterPath[128];
|
||||
sprintf(filterPath, "sdmc:/config/JKSV/0x%016lX_filter.txt", d->tid);
|
||||
fs::loadPathFilters(d->tid);
|
||||
|
||||
fldMenu->addOpt(NULL, ui::getUICString("folderMenuNew", 0));
|
||||
fldMenu->optAddButtonEvent(0, HidNpadButton_A, fs::createNewBackup, NULL);
|
||||
|
||||
for(unsigned i = 0; i < fldList->getCount(); i++)
|
||||
{
|
||||
fldMenu->addOpt(NULL, fldList->getItem(i));
|
||||
|
||||
fldMenu->optAddButtonEvent(i + 1, HidNpadButton_A, fldFuncOverwrite, NULL);
|
||||
fldMenu->optAddButtonEvent(i + 1, HidNpadButton_X, fldFuncDelete, NULL);
|
||||
fldMenu->optAddButtonEvent(i + 1, HidNpadButton_Y, fldFuncRestore, NULL);
|
||||
}
|
||||
fldMenu->setActive(true);
|
||||
fldPanel->openPanel();
|
||||
}
|
||||
|
||||
static void ttlViewCallback(void *a)
|
||||
{
|
||||
unsigned curUserIndex = data::getCurrentUserIndex();
|
||||
|
|
@ -107,7 +33,10 @@ static void ttlViewCallback(void *a)
|
|||
{
|
||||
case HidNpadButton_A:
|
||||
if(fs::mountSave(d->saveInfo))
|
||||
ui::populateFldMenu();
|
||||
{
|
||||
ttlViews[curUserIndex]->setActive(false, true);
|
||||
ui::fldPopulateMenu();
|
||||
}
|
||||
break;
|
||||
|
||||
case HidNpadButton_B:
|
||||
|
|
@ -332,6 +261,7 @@ static void ttlOptsExportSVI(void *a)
|
|||
fwrite(ctrlData->icon, 1, jpegSize, svi);
|
||||
fclose(svi);
|
||||
delete ctrlData;
|
||||
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popSVIExported", 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -403,34 +333,9 @@ static void infoPanelCallback(void *a)
|
|||
}
|
||||
}
|
||||
|
||||
static void fldMenuCallback(void *a)
|
||||
{
|
||||
switch(ui::padKeysDown())
|
||||
{
|
||||
case HidNpadButton_B:
|
||||
fs::unmountSave();
|
||||
fs::freePathFilters();
|
||||
fldMenu->setActive(false);
|
||||
fldPanel->closePanel();
|
||||
break;
|
||||
}
|
||||
ui::updateInput();
|
||||
}
|
||||
|
||||
static void fldPanelDraw(void *a)
|
||||
{
|
||||
SDL_Texture *target = (SDL_Texture *)a;
|
||||
gfx::clearTarget(fldBuffer, &ui::slidePanelColor);
|
||||
fldMenu->draw(fldBuffer, &ui::txtCont, true);
|
||||
gfx::texDraw(target, fldBuffer, 0, 0);
|
||||
gfx::drawLine(target, &ui::divClr, 10, 648, fldHelpWidth + 54, 648);
|
||||
gfx::drawTextf(target, 18, 32, 673, &ui::txtCont, ui::getUICString("helpFolder", 0));
|
||||
}
|
||||
|
||||
void ui::ttlInit()
|
||||
{
|
||||
ttlHelpX = 1220 - gfx::getTextWidth(ui::getUICString("helpTitle", 0), 18);
|
||||
fldHelpWidth = gfx::getTextWidth(ui::getUICString("helpFolder", 0), 18);
|
||||
|
||||
for(data::user& u : data::users)
|
||||
ttlViews.emplace_back(new ui::titleview(u, 128, 128, 16, 16, 7, ttlViewCallback));
|
||||
|
|
@ -439,10 +344,6 @@ void ui::ttlInit()
|
|||
ttlOpts->setCallback(ttlOptsCallback, NULL);
|
||||
ttlOpts->setActive(false);
|
||||
|
||||
fldMenu = new ui::menu(10, 8, fldHelpWidth + 44, 20, 6);
|
||||
fldMenu->setCallback(fldMenuCallback, NULL);
|
||||
fldMenu->setActive(false);
|
||||
|
||||
ttlOptsPanel = new ui::slideOutPanel(410, 720, 0, ui::SLD_RIGHT, ttlOptsPanelDraw);
|
||||
ui::registerPanel(ttlOptsPanel);
|
||||
|
||||
|
|
@ -450,12 +351,6 @@ void ui::ttlInit()
|
|||
ui::registerPanel(infoPanel);
|
||||
infoPanel->setCallback(infoPanelCallback, NULL);
|
||||
|
||||
fldPanel = new ui::slideOutPanel(fldHelpWidth + 64, 720, 0, ui::SLD_RIGHT, fldPanelDraw);
|
||||
fldBuffer = SDL_CreateTexture(gfx::render, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET, fldHelpWidth + 64, 647);
|
||||
ui::registerPanel(fldPanel);
|
||||
|
||||
fldList = new fs::dirList;
|
||||
|
||||
ttlOpts->setActive(false);
|
||||
for(int i = 0; i < 9; i++)
|
||||
ttlOpts->addOpt(NULL, ui::getUIString("titleOptions", i));
|
||||
|
|
@ -485,18 +380,14 @@ void ui::ttlExit()
|
|||
for(ui::titleview *t : ttlViews)
|
||||
delete t;
|
||||
|
||||
SDL_DestroyTexture(fldBuffer);
|
||||
delete ttlOptsPanel;
|
||||
delete ttlOpts;
|
||||
delete infoPanel;
|
||||
delete fldPanel;
|
||||
delete fldMenu;
|
||||
delete fldList;
|
||||
}
|
||||
|
||||
void ui::ttlSetActive(int usr)
|
||||
void ui::ttlSetActive(int usr, bool _set, bool _showSel)
|
||||
{
|
||||
ttlViews[usr]->setActive(true, true);
|
||||
ttlViews[usr]->setActive(_set, _showSel);
|
||||
}
|
||||
|
||||
void ui::ttlUpdate()
|
||||
|
|
@ -505,7 +396,7 @@ void ui::ttlUpdate()
|
|||
|
||||
ttlOpts->update();
|
||||
infoPanel->update();
|
||||
fldMenu->update();
|
||||
ui::fldUpdate();
|
||||
ttlViews[curUserIndex]->update();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -108,8 +108,9 @@ void ui::initStrings()
|
|||
addUIString("author", 0, "NULL");
|
||||
addUIString("helpUser", 0, "[A] Select [Y] Dump All Saves [X] User Options");
|
||||
addUIString("helpTitle", 0, "[A] Select [L][R] Jump [Y] Favorite [X] Title Options [B] Back");
|
||||
addUIString("helpFolder", 0, "[A] Select [Y] Restore [X] Delete [B] Close");
|
||||
addUIString("helpFolder", 0, "[A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close");
|
||||
addUIString("helpSettings", 0, "[A] Toggle [X] Defaults [B] Back");
|
||||
addUIString("helpDrive", 0, "[A] Download [Y] Restore [X] Delete [B] Back");
|
||||
|
||||
//Y/N On/Off
|
||||
addUIString("dialogYes", 0, "Yes [A]");
|
||||
|
|
@ -132,6 +133,7 @@ void ui::initStrings()
|
|||
addUIString("confirmCreateAllSaveData", 0, "Are you sure you would like to create all save data on this system for #%s#? This can take a while depending on how many titles are found.");
|
||||
addUIString("confirmDeleteBackupsTitle", 0, "Are you sure you would like to delete all save backups for #%s#?");
|
||||
addUIString("confirmDeleteBackupsAll", 0, "Are you sure you would like to delete *all* of your save backups for all of your games?");
|
||||
addUIString("confirmDriveOverwrite", 0, "Downloading this backup from drive will overwrite the one on your SD card. Continue?");
|
||||
|
||||
//Save Data related strings
|
||||
addUIString("saveDataNoneFound", 0, "No saves found for #%s#!");
|
||||
|
|
@ -266,6 +268,9 @@ void ui::initStrings()
|
|||
addUIString("threadStatusPackingJKSV", 0, "Writing JKSV folder contents to ZIP...");
|
||||
addUIString("threadStatusSavingTranslations", 0, "Saving the file master...");
|
||||
addUIString("threadStatusCalculatingSaveSize", 0, "Calculating save data size...");
|
||||
addUIString("threadStatusUploadingFile", 0, "Uploading #%s#...");
|
||||
addUIString("threadStatusDownloadingFile", 0, "Downloading #%s#...");
|
||||
addUIString("threadStatusCompressingSaveForUpload", 0, "Compressing #%s# for upload...");
|
||||
|
||||
//Random leftover pop-ups
|
||||
addUIString("popCPUBoostEnabled", 0, "CPU Boost Enabled for ZIP.");
|
||||
|
|
@ -278,6 +283,10 @@ void ui::initStrings()
|
|||
addUIString("popChangeOutputFolder", 0, "#%s# changed to #%s#");
|
||||
addUIString("popChangeOutputError", 0, "#%s# contains illegal or non-ASCII characters.");
|
||||
addUIString("popTrashEmptied", 0, "Trash emptied");
|
||||
addUIString("popSVIExported", 0, "SVI Exported.");
|
||||
addUIString("popDriveStarted", 0, "Google Drive started successfully.");
|
||||
addUIString("popDriveFailed", 0, "Failed to start Google Drive.");
|
||||
addUIString("popDriveNotActive", 0, "Google Drive is not available");
|
||||
|
||||
//Keyboard hints
|
||||
addUIString("swkbdEnterName", 0, "Enter a new name");
|
||||
|
|
@ -312,7 +321,7 @@ void ui::loadTrans()
|
|||
std::string transTestFile = fs::getWorkDir() + "trans.txt";
|
||||
std::string translationFile = "romfs:/lang/" + getFilename(data::sysLang);
|
||||
bool transFile = fs::fileExists(transTestFile);
|
||||
if(!transFile && (data::sysLang == SetLanguage_ENUS || cfg::config["langOverride"]))
|
||||
if(!transFile && (data::sysLang == SetLanguage_ENUS || data::sysLang == SetLanguage_ENGB || cfg::config["langOverride"]))
|
||||
ui::initStrings();
|
||||
else if(transFile)
|
||||
loadTranslationFile(transTestFile);
|
||||
|
|
|
|||
43
src/util.cpp
43
src/util.cpp
|
|
@ -11,6 +11,7 @@
|
|||
#include "ui.h"
|
||||
#include "curlfuncs.h"
|
||||
#include "type.h"
|
||||
#include "cfg.h"
|
||||
|
||||
static const uint32_t verboten[] = { L',', L'/', L'\\', L'<', L'>', L':', L'"', L'|', L'?', L'*', L'™', L'©', L'®'};
|
||||
|
||||
|
|
@ -370,23 +371,55 @@ SDL_Texture *util::createIconGeneric(const char *txt, int fontSize, bool clearBa
|
|||
return ret;
|
||||
}
|
||||
|
||||
void util::setCPU(uint32_t hz)
|
||||
void util::sysBoost()
|
||||
{
|
||||
if(R_FAILED(clkrstInitialize()))
|
||||
return;
|
||||
|
||||
ClkrstSession cpu;
|
||||
ClkrstSession cpu, gpu, ram;
|
||||
clkrstOpenSession(&cpu, PcvModuleId_CpuBus, 3);
|
||||
clkrstSetClockRate(&cpu, hz);
|
||||
clkrstOpenSession(&gpu, PcvModuleId_GPU, 3);
|
||||
clkrstOpenSession(&ram, PcvModuleId_EMC, 3);
|
||||
|
||||
clkrstSetClockRate(&cpu, util::CPU_SPEED_1785MHz);
|
||||
clkrstSetClockRate(&gpu, util::GPU_SPEED_76MHz);
|
||||
clkrstSetClockRate(&ram, util::RAM_SPEED_1600MHz);
|
||||
|
||||
clkrstCloseSession(&cpu);
|
||||
clkrstCloseSession(&gpu);
|
||||
clkrstCloseSession(&ram);
|
||||
clkrstExit();
|
||||
}
|
||||
|
||||
void util::sysNormal()
|
||||
{
|
||||
if(R_FAILED(clkrstInitialize()))
|
||||
return;
|
||||
|
||||
ClkrstSession cpu, gpu, ram;
|
||||
clkrstOpenSession(&cpu, PcvModuleId_CpuBus, 3);
|
||||
clkrstOpenSession(&gpu, PcvModuleId_GPU, 3);
|
||||
clkrstOpenSession(&ram, PcvModuleId_EMC, 3);
|
||||
|
||||
if(cfg::config["ovrClk"])
|
||||
clkrstSetClockRate(&cpu, util::CPU_SPEED_1224MHz);
|
||||
else
|
||||
clkrstSetClockRate(&cpu, util::CPU_SPEED_1020MHz);
|
||||
clkrstSetClockRate(&gpu, util::GPU_SPEED_76MHz);
|
||||
clkrstSetClockRate(&ram, util::RAM_SPEED_1331MHz);
|
||||
|
||||
clkrstCloseSession(&cpu);
|
||||
clkrstCloseSession(&gpu);
|
||||
clkrstCloseSession(&ram);
|
||||
clkrstExit();
|
||||
|
||||
}
|
||||
|
||||
void util::checkForUpdate(void *a)
|
||||
{
|
||||
threadInfo *t = (threadInfo *)a;
|
||||
t->status->setStatus(ui::getUICString("threadStatusCheckingForUpdate", 0));
|
||||
std::string gitJson = getJSONURL(NULL, "https://api.github.com/repos/J-D-K/JKSV/releases/latest");
|
||||
std::string gitJson = curlFuncs::getJSONURL(NULL, "https://api.github.com/repos/J-D-K/JKSV/releases/latest");
|
||||
if(gitJson.empty())
|
||||
{
|
||||
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("onlineErrorConnecting", 0));
|
||||
|
|
@ -412,7 +445,7 @@ void util::checkForUpdate(void *a)
|
|||
|
||||
std::vector<uint8_t> jksvBuff;
|
||||
std::string url = json_object_get_string(dlUrl);
|
||||
getBinURL(&jksvBuff, url);
|
||||
curlFuncs::getBinURL(&jksvBuff, url);
|
||||
FILE *jksvOut = fopen("sdmc:/switch/JKSV.nro", "wb");
|
||||
fwrite(jksvBuff.data(), 1, jksvBuff.size(), jksvOut);
|
||||
fclose(jksvOut);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user