diff --git a/core/libs/prx/libSceNKWebKit/Export.cpp b/core/libs/prx/libSceNKWebKit/Export.cpp index 3fefb6614b..4e30bcd424 100644 --- a/core/libs/prx/libSceNKWebKit/Export.cpp +++ b/core/libs/prx/libSceNKWebKit/Export.cpp @@ -19408,10 +19408,6 @@ int APS5_VABI _ZN3WTF19isCompilationThreadEv() { NotImplemented_nid_no_patch(__func__); } -int APS5_VABI _ZN3WTF19mimeTypeFromDataURLENS_10StringViewE() { - NotImplemented_nid_no_patch(__func__); -} - int APS5_VABI _ZN3WTF19numGraphemeClustersENS_10StringViewE() { NotImplemented_nid_no_patch(__func__); } @@ -36584,10 +36580,6 @@ int APS5_VABI _ZNK3WTF3URL24strippedForUseAsReferrerEv() { NotImplemented_nid_no_patch(__func__); } -int APS5_VABI _ZNK3WTF3URL30stringCenterEllipsizedToLengthEj() { - NotImplemented_nid_no_patch(__func__); -} - int APS5_VABI _ZNK3WTF3URL4dumpERNS_11PrintStreamE() { NotImplemented_nid_no_patch(__func__); } diff --git a/core/libs/prx/libSceNKWebKit/include/InventoryExports.hpp b/core/libs/prx/libSceNKWebKit/include/InventoryExports.hpp index 91b4326336..ff9a697bf8 100644 --- a/core/libs/prx/libSceNKWebKit/include/InventoryExports.hpp +++ b/core/libs/prx/libSceNKWebKit/include/InventoryExports.hpp @@ -1821,7 +1821,6 @@ int APS5_VABI _ZN3WTF19ParallelEnvironment7executeEPv(); int APS5_VABI _ZN3WTF19ParallelEnvironmentC1EPFvPvEmi(); int APS5_VABI _ZN3WTF19ParallelEnvironmentC2EPFvPvEmi(); int APS5_VABI _ZN3WTF19isCompilationThreadEv(); -int APS5_VABI _ZN3WTF19mimeTypeFromDataURLENS_10StringViewE(); int APS5_VABI _ZN3WTF19numGraphemeClustersENS_10StringViewE(); int APS5_VABI _ZN3WTF20ConcurrentPtrHashSet15deleteOldTablesEv(); int APS5_VABI _ZN3WTF20ConcurrentPtrHashSet5clearEv(); @@ -6140,7 +6139,6 @@ int APS5_VABI _ZNK3WTF3URL17lastPathComponentEv(); int APS5_VABI _ZNK3WTF3URL19protocolHostAndPortEv(); int APS5_VABI _ZNK3WTF3URL21truncatedForUseAsBaseEv(); int APS5_VABI _ZNK3WTF3URL24strippedForUseAsReferrerEv(); -int APS5_VABI _ZNK3WTF3URL30stringCenterEllipsizedToLengthEj(); int APS5_VABI _ZNK3WTF3URL4dumpERNS_11PrintStreamE(); int APS5_VABI _ZNK3WTF3URL4userEv(); int APS5_VABI _ZNK3WTF3URL8passwordEv(); diff --git a/core/libs/prx/libSceNKWebKit/include/WtfExports.hpp b/core/libs/prx/libSceNKWebKit/include/WtfExports.hpp index 148aaddf81..63c9dd727e 100644 --- a/core/libs/prx/libSceNKWebKit/include/WtfExports.hpp +++ b/core/libs/prx/libSceNKWebKit/include/WtfExports.hpp @@ -208,6 +208,8 @@ bool APS5_VABI _ZNK3WTF24TimeWithDynamicClockTypegeERKS0_(const WTF::TimeWithDyn bool APS5_VABI _ZNK3WTF24TimeWithDynamicClockTypegtERKS0_(const WTF::TimeWithDynamicClockType* self, const WTF::TimeWithDynamicClockType& other); bool APS5_VABI _ZNK3WTF24TimeWithDynamicClockTypeleERKS0_(const WTF::TimeWithDynamicClockType* self, const WTF::TimeWithDynamicClockType& other); WTF::Seconds APS5_VABI _ZNK3WTF24TimeWithDynamicClockTypemiERKS0_(const WTF::TimeWithDynamicClockType* self, const WTF::TimeWithDynamicClockType& other); +NKWebKit::WtfAbi::String APS5_VABI _ZN3WTF19mimeTypeFromDataURLENS_10StringViewE(NKWebKit::WtfAbi::StringView dataURL); +NKWebKit::WtfAbi::String APS5_VABI _ZNK3WTF3URL30stringCenterEllipsizedToLengthEj(const NKWebKit::WtfAbi::URL* self, unsigned length); bool APS5_VABI _ZNK3WTF3URL10protocolIsENS_10StringViewE(const NKWebKit::WtfAbi::URL* self, NKWebKit::WtfAbi::StringView protocol); NKWebKit::WtfAbi::StringView APS5_VABI _ZNK3WTF3URL11encodedUserEv(const NKWebKit::WtfAbi::URL* self); bool APS5_VABI _ZNK3WTF3URL12isAboutBlankEv(const NKWebKit::WtfAbi::URL* self); diff --git a/core/libs/prx/libSceNKWebKit/src/WtfString.cpp b/core/libs/prx/libSceNKWebKit/src/WtfString.cpp index 11d3aad8c7..0ec203f32c 100644 --- a/core/libs/prx/libSceNKWebKit/src/WtfString.cpp +++ b/core/libs/prx/libSceNKWebKit/src/WtfString.cpp @@ -916,6 +916,41 @@ StringView ViewWithoutFragment(const URL& url) { return Slice(view, 0, std::min(url.queryEnd, view.length)); } +std::size_t FindUnit(StringView view, char16_t value, unsigned start) { + for (unsigned i = start; i < view.length; ++i) { + if (Unit(view, i) == value) return i; + } + return NotFound; +} + +StringView LeftView(StringView view, unsigned length) { + return Slice(view, 0, length); +} + +StringView RightView(StringView view, unsigned length) { + return Slice(view, view.length - length, length); +} + +String ConcatViews(const StringView* parts, unsigned count) { + std::size_t total = 0; + bool is8Bit = true; + for (unsigned i = 0; i < count; ++i) { + total += parts[i].length; + is8Bit &= parts[i].is8Bit; + } + if (total > MaxStringLength) throw std::length_error("WTF string exceeds maximum length"); + void* data; + auto* impl = NewImpl(static_cast(total), is8Bit, data); + unsigned offset = 0; + for (unsigned i = 0; i < count; ++i) { + for (unsigned j = 0; j < parts[i].length; ++j, ++offset) { + if (is8Bit) static_cast(data)[offset] = static_cast(Unit(parts[i], j)); + else static_cast(data)[offset] = Unit(parts[i], j); + } + } + return String(impl); +} + } // namespace extern "C" { @@ -1022,4 +1057,20 @@ bool APS5_VABI _ZN3WTF22protocolIsInHTTPFamilyENS_10StringViewE(StringView view) return Unit(view, 4) == ':' || ((Unit(view, 4) | 32) == 's' && view.length >= 6 && Unit(view, 5) == ':'); } +String APS5_VABI _ZN3WTF19mimeTypeFromDataURLENS_10StringViewE(StringView dataURL) { + auto index = FindUnit(dataURL, u';', 5); + if (index == NotFound) index = FindUnit(dataURL, u',', 5); + if (index == NotFound) return String(EmptyImpl()); + if (index == 5) return String(CopyImpl({"text/plain", 10, true})); + return String(ConvertCase(Slice(dataURL, 5, static_cast(index - 5)), true)); +} + +String APS5_VABI _ZNK3WTF3URL30stringCenterEllipsizedToLengthEj(const URL* self, unsigned length) { + const auto& url = Checked(self); + auto view = View(url.impl); + if (view.length <= length) return String(Retain(url.impl)); + const StringView parts[] = {LeftView(view, length / 2 - 1), {"...", 3, true}, RightView(view, length / 2 - 2)}; + return ConcatViews(parts, 3); +} + } diff --git a/core/libs/prx/libSceNKWebKit/tests/Wtf.cpp b/core/libs/prx/libSceNKWebKit/tests/Wtf.cpp index a3b14714dd..8508298479 100644 --- a/core/libs/prx/libSceNKWebKit/tests/Wtf.cpp +++ b/core/libs/prx/libSceNKWebKit/tests/Wtf.cpp @@ -809,6 +809,80 @@ const auto JSRealloc = &_ZN3WTF14jsValueReallocEPvm; std::string ViewText(StringView view) { return Bytes(ViewUTF8(&view, 1)); } +const auto URLEllipsize = &_ZNK3WTF3URL30stringCenterEllipsizedToLengthEj; +const auto DataURLMime = &_ZN3WTF19mimeTypeFromDataURLENS_10StringViewE; + +bool Is8Bit(const String& value) { return value.impl && (value.impl->hashAndFlags & 4); } + +StringView ViewOf(const String& value) { + return {value.impl->data, value.impl->length, !!(value.impl->hashAndFlags & 4)}; +} + +StringView Literal(const char* text) { return {text, static_cast(std::strlen(text)), true}; } + +void TestURLStringHelpers() { + auto narrow = FromUTF8Z(U8("http://example.com/abcdefghij")); + URL narrowURL{narrow.impl, 0, 0, 0, 0, 0, 0, 0, 0}; + for (unsigned length : {29U, 30U, 40U, 0xFFFFFFFFU}) { + auto same = URLEllipsize(&narrowURL, length); + Check(same.impl == narrow.impl && narrow.impl->refCount == 4); + } + Check(narrow.impl->refCount == 2); + Text(URLEllipsize(&narrowURL, 28), "http://exampl...m/abcdefghij"); + Text(URLEllipsize(&narrowURL, 10), "http...hij"); + Text(URLEllipsize(&narrowURL, 11), "http...hij"); + Text(URLEllipsize(&narrowURL, 6), "ht...j"); + Text(URLEllipsize(&narrowURL, 5), "h..."); + Text(URLEllipsize(&narrowURL, 4), "h..."); + Text(URLEllipsize(&narrowURL, 3), "..."); + Text(URLEllipsize(&narrowURL, 2), "..."); + Text(URLEllipsize(&narrowURL, 1), "http://example.com/abcdefghij..."); + Text(URLEllipsize(&narrowURL, 0), "http://example.com/abcdefghij..."); + Check(Is8Bit(URLEllipsize(&narrowURL, 10)) && Is8Bit(URLEllipsize(&narrowURL, 3))); + Check(URLEllipsize(&narrowURL, 10).impl != narrow.impl); + + auto wide = Create16(u"http://wide.test/path", 21); + URL wideURL{wide.impl, 0, 0, 0, 0, 0, 0, 0, 0}; + Check(URLEllipsize(&wideURL, 21).impl == wide.impl); + auto wideShort = URLEllipsize(&wideURL, 10); + Text(wideShort, "http...ath"); + Check(!Is8Bit(wideShort)); + auto wideDots = URLEllipsize(&wideURL, 3); + Text(wideDots, "..."); + Check(!Is8Bit(wideDots)); + auto wideLong = URLEllipsize(&wideURL, 1); + Text(wideLong, "http://wide.test/path..."); + Check(!Is8Bit(wideLong)); + + URL absent{}; + Check(URLEllipsize(&absent, 0).impl == nullptr && URLEllipsize(&absent, 10).impl == nullptr); + auto empty = Create8(U8(""), 0); + URL emptyURL{empty.impl, 0, 0, 0, 0, 0, 0, 0, 0}; + Check(URLEllipsize(&emptyURL, 0).impl == empty.impl && URLEllipsize(&emptyURL, 5).impl == empty.impl); + Throws([&] { URLEllipsize(nullptr, 10); }); + + Text(DataURLMime(Literal("data:text/HTML;base64,x")), "text/html"); + Text(DataURLMime(Literal("data:Text/X,y")), "text/x"); + Text(DataURLMime(Literal("data:,x")), "text/plain"); + Text(DataURLMime(Literal("data:;base64,x")), "text/plain"); + Check(Is8Bit(DataURLMime(Literal("data:,x")))); + Text(DataURLMime(Literal("data:a,b;c")), "a,b"); + Text(DataURLMime(Literal("data:text/plain")), ""); + Text(DataURLMime(Literal("data:")), ""); + Text(DataURLMime(Literal("data")), ""); + Text(DataURLMime(Literal("")), ""); + Text(DataURLMime(StringView{nullptr, 0, true}), ""); + Text(DataURLMime(Literal("http://a;b")), "//a"); + auto wideData = Create16(u"data:TEXT/Plain;x", 17); + auto wideMime = DataURLMime(ViewOf(wideData)); + Text(wideMime, "text/plain"); + Check(!Is8Bit(wideMime)); + auto accented = Create16(u"data:É/X,", 9); + Text(DataURLMime(ViewOf(accented)), "\xC3\x89/x"); + auto widePlain = Create16(u"data:,x", 7); + Text(DataURLMime(ViewOf(widePlain)), "text/plain"); +} + void TestURLsAndReallocation() { struct PinnedBits { unsigned valid : 1; @@ -967,6 +1041,7 @@ void TestURLsAndReallocation() { memory = static_cast(JSRealloc(memory, 2)); Check(memory[0] == 'h' && memory[1] == 'e'); Check(!JSRealloc(memory, 0)); + TestURLStringHelpers(); } } // namespace Wtf2Tests diff --git a/docs/dev/debt/libSceNKWebKit.md b/docs/dev/debt/libSceNKWebKit.md index 3e29741ba1..830c2de40e 100644 --- a/docs/dev/debt/libSceNKWebKit.md +++ b/docs/dev/debt/libSceNKWebKit.md @@ -27,7 +27,7 @@ - The [revision-pinned identity inventory](https://gist.github.com/kyon-eth/d44995f181e1818977bd38f0e6fc0f34/8afcb14b0707a09b6274ff7f7bcf33ef46cfe2e7) records the module, library, symbol type and NIDs for the declarations in [Export.cpp](../../../core/libs/prx/libSceNKWebKit/Export.cpp); it is a metadata summary rather than independent verification. For the 255 absent from the public catalogue, [per-image ELF records](https://gist.github.com/kyon-eth/147be8dd556e9cced2577ccbed548972/1a659ecfe819e724675991a574a1aebb5fbb48e5) include the raw qualified names, module and library identities, symbol type, values and sizes; the record file SHA-256 is `44bdc4d6073192a8f41b7be359b75364b3d41dbbd11ce649924b8cebdd4ffe51`. Image labels are not authenticated. -- [Additional callable exports](../../../core/libs/prx/libSceNKWebKit/Export.cpp) - 7439 of the 8703 inventory declarations listed below throw through `NotImplemented_nid_no_patch`; signatures and behavior are unverified. The later 13.60-labelled image contains all 8703; 8448 match the public 3.20 catalogue, while 255 are absent and their presence in retail 3.20 is unverified. Per-image records show the latter in a separate 3.20-labelled image, but neither image label is authenticated. Identified names match NIDs in the [public symbol database](https://github.com/zecoxao/sce_symbols/blob/2883963a0a514ba6e77407a08ef4730a65e88254/aerolib.csv) or [supplemental catalog](https://github.com/claimore22/ps5rs/blob/2304be5131221bae0dac24b9767cabffda33f747/data/nids.csv). Data exports need separate analysis. +- [Additional callable exports](../../../core/libs/prx/libSceNKWebKit/Export.cpp) - 7437 of the 8703 inventory declarations listed below throw through `NotImplemented_nid_no_patch`; signatures and behavior are unverified. The later 13.60-labelled image contains all 8703; 8448 match the public 3.20 catalogue, while 255 are absent and their presence in retail 3.20 is unverified. Per-image records show the latter in a separate 3.20-labelled image, but neither image label is authenticated. Identified names match NIDs in the [public symbol database](https://github.com/zecoxao/sce_symbols/blob/2883963a0a514ba6e77407a08ef4730a65e88254/aerolib.csv) or [supplemental catalog](https://github.com/claimore22/ps5rs/blob/2304be5131221bae0dac24b9767cabffda33f747/data/nids.csv). Data exports need separate analysis. | Name | NID | | --- | --- | @@ -1760,7 +1760,6 @@ | `_ZN3WTF19ParallelEnvironmentC1EPFvPvEmi` | `Efn-a1tGPqw` | | `_ZN3WTF19ParallelEnvironmentC2EPFvPvEmi` | `ciXM3j2URKk` | | `_ZN3WTF19isCompilationThreadEv` | `qoO6VaMuvG0` | -| `_ZN3WTF19mimeTypeFromDataURLENS_10StringViewE` | `kie+nv-1HCM` | | `_ZN3WTF19numGraphemeClustersENS_10StringViewE` | `K7qAbz7P3rs` | | `_ZN3WTF20ConcurrentPtrHashSet15deleteOldTablesEv` | `K59xDVxbCyM` | | `_ZN3WTF20ConcurrentPtrHashSet5clearEv` | `sDuWnr1d9ko` | @@ -6054,7 +6053,6 @@ | `_ZNK3WTF3URL19protocolHostAndPortEv` | `q8fEMeIqd5w` | | `_ZNK3WTF3URL21truncatedForUseAsBaseEv` | `uekVJTVqBGc` | | `_ZNK3WTF3URL24strippedForUseAsReferrerEv` | `CyN41AniueA` | -| `_ZNK3WTF3URL30stringCenterEllipsizedToLengthEj` | `JRPrmfTHt08` | | `_ZNK3WTF3URL4dumpERNS_11PrintStreamE` | `ITwB6pPwmRc` | | `_ZNK3WTF3URL4userEv` | `ETN4mn+-5l0` | | `_ZNK3WTF3URL8passwordEv` | `aCtpeXWclTE` |