From 5b0a296149780de7f68ae6631bdc9d7eeeb0f350 Mon Sep 17 00:00:00 2001 From: Pirky10 Date: Wed, 3 Dec 2025 19:56:40 +0100 Subject: [PATCH] Implement sceHttpUriEscape and sceHttpUriUnescape --- src/core/libraries/network/http.cpp | 109 +++++++++++++++++++++++++++- src/core/libraries/network/http.h | 2 +- 2 files changed, 107 insertions(+), 4 deletions(-) diff --git a/src/core/libraries/network/http.cpp b/src/core/libraries/network/http.cpp index 1ae48dfed..4c03532ef 100644 --- a/src/core/libraries/network/http.cpp +++ b/src/core/libraries/network/http.cpp @@ -1,6 +1,9 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include +#include + #include "common/logging/log.h" #include "core/libraries/error_codes.h" #include "core/libraries/libs.h" @@ -712,8 +715,61 @@ int PS4_SYSV_ABI sceHttpUriCopy() { return ORBIS_OK; } -int PS4_SYSV_ABI sceHttpUriEscape() { - LOG_ERROR(Lib_Http, "(STUBBED) called"); +int PS4_SYSV_ABI sceHttpUriEscape(char* out, u64* require, u64 prepare, const char* in) { + LOG_TRACE(Lib_Http, "called"); + + if (!in) { + LOG_ERROR(Lib_Http, "Invalid input string"); + return ORBIS_HTTP_ERROR_INVALID_VALUE; + } + + auto IsUnreserved = [](unsigned char c) -> bool { + return std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~'; + }; + + u64 needed = 0; + const char* src = in; + while (*src) { + unsigned char c = static_cast(*src); + if (IsUnreserved(c)) { + needed++; + } else { + needed += 3; // %XX format + } + src++; + } + needed++; // null terminator + + if (require) { + *require = needed; + } + + // If only calculating size, return success + if (!out) { + return ORBIS_OK; + } + + if (prepare < needed) { + LOG_ERROR(Lib_Http, "Buffer too small: need {} but only {} available", needed, prepare); + return ORBIS_HTTP_ERROR_OUT_OF_MEMORY; + } + + static const char hex_chars[] = "0123456789ABCDEF"; + src = in; + char* dst = out; + while (*src) { + unsigned char c = static_cast(*src); + if (IsUnreserved(c)) { + *dst++ = *src; + } else { + *dst++ = '%'; + *dst++ = hex_chars[(c >> 4) & 0x0F]; + *dst++ = hex_chars[c & 0x0F]; + } + src++; + } + *dst = '\0'; + return ORBIS_OK; } @@ -1077,7 +1133,54 @@ int PS4_SYSV_ABI sceHttpUriSweepPath(char* dst, const char* src, u64 srcSize) { } int PS4_SYSV_ABI sceHttpUriUnescape(char* out, u64* require, u64 prepare, const char* in) { - LOG_ERROR(Lib_Http, "(STUBBED) called"); + LOG_TRACE(Lib_Http, "called"); + + if (!in) { + LOG_ERROR(Lib_Http, "Invalid input string"); + return ORBIS_HTTP_ERROR_INVALID_VALUE; + } + + u64 needed = 0; + const char* src = in; + while (*src) { + if (*src == '%' && std::isxdigit(static_cast(src[1])) && + std::isxdigit(static_cast(src[2]))) { + src += 3; + } else { + src++; + } + needed++; + } + needed++; // null terminator + + if (require) { + *require = needed; + } + + // If only calculating size, return success + if (!out) { + return ORBIS_OK; + } + + if (prepare < needed) { + LOG_ERROR(Lib_Http, "Buffer too small: need {} but only {} available", needed, prepare); + return ORBIS_HTTP_ERROR_OUT_OF_MEMORY; + } + + src = in; + char* dst = out; + while (*src) { + if (*src == '%' && std::isxdigit(static_cast(src[1])) && + std::isxdigit(static_cast(src[2]))) { + char hex[3] = {src[1], src[2], '\0'}; + *dst++ = static_cast(std::strtol(hex, nullptr, 16)); + src += 3; + } else { + *dst++ = *src++; + } + } + *dst = '\0'; + return ORBIS_OK; } diff --git a/src/core/libraries/network/http.h b/src/core/libraries/network/http.h index 701bb0e05..2ad5e171f 100644 --- a/src/core/libraries/network/http.h +++ b/src/core/libraries/network/http.h @@ -148,7 +148,7 @@ int PS4_SYSV_ABI sceHttpUnsetEpoll(); int PS4_SYSV_ABI sceHttpUriBuild(char* out, u64* require, u64 prepare, const OrbisHttpUriElement* srcElement, u32 option); int PS4_SYSV_ABI sceHttpUriCopy(); -int PS4_SYSV_ABI sceHttpUriEscape(); +int PS4_SYSV_ABI sceHttpUriEscape(char* out, u64* require, u64 prepare, const char* in); int PS4_SYSV_ABI sceHttpUriMerge(char* mergedUrl, char* url, char* relativeUri, u64* require, u64 prepare, u32 option); int PS4_SYSV_ABI sceHttpUriParse(OrbisHttpUriElement* out, const char* srcUri, void* pool,