fix(libs): route DateTime zone suffix through RFC3339 path, throw on unverified shapes
This commit is contained in:
parent
af20824af4
commit
e67d50cb2f
|
|
@ -122,7 +122,7 @@ int APS5_VABI sceAudioInInput(int handle, void* dest) {
|
|||
if (device != 0) {
|
||||
captured = capture(device, out, bytes, deadline);
|
||||
} else {
|
||||
std::this_thread::sleep_until(wake);
|
||||
while (Clock::now() < wake) std::this_thread::sleep_until(wake);
|
||||
}
|
||||
std::memset(out + captured, 0, bytes - captured);
|
||||
lock.lock();
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ endif()
|
|||
if(BUILD_TESTING)
|
||||
add_test_executable(guest_rtc_tests ${LIBS_INCLUDE_DIR}/tests/GuestRtc.cpp)
|
||||
target_include_directories(guest_rtc_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_rtc_tests PRIVATE libSceRtc)
|
||||
target_link_libraries(guest_rtc_tests PRIVATE libSceRtc libc)
|
||||
configure_windows_unwind(guest_rtc_tests)
|
||||
add_test(NAME guest_rtc COMMAND guest_rtc_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_rtc PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
|
|
|
|||
|
|
@ -139,6 +139,23 @@ bool parseDigits(const char*& cursor, int count, int& value) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool parseZoneSuffix(const char*& cursor, std::int64_t& offsetMinutes) {
|
||||
offsetMinutes = 0;
|
||||
if (*cursor == 'Z' || *cursor == 'z') {
|
||||
++cursor;
|
||||
return true;
|
||||
}
|
||||
if (*cursor == '+' || *cursor == '-') {
|
||||
const int sign = *cursor++ == '-' ? -1 : 1;
|
||||
int offsetHours = 0, offsetMinute = 0;
|
||||
if (!parseDigits(cursor, 2, offsetHours) || *cursor++ != ':' || !parseDigits(cursor, 2, offsetMinute)) return false;
|
||||
if (offsetHours > 23 || offsetMinute > 59) return false;
|
||||
offsetMinutes = sign * (offsetHours * 60 + offsetMinute);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
|
@ -282,17 +299,7 @@ int APS5_VABI sceRtcParseRFC3339(RtcTick* utc, const char* date_time) {
|
|||
for (; *cursor >= '0' && *cursor <= '9'; ++cursor, scale /= 10) microsecond += static_cast<std::uint32_t>(*cursor - '0') * scale;
|
||||
}
|
||||
std::int64_t offsetMinutes = 0;
|
||||
if (*cursor == 'Z' || *cursor == 'z') {
|
||||
++cursor;
|
||||
} else if (*cursor == '+' || *cursor == '-') {
|
||||
const int sign = *cursor++ == '-' ? -1 : 1;
|
||||
int offsetHours = 0, offsetMinute = 0;
|
||||
if (!parseDigits(cursor, 2, offsetHours) || *cursor++ != ':' || !parseDigits(cursor, 2, offsetMinute)) return SCE_RTC_ERROR_BAD_PARSE;
|
||||
if (offsetHours > 23 || offsetMinute > 59) return SCE_RTC_ERROR_BAD_PARSE;
|
||||
offsetMinutes = sign * (offsetHours * 60 + offsetMinute);
|
||||
} else {
|
||||
return SCE_RTC_ERROR_BAD_PARSE;
|
||||
}
|
||||
if (!parseZoneSuffix(cursor, offsetMinutes)) return SCE_RTC_ERROR_BAD_PARSE;
|
||||
if (*cursor != 0) return SCE_RTC_ERROR_BAD_PARSE;
|
||||
const RtcDateTime time{static_cast<std::uint16_t>(year), static_cast<std::uint16_t>(month), static_cast<std::uint16_t>(day),
|
||||
static_cast<std::uint16_t>(hour), static_cast<std::uint16_t>(minute), static_cast<std::uint16_t>(second), microsecond};
|
||||
|
|
@ -305,23 +312,29 @@ int APS5_VABI sceRtcParseDateTime(RtcTick* utc, const char* date_time) {
|
|||
if (!utc || !date_time) return SCE_RTC_ERROR_INVALID_POINTER;
|
||||
const char* cursor = date_time;
|
||||
int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
|
||||
if (!parseDigits(cursor, 4, year) || *cursor++ != '-' || !parseDigits(cursor, 2, month) || *cursor++ != '-' || !parseDigits(cursor, 2, day)) return SCE_RTC_ERROR_BAD_PARSE;
|
||||
if (*cursor != 'T' && *cursor != 't' && *cursor != ' ') return SCE_RTC_ERROR_BAD_PARSE;
|
||||
++cursor;
|
||||
if (!parseDigits(cursor, 2, hour) || *cursor++ != ':' || !parseDigits(cursor, 2, minute) || *cursor++ != ':' || !parseDigits(cursor, 2, second)) return SCE_RTC_ERROR_BAD_PARSE;
|
||||
bool ok = parseDigits(cursor, 4, year) && *cursor++ == '-' && parseDigits(cursor, 2, month) && *cursor++ == '-' && parseDigits(cursor, 2, day);
|
||||
ok = ok && (*cursor == 'T' || *cursor == 't' || *cursor == ' ');
|
||||
if (ok) ++cursor;
|
||||
ok = ok && parseDigits(cursor, 2, hour) && *cursor++ == ':' && parseDigits(cursor, 2, minute) && *cursor++ == ':' && parseDigits(cursor, 2, second);
|
||||
std::uint32_t microsecond = 0;
|
||||
if (*cursor == '.') {
|
||||
if (ok && *cursor == '.') {
|
||||
++cursor;
|
||||
std::uint32_t scale = 100000;
|
||||
if (*cursor < '0' || *cursor > '9') return SCE_RTC_ERROR_BAD_PARSE;
|
||||
for (; *cursor >= '0' && *cursor <= '9'; ++cursor, scale /= 10) microsecond += static_cast<std::uint32_t>(*cursor - '0') * scale;
|
||||
ok = *cursor >= '0' && *cursor <= '9';
|
||||
for (; ok && *cursor >= '0' && *cursor <= '9'; ++cursor, scale /= 10) microsecond += static_cast<std::uint32_t>(*cursor - '0') * scale;
|
||||
}
|
||||
std::int64_t offsetMinutes = 0;
|
||||
if (ok && *cursor != 0) ok = parseZoneSuffix(cursor, offsetMinutes);
|
||||
if (ok && *cursor != 0) ok = false;
|
||||
if (!ok) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return SCE_RTC_ERROR_BAD_PARSE;
|
||||
}
|
||||
if (*cursor != 0) return SCE_RTC_ERROR_BAD_PARSE;
|
||||
const RtcDateTime time{static_cast<std::uint16_t>(year), static_cast<std::uint16_t>(month), static_cast<std::uint16_t>(day),
|
||||
static_cast<std::uint16_t>(hour), static_cast<std::uint16_t>(minute), static_cast<std::uint16_t>(second), microsecond};
|
||||
if (const int result = validate(&time); result != 0) return result;
|
||||
utc->tick = toTick(time);
|
||||
return 0;
|
||||
const RtcTick local{toTick(time)};
|
||||
return addTicks(utc, &local, -offsetMinutes, TICKS_PER_MINUTE);
|
||||
}
|
||||
|
||||
int APS5_VABI sceRtcTickAddTicks(RtcTick* dst, const RtcTick* src, int64_t ticks) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
|
||||
extern "C" {
|
||||
int APS5_VABI sceRtcCheckValid(const RtcDateTime*);
|
||||
|
|
@ -21,6 +22,7 @@ int APS5_VABI sceRtcGetWin32FileTime(const RtcDateTime*, std::uint64_t*);
|
|||
int APS5_VABI sceRtcSetWin32FileTime(RtcDateTime*, std::uint64_t);
|
||||
int APS5_VABI sceRtcFormatRFC3339(char*, const RtcTick*, int);
|
||||
int APS5_VABI sceRtcParseRFC3339(RtcTick*, const char*);
|
||||
int APS5_VABI sceRtcParseDateTime(RtcTick*, const char*);
|
||||
int APS5_VABI sceRtcTickAddTicks(RtcTick*, const RtcTick*, std::int64_t);
|
||||
int APS5_VABI sceRtcTickAddSeconds(RtcTick*, const RtcTick*, std::int64_t);
|
||||
int APS5_VABI sceRtcTickAddDays(RtcTick*, const RtcTick*, std::int32_t);
|
||||
|
|
@ -123,6 +125,30 @@ int main() {
|
|||
Require(sceRtcParseRFC3339(&tick, "2024-02-29T12:34:56.789-23:59") == 0 && tick.tick == leapDayTick + 86340000000ull);
|
||||
Require(sceRtcParseRFC3339(nullptr, "1970-01-01T00:00:00Z") == invalidPointer);
|
||||
|
||||
Require(sceRtcParseDateTime(&tick, "2024-02-29T12:34:56.789") == 0 && tick.tick == leapDayTick);
|
||||
Require(sceRtcParseDateTime(&tick, "2024-02-29 12:34:56") == 0 && tick.tick == leapDayTick - 789000ull);
|
||||
Require(sceRtcParseDateTime(&tick, "2024-02-29T14:04:56.789+01:30") == 0 && tick.tick == leapDayTick);
|
||||
Require(sceRtcParseDateTime(&tick, "2024-02-29t12:34:56.789z") == 0 && tick.tick == leapDayTick);
|
||||
Require(sceRtcParseDateTime(&tick, "1970-01-01T00:00:00Z") == 0 && tick.tick == unixEpochTick);
|
||||
Require(sceRtcParseDateTime(&tick, "2023-02-29T00:00:00") == invalidDay);
|
||||
Require(sceRtcParseDateTime(nullptr, "1970-01-01T00:00:00Z") == invalidPointer);
|
||||
const char* unparseable[] = {
|
||||
"2024-02-29",
|
||||
"2024/02/29T12:34:56",
|
||||
"2024-02-29T12:34:56Zjunk",
|
||||
"2024-02-29T12:34:56+99:99",
|
||||
"2024-02-29T12:34:56.",
|
||||
};
|
||||
for (const char* text : unparseable) {
|
||||
bool thrown = false;
|
||||
try {
|
||||
sceRtcParseDateTime(&tick, text);
|
||||
} catch (const std::exception&) {
|
||||
thrown = true;
|
||||
}
|
||||
Require(thrown);
|
||||
}
|
||||
|
||||
RtcTick source{leapDayTick};
|
||||
RtcTick result{};
|
||||
Require(sceRtcTickAddSeconds(&result, &source, 3600) == 0 && result.tick == leapDayTick + 3600000000ull);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ Throughout the project, every function at every stage either **does exactly what
|
|||
### Unknown function info
|
||||
|
||||
- [sceVideoOutOpen](../../core/libs/prx/libSceVideoOut/src/Output.cpp) (libSceVideoOut) - the open param's first word is unknown (PPSA21564 passes 16; it is not the byte size, since the affinity mask is at offset 16); only 16 is accepted. Whether the param continues past offset 24 is also unknown
|
||||
- [sceRtcParseDateTime](../../core/libs/prx/libSceRtc/Export.cpp) (libSceRtc) - accepted format assumed to be the ISO 8601 subset `YYYY-MM-DDTHH:MM:SS[.ffffff]` (T/t/space separator, optional fractional seconds), matching the sibling RFC 3339 parser; unverified against hardware
|
||||
- [sceRtcParseDateTime](../../core/libs/prx/libSceRtc/Export.cpp) (libSceRtc) - accepted format assumed to be the ISO 8601 subset `YYYY-MM-DDTHH:MM:SS[.ffffff]` (T/t/space separator, optional fractional seconds) with the sibling RFC 3339 zone suffix (`Z` or `±HH:MM`); a string without a zone is taken as UTC, and anything outside this shape throws instead of returning a parse error, unverified against hardware
|
||||
- [AMPR WaitOnAddress / WaitOnCounter](../../core/libs/prx/libkernel/Apr/src/Apr.cpp) (libSceAmpr) - compare encoding assumed to be the WAIT_REG_MEM one (0 always, 1 <, 2 <=, 3 ==, 4 !=, 5 >=, 6 >)
|
||||
- [sceAgcSetSubmitMode](../../core/libs/prx/libSceAgc/Misc/src/Suspend.cpp) (libSceAgc) - mode values unknown; only 0 is accepted
|
||||
- [zARR5aCmkoY](../../core/libs/prx/libSceAgc/DcbFlow/src/Control.cpp) (libSceAgc) - unknown name, signature
|
||||
|
|
|
|||
Loading…
Reference in New Issue