From 1b6aa55fbe89e0f226249cb111e13eacb77cdfff Mon Sep 17 00:00:00 2001 From: Ivan Epifanov Date: Tue, 22 Apr 2025 16:25:46 +0300 Subject: [PATCH 1/3] Fix qr threads race condition and improve qr scan accuracy --- browser.c | 12 ++++++++---- init.c | 2 -- main.c | 1 + qr.c | 10 +++++++--- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/browser.c b/browser.c index 6809ad7..57aa87a 100644 --- a/browser.c +++ b/browser.c @@ -470,10 +470,14 @@ int shortCuts() { } // QR - if (current_pad[PAD_CIRCLE] && enabledQR()) { - startQR(); - initMessageDialog(MESSAGE_DIALOG_QR_CODE, language_container[QR_SCANNING]); - setDialogStep(DIALOG_STEP_QR); + if (current_pad[PAD_CIRCLE]/* && enabledQR()*/) { + initQR(); + if (enabledQR()) + { + startQR(); + initMessageDialog(MESSAGE_DIALOG_QR_CODE, language_container[QR_SCANNING]); + setDialogStep(DIALOG_STEP_QR); + } } return 0; diff --git a/init.c b/init.c index e97d5d3..916c738 100644 --- a/init.c +++ b/init.c @@ -372,7 +372,6 @@ void initVitaShell() { initVita2dLib(); initSceAppUtil(); initNet(); - initQR(); initSQLite(); // Init power tick thread @@ -437,7 +436,6 @@ void finishVitaShell() { finishNet(); finishSceAppUtil(); finishVita2dLib(); - finishQR(); vitaAudioShutdown(); // Unload modules diff --git a/main.c b/main.c index e6fd1e0..2375d29 100644 --- a/main.c +++ b/main.c @@ -951,6 +951,7 @@ int dialogSteps() { if (msg_result == MESSAGE_DIALOG_RESULT_FINISHED) { setDialogStep(DIALOG_STEP_QR_WAITING); stopQR(); + finishQR(); SceUID thid = sceKernelCreateThread("qr_scan_thread", (SceKernelThreadEntry)qr_scan_thread, 0x10000100, 0x100000, 0, 0, NULL); if (thid >= 0) sceKernelStartThread(thid, 0, NULL); diff --git a/qr.c b/qr.c index f817bb5..71114b2 100644 --- a/qr.c +++ b/qr.c @@ -64,6 +64,8 @@ int qr_thread() { qr = quirc_new(); quirc_resize(qr, CAM_WIDTH, CAM_HEIGHT); qr_next = 1; + qr_scanned = 0; + memset(last_qr, 0, MAX_QR_LENGTH); while (1) { sceKernelDelayThread(10); if (qr_next == 0 && qr_scanned == 0) { @@ -74,7 +76,8 @@ int qr_thread() { int i; for (i = 0; i < w*h; i++) { colourRGBA = qr_data[i]; - image[i] = ((colourRGBA & 0x000000FF) + ((colourRGBA & 0x0000FF00) >> 8) + ((colourRGBA & 0x00FF0000) >> 16)) / 3; + image[i] = MIN( MIN((colourRGBA & 0x000000FF), (colourRGBA & 0x0000FF00)), (colourRGBA & 0x00FF0000)); +// image[i] = ((colourRGBA & 0x000000FF) + ((colourRGBA & 0x0000FF00) >> 8) + ((colourRGBA & 0x00FF0000) >> 16)) / 3; } quirc_end(qr); int num_codes = quirc_count(qr); @@ -90,6 +93,7 @@ int qr_thread() { memcpy(last_qr, data.payload, data.payload_len); last_qr_len = data.payload_len; qr_scanned = 1; + break; } } else { memset(last_qr, 0, MAX_QR_LENGTH); @@ -115,7 +119,7 @@ int qr_scan_thread(SceSize args, void *argp) { } initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_NONE, language_container[PLEASE_WAIT]); - + // check for attached file const char *headerData; unsigned int headerLen; @@ -201,7 +205,7 @@ int qr_scan_thread(SceSize args, void *argp) { // VPK type vpk = getFileType(fileName) == FILE_TYPE_VPK; } - + if (vpk) initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[QR_CONFIRM_INSTALL], data, fileName, sizeString); else From 99604665c788dc8226211bbea1485f7acdf5442c Mon Sep 17 00:00:00 2001 From: Ivan Epifanov Date: Tue, 22 Apr 2025 23:37:12 +0300 Subject: [PATCH 2/3] Migrate downloads to curl --- CMakeLists.txt | 5 +- file.h | 1 + init.c | 9 -- main.c | 1 + network_download.c | 370 +++++++++++++++++++++++++-------------------- network_download.h | 3 +- network_update.c | 15 +- qr.c | 94 ++++-------- 8 files changed, 257 insertions(+), 241 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a8f97a..25e60ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ endif() project(VitaShell) include("${VITASDK}/share/vita.cmake" REQUIRED) set(VITA_APP_NAME "VitaShell") -set(VITA_TITLEID "VITASHELL") +set(VITA_TITLEID "VITASHEL2") set(VITA_VERSION "02.05") # Flags and includes @@ -157,6 +157,9 @@ add_dependencies(VitaShell usbdevice.skprx-self) target_link_libraries(VitaShell ${CMAKE_CURRENT_BINARY_DIR}/modules/user/libVitaShellUser_stub_weak.a + curl + ssl + crypto ftpvita vita2d vorbisfile diff --git a/file.h b/file.h index a0a3447..d99e7d9 100644 --- a/file.h +++ b/file.h @@ -76,6 +76,7 @@ typedef struct { uint64_t max; void (* SetProgress)(uint64_t value, uint64_t max); int (* cancelHandler)(); + SceUID fp; } FileProcessParam; typedef struct FileListEntry { diff --git a/init.c b/init.c index 916c738..c9e9132 100644 --- a/init.c +++ b/init.c @@ -288,11 +288,6 @@ static void initNet() { sceNetInit(¶m); sceNetCtlInit(); - sceSslInit(300 * 1024); - sceHttpInit(40 * 1024); - - sceHttpsDisableOption(SCE_HTTPS_FLAG_SERVER_VERIFY); - sceNetAdhocInit(); SceNetAdhocctlAdhocId adhocId; @@ -305,8 +300,6 @@ static void initNet() { static void finishNet() { sceNetAdhocctlTerm(); sceNetAdhocTerm(); - sceSslTerm(); - sceHttpTerm(); sceNetCtlTerm(); sceNetTerm(); free(net_memory); @@ -363,7 +356,6 @@ void initVitaShell() { sceSysmoduleLoadModule(SCE_SYSMODULE_MUSIC_EXPORT); sceSysmoduleLoadModule(SCE_SYSMODULE_PHOTO_EXPORT); sceSysmoduleLoadModule(SCE_SYSMODULE_NET); - sceSysmoduleLoadModule(SCE_SYSMODULE_HTTPS); sceSysmoduleLoadModule(SCE_SYSMODULE_PSPNET_ADHOC); sceSysmoduleLoadModule(SCE_SYSMODULE_SQLITE); @@ -441,7 +433,6 @@ void finishVitaShell() { // Unload modules sceSysmoduleUnloadModule(SCE_SYSMODULE_SQLITE); sceSysmoduleUnloadModule(SCE_SYSMODULE_PSPNET_ADHOC); - sceSysmoduleUnloadModule(SCE_SYSMODULE_HTTPS); sceSysmoduleUnloadModule(SCE_SYSMODULE_NET); sceSysmoduleUnloadModule(SCE_SYSMODULE_PHOTO_EXPORT); sceSysmoduleUnloadModule(SCE_SYSMODULE_MUSIC_EXPORT); diff --git a/main.c b/main.c index 2375d29..8689c3d 100644 --- a/main.c +++ b/main.c @@ -989,6 +989,7 @@ int dialogSteps() { case DIALOG_STEP_QR_DOWNLOADED_VPK: { if (msg_result == MESSAGE_DIALOG_RESULT_FINISHED) { + initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[INSTALLING]); setDialogStep(DIALOG_STEP_INSTALL_CONFIRMED_QR); } diff --git a/network_download.c b/network_download.c index 87cc055..b265e38 100644 --- a/network_download.c +++ b/network_download.c @@ -16,6 +16,13 @@ along with this program. If not, see . */ +#include +#include +#include +#include +#include +#include + #include "main.h" #include "io_process.h" #include "network_download.h" @@ -28,198 +35,229 @@ #define VITASHELL_USER_AGENT "VitaShell/1.00 libhttp/1.1" -int getDownloadFileSize(const char *src, uint64_t *size) { - int res; - int statusCode; - int tmplId = -1, connId = -1, reqId = -1; - - res = sceHttpCreateTemplate(VITASHELL_USER_AGENT, SCE_HTTP_VERSION_1_1, SCE_TRUE); - if (res < 0) - goto ERROR_EXIT; - - tmplId = res; - - res = sceHttpCreateConnectionWithURL(tmplId, src, SCE_TRUE); - if (res < 0) - goto ERROR_EXIT; - - connId = res; - - res = sceHttpCreateRequestWithURL(connId, SCE_HTTP_METHOD_GET, src, 0); - if (res < 0) - goto ERROR_EXIT; - - reqId = res; - - res = sceHttpSendRequest(reqId, NULL, 0); - if (res < 0) - goto ERROR_EXIT; - - res = sceHttpGetStatusCode(reqId, &statusCode); - if (res < 0) - goto ERROR_EXIT; +static char *parse_filename(const char *ptr, size_t len) +{ + char *copy; + char *p; + char *q; + char stop = '\0'; + + /* simple implementation of strndup() */ + copy = malloc(len + 1); + if(!copy) + return NULL; + memcpy(copy, ptr, len); + copy[len] = '\0'; + + p = copy; + if(*p == '\'' || *p == '"') { + /* store the starting quote */ + stop = *p; + p++; + } + else + stop = ';'; + + /* scan for the end letter and stop there */ + q = strchr(p, stop); + if(q) + *q = '\0'; + + /* if the filename contains a path, only use filename portion */ + q = strrchr(p, '/'); + if(q) { + p = q + 1; + if(!*p) { + free(copy); + return NULL; + } + } - if (statusCode == 200) { - res = sceHttpGetResponseContentLength(reqId, size); + /* If the filename contains a backslash, only use filename portion. The idea + is that even systems that do not handle backslashes as path separators + probably want the path removed for convenience. */ + q = strrchr(p, '\\'); + if(q) { + p = q + 1; + if(!*p) { + free(copy); + return NULL; + } } -ERROR_EXIT: - if (reqId >= 0) - sceHttpDeleteRequest(reqId); + /* make sure the filename does not end in \r or \n */ + q = strchr(p, '\r'); + if(q) + *q = '\0'; - if (connId >= 0) - sceHttpDeleteConnection(connId); + q = strchr(p, '\n'); + if(q) + *q = '\0'; - if (tmplId >= 0) - sceHttpDeleteTemplate(tmplId); + if(copy != p) + memmove(copy, p, strlen(p) + 1); - return res; + return copy; } -int getFieldFromHeader(const char *src, const char *field, const char **data, unsigned int *valueLen) { - int res; - char *header; - unsigned int headerSize; - int tmplId = -1, connId = -1, reqId = -1; - - res = sceHttpCreateTemplate(VITASHELL_USER_AGENT, SCE_HTTP_VERSION_1_1, SCE_TRUE); - if (res < 0) - goto ERROR_EXIT; - - tmplId = res; - - res = sceHttpCreateConnectionWithURL(tmplId, src, SCE_TRUE); - if (res < 0) - goto ERROR_EXIT; - - connId = res; - - res = sceHttpCreateRequestWithURL(connId, SCE_HTTP_METHOD_GET, src, 0); - if (res < 0) - goto ERROR_EXIT; - - reqId = res; - - res = sceHttpSendRequest(reqId, NULL, 0); - if (res < 0) - goto ERROR_EXIT; - - res = sceHttpGetAllResponseHeaders(reqId, &header, &headerSize); - if (res < 0) - goto ERROR_EXIT; - - res = sceHttpParseResponseHeader(header, headerSize, field, data, valueLen); - if (res < 0) { - *data = ""; - *valueLen = 0; - res = 0; - } - -ERROR_EXIT: - if (reqId >= 0) - sceHttpDeleteRequest(reqId); - - if (connId >= 0) - sceHttpDeleteConnection(connId); - if (tmplId >= 0) - sceHttpDeleteTemplate(tmplId); +//static char* fname = NULL; - return res; -} +size_t header_cb(char *buffer, size_t size, size_t nitems, void *userdata) +{ + const size_t cb = size * nitems; + const char *end = (char *)buffer + cb; + const char *str = buffer; -int downloadFile(const char *src, const char *dst, FileProcessParam *param) { - int res; - int statusCode; - int tmplId = -1, connId = -1, reqId = -1; - SceUID fd = -1; - int ret = 1; + if((cb > 20) && curl_strnequal(buffer, "Content-disposition:", 20)) { + const char *p = buffer + 20; - res = sceHttpCreateTemplate(VITASHELL_USER_AGENT, SCE_HTTP_VERSION_1_1, SCE_TRUE); - if (res < 0) - goto ERROR_EXIT; + for(;;) { + char *filename; + size_t len; - tmplId = res; + while((p < end) && *p && !isalpha((int)*p)) + p++; + if(p > end - 9) + break; - res = sceHttpCreateConnectionWithURL(tmplId, src, SCE_TRUE); - if (res < 0) - goto ERROR_EXIT; + if(memcmp(p, "filename=", 9)) { + // no match, find next parameter + while((p < end) && *p && (*p != ';')) + p++; + if((p < end) && *p) + continue; + else + break; + } + p += 9; - connId = res; + len = cb - (size_t)(p - str); - res = sceHttpCreateRequestWithURL(connId, SCE_HTTP_METHOD_GET, src, 0); - if (res < 0) - goto ERROR_EXIT; + filename = parse_filename(p, len); - reqId = res; + if(filename) { + *(char**)userdata = strdup(filename); + free(filename); + } + break; + } + } - res = sceHttpSendRequest(reqId, NULL, 0); - if (res < 0) - goto ERROR_EXIT; + return nitems * size; +} - res = sceHttpGetStatusCode(reqId, &statusCode); - if (res < 0) - goto ERROR_EXIT; +int getDownloadFileInfo(const char* url, int64_t* size, char** fileName, long* response_code) +{ + CURL *curl; + CURLcode res; + static char* fname = NULL; + + curl = curl_easy_init(); + + if (curl) { + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_NOBODY, 1); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + + if (fileName) + { + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_cb); + curl_easy_setopt(curl, CURLOPT_HEADERDATA, &fname); + } - if (statusCode == 200) { - res = sceIoOpen(dst, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777); - if (res < 0) - goto ERROR_EXIT; + res = curl_easy_perform(curl); + + // try to get size + curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, size); + + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, response_code); + + if (fileName) + { + // try to get filename + char *url = NULL; + curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url); + + if (fname) + { + *fileName = strdup(fname); + free(fname); + fname = NULL; + } + else if (url) + { + *fileName = strdup(basename(url)); + } + } - fd = res; + curl_easy_cleanup(curl); + } - uint8_t buf[4096]; + return 0; +} - while (1) { - int read = sceHttpReadData(reqId, buf, sizeof(buf)); - - if (read < 0) { - res = read; - break; - } - - if (read == 0) - break; - - int written = sceIoWrite(fd, buf, read); - - if (written < 0) { - res = written; - break; - } +static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) +{ + FileProcessParam *param = (FileProcessParam*)stream; + size_t written = sceIoWrite(param->fp, ptr, size*nmemb); - if (param) { - if (param->value) - (*param->value) += read; + if (param) { + if (param->value) + (*param->value) += written; - if (param->SetProgress) + if (param->SetProgress) param->SetProgress(param->value ? *param->value : 0, param->max); - if (param->cancelHandler && param->cancelHandler()) { - ret = 0; - break; - } + if (param->cancelHandler && param->cancelHandler()) { + return CURL_WRITEFUNC_ERROR; } - } } -ERROR_EXIT: - if (fd >= 0) - sceIoClose(fd); - - if (reqId >= 0) - sceHttpDeleteRequest(reqId); - - if (connId >= 0) - sceHttpDeleteConnection(connId); + return written; +} - if (tmplId >= 0) - sceHttpDeleteTemplate(tmplId); +int downloadFile(const char* url, const char* path, FileProcessParam *param) +{ + CURL *curl; + FILE *fp; + CURLcode res; + + curl = curl_easy_init(); + if (curl) { + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_NOBODY, 0L); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); + + param->fp = sceIoOpen(path, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777); + + long response_code = 0; + if (param->fp >= 0) + { + curl_easy_setopt(curl, CURLOPT_WRITEDATA, param); + res = curl_easy_perform(curl); + + sceIoClose(param->fp); + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + curl_easy_cleanup(curl); + } + if (response_code != 200) return -1; + } - if (res < 0) - return res; + return 0; - return ret; } int downloadFileProcess(const char *url, const char *dest, int successStep) { @@ -233,8 +271,16 @@ int downloadFileProcess(const char *url, const char *dest, int successStep) { sceKernelDelayThread(DIALOG_WAIT); // Needed to see the percentage // File size - uint64_t size = 0; - getDownloadFileSize(url, &size); + int64_t size = 0; + long code = 0; + + getDownloadFileInfo(url, &size, NULL, &code); + if (size < 0 || code != 200) + { + closeWaitDialog(); + setDialogStep(DIALOG_STEP_CANCELED); + errorDialog(code); + } // Update thread thid = createStartUpdateThread(size, 1); @@ -249,7 +295,7 @@ int downloadFileProcess(const char *url, const char *dest, int successStep) { param.cancelHandler = cancelHandler; int res = downloadFile(url, dest, ¶m); - if (res <= 0) { + if (res < 0) { sceIoRemove(dest); closeWaitDialog(); setDialogStep(DIALOG_STEP_CANCELED); diff --git a/network_download.h b/network_download.h index 09f2674..e37530b 100644 --- a/network_download.h +++ b/network_download.h @@ -25,8 +25,7 @@ #ifndef __NETWORK_DOWNLOAD_H__ #define __NETWORK_DOWNLOAD_H__ -int getDownloadFileSize(const char *src, uint64_t *size); -int getFieldFromHeader(const char *src, const char *field, const char **data, unsigned int *valueLen); +int getDownloadFileInfo(const char* url, int64_t* size, char** fileName, long* response_code); int downloadFile(const char *src, const char *dst, FileProcessParam *param); int downloadFileProcess(const char *url, const char *dest, int successStep); diff --git a/network_update.c b/network_update.c index e4f3fb8..dcb1c01 100644 --- a/network_update.c +++ b/network_update.c @@ -38,9 +38,18 @@ extern unsigned char _binary_resources_updater_param_bin_start; extern unsigned char _binary_resources_updater_param_bin_size; int network_update_thread(SceSize args, void *argp) { - uint64_t size = 0; - if (getDownloadFileSize(BASE_ADDRESS VERSION_URL, &size) >= 0 && size == sizeof(uint32_t)) { - int res = downloadFile(BASE_ADDRESS VERSION_URL, VITASHELL_VERSION_FILE, NULL); + int64_t size = 0; + long code = 0; + if (getDownloadFileInfo(BASE_ADDRESS VERSION_URL, &size, NULL, &code) >= 0 && size == sizeof(uint32_t)) { + uint64_t value = 0; + + FileProcessParam param; + param.value = &value; + param.max = size; + param.SetProgress = NULL; + param.cancelHandler = NULL; + + int res = downloadFile(BASE_ADDRESS VERSION_URL, VITASHELL_VERSION_FILE, ¶m); if (res <= 0) goto EXIT; diff --git a/qr.c b/qr.c index 71114b2..2bb18a5 100644 --- a/qr.c +++ b/qr.c @@ -102,6 +102,7 @@ int qr_thread() { sceKernelDelayThread(250000); } } + return 0; } int qr_scan_thread(SceSize args, void *argp) { @@ -125,20 +126,18 @@ int qr_scan_thread(SceSize args, void *argp) { unsigned int headerLen; unsigned int fileNameLength = 0; int vpk = 0; - char *fileName = ""; - uint64_t fileSize; + char *fileName = NULL; + int64_t fileSize; + long code = 0; char sizeString[16]; int ret; - ret = getDownloadFileSize(data, &fileSize); - if (ret < 0) - goto NETWORK_FAILURE; - ret = getFieldFromHeader(data, "Content-Disposition", &headerData, &headerLen); + ret = getDownloadFileInfo(data, &fileSize, &fileName, &code); + if (ret < 0) goto NETWORK_FAILURE; - getSizeString(sizeString, fileSize); sceMsgDialogClose(); // Wait for it to stop loading @@ -146,64 +145,24 @@ int qr_scan_thread(SceSize args, void *argp) { sceKernelDelayThread(10 * 1000); } - if (headerLen <= 0) { - char *next; - fileName = data; - while ((next = strpbrk(fileName + 1, "\\/"))) fileName = next; - if (fileName != last_qr) fileName++; - - char *ext = strrchr(fileName, '.'); - if (ext) { - vpk = getFileType(fileName) == FILE_TYPE_VPK; - } else { - initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[QR_OPEN_WEBSITE], data); - setDialogStep(DIALOG_STEP_QR_OPEN_WEBSITE); - return sceKernelExitDeleteThread(0); - } - } else { - if (strstr(headerData, "inline") != NULL) { - initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[QR_OPEN_WEBSITE], data); - setDialogStep(DIALOG_STEP_QR_OPEN_WEBSITE); - return sceKernelExitDeleteThread(0); - } - - char *p = strstr(headerData, "filename="); - if (!p) - goto EXIT; - - fileName = p+9; - - p = strchr(fileName, '\n'); - if (p) - *p = '\0'; - - // Trim at beginning - while (*fileName < 0x20 || - *fileName == ' ' || *fileName == '\\' || - *fileName == '/' || *fileName == ':' || - *fileName == '*' || *fileName == '?' || - *fileName == '"' || *fileName == '<' || - *fileName == '>' || *fileName == '|') { - fileName++; - } + if (code != 200 || fileSize < 0) + { + free(fileName); + initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[QR_OPEN_WEBSITE], data); + setDialogStep(DIALOG_STEP_QR_OPEN_WEBSITE); + return sceKernelExitDeleteThread(0); + } - // Trim at end - int i; - for (i = strlen(fileName)-1; i >= 0; i--) { - if (fileName[i] < 0x20 || - fileName[i] == ' ' || fileName[i] == '\\' || - fileName[i] == '/' || fileName[i] == ':' || - fileName[i] == '*' || fileName[i] == '?' || - fileName[i] == '"' || fileName[i] == '<' || - fileName[i] == '>' || fileName[i] == '|') { - fileName[i] = 0; - } else { - break; - } - } + getSizeString(sizeString, fileSize); - // VPK type + char *ext = strrchr(fileName, '.'); + if (ext) { vpk = getFileType(fileName) == FILE_TYPE_VPK; + } else { + free(fileName); + initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[QR_OPEN_WEBSITE], data); + setDialogStep(DIALOG_STEP_QR_OPEN_WEBSITE); + return sceKernelExitDeleteThread(0); } if (vpk) @@ -219,6 +178,7 @@ int qr_scan_thread(SceSize args, void *argp) { // No if (getDialogStep() == DIALOG_STEP_NONE) { + free(fileName); goto EXIT; } @@ -226,8 +186,7 @@ int qr_scan_thread(SceSize args, void *argp) { char download_path[MAX_URL_LENGTH]; char short_name[MAX_URL_LENGTH]; int count = 0; - - char *ext = strrchr(fileName, '.'); + if (ext) { int len = ext-fileName; if (len > sizeof(short_name) - 1) @@ -238,6 +197,7 @@ int qr_scan_thread(SceSize args, void *argp) { strncpy(short_name, fileName, sizeof(short_name) - 1); ext = ""; } + while (1) { if (count == 0) snprintf(download_path, sizeof(download_path) - 1, "ux0:download/%s", fileName); @@ -250,14 +210,20 @@ int qr_scan_thread(SceSize args, void *argp) { break; count++; } + + free(fileName); sceIoMkdir("ux0:download", 0006); strcpy(last_download, download_path); if (vpk) + { return downloadFileProcess(data, download_path, DIALOG_STEP_QR_DOWNLOADED_VPK); + } else + { return downloadFileProcess(data, download_path, DIALOG_STEP_QR_DOWNLOADED); + } EXIT: return sceKernelExitDeleteThread(0); From 418367937f46a29c2e99276ca952e6b437d9055e Mon Sep 17 00:00:00 2001 From: Epifanov Ivan Date: Fri, 8 Aug 2025 18:39:14 +0300 Subject: [PATCH 3/3] Update CMakeLists.txt --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 25e60ce..24427a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ endif() project(VitaShell) include("${VITASDK}/share/vita.cmake" REQUIRED) set(VITA_APP_NAME "VitaShell") -set(VITA_TITLEID "VITASHEL2") +set(VITA_TITLEID "VITASHELL") set(VITA_VERSION "02.05") # Flags and includes