Files
AnyPS5/core/libs/tests/GuestNKWebKitNumbers.cpp
T
KernelPanicNT 78c9c9127a feat(libSceNKWebKit): parse decimal numbers as WTF double-conversion
Implement the six WTF::charactersToDouble and WTF::charactersToFloat
overloads for Latin-1 and UTF-16 input and the four static
WTF::double_conversion::StringToDoubleConverter StringToDouble and
StringToFloat overloads for char and uint16_t input, following pinned
public WebKit. One parser follows StringToIeee: the number grammar, the
772-digit cut with a sticky digit, the exponent saturation and the
processed length. charactersToDouble and charactersToFloat add
toDoubleType's leading ASCII spaces and ok/parsedLength results, map
UTF-16 code units above 0x7F to 0 and round the float overloads through
double. StringToDoubleConverter reads the code units as they are, skips
no spaces and rounds StringToFloat directly to float as Strtof does.
Null characters with a nonzero length and a null processed length throw
where WebKit faults, a decimal exponent that leaves the range of
WebKit's int throws where WebKit overflows, and a UTF-16 charactersTo*
length above UINT32_MAX throws where WebKit's conversion Vector crashes.
2026-10-31 03:59:10 +01:00

263 lines
12 KiB
C++
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "prx/libc/include/general/VabiMacros.hpp"
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <limits>
#include <stdexcept>
#include <string>
#include <vector>
extern "C" {
float APS5_VABI _ZN3WTF17charactersToFloatEPKDsmPb(const char16_t* data, std::size_t length, bool* ok);
float APS5_VABI _ZN3WTF17charactersToFloatEPKDsmRm(const char16_t* data, std::size_t length, std::size_t* parsedLength);
float APS5_VABI _ZN3WTF17charactersToFloatEPKhmPb(const unsigned char* data, std::size_t length, bool* ok);
float APS5_VABI _ZN3WTF17charactersToFloatEPKhmRm(const unsigned char* data, std::size_t length, std::size_t* parsedLength);
double APS5_VABI _ZN3WTF18charactersToDoubleEPKDsmPb(const char16_t* data, std::size_t length, bool* ok);
double APS5_VABI _ZN3WTF18charactersToDoubleEPKhmPb(const unsigned char* data, std::size_t length, bool* ok);
float APS5_VABI _ZN3WTF17double_conversion23StringToDoubleConverter13StringToFloatEPKcmPm(const char* buffer, std::size_t length, std::size_t* processedCharactersCount);
float APS5_VABI _ZN3WTF17double_conversion23StringToDoubleConverter13StringToFloatEPKtmPm(const std::uint16_t* buffer, std::size_t length, std::size_t* processedCharactersCount);
double APS5_VABI _ZN3WTF17double_conversion23StringToDoubleConverter14StringToDoubleEPKcmPm(const char* buffer, std::size_t length, std::size_t* processedCharactersCount);
double APS5_VABI _ZN3WTF17double_conversion23StringToDoubleConverter14StringToDoubleEPKtmPm(const std::uint16_t* buffer, std::size_t length, std::size_t* processedCharactersCount);
}
static void Check(bool value, int line) {
if (!value) {
std::fprintf(stderr, "WTF number parsing check failed at line %d\n", line);
std::abort();
}
}
#define Require(value) Check((value), __LINE__)
static bool Same(double first, double second) {
return std::memcmp(&first, &second, sizeof(double)) == 0;
}
static bool Same(float first, float second) {
return std::memcmp(&first, &second, sizeof(float)) == 0;
}
static std::u16string Wide(const std::string& text) {
return std::u16string(text.begin(), text.end());
}
static void Double(const std::string& text, double expected, bool expectedOk) {
const auto* latin1 = reinterpret_cast<const unsigned char*>(text.data());
bool ok = !expectedOk;
Require(Same(_ZN3WTF18charactersToDoubleEPKhmPb(latin1, text.size(), &ok), expected));
Require(ok == expectedOk);
const auto wide = Wide(text);
ok = !expectedOk;
Require(Same(_ZN3WTF18charactersToDoubleEPKDsmPb(wide.data(), wide.size(), &ok), expected));
Require(ok == expectedOk);
Require(Same(_ZN3WTF18charactersToDoubleEPKhmPb(latin1, text.size(), nullptr), expected));
}
static void Float(const std::string& text, float expected, bool expectedOk, std::size_t expectedLength) {
const auto* latin1 = reinterpret_cast<const unsigned char*>(text.data());
const auto wide = Wide(text);
bool ok = !expectedOk;
Require(Same(_ZN3WTF17charactersToFloatEPKhmPb(latin1, text.size(), &ok), expected));
Require(ok == expectedOk);
ok = !expectedOk;
Require(Same(_ZN3WTF17charactersToFloatEPKDsmPb(wide.data(), wide.size(), &ok), expected));
Require(ok == expectedOk);
std::size_t parsedLength = 12345;
Require(Same(_ZN3WTF17charactersToFloatEPKhmRm(latin1, text.size(), &parsedLength), expected));
Require(parsedLength == expectedLength);
parsedLength = 12345;
Require(Same(_ZN3WTF17charactersToFloatEPKDsmRm(wide.data(), wide.size(), &parsedLength), expected));
Require(parsedLength == expectedLength);
}
static void Grammar() {
Double("1.5", 1.5, true);
Double(" \t\n\v\f\r-2.5e3", -2500.0, true);
Double("+5", 5.0, true);
Double("5.", 5.0, true);
Double(".5", 0.5, true);
Double("-0", -0.0, true);
Double("-.0e5", -0.0, true);
Double("2E-3", 0.002, true);
Double("1.5 ", 1.5, false);
Double("", 0.0, false);
Double(" ", 0.0, false);
Double("-", 0.0, false);
Double("- 5", 0.0, false);
Double(".", 0.0, false);
Double("-.e1", 0.0, false);
Double("Infinity", 0.0, false);
Double("NaN", 0.0, false);
Double("0x10", 0.0, false);
Float("1.5x", 1.5f, false, 3);
Float(" 12abc", 12.0f, false, 4);
Float("1e", 1.0f, false, 1);
Float("1e+", 1.0f, false, 1);
Float("1e-x", 1.0f, false, 1);
Float("7e2.", 700.0f, false, 3);
Float("0x10", 0.0f, false, 1);
Float("-", 0.0f, false, 0);
Float(" ", 0.0f, false, 0);
Float("-00.", -0.0f, true, 4);
}
static void Range() {
const double infinity = std::numeric_limits<double>::infinity();
Double("1e400", infinity, true);
Double("-1e400", -infinity, true);
Double("1e-400", 0.0, true);
Double("1e99999999999999999999", infinity, true);
Double("0e99999999999", 0.0, true);
Double("1.7976931348623157e308", std::numeric_limits<double>::max(), true);
Double("1.7976931348623158e308", std::numeric_limits<double>::max(), true);
Double("1.7976931348623159e308", infinity, true);
Double("4.9406564584124654e-324", std::numeric_limits<double>::denorm_min(), true);
Double("2.4703282292062328e-324", std::numeric_limits<double>::denorm_min(), true);
Double("2.4703282292062327e-324", 0.0, true);
Float("3.4028235e38", std::numeric_limits<float>::max(), true, 12);
Float("3.4028236e38", std::numeric_limits<float>::infinity(), true, 12);
Float("1e-50", 0.0f, true, 5);
}
static void Rounding() {
Float("1.0000000596046447755", 1.0f, true, 21);
Float("1.00000006", std::nextafter(1.0f, 2.0f), true, 10);
const std::string midpoint = "1.00000000000000011102230246251565404236316680908203125";
Double(midpoint, 1.0, true);
Double(midpoint + std::string(800, '0'), 1.0, true);
Double(midpoint + std::string(800, '0') + "1", std::nextafter(1.0, 2.0), true);
Double("0." + std::string(400, '0') + "100000000000000011102230246251565404236316680908203125" + std::string(800, '0') + "1e401", std::nextafter(1.0, 2.0), true);
Double(std::string(900, '9') + "e-900", 1.0, true);
}
static void Utf16() {
const std::u16string dotted = u"ı1.5";
bool ok = true;
Require(Same(_ZN3WTF18charactersToDoubleEPKDsmPb(dotted.data(), dotted.size(), &ok), 0.0));
Require(!ok);
const std::u16string arabic = u"2١";
std::size_t parsedLength = 0;
Require(Same(_ZN3WTF17charactersToFloatEPKDsmRm(arabic.data(), arabic.size(), &parsedLength), 2.0f));
Require(parsedLength == 1);
const std::u16string space = u" 1";
ok = true;
Require(Same(_ZN3WTF17charactersToFloatEPKDsmPb(space.data(), space.size(), &ok), 0.0f));
Require(!ok);
const std::u16string shifted = u"1ĵ";
parsedLength = 0;
Require(Same(_ZN3WTF17charactersToFloatEPKDsmRm(shifted.data(), shifted.size(), &parsedLength), 1.0f));
Require(parsedLength == 1);
std::u16string longer(70, u'0');
longer += u"1.25";
ok = false;
Require(Same(_ZN3WTF18charactersToDoubleEPKDsmPb(longer.data(), longer.size(), &ok), 1.25));
Require(ok);
longer += u"ĵ";
longer += u"5";
parsedLength = 0;
Require(Same(_ZN3WTF17charactersToFloatEPKDsmRm(longer.data(), longer.size(), &parsedLength), 1.25f));
Require(parsedLength == 74);
}
static std::vector<std::uint16_t> Units(const std::u16string& text) {
return std::vector<std::uint16_t>(text.begin(), text.end());
}
static void Converter(const std::u16string& text, double expectedDouble, float expectedFloat, std::size_t expectedLength) {
const auto units = Units(text);
std::size_t processed = 12345;
Require(Same(_ZN3WTF17double_conversion23StringToDoubleConverter14StringToDoubleEPKtmPm(units.data(), units.size(), &processed), expectedDouble));
Require(processed == expectedLength);
processed = 12345;
Require(Same(_ZN3WTF17double_conversion23StringToDoubleConverter13StringToFloatEPKtmPm(units.data(), units.size(), &processed), expectedFloat));
Require(processed == expectedLength);
for (const auto unit : text) {
if (unit > 0xFF) return;
}
const std::string bytes(text.begin(), text.end());
processed = 12345;
Require(Same(_ZN3WTF17double_conversion23StringToDoubleConverter14StringToDoubleEPKcmPm(bytes.data(), bytes.size(), &processed), expectedDouble));
Require(processed == expectedLength);
processed = 12345;
Require(Same(_ZN3WTF17double_conversion23StringToDoubleConverter13StringToFloatEPKcmPm(bytes.data(), bytes.size(), &processed), expectedFloat));
Require(processed == expectedLength);
}
static void StringToDoubleConverter() {
Converter(u"1.5", 1.5, 1.5f, 3);
Converter(u"00012.50e-1z", 1.25, 1.25f, 11);
Converter(u" 1", 0.0, 0.0f, 0);
Converter(u"-", 0.0, 0.0f, 0);
Converter(u"-0", -0.0, -0.0f, 2);
Converter(u"-.0e5", -0.0, -0.0f, 5);
Converter(u"1e+x", 1.0, 1.0f, 1);
Converter(u"0x10", 0.0, 0.0f, 1);
Converter(u"1\u00B1", 1.0, 1.0f, 1);
Converter(u"1\u01315", 1.0, 1.0f, 1);
Converter(u"1e99999999999999", std::numeric_limits<double>::infinity(), std::numeric_limits<float>::infinity(), 16);
Converter(u"1.0000000596046447755", 1.0000000596046447755, std::nextafter(1.0f, 2.0f), 21);
Converter(u"1.000000059604644775390625", 1.000000059604644775390625, 1.0f, 26);
Converter(u"3.4028235677973366e38", 3.4028235677973366e38, std::numeric_limits<float>::max(), 21);
Converter(u"3.4028235677973367e38", 3.4028235677973367e38, std::numeric_limits<float>::infinity(), 21);
Converter(u"7.0064923216240854e-46", 7.0064923216240854e-46, std::numeric_limits<float>::denorm_min(), 22);
Converter(u"7.006492321624085e-46", 7.006492321624085e-46, 0.0f, 21);
std::u16string longer(70, u'0');
longer += u"1.25\u0135";
Converter(longer, 1.25, 1.25f, 74);
}
template<typename TCall>
static void RequireInvalidArgument(TCall call, int line) {
try {
call();
} catch (const std::invalid_argument&) {
return;
}
Check(false, line);
}
static void NullPointers() {
bool ok = true;
Require(Same(_ZN3WTF18charactersToDoubleEPKhmPb(nullptr, 0, &ok), 0.0));
Require(!ok);
ok = true;
Require(Same(_ZN3WTF17charactersToFloatEPKDsmPb(nullptr, 0, &ok), 0.0f));
Require(!ok);
std::size_t parsedLength = 12345;
Require(Same(_ZN3WTF17charactersToFloatEPKhmRm(nullptr, 0, &parsedLength), 0.0f));
Require(parsedLength == 0);
RequireInvalidArgument([] { _ZN3WTF18charactersToDoubleEPKhmPb(nullptr, 1, nullptr); }, __LINE__);
RequireInvalidArgument([] { _ZN3WTF18charactersToDoubleEPKDsmPb(nullptr, 1, nullptr); }, __LINE__);
RequireInvalidArgument([] { _ZN3WTF17charactersToFloatEPKhmPb(nullptr, 1, nullptr); }, __LINE__);
RequireInvalidArgument([] { _ZN3WTF17charactersToFloatEPKDsmPb(nullptr, 1, nullptr); }, __LINE__);
const unsigned char latin1[] = {'1'};
const char16_t wide[] = {u'1'};
RequireInvalidArgument([&] { _ZN3WTF17charactersToFloatEPKhmRm(latin1, 1, nullptr); }, __LINE__);
RequireInvalidArgument([&] { _ZN3WTF17charactersToFloatEPKDsmRm(wide, 1, nullptr); }, __LINE__);
RequireInvalidArgument([] { _ZN3WTF17charactersToFloatEPKhmRm(nullptr, 0, nullptr); }, __LINE__);
parsedLength = 12345;
Require(Same(_ZN3WTF17double_conversion23StringToDoubleConverter14StringToDoubleEPKcmPm(nullptr, 0, &parsedLength), 0.0));
Require(parsedLength == 0);
parsedLength = 12345;
RequireInvalidArgument([&] { _ZN3WTF17double_conversion23StringToDoubleConverter13StringToFloatEPKtmPm(nullptr, 1, &parsedLength); }, __LINE__);
Require(parsedLength == 0);
const char bytes[] = {'1'};
const std::uint16_t units[] = {u'1'};
RequireInvalidArgument([&] { _ZN3WTF17double_conversion23StringToDoubleConverter14StringToDoubleEPKcmPm(bytes, 1, nullptr); }, __LINE__);
RequireInvalidArgument([&] { _ZN3WTF17double_conversion23StringToDoubleConverter14StringToDoubleEPKtmPm(units, 1, nullptr); }, __LINE__);
RequireInvalidArgument([&] { _ZN3WTF17double_conversion23StringToDoubleConverter13StringToFloatEPKcmPm(bytes, 1, nullptr); }, __LINE__);
RequireInvalidArgument([] { _ZN3WTF17double_conversion23StringToDoubleConverter13StringToFloatEPKtmPm(nullptr, 0, nullptr); }, __LINE__);
}
int main() {
NullPointers();
Grammar();
Range();
Rounding();
Utf16();
StringToDoubleConverter();
}