Implement http uri escape unescape (#3853)

* Implement sceHttpUriEscape and sceHttpUriUnescape

* Implement sceHttpUriEscape and sceHttpUriUnescape

* edge case

---------

Co-authored-by: Pirky10 <odukoyaabdullah@gmail.com>
This commit is contained in:
Odukoya Abdullahi Ademola
2025-12-04 09:50:01 +01:00
committed by GitHub
parent 98fd0689ac
commit 9e80cde60d
2 changed files with 121 additions and 4 deletions

View File

@@ -712,8 +712,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 (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
c == '-' || c == '_' || c == '.' || c == '~';
};
u64 needed = 0;
const char* src = in;
while (*src) {
unsigned char c = static_cast<unsigned char>(*src);
if (IsUnreserved(c)) {
needed++;
} else {
needed += 3; // %XX format
}
src++;
}
needed++; // null terminator
if (require) {
*require = needed;
}
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<unsigned char>(*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 +1130,71 @@ 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;
}
// Locale-independent hex digit check
auto IsHex = [](char c) -> bool {
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
};
// Convert hex char to int value
auto HexToInt = [](char c) -> int {
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
return 0;
};
// Check for valid percent-encoded sequence (%XX)
auto IsValidPercentSequence = [&](const char* s) -> bool {
return s[0] == '%' && s[1] != '\0' && s[2] != '\0' && IsHex(s[1]) && IsHex(s[2]);
};
u64 needed = 0;
const char* src = in;
while (*src) {
if (IsValidPercentSequence(src)) {
src += 3;
} else {
src++;
}
needed++;
}
needed++; // null terminator
if (require) {
*require = needed;
}
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 (IsValidPercentSequence(src)) {
*dst++ = static_cast<char>((HexToInt(src[1]) << 4) | HexToInt(src[2]));
src += 3;
} else {
*dst++ = *src++;
}
}
*dst = '\0';
return ORBIS_OK;
}

View File

@@ -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,