From 2c1ccc743791923b7d01a679d021e1a0476a4a46 Mon Sep 17 00:00:00 2001 From: Vincent Hengel Date: Mon, 27 Jul 2026 21:28:49 +0200 Subject: [PATCH] gfx: use game metadata for Linux windows --- delta/formats/pkg_object.cpp | 6 +- delta/gfx/CMakeLists.txt | 15 ++++ delta/gfx/gfx.h | 5 ++ delta/gfx/gfx_vk.cpp | 94 +++++++++++++++++++++++++ delta/main/_res/logo.png | Bin 29718 -> 29857 bytes delta/main/dcore.cpp | 128 +++++++++++++++++++++++++++++++---- 6 files changed, 235 insertions(+), 13 deletions(-) diff --git a/delta/formats/pkg_object.cpp b/delta/formats/pkg_object.cpp index 7b9e1c17..7738bd58 100644 --- a/delta/formats/pkg_object.cpp +++ b/delta/formats/pkg_object.cpp @@ -674,7 +674,11 @@ struct PkgImpl { if (be32(e) != wantId) continue; uint32_t off = be32(e + 16), sz = be32(e + 20); - if (sz == 0 || static_cast(off) + sz > pkg.GetSize()) + const uint32_t maxSize = + wantId == 0x1000 ? 1u << 20 + : (wantId == 0x1200 ? 16u << 20 : UINT32_MAX); + if (sz == 0 || sz > maxSize || + static_cast(off) + sz > pkg.GetSize()) return false; out.resize(sz); R(off, sz, out.data()); diff --git a/delta/gfx/CMakeLists.txt b/delta/gfx/CMakeLists.txt index e205c1b3..71478d2a 100644 --- a/delta/gfx/CMakeLists.txt +++ b/delta/gfx/CMakeLists.txt @@ -26,4 +26,19 @@ else() ${_imgui}/imgui_tables.cpp ${_imgui}/imgui_widgets.cpp) target_include_directories(delta_gfx PRIVATE ${_imgui}) + + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(_logo ${CMAKE_SOURCE_DIR}/delta/main/_res/logo.png) + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${_logo}) + file(READ ${_logo} _logo_hex HEX) + string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," _logo_bytes + "${_logo_hex}") + file(CONFIGURE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/prosperity_logo.h + CONTENT + "static constexpr unsigned char kProsperityLogoPng[] = {${_logo_bytes}};\n" + @ONLY) + target_include_directories(delta_gfx PRIVATE + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/vendor/equilibrium/external/tracy/profiler/src) + endif() endif() diff --git a/delta/gfx/gfx.h b/delta/gfx/gfx.h index 39eedcaf..b80c6786 100644 --- a/delta/gfx/gfx.h +++ b/delta/gfx/gfx.h @@ -8,6 +8,7 @@ * in the root of the source tree. */ +#include #include // SDL3 window backed by a Vulkan swapchain. present() uploads a CPU framebuffer @@ -24,6 +25,10 @@ enum class PixelFormat { // already exists, otherwise it overrides the title the creator passes. void setTitle(const char *title); +// Set PNG artwork for the game window. The desktop backend applies a small +// emulator badge before using it as the taskbar icon. +void setIcon(const uint8_t *png, size_t size); + // Create the window, Vulkan device and swapchain. Returns false on failure. // Idempotent: returns true immediately if a window already exists. bool init(const char *title, uint32_t width, uint32_t height); diff --git a/delta/gfx/gfx_vk.cpp b/delta/gfx/gfx_vk.cpp index 44c27c9a..414007e0 100644 --- a/delta/gfx/gfx_vk.cpp +++ b/delta/gfx/gfx_vk.cpp @@ -17,6 +17,7 @@ // (gfx_headless.cpp) and the GPU renderer dumps frames instead of presenting. #ifndef __ANDROID__ +#include #include #include #include @@ -26,6 +27,14 @@ #include #include +#if defined(__linux__) +#define STBI_ONLY_PNG +#define STB_IMAGE_IMPLEMENTATION +#include + +#include "prosperity_logo.h" +#endif + #include #include #include @@ -52,6 +61,7 @@ namespace { // videoout HLE race to bring the window up and each passes its own generic // title, so whoever wins uses this instead when it is set. std::string g_title; +std::vector g_iconPng; constexpr uint32_t kFrameSlotCount = 2; @@ -106,6 +116,75 @@ struct State { State g; std::atomic_bool g_canPresent{true}; constexpr uint64_t kPresentWaitSliceNs = 50'000'000; +constexpr size_t kMaxIconSize = 16u << 20; +constexpr int kMaxIconDimension = 4096; + +#if defined(__linux__) +void drawBadge(uint8_t *pixels, int width, int height, const uint8_t *logo, + int logoWidth, int logoHeight) { + const int size = std::max(1, std::min(width, height) * 3 / 8); + const int left = width - size; + for (int y = 0; y < size; ++y) { + for (int x = 0; x < size; ++x) { + const int px = left + x; + uint8_t *rgba = pixels + (static_cast(y) * width + px) * 4; + const uint8_t *badge = + logo + (static_cast(y * logoHeight / size) * logoWidth + + x * logoWidth / size) * + 4; + const uint32_t alpha = badge[3]; + const uint32_t dstAlpha = rgba[3]; + const uint32_t outAlpha = alpha * 255 + dstAlpha * (255 - alpha); + if (outAlpha) { + for (int channel = 0; channel < 3; ++channel) + rgba[channel] = static_cast( + (badge[channel] * alpha * 255 + + rgba[channel] * dstAlpha * (255 - alpha) + outAlpha / 2) / + outAlpha); + } + rgba[3] = static_cast((outAlpha + 127) / 255); + } + } +} + +void applyWindowIcon() { + if (!g.window || g_iconPng.empty() || g_iconPng.size() > kMaxIconSize) + return; + int width = 0; + int height = 0; + int channels = 0; + if (!stbi_info_from_memory(g_iconPng.data(), + static_cast(g_iconPng.size()), &width, + &height, &channels) || + width > kMaxIconDimension || height > kMaxIconDimension) + return; + stbi_uc *pixels = stbi_load_from_memory( + g_iconPng.data(), static_cast(g_iconPng.size()), &width, &height, + &channels, STBI_rgb_alpha); + if (!pixels) { + stbi_image_free(pixels); + return; + } + int logoWidth = 0; + int logoHeight = 0; + stbi_uc *logo = + stbi_load_from_memory(kProsperityLogoPng, sizeof(kProsperityLogoPng), + &logoWidth, &logoHeight, nullptr, STBI_rgb_alpha); + if (!logo) { + stbi_image_free(pixels); + return; + } + drawBadge(pixels, width, height, logo, logoWidth, logoHeight); + SDL_Surface *surface = SDL_CreateSurfaceFrom( + width, height, SDL_PIXELFORMAT_RGBA32, pixels, width * STBI_rgb_alpha); + if (surface) { + SDL_SetWindowIcon(g.window, surface); + SDL_DestroySurface(surface); + } + stbi_image_free(logo); + stbi_image_free(pixels); +} +#endif void stopPresenting(const char *operation, VkResult result) { std::fprintf(stderr, "[gfx] %s failed: VkResult=%d\n", operation, result); @@ -425,6 +504,9 @@ bool init(const char *title, uint32_t width, uint32_t height) { std::fprintf(stderr, "[gfx] SDL_CreateWindow failed: %s\n", SDL_GetError()); return false; } +#if defined(__linux__) + applyWindowIcon(); +#endif // Instance: SDL-required extensions + optional validation. uint32_t nExt = 0; @@ -761,6 +843,18 @@ void setTitle(const char *title) { SDL_SetWindowTitle(g.window, g_title.c_str()); } +void setIcon(const uint8_t *png, size_t size) { +#if defined(__linux__) + if (size > kMaxIconSize) + return; + g_iconPng.assign(png, png + size); + applyWindowIcon(); +#else + (void)png; + (void)size; +#endif +} + bool available() { return g.window != nullptr && g.swapchain != VK_NULL_HANDLE; } diff --git a/delta/main/_res/logo.png b/delta/main/_res/logo.png index fa317fa8a4caf0f33328a8fd3faba66654b7f810..ca6cfa7a8b1fd0a7a8655938ce3b29ff8b5c2349 100644 GIT binary patch literal 29857 zcmc$F^;cVM({%_0cQ5WX*?5Dq>xGG9Q0B}!iQjFdJI3R+6Co;YS1mH{T4@Ab!#-de+eR*SsfJ!9+5sQ+5 zLqMJk#bNsI1Wq6bn@WOGE*k(uIOzHRcakr0BC)unq<}N>ZxgX43lv9ZY$k{pDgjP8 z<@k#({)g9wt&DovI=A!_E|9<_Y@L*{6#wgQQgSJ^$LjY;~&Mr2x}C5KyzR zXo6hIDCb|IfgddYO28BPcvH^5(nq#uWu8=n1gif#U4|#ggh2XQgyjVvM?3l`_J{pS zc$VKj9oG9U6qq%hh&741nkdj5fcUaLU*q3OxE_aDlsoRR8@>yr?w~oE!^|g!AoVyE zM!ztiEkNO{LDw(IUBndL`2DKX(J?_bxv^qflBx z@M0w3Zg8-@Ivao%>?ei~cKSg`G8+7iC`uKcSe>thcmizzMihVG0eo0aaV}0|2bv;6 z44?$z$myvZsrnJB+g5#zfX>nNQ3kd>K-h%|o_wcGXe|`TOGPZ#mo3NETu(0Sz^5Ss zM~m)Q12exCnN1XhEZftE-Wpr&w)QTXh+M>(&ML}ZZ;k-c1@e7rM1gQ*{4Qp6;nT*4 zCr%dmv_bFn*cLdJZk;jx+eF>A$K05^ahpIuAp#KOh?++-W3^y*r{fo70?~X!jS?)y zydH-l$F91Pg%D*UQKVU;s-wS!&6l4u`BFHak2xb zPKu8!LBWflHJS4fHSAtw_`EEUl@SIQGc7ESw`jueQ_ePm^7$LgoDDpL8|sT*%fbqhRtb15scBZ8_R9J&_E=XYC612J<>@aaAXsGIl!gi58aQl*`x zmZKyi7ULVjqZfemXVGoMvW2O5(S9T>$DjY%6dA+Sc3cT8^uTsZtp4Ua2{A>-KufDW zidbuUE*yA4fKx?<87qP+iQ?1DqS!g@!wCervS5h=gJki(0Krj&`+-slyth5eD@GT~MB!4%(*f-;ygAq_D*nvd_|!FM zs~m~=uN}1$h4o!%hqXwV3;Ob%TK0(p+%>((>1P=dTK0;8?hT))0SbZTY9xV2SQv1~ zF|B3a^60+4ujvbO-zubXd#Te%0U%XhL!333}-fF_) zohXmG`l@F4ZwL>YN$qRcZDnN$7nqHWq=#1gDQZid?>yjcJT!YItPN5KD!lJ0IbQE^ z0DJK6U^!mFOk*73F_-c$WINz@LIA}TMP#873ln=Lpj`~EgB^J^g0sp6SZCs+Sm%%F z@I4?yr+naWfud{VzR~R22wF+gH3WkTFWRtp`!Kdw&25P}UU<6;#W#YZ_E^fO?Wi2i z;#P+xZ^K;AG>I0ksz$z` zpW+^v<4xp88q~zE_g5J&k^{Znyb{Nf9v`1DI{2=ig6Vx7ZBrv8`|otXOhsA$>;`35 z2+^yF3glNf3?;ak;)xM;jUO>?+s$kDlpcy7N|D>IC`OlPO)<*M6(P8uzgXa|mdP~G ze9w@BD3?#}i*#O{=H0Qj6M5hXCtG2TY8OfWJ-x$yafmn&;WCGPvK9^=jQ~ z?C^$sgeIKBL5jiWoq`0PI;CbaNfa9_*Pu~T*S1*7nq69-^5fO7&BK9oefe@};N7MN zEUC7`ZDBvn`CdLP3NJTV)M{cSy1*Z4IdrG<0<4v#;<1!gfq_j(Ph~mC;;$|HdDHq5 z2#JAd)&K6?UPf*uC93xSy9R)u{s-g2DWz*5ilLKtnUJrIy7+47#S{7DMCvda@Ii0& zc0n&n{$LI(o6P#&$G9Z>8|Q6=(CFh>p*~R=%WMzKg()!UGo`?{>F34o9~C=o#IfY% z4~F>7l*!R;tugR>9*Idbfb(6b2TJ`kJ_|}0g&wo|c)C7sR1IabQzWB=Cx2l^!IJ+x zS8~mY$y@Q)$>5Jx@N~T71Ba1D(;50*c=ujLtTcaNBD0Rjyn+Q(W-)teR zU*CTh&I_CDsr*a4hWv-N3cc8X*wajz62bR~Du}=Rl=-~^5&c-uh6KayaFhq1lc&7* zzqe~oI5<^o*utdai-`G)mOkAPC`~*$cAWB==<*`aOS6L7&q}0xk7rV@16$xTxObAKQ!DQBRl580woi9``dkG z^HJ$mV`Si~&P(bf<8tlm_FFv#lcv}?eW*hrsGe~nNX&*R%FjmbE%>P_jGe2WUouM+ zeT%V?d`p44t~X1Ty)Ci|2_vF}mmW9Vp`ots)9JA$FdZ9)ZAiH-W__zA?HGE77kCnk z^WwOYW_>aTJ;ylfFJe-p?e|X>Hh*KWYRVvFFVtk1U@?+tC_~o7+uQ&Im=1v5Bvev~KPavG>32?98n-XObX@s< z6hg?{%mrM|2_ClBt8`Z(E4JTP;hRHg)2NbAef^YEm6?EBW@6TU>DTvml)9NXRcI)N zI}5`VXF_D<4GQe8(NFN!=vZnvt${^5TB% zN}cC^c*0%M4K8yLK+~s)>|-CY=qJb&sMy4#2%=EVKR6UjuIO)!2Z3X&1~{f(oA=Fx0V8T|UH zk|LdEiv7e<)Dov(E9T!leHjM*C+MMsK{9C-8zfkfrSujI#IA+_?P!FEb1>ku+h5q3 zTC?XnX`e_QJ?oXWh>(M&w6-rFbWTrC-(m+M(HztNi}3*Mp7bq@&;s8+?w5xX8J0Qh z8~PnHUAe6wbT(nIgT}Df4<@PK>$29*Nb-YQzpF}SdRtbkA)CQ9;t@K!SL?5yUDCjl$-`{ONJSSalrCS z^wF5o2+4PgNruuh5CnD3Sz|kOrz3O&35v2?(QZ~!Foj!PqOVJ+#7h@a3=eJ$*0b!(EMR0wdw5PswrIi<8HreH0 zoqW2ga(DH~Q_HHK&`Ed&qHf(oWa>WB;R?ob`nUdQUVRl~7wB@5$Ofo#ONF;sO8c#s z8_IorF22_bd&fRbis7sNzIKpCU2l9oRg)^DSs^G<_nEmob=-)V8b2BL$b_=dAn*q! z5nIK?J~C5VaEcD8@8QlBXjc zj-o|zk9r%=tRHIh>(*soP$5K@T!fQr>ukAdMeWtjxKdz`juVmDXkz5+x*W_~cXyYK zQpH1eR6!G`1w_k+HQ5{a*_|dkbwX^^V8W?7Q+fFTHQ!UR%@mm5G2&d7T&k!92b)Nb ztL0&>{2~1z-}6nemCz`&i1DCxPwsMwfhY8@*B7FM#sgeaYGnT0s;{_ZVdku;T;wUx zf2q;D~q24UQ((2^Fe*FSLHkh6ImNRZQkF;hn z->TL?p5iTdv4;kZ6Fq)meY`;^l$3bCNRecmi2W&D52R zP?+)e*!pcM7I7C5te6PEQRUU)O^tNW5{_U7-$DtaJoB>AD8q?h&DRaVHQQ3_2Ed?rHk;IR~%q zegM9d&mi<_0F$0Ga1pO6#iLgXT4PaeIpmq})07gr_WnaXmr*Q=Y$I4*g+OD#^F_j9 zAl*TtaCQUBcYYCFq@CIf2}-xI&OAd91wm`W_7mh`>Tn+)4NgA<7=L8)Q@&SkFq&HS zj~RgSmq{T;5DE?pPm1=6_zGn zxY|18amoyx^UKR#?euCA$d0S9fWZqYN#pr9Ul;uv@a3uO9xFKBL>MF|^<~~ZB`T^a6#cfcErOcOu3N+TS|vr=TYj50@e_8Tx)7<{%M?;MmcEHz~jU zUzw@!R&b@})r(81%KsYIRf#vPVX1B>%CW>mR=f<#w=8VF9=t&~u^phn8KNtl$P!HM zRoP@TtO5P$2j~t>9u6L<4Gs_u6Y#%o|56)rcPsAS@n&Zd4<6ygCUqzL$up71^QOMo z?tf4lV5JA4lG5*L3?sd;jw2N5fWh=-P(gO{zueLtN`|k79rJg!rkF*tPE*A5G+n%{ zy5#g9p7wtDo1t~Elyxi?Mhf_+h;N?Ai_@yfLCcBa)|`prjVNPLaG>h9*nj?Qbf+cs zGGqoG*xu7Lp8A<61~mck@WOjB?Ck8sFZ`|me*f((O#3t{{`PdnA!N(l{}Vy*+^-?H zT(%2F{wK$8-euek8?x5^vNy8z@x8=<@H=zx6iK-=HeU z3m8=vXgHwaKKJaZV*~wWU2!(Rl=V#u%*6*_^fYZh1Nb174T!-@kU>?+(P@;sD-L|U zz2`SorWh7_C=wzvXEt}Zy2qIYOJ8F=FKsR~O(uPJxon(JNu~@Lk zN>@+J^p;ck`a+*nDbaw!N+ECdh|ry(qYq+#Nn%yr`zr=Iz`wURP&7`M_JH^Rti)-W z;FfxbB^I*F6yWL@PbnY5&!NIR4av zQ1Co@S0sQBFer_IuhZ8l`)K6)+pS1_$H7hqE3vpxlI=NW$1KQJQ;UJrnjF3zer zF?|J9bh7H28%BhE$*KNjBE6yGO3VyYxo>rYYHv4omYHvYkE5-Xsvtv^d8+ztx8Kdg z`TKvAAuaF1ACqYsZ~gGy%I?YZHcxw!@aP@QV96isMX3$ofZdl%uI{Ucs}?lsoH|QX zIk{szJD`Yz1dUfu;(gP}yKQ&R^(HEpm z-gu&WzrB#@j{1F(S&7nNQ!kDw>K-2!?SX{D_N#X737z{XW4oGK>b!Xrbip~n3uY@P&VCQ>>L*xfCxo5kRJRM zNay9CD0L8)rui)+14YWEVWU)y>UlZKxBfA=oAO8;bBJDV1ua71*H3&gzF)B!nBshP z@3w2l<-V>t3<>(?gXHOO!&g?8mpk@63jy*l@iK;bI&p?^!A1F@Mz-wtoQ`n?>*N?O z#^c;CGX`m8IQ5b5CHX6Z>>{sr2?qLwwv|;c0brM{{Ya|Z9*Tp@T7}R4*1TS_Vp*Mq z>P+8n___e{{{V}-*ReG| z+~;upiqn6Rt$RHKFMscO7V&4;MqT~HMp#LM`q#lp7QzloG8RF@4|RPyp@`tWbv2&^ zL^%QGl4HZXMhQKNCF)mhH|dfQ**t;6^n=B_zupDlvsqRPC$<8A{){U`hp!l&I*m?J zi}!pn(I=p6Yj|K-DJlL&H@^<3=R;{o^Hhis4*P-jCaY;ayQaX_iQXKImGf{%IH4F? z2;yK+-gIyNbVls}kKrf)%hSXXk$MA9^z2W3cUE{whMCslA_pZM#7hwMoLTI&PdEu4 zxKd#RzfltO4V74)wt$66C~Z4(3Qho_wZ_xbth}auSCiLQn|83vKN6X*Y_)mNoEnSk zUtGR)pNX{8g&xbm;6J*)D520>+m7h~1e}%zDp+-iG98db?hh0|w5GTSR>Eu5Qc_NY zJ%?^<6+B%nf+zyKbVwGqBEw+YPgUN7O@A-FkB;tt!?6^m+*A^4;Npl81b$$5h}&H~ zj+YLWJriWK9lr*IU)UzzDrCG7xS?y7T)u!JP^U{Pr$Q})&6$JpP?jjAh87lXKs_iV&gstk%$e}Q1#CSFY} zdyPIi$|bMbb^^VFC3el}sbUftn>i|YcdViSE)2BO*jI#p=$bl>ScKmVjizm-yvux4uq@KES2JH3mY-zWvUC?mLXC2+s*N2ogf4;wqq}WYRkmi6R>h2)ZzU z5gRVwGnM$*UwO)uvf_2$=hFp<`#gJ2k$qB(zMG8|$2o&c2gih{`T+RCcvOX`N^E6q zc1zGr|ISskSgOWDNps))-d7w6BKYvA%<#pZN_P3Q%uJ8iF(cIdLtl&#n1X2{lv6_= zrX#1EHaaE4y|NgyZI;!$f%f)xcCRI{^y31H5Ha}a`X2>4_0caivI}<>Vy#Gs67)h8 z!5v>|%7!`dmk*>}%Ukhy@lL^0!Bk2~b(Tx^&3qC*9Ncgbt)ik0OY0${J>s;TSe}j0 zpeNQTI$YLDsUk3*ttJf*R(2FXBSf!S$}gx5@s*@SPZWn0Wh z$X{&FeF|D4x&;x3@9I51LB9X?Jfqk(@$TopjaB^|v^YJ%B`UWTrh1I6c#Y93@PTCF zp$bFSIF!32jTtUy^g#LW;^8u^vIXC+^TFE$PEuCm8!}o`o<5tgB7Q&?b26L&EI}p| z+3VM|U2SG7`D%b!KDZKaE+_-7|0$K7>UFekqt@-bNH13?nKxIu|k@))ngU7pq zdNhqtN&H5KyFTE-_rLmVcgNrPytA@KP)uRmUEbeutV`xs!;?cl(x@PbsLjH#J%_Kxi3FmldP`7 zGhb=c8So*rxL+b9W1f=rUutYRsJ@GL?#WtaHMd6INZgy=LSI9uUB~OA?s{0Xq;M0i z_+@i%&Q_6Kc2BVUB#kFXk@IP`2|1YE3^^MP$Yin}Xq}HK=qkeRBYM@Dcr%#%k5^V! z-jZQn%!z>7#fUqm6{^!1-T8NTPpR}06NzOi4R{@3BOx870T!fG%Sk|C_htqmeR(>6 z(Ojjp(RD1|L}O8Xz4#7C4t{he&hi7$CtV1*2@hp`dZw2NiLNRKry5PYKcFeNw-0@s zws$|;BFzGJuAuIPymJF21m3dKRmkqqH)dDef`kPQEiwU4@D)S**Y^aGef;g8^#L$B z`~iZCk|)-%`!pyYu2C?JdEOx&pVmxkHcom});ADS*d)tM4+6jZkla&A?G6N6E#rl- zeMBkZ)>2oOsx9UoviHD$BnoqlenNgBKnqh%37q{Ic}f8`&rTAi4v+pQYhy9ZiShEq z6l%t*&ZN$RA+NGli*eMQquxK?ayovfe{I%Vr|luO#OE}uP$S6vxo-robZ8rV{Y7`Qe11o#H z>^MA!c?EpLW%!^M*c#}SQqS}6?i$SBJChL8mE~-gvBvvuapAk4-((Q}xkf<7^H^U2 zAtK{L}n9<>5cw;B=Mw-*smy5_PYFhJ!mTL$U*Y%H>2clbxmT zUfd6Y^Qv~foOi3m+Ti14)dMd<``v68*9pu-7ZV68RS%C<*V%TjOCW{&$XbGH>h4)0 ztWdWniK?Mr>7vAf-9Wi0si)BqrwgmMq6D(u|7iizEan$ME;R8EemUy;q@#p4Arf#N zGHa99VtbqPBMPZt5K_9mH6XbB`|Px! zy8XOynAtnCs8V!DqW$Sghc7hi2}1iB~&29|7cj+ zo{@hg;y?EsnvA)Nm_~JNR0+zK-;YRVmT#nJMZLK2$Ws zIlccWaP{9UC#KKI62T_iUygm}X79+pZ9WI0b$(bD?2!nU)A()Z_UoxbY!>sya|c={ z-@)yG&*|P|Av!|4M;MzV+#&uZ{|CBj7rX-aD8P2ebGh!s%J$pN(%1vg93A^qdS4hV z);}TZGnCIcGGO1Vs8E4m838eTdll4IJEud>l{ovnJNOaT84!8lw=>0`!$tx6VlH~j zwyVv9yN8#`i8e$}lyh4_`G|^KQX<3@uduodQ%+Q>O4RRRRx?xQI*4jMd=2dUUQ_tf zZ+lBJcfOMWZm-QINX%N``{*P~eUUS7CtV39_)_?v+_`Yqw4cjS^**1;E?pgv!xj2| zvVZcwSJEioHx8eqCSnfL=q_zi4yzgpH+)@c$XYfISZ6T9IvV1>qj!`dErJ1{d zH51}N+epH`)er?bXTiru6|pSv@QkW2HmswKxV8MXoI(jocp;n8SC zjf0Bo&Ahje-93qph#iSMkGT*)-`CYIH=z>ccW_e7BqERB)%x5z4sZc&v#W!$-;;n` z<-klL2ZO6{xk0&O@aj%yu8VIwm7X1hn9E`(=V7E(i@al|4W>k}7Kc6>wT4A zC^!qy#>s$6Vq`NR`L-9?`zjFn1z9FZaxXXMo7O;+4W&G-)|Y+0DRhX)guXQ!qv zD>L1Xq+!b?3i}Xqs8_7kj(%$uP@ib=*!!l(v-czP~oBa5@{Hi$p7f_JAvYD~8=c(#YnY2^8qe!ckJ`qLJg5$K45KVPq%;)o zB65RZdQ@~T#zSPqacet9!8t6O?S)wvDZX!Fx%%i*QrQdzUF}YgA*PGWawB{(*YWWE3u|KO!e#P`(PN=hG>?IyD!{te)5`1H;6Mfmp zOeBp4S*P*E!$wdV>+4^m3p1Wz%}wDZ7s_%ue@Q>LiwC9J-W%UY!-FkXW`{XwXTem; zThH!^@p0}yI7(fLTwb&vRVdNFJnE-_mz9|k2dFId{i}UBZk`*doX1wD;U+EmdH+mw zkfe^O{e5tWt%OjS!SU}p!?;-AcIi6e3_ms#07X&6e|h)H!PH$T&)2GL3LN=TI7Z<= zIf|q1+)%G62+v8dkW2chXmJ`Yf*gqLFU(kk6!xwOJ$Fy{P$Jyyy~TXpF8}i`rMkzf zLDnr)$ov-}jZ=T$U5%v=S%D$TW=$dyoMJ&(`ZubxiXVj8{RBbdsS(@#pE?{!zTKUi1sV{CyN+a}=hLf_{ z06Og(qdF0%?8hHT8(we22(xHkdvgEQ(oFOyxvU$IX(30Zt2NS%py(Y0ZB)8ggeY<2 z)r~F4drw|YPNYb9H$oX^^?`@i_Mu62&-eoSNiiEA-xMO_hu0vA$XLx-IpHdtdQqW| z8xvftKD%TceL%>+P$Z4EI@6+&G$~b~&t;AVJEXeW(A3p${{jq=T zqZRh(H3>evO2g)$xz+ClGzfa^x=s3ukk0&6|y! zr|$RFtEZqIW*Y*zb6E@At%(V_GqBjAAj>kjzC;z|g(FMex*Nb09(P?WVDAG>9TdA} zw9N9Ibdb2H(`R$@gb8Y$9;BniupSVk;*963X(Hb+2=q(+4IEtU&=~ur{e3PgFCCFd#9&IeeI)l~ zJ+e#$Ab&V8ib+S`naKPvx={4*hF4>5!oC5M(90K9s_n~oTJ7$|7co?<&WMXXE$U$| zd_U!K?(iD}y}YVZS>n_8ekAE32dF)dK2W&N3+|q4huSc&lw$ezEy<+NN1x29#3zH5 zV-n>yiwl_3ypuhJ!qY-7fG5v6f*+1|82ULYFT%}ux&?4Eu*qwr3v`w-o^;UFlYj?v zi2I-XxQ8Wj{)jO2jG*14QZm+apMeddpO9MHpZG!2h{Ip`-F&&PwBFIMZSoSYh(YG! z8;LkXa1R(BX|BM_2w%oIivn3rrD$`QhK_s7=m)3kHUr9 ztD10n_rWzP)d$nFUG0^N-)!ye&tXP_MYn3QIAXSZ3EGRyhE65hbpG#=j_(UwD*GZj zLXUCjn3`U=$^)x~xUD<)DVGAs{b=4?2sUpX8>wK83Bu2Vc`2f+I!IKP>$ZP_<_Utn zqDxvY3E-cvANcBi(GL7L6M*$yZg)92pMS27hcc09HSDCH5gC4YBoPvNxmXLTjFh42 zWW`72@NSFJ!u2(TvnH5RRB`TeFaO+(I&v%mMjesySl16KK=-euh~A||OF&cieDmS+ z)lGCG@cW?H_=T`Rx*pEuw4&&r>7mXqC!L@2%;m$BYl1fjMO-{Ink;&)WlGjj)vlsF_1NIE_Y|^_zy%S@h(zhIdI# z8Q>3c2V?lbc4p!|x}(J5^CDuBoucI+El<78dMZ!$aFALXre(Ys50AJ{=I`6Hv9z>MI$9wQ%qyK&2MynKwJ%@Ph& zU~fU58oEAVHww@R!_RuI!9#c^gzG*N%5&AT=!sEcbKC7sWfFTujA|6SN+e{fSi$st z#grk6t+6tI!M*8c3>NmbchAs;dV5G8ytN@GMeK&+DufZeXK~+-vykwq07!*p{AF!> zLjI0%|F`0R8I68^6{@V1G!k{2BTe2J1IHdgX`tZflCzM7Fpjs9)APefyvrpLHamnG zK||eXol%VqM|FQ-MlSU<_HEjGmeOsLgV&Vqr)_1;0zI2zpV%HR#iuS=LRgQo2-~vs z$t(TL%SOoQ)MTqBMN zWP!9R)qO1&pA|nSULDOz9Q$_!+YIivJN4UvZZAj1mwPPycW^BYrn2Y+RwjWj^Hyec zWT~?nn?s*3>2sU9O)U?dr zO1RHpFZun+hmJ5awBZ>#rWamSQUZ^R_CTTm;P+TR#Fxy{0ub~hPehX!b#`;t!oo@W zj}}+2SYup%rm4b|=TmwAjOQ0TYqDbwnpaiN42&g$IC0jGk0^u^|`N6 zB&i}?*P5p@22=F3c?zk>m6@jHj+bfYNsGpm1C0SR#?(@i-F;3}w}I~pyt;QJ@YnKU zefi3+PojrP9{YkT+tLyX)9W7Da7WnXT<)CtS#z>iUi=ydwk-aLqRC)a{ecWRCmIW; zi!o_pW{G)LNB+ybc)?7eZ1iBo%nh?16mLR_=jo>w$>|g|ila=sH9HUo5D=|K!HYvl znipWgJgk!HFlNH%(`S1>%RlLk5Af_@Nh8c664Y*<|064&`TR_(jxDZLG==- zl%ANld(B8_5;ofM9JlfkRS7Yr!!?ji=n96los(e{^?Aw)U*eCOzOUhLx7N9&DG@Yr ztWNob(I7eB@c>qy2)b4JdF@Fro8Lbt9&$kNae)DQj(3b@d8g1U$&KrZ`=2IaT-416 zz+Q%oe=rHx3+NE~q|EgDc{AOxI#I%9PJ1_NIb?hOez4xthfJCUmDHW)epi=nUfKK_ z0l~uj{m@Zqyx6hfZeyo1uhril!BqZo_+56r7#_2nQL*i3v%jbK@d5Qv45bR~`xKt{ zW8PEA`NzmA#1VtJ#W5R|5n+D(OgMh~5??kFPbV`VRU5lYV|JbtH$5W4)u&1oF;j_$GMKD;666Fmm5%qw;yoZWt+9<)MJRieW+`DSbT?Cqep)H=n8FHvTH z5@z{aC0u6SFw%0*E}1oHO*~b*FI8TzcaOufO_l&U!T;Dzp!!ITh9%JKs*sha_9s3S zq=gA0f8Y6vl#=RZ(jhLpC%8bn>HsjxFIyQx3H^&B8r1WB(=!vG0i5!*h|3Ztc^qi) zaG;c1lyW*|-=$cITHODa$g7bLGW;eZ{nWh@zwv_K>|X8%AJBMtXC^FSELYjbTnU)< zAgjl)0xLaAIMlVFig%T1Se|+4UQf{Mr>zW1kMSMI~3BE2dKPU)eGxGLMWCd>jb3d)iPKHpm>+NF2H}4C|{EH4;-cUvR=9nnq zu}ep%`^mqd)lXp+?Ho>0N9Py?E&H^m;-XE9oH~%rf5R-1hmM`Y#*pPmXxA!mIFw={PT09hjI`bhUgu)+VNJj+3aNqfEXkvW+6-mLC#r-`z8Eze zBFL{jjV~1}F7|AM&!T2PEKgG9^Iqn1KzCwv@gJc_!a5>W-??X^$gpw|^5qMLR{0J~ zj8-q+R+em7S;p zhPd%=d{yWSb*Ox*g%nBD?_{-kQ2Y%sN))Nh3N+~USlCF@=7>u(6H-G0kE&as(rIrm zcXUEJc{L+^;-9EidV&~{tBnnERDubr4r%|GSHwx(~YS{N#N;M8KblFB*%x{Z1&jLQ!@u#J*o`YN6>*Kx~`-<9fr4toQfQF|p z=r)+XaD4U<;@)ULV==)@tW>9?+>qHn`N9}1L16cTK6igY`k(xL&Y!v~M=E>B(zO5T z+A%hTD0W!LVw57uJ>Hq2*VN;nD45cjl=A*J;U~$2E)WcW#6?bL(VT{1sr@#t-^1yK ze=NqW??=115t)|s_dd2DMBU^vZCkLz8?Mx-SaKRN3fOqLZf1Xbqz4r~ry|tvP3`XI zB5Z_bSEBe!GL4XZgau0LTHQ&#)?8SR%;{r4q2d7Bxt?ETFCFuKy?VicRQM!hGvFgr zg*Qg9if~w!SKi5ugRajPBnuc#AMhSh)V!7a~VczM|O6je!=nh>18byh%K1r;@ z7HE87hSxh)6;O6@(Mji>+@5sQt=6Ud{!=IernJi?FM~t`-R_oHtYRdg#d=}5H`^@+Wnp0~(W8N+*saz$M%lsdYla6D35=i0DyiO%@Hkhn zJl#?3^fpPZeh`@fe~X^ZMmi2N13qZv(A5o@)M65lz92x^NFI#DNVh)Ho@}P#w`q>7 zYFus#MTyJctuz? zA9Y`2m&;ZIHjbUFLkYVnZPbc-0Ty-7AVx`H5!7;AZ( zq-<%KID^fPC7WPV^R+cL{_%Iv6KJB+AvkBU>(ltagkzDTiSUpTY z?SYV~;n-(PsjUm3XNPRBO5J;tpb@V{^_Cb|zpdd}DpOEu8J12>hpbX&$?T?0ES1SM z35YNeXT5pu^1Xuk-1$7e>ZgO!-$lz!4DUJL{|9zm%=rK*omUpzc$-E8?-h?crKps>)zMG>aD=yWjEqC)G7Ep+<=)eK__;eSpzLlmAPYD*(RXvJPHztL6^Q6} zX(Z^=QWc7imH$3`=0D5h4_#vVm0cR4$NoF|<$6Wk!-2z0hJsRuJLRR{Zg9c_{?foA zRf@MyfQi=nB=ljsG#mUNWE=m_BK49tgHd7?Qm8!h{gN*wGgeC;Zqh|!iPe#S4D+$i32 zw^M(_eu8S%xb!&m#=(M$;-lL!F z(`V-~O&;w;Rs=W9BR+LGsb?fzZQNlo%D%Uzfqxgq(*Z7-65hf!Y9f)72WGwWQ9==+ zD&-8FT7@P--3&rT7a9|AlIt=z=(z~&hX)4_sW3!>Q+)@*wj-Vq*Co4Dsg1inA0v8IjpPm?9I}Ty<|tM7xF%*i@RJ3<7q%k!4HW+ zCYWhle_7D(1hHe<1nl{x4@!tb@?SHXDVLHd?-Mg?Zh+mig|rh1M<*%J9Bi zmB=*wJp-HRKD&N%TVoR@rP6>2G-5HK8hP%|yH_h_$u%)6>jxhhD`UtBkNcCMdSVk$ z8rJs;WP+@Sp3eq4DKbH1W=5OizxNQSdprLVSMqr~#xSv;swIA$4VJd+2G;vU& zsswZ?*~bzA|G-;JZl&iquFdhoY+HGm@>$Ddu;O-Pg}m7c9w%0tgZt;pFa^4+VA!yi zJFEdTf2}Ht-);f8v5oi%WHi53y=v+j zd~G4b*yabDrcx!47S!C=$P%2%k38L| zL)UlAmTxU07)5Cr;;imZN-yA%yVuC`a~j^;jX~R3*K_=!o^P;esq!|=Zz4y8ulg0G z+xohTgq2#^YR&{~hxH=*taNr9Y;D_y9*CJ|ftG81u?oQ~0qc={T3rTVyfGESY{4QC zma3Mf@VH9*d9M{no-^23_mSVN>guSTcV`s*pt#%i#oHDGA3kQfaiJPf$e8V4?|Prx z{B;!YAyh+K-?1sAh%kmRQ5|>|+#$gY?mLQz9<}Az@1$8^5~;v6vZKlblyYoM90j7J zs#Q%?B_=$0musKl3E|fvk&FL^SWX=pD7lI+1^20i%qT|Ngpo&BXvu5d9Gd<73Q?TQ zh5Onu1-~4sdxcl9N)39ZmJb>HGNss4>~ktr)?-ejd!x^1<(JlYZ>&3tm6Rro7aU!g zdoj*_HE^%6^nsxHy%A2T(7Q_mypyCensMnflcpB9VvtGy-!-G55BOWI4OEhB@d`e_ z8tvw&{-*_0K?Yz5ecPg?CVj30(Dq))^80{^|Fv5l3?_MqM1Lo9@b*dAPM7b83Zb)- z3xHi*Zpn7cCD_nDMnjC|a&xN74;4T3+#&)Ht-%Us^&V}-K?()V#$q8aNdvQ@(Vu;W(5|KRC~t-ze|$W#s1gF5~?FdON4aI>I#y@7T7zV>M}# z#%yfcw(acLww=aqW7~}z+cr+l#rX?o?&oH{i+N|g&$H$lJgXYFrPthcV^k0w;X?5G z-ys~m#q9+6Q>Ae0!R@oa{`r69Pb`1_3+>16ml;ygw&1KetUYped@C)%|^41=A^8z!s6{C zhlSloHzrhf+PgoM9Bb=&lX{iH*T?WnrRPDWWxxAqE6&+z9@7SEXSWUw9Tmlt!0Fbh zri)hs7y1a^dVt+arFAn(W`c-o(IN3VO(C$SYkRp*3LhqaCiL@!eGnZX=&EeZ41fF2 zJAC4W%f9n|JN;Yp@{AVmyne`&} z5}7GftRHFf{eQGC`Qq`ZNowUF{YT z9+lW^baq0pxmnubO=U-RoJuUD|BY0?nqb(Emc>CtG+lkGM=qlixbq=D^RSmBQOmc< zgn+#SwT2}n^9LM66esj~Cp%pOuqXGTH3ah~6_EEPkeL>$RR(BPa%7h4U12$2_RQ13Z0UB3{kpQI-= zV)rb~*#xrb&@)Qh{_2QA9;MewUP^1ZT-%C4D0^l*q1N+0X*%g`hlUH1wV~HZ1%rg^ zx#|%BehLbNk6^C4w?FadVjC%1#E<33QkLP z$G-vCghL5+R^&Z&?mSs>&s6Yohj;!~bub~dsD+L^O z3ArW`MD4R_W2vrLv#h*|BIC7-fGucSV_K4L)S{#5^J`!ZcH3#ygTAE%^EG0{dPl=a zaH=3R2>aHSE$#z$C=kU*EYosU{^o8Rm6$hU@&Uus*W3p^N4>it^0$$?Mp(rW z-A>9x8BYV7o*z3&m`s5XUA4cDI{T}(X^*LJj z9rb~(sSq}yalyWm~%@Y&4)u*UX5!f?&y=RgDE%)QBrFAn+D;2mOl4h zvSwA7Dmb^9j42t?*YcLhqrJ5EsByRgOLvhlhN= zDj3%%8jzZ@%%ahw5j113*t$O}EoPR+P)Kd1erbK(w;l76KWh~M^?q#BRYc#_=eIN^ z?+zSD{Z*;3h3;4P!_~#JBfHV7nV-*Zq6MyV6iZ1(yVfd#(vd8$H-yZ=aDob&n=TN17~A68Ox`Y9|k;W!tNsscm$x{z2HZ|pV4=)`?U)Av38 z1R=zMMaw=}E(D!H`0v)I%r*C0>gG%dnWO`QoQmb%9S&@PX zX)!jh@!X6~7fX$RcY^=M43u9%+=H&5J6~y`Rt81v5)#oa+|SZTnG6pxs*%BRL@`{ zD0tMP(pQ_%jd*+IF~Gjr&=88vw7CGuLQR{${ji!nWO_j?@aHsI0AUyDs&JM3s;K7qcR#i@ktFD_q- z)K$(9=9@fFPrDC_Mxg6S9A4>1Jb3g_uYA1cQ=VtvKjV$O>I)H{SyN6@m6Voobt(b9 zX!Q>Be$*f&u67sm=)@kjUhE|U;YC$sh#47mFj(4FkF8n7+@0)rlz_xiva@Af7WAZf z@53h_0!0+kH>~?8=0Mmz zn(QJPDO{{wX0eBJafRj97#f31OQAvl69vOo>)s))eee&@qicA<7AtP0P?+du$*E%to8sz#$hzDy+hAgP(11sJ zNh)n8DA7v5!PK(+;=xF}UN2vvfgPJ-80fETB^BZtcSzN9WWeoaBWm?zLKzxM!7%G^ktQWaSV=4y>rM3_aC@%w+Z7U(3RN1I zv`KB(bGzpnCx`Ih0TqANdWUcj7%Qgc+4tl?YDT^=6TLSfrtrLn@*)`VP5oMLKgl=S zqEXZuv=v33nkdi-djlseFQBYTH)#fw820UR!^~vyeJJ<*5K9z(Ard%%voYkO!|`2{ zDGbY9h!%st_a{SylyvgH2x*!`z%7JD>K{JN5GJ;-^=USfF-&qYP{*uCBV?aAuX7L0 zhwcf8@{`8Mi=`G-#S;ps3|~rgX1u6(ScCPMmGbL?X&G(>sG}@T^XfyW;f^AW;DxT{ zq{KHLDw35a+T;lf6Bkd?~_^&UOU5XtH?|IDGW?%pTCu( z2IJEL6FnWeL!cMwGQ;P`eh6VqKmIX}DyLo-CW0l)!l14p=1Gr%I{z_Y>5FvyjJBx% z@VTw!f35Y@6q>)hcYN+~Q^tbqyEXl|bSp8{j=x>XssLZZth;e0Leqd=&@2T~fm~!D z<}!ZOpiwQ_@!E#x1@(e7)p)6_WE_J%cYLNU`c`kxzhz z1^1h>5 zQk}7rTOv4m96xEP?>B)Osa46C5`AFDzqe!cH{_q@jFL@hUlM6LbZANtmLwIt+a@CG zsqJz=iHe@QViU{?VhO0NFWB}7Kp3X)8V-wDut4w0|KCI}q{|GFv)L-7nHNI$jeyJ$kC)G=W)PUYOTe zr7)iw*noAJjC$lTeY6e%@9PJUma}3RVpkw)~PM3 zCBE6OWV8UhSns0bc4E`ibgauOK>Kp8Ux9RzH_cxZO}lI{8k5R(ME=h7zt8~)JjLB8 zHdF;#c7VABi~Om*zG-Ea)M`{rryk1deT;r!f$=N!bUlE(s&4s)Rx5&D;m;O>lb`Zj z0Q`aj<}q9v`Qr!MjJCj)Dj9Cf&)SKvcMUqQZggIb8kg_untEiNM--6KCx)fFdOm3eTq%1x_KQ0;!FHO1h+z)(H%&>zfx!bI7cwv%Cj>oU+o zscp^qx1b0xCq=Nd-t18`TvQBte_UIM{zwv5zMX0?5_|N+PgF8&M3!~`MIKMfq~3&J z%n*eAR!7t63rKZ~DLfZ0c;r8#Tm8xDd!Btda<| z`YJRLPS^ZpNUmf&)mwlh5SkZ|Us*ZX#8v(!(#&Ga2Yo$*f!Ca_2^+Rg&kHZ7aPM(>}4n^28GCGZ1> zn?l8OV}%3y#}PMkedFEKd*Lv{9J?*~a6CB`4z9 zOonaIQ+4;(=HR^GNeDWzlVH9PZ3>G;d~?G^Ubh|akQ$B1DQ#?9H0T=@KYwGiC_5bL zm59rVfgm6;as|)T0o!RkCJLLmIcbzwL^RSQ7%!m5CeZilqZ;YB<$`~0g|>@2{a+T~ zjSPF^37&=qygL1Id&|pmIw>YkxAcAfMg*Js$pcBO&t#v0ljeJiD7KcP`^2 z>X!R_92BpuQm&jEMQ2(Cjo! zp${(3xRqAQX*ESOFve&?40)aQ?PlVJ^=dk2`iVbh5$foq;Bek@|1>2fe3a+yM6F`I zjx0m$oTp+2os=j(j8R4Z$-$IqAnE4xgWE`kKwO>Oi7w?2L>@k6; z;GIQJV*ijAqQ^nKi;A1(n{@Ujdc!+*W0^glOV{CcwieeE0zVytD@6^DA{)D_VUPXT z0p+*e1-&dHCIXd8h{JzLH+V6YQ48+w=TnUzsV}buL&T*dV>cS!f2bf5M`*}m$mkv# zD=iboXxy?>ir0v(Rdw%(>520*5uwN<=zU25OMJ+CZAHU00T#Oxnk-e_CMVT3_2NE^1ajJ;`;a`HLDuLfgh8b&*7p*82v;Z)e# z)KIl-P?CgPcW89yhTY9*oOudd3zOI&D2~Z4K_rK&ifO~TGV3ELIAecOgp^1Q@I>E(XQ!ql8-IPK#rxKKcxUp<&^N-n!32XWfY@jI$5x#be_VuabV367AU` z#R@NY3Pl-4R9EhsC9jej`NH$!JJ;3Atwm<%A`vf7M{g-?*|2W-*~R^gwtG@H=rO>6 z9sga461_c&B@k%?+SzB80uvC^_LJV+r_7_SI+Nd3&-`unJhA928uN*Me=P8anfD7A zyxkd58WmB0A%*X!;9qJpV6~!W=&Cc@D(Nyh3;8ltp5-wgyUw1442)S^2SS;}UGCZ$ z>PoLzxz7i%MsF-HzH_O@luq*h$(p2j{7fQnhK1U~yez+HCo&x!cggX9K{=vDmyZ93 zc`e)~mP#@529c@2#t2-lqyu-0b)If%{RipCt|x7C{TMqv?UtYl;k-I(Zr90<^=;k} zYs68+P$e!W>H%d#wEjKdaf<=Ze4Hl>4goi8FF=uj!{9nB6xx=;bvGX0nOKYC4K_zr z|B>`DADAKImqioc+=;aJR47gpuowRq=j0sJ?1%kea{rOyTAtpXsapKwPh=!}58T4& zT?^rj`F=_B8N1eT3;FwCNa%X!4z+#3?!LYU8N*zlOnE(B@qr(dmZ&p$nlKm(iB@DF z?oJRSkKiGY;HJaVd@gQ(14mp^!@*2!Oc_%}RSCC{s-~lc|GIHSXlzg;N#la;2sJfr)=2HET98x& zAphHMy)ctsd%7Z%VeZSd49ZVQQWun6Y>;GgTBCocgC8H#=LrIyoonua50+Qq59&|4&;qZ-3Ys=5Gm5SX?6egsj_ zbnbkpQKpjO+rwH<##$z)?lrs@-=nSgI=nf3Xye+u<;ncSNk%`Xv*`3DL#E&AW+WbT zuY3t<#tEZoeLxmL?Ib;qTENVrU1pGLtd(Vf_G2GsQ51m)y6lWx5A3{JO_7{sZ}M*= zV*Jxm=(XVDM(C&mTIXWa1C3Rv8*XB3w%CWdW9QGA4&6S#>B}ZfISP1kRlo;8EA;(M zs^z#jU`O~(A0Zwf#^qeNsZlIGVOrJ2out?1(9neUsm&$!t@3rNp;02}V8*__Gkujl zmyK0h!3h7()$WjcPp^ATy&sl)g?e4kV!vs81zyOgf)4E*X9XVZ+1&{LZ6!(l94wE9 zqDDv$LU4NwflPh7*GU%uOC=nOme7cj+SI-GFru=ln4J7O2?6!l3j~{gY$5%zrqp)c z`aN|}Gbrg|w;L%#k0waEJlk`bgr@1IzNq!{Gvk4hMeG`l6Cy`-LvZNV`j%2P@HZU7 zRqu;H56(O#r_E-IdHjh0WPvDtAr-oJ?1;d%&}{;411b>@$pazafWg4)OB_)0_I?%c zAepEimQ)2KWL_6FFV|Tkgz+n$TU5eqm-RMEV5(xIH8zo)-cii1-8>a&u*|DSb2O4A z2N%N)A= z2eGMQ{Fx)|2ZDf3s0xr6Ig9H-1#I1S zG=GO}>qHS?GV+08*-6(IPlF=UqT%k>WFb=efx9z*vSwRekx1$RSna_i+dWy#1&%M@ zrcB!!3QoU^(#PZbvpRWm_KpzW?ZTI{GfJ$5p^!9GB*0gbJ~T)(-ht^aL>%s@e)s%3r~S#J@b_*|s; znDa9^n+0=@$9;uz0{HQIB1(-KpVC1Mno^MCFs~Dq&HQ8f$rN&dTxvOQw3dPz9DuoT`s>ajf5r)%F|^4JQ1Xw? z7`G6rO&Lj}f#i41t07qLS9x4n(QcA1OO$7>?F~2rjJq9hdL5VY1g5@H5N6;r`Y|tJ zFFeKK--~q{{LzSlsw?i79@N^@w0`DDI!s6{3nofnKE-+Wl#;q~kn@rR!;)Msdj3S^ zb`=fnPw2;Ffp-nL;xZNg9^cn&^}xFI^g*KxK9whjC@wnw;}jE7(0(oK0p}gtW!4pL zS7NFSip=PHwqDTObIu=w_MqXH{RpYf&+blol*A(L%gxi{A8u|BGsKBAP~d^fDIt`R zuMMU=*^YIx*&(>b4zRsgh|8)5iEVVMqa+nlRH_w(DJlsA1;R#z!zq}O4#GPW{4B_< z2dJ<{(Ja{FGfrn06KC1)bC;c$-j}Y^XXW0^+Y_&f<27ET`rQ|Po4&j?*@-*i-`L@& z$?C_A@_X(1k1tthzustNTn?OK4 z-wz}YiUshSB7$OjQgjp~W}c2$Ee((3teI@S#4)n;@qPZ>=|i#Cy09c!GgC($T*1;d zrrk8T&&i+d-)8E+%b>ufRJp7UHfa8AWb6~@lA9<1(M1YqajTgX`%<;|x)^q=K|q%Z0G^YWl`ZAc1?17_bHd^T8iErBf0Yy13toFD z6mUC1MnZ67rJvpPtRpD?HiA~PWY}-wfJ<*^|K1C&WyD5qSHskokL6iTn1hKpqBh)E zjT)kRNpd6$E=ey4L!wSKP^*X+wa#+a75npca^-d$ zXo@(ptOgOXDGajStLKKC%;%|7Q|A1kp~T|`lRA8}8hPXW=b2W(z3Ca0u#*U9XpDL+ z)o+{_81ASwbZNK*?qXbV;up?^rQS%4;dL*vON+YLs#FW%vSBGs+DbzH1BjWR|os}S4wL2eMS#Bbb)@@L@|D2bEJAcq&yWE26&<|Sh3zid5^?~ewrb>0{`O+gyY z(D4Lo?HQ(=o2zuw&p^duPOeH#jMv(rzN7M~;k3NLH$L`4xd$+fyLTlLz#4D(@?J7H zJ)bQpf!spwo3usuyKtnBe{(s^qb|%~_3HwwnI9`=A$L<4zMzS=O$TQvKLGx(qPfnR zV}adh`DRP!FMiBH#-AnI*vE?4i3;7WH!-}w_8MKUud!pm{UZpMVPN1Kw!gc-#<~~vY!gYTJ#cD$D7eG#e^~&-g+1JD zTPUi&)k>gY`ueS&$1%ZU#jDhaN=R|ub8o-GDmN4;;eIC3GF!*Y4$hXg`yCy3`9rUq z_Z1~#Elg2^WdYodCT+Ys$p%Ot{M{7rT%V&HzviRu{b6zAzxDeR4-DcI7}N7sGMP@{b6w zcH&Ve7dL+7Lx+2S1u|dkIG(7mo5wBD9nSp8LTgb(&uUSGz(03ywQOCYD5j8v>OTe^ zYfK)upig8~FA{Eb!AF9ssSZfCXPk2uKWX1 z1ll3Xf@IN#BTw384&GoAR}iQU?*BIN$9kWWdOk!yWCVBB4LjO~A44?Em1NT{fWx6! z*I?MF^-M<4l6JA+3>CdPIjKMXGQP>QhR|+@NR7A~1z)@?Se74SN^kGgz7sdpO%LH$ z%}@-iY9?tBi@v!ek*|FFa5@>5(ABmilJs9>@Ra-A?Zbz`HvR<_HyF-hl3H_wUmg1W zxVE&Ttdu9)&*@pzIkC3;bt1|_#5f_n;ehHis%GMjSeJ0RX`#>+Ai@Zp&_6FkhA#4` zpb!ko6CP`jJx4#D8cpc*1j6A!CU=e|#~b43IA$bE`{_T0yu3iSqD(FZn!YUZ!V4s(G7rh0<%he3Xhh^;gjDdndNNdqzp==es}DG#6M zD*8`!O&i?VZRP=jOlhxBHY5)u5%OBliy>epVRAIRJuTBsRw+K}BHn0_1&~An?*PnU zIam^|PSO*o;h1{D;Oc{u&v9qAF%A#6Z#VnRvRbTYN*0zP&lTMP2NS)?%^$8b za{BZb{sTt!#>m`qa!9N*a6Oujka$V2c9b+l9w0x+(4HMJHmMtDqRd8dJ(&u5@<3eR zNjeZ1DrHO1ku|U2A3MOPNydpRIo+^{Tk)tnq$u4cayF@2c|aS$$^-IRUYsPiJtre{ci}<&s!*QbcTpdH^Afs4f|CvWLl866Ur?$j z>oWJP?gUYgclqq8E3PHzjLIpkcp$bLh!~p(yIYonvZ`7$JOJt*QP8a#8c6KBN|SPn z2-C^95USm^(j&I2^~1qN_9Z@jOPbWhe0`$W248merFr+=s@AHtr=ZBM(^TUf-JdZWwtZMTUacDjGbUyjaw8Y( zS&YJICv~h$xdoq}CXH8GqvXh-Cl@k)QnnlHu`v?MgK$FHhp3mKJ~+LxjdSB1L|H3X zn3nfNb^5#|UGRUp{07GWR~JzZi?E?lq4GgFD>>d%$rf;S^nkH46RWM=SnJJTIFzT7 z_s$S4PZF>`)7DfX*)fVXv!x>Zy9ypP@CDk|eY|+jh)5^n^guR{ulcrLYG6hVXq%_Z6A*cOfqi-!kVxW1| zX{Ky^PEgWr(-Q?^0RLf|Klrdlskjk#nEB#S4pN6jB(W8{SK97~@7$ZLSN$7gg!-c* z>gBBQEU-)|NjVpukJ0Rn_ReGPk=I!)lcyhDs^3QP)#NExVz=o4D>nmf>0(Q>o55S` z>P2VAjCI@D#7HDT0l}kg#fDhUWe&Z*5>e1Y(3xPW+q2+ivB|0^Mdm&2`6KJG=PDLK zI5t~IHQO?-wdvDzx^hsZYRWkBYGScXrtBS80xSL?eN_1TIm}@D*ja-}-$^itCP03v!*{mGU35H(ep5r;u);GFuo`|M+cG@dORu zyEZ)U%q&LDJgjg9t-Jw-KZ z8Aq!na{QQHAkh0MiFQ8-?D(mFntgk;EsUtV%pPj3DZ#}kA)*MJZ5bb%2R8RS5w;zU zI!B1poqyGk=-m(vL_@NPzhcB482QJEy`unT`G5iGGG}0OMR2q>M?pOKeoxk@DzQK} zSfkfEZKw8i95rY40###xpJ8(E$ka54m2-cOQqwbh$>+#}vw_1rJ7hKV@89Xsn)JU7 z(zlE|Y3z#i)RVR}mYR0wcB~2o-jw~3CYSQ02Ae^<_6DydEOon5sInjA?hFwPV(vw? zAd(7_^+*Y~aWQSxm9z{AZHH!?wFH0Z&#rw+756VVP;vD4cv<|^;~u^u zNbz(O&?Kdc@cUhZJfa0kWnDhj{ibu z8^SfgZBTKi@8{hw2VUM9S?~^MK9ZZI<90Xi7>JzpM#(SWco^U}fxK z)kHnVj2fKT1GFro2MJRgcgn7NjFM&cF$PHT3;_>VSC{EeY^;9d9;JBc@jFW7;@N&K zC}xB?!GZIsm3-=l=(|g^M5j8(lh+!e5P}%`)}H^~kPLLC{g+PPh)Y6GfxiIU?>Zlo zj0XmMMF2(_BVp?H|A9 z)3*3abzm^0O%!^pP7B(NgPag6BX_^ChGPGk0f6hIH*JSx5 zvs=~t^_}95(2!)Y+oUynLMw2RMPhKv#h{L~k?Lp0w+Jv|zvJ4v{X^n=LTtTn(wnzn z>Uk^jFK@Y*%f5*+>^`>c&0D6*34IuJ;r_J%(DS6{q<_KL#UFBqNgPTkPngXTQ311!IyxU$%l2M~j)!_n&b#P&8D>=v?Jt((Y$M6g zU;llo72F*R3tTdr4}l_Mhqx$TI{jR>;qXsCDh|<5gx&(pF}LpP=G8DveXq?q3H4%L$B3#z;*XH~}H-*5>>==)yywZr(}59cWyHYAw~IzEb* z?8-+GlB*>j(6JwA-=5v+JG_%M+688L8;y}!RP`iyQ>SF{YA}3Yt;?t34HfX$dEL)* z@};bkbDxi?>8ySLoAqG51;%9Jg>9!p*5zl&waBBxy$G|4QlD7COK*?V1`lm9f;jaf z(Y_HaN#R*-{lpLy*s(4YhDazt5xk#~?#Hyn zE&T~OH@Ok_Q_HJ@R}o2Ua>=i$7z~#rU`7Trt}eHIDwEaNrGRIq0|e`Zw$osaUBHUX zW5x>0#}So>N%V`Ln{r;zpKsQvm&_Kf79|s+J^(QjW5=jqQ6*2F;r)I_=d0yH;;U6x zU;(l#_hgS)gB5xUC3=5lx#rL6W)8Ce=~5w3&T1YAJ9TJ6({YDfnSIv!6)V1>!< zcTuOp6m!H=8bSgGLFG1qyMDD-vt#2Q2c4p*)=<<*ZhHB3i0Ty_<&rmUEIDw~0OIq%{}kN8G=&F5 zd04^CIbzZPdssqM1a9&ad@n9d!Q+Gbd5GF3pSpw#9Gu&AKC1U)TW!9g9fA9WpJqqO z4Xei<5}z}R({Xlz*F-RaXkBA`M|$XpLz_;~fYbgG9H%_Qu&SSPLzcJ# z&%*hWq^6}bTI6mPS*N&|X?XsVt^RIZpgBJ)wi z9_DK1dRHEMd(Kq~X(D4yRMrn0Fkl%IOg9T6n7!5g#)IhB?61a=Q_l5^_tt&pX_GqV z{PGF|0TCgRJJ23dh~-Z*>sK8GB%|rDTzBcl0~3hUGpiO0w0!RR>dDgKSsVR4PYi~5 z?vE{hO779MzF2j$&{@%P@8;l92G$=0Bg`lm0;SwaimibTF@kKXH7!l;3)Coo8jgB; z-=VQtclESDc&22EUSF4Lx>r4)VGSipZQhCJhRLlxQzqN208HY;|Q|HE#H z0#`QT`Fx)iQodWc4U2OutJmBQtrvF4kOACId+Rcudvv09t1Q)=@eN5hwf<8&+Gn-< zkYktVJFUj{a{VQ+*nzFPyBBogXcvO*(F37K-xG{!4`QuVARJXWO*&VjP@N7~K+M<8 z%CRPSUOk^Ffp^}Yd3F3Q9OQp2{+U|t?%PyO!@~GGuAR=3^l z%1$}-pPjg|sv=2u8?mi^DajH^*=sRmKzwyKwF^D8KTjEzO%bhGoiEewVph;S!Dbi( z(~gi>BQ=cp)_!6zVSk4*?NKhawyvfEjRDBWzKFvBLc$l^STHWGJ61vn2ZtkLF6gbT ynPCUSp5B7EZQOuh5t4pZ08AKv=>O@4=ue1RnD|5mze*tB>yi|c6Ri<82>K7qmuyD> literal 29718 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
v!CRJXbGX54qAk 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 diff --git a/delta/main/dcore.cpp b/delta/main/dcore.cpp index 771213b2..a71c0879 100644 --- a/delta/main/dcore.cpp +++ b/delta/main/dcore.cpp @@ -35,6 +35,9 @@ bool deltaCore::init() { } namespace { +constexpr uint64_t kMaxSfoSize = 1u << 20; +constexpr uint64_t kMaxIconSize = 16u << 20; + // Minimal param.sfo reader: return the string value of `key` (e.g. "TITLE_ID"), // or "" if absent. The SFO is a small flat table; all offsets are bounds-checked. std::string sfoGet(const uint8_t *d, size_t n, const char *key) { @@ -90,6 +93,28 @@ std::string jsonGetString(const std::string &js, const char *key) { return js.substr(open + 1, close - open - 1); } +bool readHostFile(const std::string &path, uint64_t maxSize, + std::vector &out) { + utl::File file(base::String(path.c_str()), utl::fileMode::read); + if (!file.IsOpen()) + return false; + const uint64_t size = file.GetSize(); + if (size == 0 || size > maxSize) + return false; + out.resize(static_cast(size)); + if (file.Read(out.data(), out.size()) != size) { + out.clear(); + return false; + } + return true; +} + +std::string parentPath(const base::String &path) { + const std::string value(path.c_str()); + const size_t slash = value.find_last_of("/\\"); + return slash == std::string::npos ? std::string(".") : value.substr(0, slash); +} + // param.json stores sdkVersion as "0xMMmmpppp00000000"; libkernel wants the top // half (0x03000000 for a 3.00 title). Empty/unparsable -> 0. uint32_t parseSdkVersion(const std::string &s) { @@ -154,6 +179,19 @@ class PkgProvider : public krnl::vfs::VirtualProvider { return {}; } + std::string title() { + std::vector sfo; + if (fs_.readPkgEntry(0x1000, sfo) > 0) + return sfoGet(sfo.data(), sfo.size(), "TITLE"); + return {}; + } + + std::vector icon() { + std::vector png; + fs_.readPkgEntry(0x1200, png); + return png; + } + // SOTTR workaround: cache every .manifest.bin's bytes keyed by its base name // (e.g. "PRIORITY7_ENGLISH"), so the count-setter can fill the header buffer // with correct data (the engine's async manifest reader races on our threads). @@ -305,6 +343,18 @@ class Ufs2Provider : public krnl::vfs::VirtualProvider { // instead of the PS4 param.sfo; pull the "titleId" string out of it. std::string titleId() { return paramJsonField("titleId"); } + std::vector icon() { + const auto *node = fs_.find("/sce_sys/icon0.png"); + if (!node || node->size > kMaxIconSize) + return {}; + std::vector png(node->size); + const int64_t read = fs_.read(*node, png.data(), 0, node->size); + if (read <= 0) + return {}; + png.resize(static_cast(read)); + return png; + } + // param.json spells the SDK version as a 64-bit hex string ("0x0300...") // whose top half is the 0xMMmmpppp form libkernel compares against. uint32_t sdkVersion() { return parseSdkVersion(paramJsonField("sdkVersion")); } @@ -361,13 +411,24 @@ void deltaCore::boot(const base::String &xdir) { const bool isPkg = endsWithIgnoreCase(xdir, ".pkg"); const bool isFfpkg = endsWithIgnoreCase(xdir, ".ffpkg"); - // A raw app dump: the extracted /app0 tree itself, identified by its PS5 - // sce_sys/param.json. Host-mounted rather than read through an image reader. - std::string appJson = std::string(path.c_str()) + "/sce_sys/param.json"; - const bool isAppDir = !isPkg && !isFfpkg && utl::File(base::String(appJson.c_str()), - utl::fileMode::read).Exists(); + // A raw app dump: the extracted /app0 tree itself, identified by its console + // metadata. Host-mounted rather than read through an image reader. + const std::string appRoot(path.c_str()); + const std::string appSfo = appRoot + "/sce_sys/param.sfo"; + const std::string appJson = appRoot + "/sce_sys/param.json"; + const bool isPs4AppDir = + !isPkg && !isFfpkg && + utl::File(base::String(appSfo.c_str()), utl::fileMode::read).Exists(); + const bool isPs5AppDir = + !isPkg && !isFfpkg && !isPs4AppDir && + utl::File(base::String(appJson.c_str()), utl::fileMode::read).Exists(); + const bool isAppDir = isPs4AppDir || isPs5AppDir; base::String mainModule = path; uint32_t sdkVersion = 0; + std::string gameTitle; +#if defined(__linux__) && !defined(__ANDROID__) + std::vector gameIcon; +#endif if (isPkg) { auto provider = std::make_shared(path); @@ -380,6 +441,10 @@ void deltaCore::boot(const base::String &xdir) { // Publish the title id so savedata can give this game its own host save // root (else saves for different titles collide under one directory). krnl::vfs::setTitleId(provider->titleId()); + gameTitle = provider->title(); +#if defined(__linux__) && !defined(__ANDROID__) + gameIcon = provider->icon(); +#endif mainModule = base::String("/app0/eboot.bin"); } else if (isFfpkg) { // PS5 game backup (UFS2). Mount it at /app0 and prefer the decrypted/ tree @@ -393,6 +458,9 @@ void deltaCore::boot(const base::String &xdir) { bool decrypted = provider->hasDecrypted(); krnl::vfs::mountVirtual("/app0", provider); krnl::vfs::setTitleId(provider->titleId()); +#if defined(__linux__) && !defined(__ANDROID__) + gameIcon = provider->icon(); +#endif sdkVersion = provider->sdkVersion(); mainModule = base::String(decrypted ? "/app0/decrypted/eboot.bin" : "/app0/eboot.bin"); @@ -400,15 +468,43 @@ void deltaCore::boot(const base::String &xdir) { krnl::vfs::titleId().c_str(), mainModule.c_str()); } else if (isAppDir) { krnl::vfs::mount("/app0", path.c_str()); - if (utl::File f(base::String(appJson.c_str()), utl::fileMode::read); f.IsOpen()) { - std::string js(static_cast(f.GetSize()), '\0'); - f.Read(js.data(), js.size()); + if (isPs4AppDir) { + std::vector sfo; + if (readHostFile(appSfo, kMaxSfoSize, sfo)) { + krnl::vfs::setTitleId(sfoGet(sfo.data(), sfo.size(), "TITLE_ID")); + gameTitle = sfoGet(sfo.data(), sfo.size(), "TITLE"); + } +#if defined(__linux__) && !defined(__ANDROID__) + if (!readHostFile(appRoot + "/sce_sys/icon0.png", kMaxIconSize, gameIcon)) + readHostFile(appRoot + "/icon0.png", kMaxIconSize, gameIcon); +#endif + } else { + std::vector json; + readHostFile(appJson, kMaxSfoSize, json); + const std::string js(json.begin(), json.end()); krnl::vfs::setTitleId(jsonGetString(js, "titleId")); sdkVersion = parseSdkVersion(jsonGetString(js, "sdkVersion")); +#if defined(__linux__) && !defined(__ANDROID__) + if (!readHostFile(appRoot + "/sce_sys/icon0.png", kMaxIconSize, gameIcon)) + readHostFile(appRoot + "/icon0.png", kMaxIconSize, gameIcon); +#endif } mainModule = base::String("/app0/eboot.bin"); LOG_INFO("mounted app dir at /app0 ({}), boot module {}", krnl::vfs::titleId().c_str(), mainModule.c_str()); + } else { + const std::string root = parentPath(path); + std::vector sfo; + if (!readHostFile(root + "/sce_sys/param.sfo", kMaxSfoSize, sfo)) + readHostFile(root + "/param.sfo", kMaxSfoSize, sfo); + if (!sfo.empty()) { + krnl::vfs::setTitleId(sfoGet(sfo.data(), sfo.size(), "TITLE_ID")); + gameTitle = sfoGet(sfo.data(), sfo.size(), "TITLE"); + } +#if defined(__linux__) && !defined(__ANDROID__) + if (!readHostFile(root + "/sce_sys/icon0.png", kMaxIconSize, gameIcon)) + readHostFile(root + "/icon0.png", kMaxIconSize, gameIcon); +#endif } // /download0 is the title's writable data volume (patches, add-on content, @@ -426,14 +522,22 @@ void deltaCore::boot(const base::String &xdir) { // These all boot from an /app0 mount rather than a bare host path. const bool mounted = isPkg || isFfpkg || isAppDir; - const bool isPs5 = isFfpkg || isAppDir; - // Name the window after the booted title, since the renderer and the videoout + const bool isPs5 = isFfpkg || isPs5AppDir; + // Name the window after the booted game, since the renderer and the videoout // HLE both bring it up with a generic title depending on who gets there first. { const std::string &tid = krnl::vfs::titleId(); - gfx::setTitle(("prosperity - " + (tid.empty() ? std::string("unknown") : tid) + - (isPs5 ? " (PS5)" : " (PS4)")).c_str()); + std::string title = + gameTitle.empty() ? (tid.empty() ? std::string("unknown") : tid) + : gameTitle; + title += " - prosperity"; + title += isPs5 ? " (PS5)" : " (PS4)"; + gfx::setTitle(title.c_str()); } +#if defined(__linux__) && !defined(__ANDROID__) + if (!gameIcon.empty()) + gfx::setIcon(gameIcon.data(), gameIcon.size()); +#endif std::thread ctx([mainModule = std::move(mainModule), mounted, isPs5, sdkVersion]() { auto p = base::MakeUnique(); if (isPs5)