From 31953464e70f0fc4009dfca02923bb16f71c51c4 Mon Sep 17 00:00:00 2001 From: Nikolai Fedorov Date: Sun, 14 Jul 2024 20:20:03 +0300 Subject: [PATCH] initial commit --- .DS_Store | Bin 0 -> 8196 bytes .../index/Main.cpp.685062F8D32EB8FC.idx | Bin 0 -> 1604 bytes .../MainApplication.cpp.79A72745C41D6043.idx | Bin 0 -> 822 bytes .../MainApplication.hpp.221A9A34681ED2E1.idx | Bin 0 -> 648 bytes .../index/Plutonium.176CA4CACA9A1290.idx | Bin 0 -> 568 bytes .../TitlesLayout.cpp.45180DB29A164B8B.idx | Bin 0 -> 1430 bytes .../TitlesLayout.hpp.75FC133FF2EF41D2.idx | Bin 0 -> 624 bytes .../UsersLayout.cpp.88C1C105F3F43467.idx | Bin 0 -> 1332 bytes .../UsersLayout.hpp.1712702588294560.idx | Bin 0 -> 736 bytes .../audio_Music.hpp.8B2BCABF9BE0D597.idx | Bin 0 -> 1440 bytes .../index/audio_Sfx.hpp.20BB10D088C7D73C.idx | Bin 0 -> 614 bytes .../clangd/index/const.h.BA34DD522C225A5C.idx | Bin 0 -> 184 bytes .../index/data.cpp.92E1D4C612A67155.idx | Bin 0 -> 6758 bytes .../clangd/index/data.h.FB9692DD59DD0CA9.idx | Bin 0 -> 3524 bytes .../clangd/index/dir.cpp.84282E8F15A0C3E7.idx | Bin 0 -> 3678 bytes .../clangd/index/dir.h.8134312F1E0EEB8F.idx | Bin 0 -> 2302 bytes .../index/elm_Button.hpp.018512E7528A66C7.idx | Bin 0 -> 3668 bytes .../elm_Element.hpp.14E03F7E0D260C63.idx | Bin 0 -> 3406 bytes .../index/elm_Image.hpp.FAD5FE2703E71E60.idx | Bin 0 -> 2352 bytes .../index/elm_Menu.hpp.52144C9486AEB8A4.idx | Bin 0 -> 7952 bytes .../elm_ProgressBar.hpp.5BE7F064B955686E.idx | Bin 0 -> 3448 bytes .../elm_Rectangle.hpp.E8436387021D3723.idx | Bin 0 -> 2420 bytes .../elm_TextBlock.hpp.B8CCDCBE3879D2C2.idx | Bin 0 -> 2184 bytes .../index/elm_Toggle.hpp.F643B22B4EBE2394.idx | Bin 0 -> 2932 bytes .../extras_Toast.hpp.1CB990ED4FA33D5B.idx | Bin 0 -> 1154 bytes .../index/file.cpp.5237F76D2447B003.idx | Bin 0 -> 5404 bytes .../clangd/index/file.h.ECED60B58854FB92.idx | Bin 0 -> 2402 bytes .../clangd/index/fs.cpp.2C750D58CF93396A.idx | Bin 0 -> 10148 bytes .cache/clangd/index/fs.h.B7E897F33D9D7EE5.idx | Bin 0 -> 2726 bytes .../index/fsfile.c.867FA10C150715C4.idx | Bin 0 -> 3438 bytes .../index/fsfile.h.35B524E0BEF369EF.idx | Bin 0 -> 2786 bytes .../index/fstype.h.DEBE4E158EC53C0F.idx | Bin 0 -> 2320 bytes .../clangd/index/ldn.cpp.393680BBDDA86121.idx | Bin 0 -> 8148 bytes .../clangd/index/ldn.h.1D557AF101A575C7.idx | Bin 0 -> 4290 bytes .../index/pu_Include.hpp.C523922F5EC060FC.idx | Bin 0 -> 1072 bytes .../render_Renderer.hpp.6683E79ACA4A54CC.idx | Bin 0 -> 8114 bytes .../render_SDL2.hpp.18A6D5991D9EFEE8.idx | Bin 0 -> 934 bytes .../sdl2_CustomTtf.h.DA6EB9766D3A2A8C.idx | Bin 0 -> 9286 bytes .../index/sdl2_Types.hpp.14E8D52331FEA768.idx | Bin 0 -> 758 bytes .../index/threads.cpp.3D4AF726B9B95CFB.idx | Bin 0 -> 1834 bytes .../index/threads.h.BB90B2C1D3A0674C.idx | Bin 0 -> 1972 bytes .../clangd/index/type.h.3039A978BD63D81E.idx | Bin 0 -> 1226 bytes .../ui_Application.hpp.C3BE54443DABA7BF.idx | Bin 0 -> 3634 bytes .../ui_Container.hpp.DBA564B6F57F0254.idx | Bin 0 -> 1922 bytes .../index/ui_Dialog.hpp.BA5E55C427BB5263.idx | Bin 0 -> 4508 bytes .../index/ui_Layout.hpp.30029BE965429247.idx | Bin 0 -> 2100 bytes .../index/ui_Overlay.hpp.177672D215C52C40.idx | Bin 0 -> 1660 bytes .../index/ui_Types.hpp.D33AC0C2311B451E.idx | Bin 0 -> 3832 bytes .../index/util.cpp.7798728B5E2F0E42.idx | Bin 0 -> 5358 bytes .../clangd/index/util.h.4B818D27750FB9A3.idx | Bin 0 -> 5730 bytes .../clangd/index/zip.cpp.BDB97FF96BC149B8.idx | Bin 0 -> 4696 bytes .../clangd/index/zip.h.74C41B03268B991E.idx | Bin 0 -> 966 bytes .gitmodules | 3 + .idea/.gitignore | 8 + .idea/misc.xml | 18 + .idea/vcs.xml | 7 + .vscode/c_cpp_properties.json | 23 + .vscode/settings.json | 101 ++++ Iridium_Icon256.png | Bin 0 -> 23661 bytes Makefile | 203 +++++++ NXST.lst | 2 + cleanup | 10 + compile_commands.json | 428 ++++++++++++++ icon.jpg | Bin 0 -> 5728 bytes include/.DS_Store | Bin 0 -> 6148 bytes include/MainApplication.hpp | 21 + include/TitlesLayout.hpp | 19 + include/UsersLayout.hpp | 22 + include/const.h | 2 + include/data.h | 91 +++ include/fs.h | 54 ++ include/fs/dir.h | 54 ++ include/fs/file.h | 64 +++ include/fs/fsfile.h | 100 ++++ include/fs/fstype.h | 46 ++ include/fs/ldn.h | 94 +++ include/fs/zip.h | 18 + include/threads.h | 44 ++ include/type.h | 29 + include/util.h | 152 +++++ lib | 1 + source/.DS_Store | Bin 0 -> 6148 bytes source/Main.cpp | 59 ++ source/MainApplication.cpp | 21 + source/TitlesLayout.cpp | 71 +++ source/UsersLayout.cpp | 39 ++ source/data.cpp | 352 ++++++++++++ source/fs.cpp | 519 +++++++++++++++++ source/fs/dir.cpp | 266 +++++++++ source/fs/file.cpp | 383 ++++++++++++ source/fs/fsfile.c | 150 +++++ source/fs/zip.cpp | 251 ++++++++ source/ldn.cpp | 543 ++++++++++++++++++ source/threads.cpp | 69 +++ source/util.cpp | 351 +++++++++++ 95 files changed, 4688 insertions(+) create mode 100644 .DS_Store create mode 100644 .cache/clangd/index/Main.cpp.685062F8D32EB8FC.idx create mode 100644 .cache/clangd/index/MainApplication.cpp.79A72745C41D6043.idx create mode 100644 .cache/clangd/index/MainApplication.hpp.221A9A34681ED2E1.idx create mode 100644 .cache/clangd/index/Plutonium.176CA4CACA9A1290.idx create mode 100644 .cache/clangd/index/TitlesLayout.cpp.45180DB29A164B8B.idx create mode 100644 .cache/clangd/index/TitlesLayout.hpp.75FC133FF2EF41D2.idx create mode 100644 .cache/clangd/index/UsersLayout.cpp.88C1C105F3F43467.idx create mode 100644 .cache/clangd/index/UsersLayout.hpp.1712702588294560.idx create mode 100644 .cache/clangd/index/audio_Music.hpp.8B2BCABF9BE0D597.idx create mode 100644 .cache/clangd/index/audio_Sfx.hpp.20BB10D088C7D73C.idx create mode 100644 .cache/clangd/index/const.h.BA34DD522C225A5C.idx create mode 100644 .cache/clangd/index/data.cpp.92E1D4C612A67155.idx create mode 100644 .cache/clangd/index/data.h.FB9692DD59DD0CA9.idx create mode 100644 .cache/clangd/index/dir.cpp.84282E8F15A0C3E7.idx create mode 100644 .cache/clangd/index/dir.h.8134312F1E0EEB8F.idx create mode 100644 .cache/clangd/index/elm_Button.hpp.018512E7528A66C7.idx create mode 100644 .cache/clangd/index/elm_Element.hpp.14E03F7E0D260C63.idx create mode 100644 .cache/clangd/index/elm_Image.hpp.FAD5FE2703E71E60.idx create mode 100644 .cache/clangd/index/elm_Menu.hpp.52144C9486AEB8A4.idx create mode 100644 .cache/clangd/index/elm_ProgressBar.hpp.5BE7F064B955686E.idx create mode 100644 .cache/clangd/index/elm_Rectangle.hpp.E8436387021D3723.idx create mode 100644 .cache/clangd/index/elm_TextBlock.hpp.B8CCDCBE3879D2C2.idx create mode 100644 .cache/clangd/index/elm_Toggle.hpp.F643B22B4EBE2394.idx create mode 100644 .cache/clangd/index/extras_Toast.hpp.1CB990ED4FA33D5B.idx create mode 100644 .cache/clangd/index/file.cpp.5237F76D2447B003.idx create mode 100644 .cache/clangd/index/file.h.ECED60B58854FB92.idx create mode 100644 .cache/clangd/index/fs.cpp.2C750D58CF93396A.idx create mode 100644 .cache/clangd/index/fs.h.B7E897F33D9D7EE5.idx create mode 100644 .cache/clangd/index/fsfile.c.867FA10C150715C4.idx create mode 100644 .cache/clangd/index/fsfile.h.35B524E0BEF369EF.idx create mode 100644 .cache/clangd/index/fstype.h.DEBE4E158EC53C0F.idx create mode 100644 .cache/clangd/index/ldn.cpp.393680BBDDA86121.idx create mode 100644 .cache/clangd/index/ldn.h.1D557AF101A575C7.idx create mode 100644 .cache/clangd/index/pu_Include.hpp.C523922F5EC060FC.idx create mode 100644 .cache/clangd/index/render_Renderer.hpp.6683E79ACA4A54CC.idx create mode 100644 .cache/clangd/index/render_SDL2.hpp.18A6D5991D9EFEE8.idx create mode 100644 .cache/clangd/index/sdl2_CustomTtf.h.DA6EB9766D3A2A8C.idx create mode 100644 .cache/clangd/index/sdl2_Types.hpp.14E8D52331FEA768.idx create mode 100644 .cache/clangd/index/threads.cpp.3D4AF726B9B95CFB.idx create mode 100644 .cache/clangd/index/threads.h.BB90B2C1D3A0674C.idx create mode 100644 .cache/clangd/index/type.h.3039A978BD63D81E.idx create mode 100644 .cache/clangd/index/ui_Application.hpp.C3BE54443DABA7BF.idx create mode 100644 .cache/clangd/index/ui_Container.hpp.DBA564B6F57F0254.idx create mode 100644 .cache/clangd/index/ui_Dialog.hpp.BA5E55C427BB5263.idx create mode 100644 .cache/clangd/index/ui_Layout.hpp.30029BE965429247.idx create mode 100644 .cache/clangd/index/ui_Overlay.hpp.177672D215C52C40.idx create mode 100644 .cache/clangd/index/ui_Types.hpp.D33AC0C2311B451E.idx create mode 100644 .cache/clangd/index/util.cpp.7798728B5E2F0E42.idx create mode 100644 .cache/clangd/index/util.h.4B818D27750FB9A3.idx create mode 100644 .cache/clangd/index/zip.cpp.BDB97FF96BC149B8.idx create mode 100644 .cache/clangd/index/zip.h.74C41B03268B991E.idx create mode 100644 .gitmodules create mode 100644 .idea/.gitignore create mode 100644 .idea/misc.xml create mode 100644 .idea/vcs.xml create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/settings.json create mode 100644 Iridium_Icon256.png create mode 100644 Makefile create mode 100644 NXST.lst create mode 100755 cleanup create mode 100644 compile_commands.json create mode 100644 icon.jpg create mode 100644 include/.DS_Store create mode 100644 include/MainApplication.hpp create mode 100644 include/TitlesLayout.hpp create mode 100644 include/UsersLayout.hpp create mode 100644 include/const.h create mode 100644 include/data.h create mode 100644 include/fs.h create mode 100644 include/fs/dir.h create mode 100644 include/fs/file.h create mode 100644 include/fs/fsfile.h create mode 100644 include/fs/fstype.h create mode 100644 include/fs/ldn.h create mode 100644 include/fs/zip.h create mode 100644 include/threads.h create mode 100644 include/type.h create mode 100644 include/util.h create mode 160000 lib create mode 100644 source/.DS_Store create mode 100644 source/Main.cpp create mode 100644 source/MainApplication.cpp create mode 100644 source/TitlesLayout.cpp create mode 100644 source/UsersLayout.cpp create mode 100644 source/data.cpp create mode 100644 source/fs.cpp create mode 100644 source/fs/dir.cpp create mode 100644 source/fs/file.cpp create mode 100644 source/fs/fsfile.c create mode 100644 source/fs/zip.cpp create mode 100644 source/ldn.cpp create mode 100644 source/threads.cpp create mode 100644 source/util.cpp diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..b8a22bf3c9622030cc3d3cbc592be654b678751a GIT binary patch literal 8196 zcmeHM&1(}u6n~SX&6ZkP@Pncr7Svm{t(8LY64QtW52EpdQl-symuBf^CuEbRSSq0h zQ4sMW2!eltz4(FPMN#jfc-22Z4<38cHy>$db`$g@md?P;o6LK^dB6O!yTjW60LeGp zae!d}u&^^b)Q>}l#{8@&T1u`QMN1G5PzEnp94{`=N;MH}7K{Q$0i%FXz$jo8_#YI& zGn+N5%egPSW;6;I1$LzZ?D=40XErBoOIZHsz=4+lXfwFX8_ux~;22xloU|=rITZI4 z)dP`GB1;S+;OMtmINF@FEnx*5h=2o;nTf1W2+xiaKVF;mKlzX>RvVX=B*2lS43_FU!mLC zJ4a~wVV>pBV*X`_P=Cr;=o|)Sk`XG8r>_rhet*I>i0z|t=^mx?u^FEpaG-&T1mLP% z$jY0Gx>x1#=;!+JJ%jvOQ1B{;&Jk*Ua+BxJV(t*t2#`fWk0tiNk430FHpthRgRi6> z+CD0m?olcqAf5Ou7i(ca!$su54x=>k^ubY;f*%{R+a8sjcjbQjij_E(Rnn`nA*lzr zDc-FSUMCHxp+cV1jH>c(eBo3BKdO(7eIcoIrl&V+WvzbeMzKtr#d@jUi1MY{Ec*bu|?sq`mDaWp#!U{V(L&%LLk7?s zn!uzn8276(uTOvceD58<2(&#^vAe~nk^}jMX>=a3pP%_nGYafL1=51^FsuL1c7OlB z1HYM}Y!omG{H+2cQz#bl7~MXk<3Ltx+t}x^v&Q0D!g2@>yc|c%%W3b(1%3mWmR}73 literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/Main.cpp.685062F8D32EB8FC.idx b/.cache/clangd/index/Main.cpp.685062F8D32EB8FC.idx new file mode 100644 index 0000000000000000000000000000000000000000..0da004a1f6a79529f13b1fc5fdcdd233f9bdb607 GIT binary patch literal 1604 zcmZva3rtg27{_nzp)Kugdt0Eiw55d>+ERHd-~+bEz%dzu$apO%P!OevQpQ7ZXhg&j z<)tGSU`!nZwh2+0!axI(No77zgdjK+0)hdYU=$Ex2bR-h$xd>=-1GbY@AtUp?C|sT z-AutSZ;f9@Qe0{@z%YyhA6;t7-ZBz~Es!xRqr9;=D0x6i+?n_4ElZ2&t1FgNS3jO9 zwBHf@YclWHZQr(|&;M>o-c_!Q*r^JSdWS8(S-x}7>kP>WGrO0^q0~1_)YWBKaW-A@ z%~O7G{Gl!L&zr)sK!%93F59o9WAOJ{X#~(`%tfEt)U5UdkMbkA33P?y>i3 zdm{hxW1m0I+wU6i|Ep|sIpy84_s#Lx)+WXCAVC^ zVm{VsADFMLt(1$!mBE9hfe|k@etS4{sK*`W)>iA9>h{0x&%SXWvbSK$NH<$?WNh~S zj{|dc9haXNO$N4;72dlKzbJF#Nj5B}3-2%b*}S^habux@D}S|gD5@rLyx`V4)3!m) z>48Rlm$++Gqo2=oN$uGd`gRi`jV{G>nMpBO@T8_*biQUk9i}re8w`^H2H>p*sH`q0 z^B(@lbV@jm$)PL6~ge`s9~F$=JSC`sW3{X$4<>t={8fCU|u zv`grcIh$4ZK+FbgL&>Gda~Gcuk9`3#128x!N!dM9;deFp+aOjdlp9e=dfdC8wS^l3 zAr=9VVH_lr=>K~gAYQo&=$JESceNCHvZ7!TXNof&eQYA=@7FXp$3v{5s07IEd7zS> zo93Acv4gdP9da)@Hqd8PY@GaLX6z&_utKMPo3(7 z*j46gi`+?R)G|ph(nwN|)>qpRSN7(U^yD%i}_XY1idPqQ~G*=1`c6ck+2fKIo zLN^mI4Gk_wJ&4G6mOO*lVXcEBawm9~WZp}Ncn&cg&<#ht*!!_Kx4-ix#45GwQ{=9& z(A?(sD8?b?1HR!8E~c-W4oPpDgIGfGkpMzYk(8nZG8SZtC;yRsEYgyc0ilOZ-`am>tl1cgeY8`F${3D<(nmk3Cf*gwhK BG6ett literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/MainApplication.cpp.79A72745C41D6043.idx b/.cache/clangd/index/MainApplication.cpp.79A72745C41D6043.idx new file mode 100644 index 0000000000000000000000000000000000000000..3c7e1ab39e973d7f7786ff36184273ee0202431e GIT binary patch literal 822 zcmWIYbaT^VW?*nm@vO*AElFfyU|d!(yY4O zf-m$G^RA{9E<3%#kL(Ryx7SlgX8qItfPc1r-malnWNbb>DBWbe**dD9L4d((MkCXg zH7oPdH&603+A<|ev-#D%J#5GO8gi5qHr}g15HS4K7)*U4~y3ZXmybw3h{x`p-B;(qKx|j@I zXZt;@mcfowKOa`toBHJS316xGn-)ijnr>mQEZ1K!h1vC-qhN+`R?YLhre1Pt4>oJP z5A%Hgu`yO@x{_Xo!s&TTc{A3&T4MQ7?8=Fp;H}{=Lk`LuPHa8pb^X!X*wWy;937t5 z*Ph;d^X=Xr{LJM~_iYjHdA9r4nd{o_+aIp_VkaE+lJi*M?D~Ky-yazre{``nX{Bqj z&RN0uZLd??*Ok;xv|0G#$lMK|^)H9rwQtzyA=$I2WA4S)oAU16InO>j@3;`O$)0ge zQ~AN-%G@M7V0>}uGA*b-Q{pJVq@d2A#3{w8pvcF|C(OVBlmh~%Orv$>zLL9n8C2C6 zl-NbtWxxbPl7XQpHLZ9rkn_Rq(1d`qe$0$KO5B>S!=y?^~JX3Gl53(X!Gd7RP77!%n#gtaVy9s8E$o$FwAHs zF0lLV=~^6Ws=MFIqr}C*#Sc@IC&zKZ%&6=p$VgcpO_(sy7deR_9~BoR7wdxV-i4JmI{bZUS6=D^-{iXql!&b!^8cjhYGd~!y_SygoV^f2clTf-^_3sD&^ zkITuI9Nj%E4!x^+)1b0RwT1P5Oz}VYcPoshnccbi%Bsj{4dYC`f`rvtDcj3^wnhG# z8+fJdhpnaE@7KqL(x3b-5j!{C>i=80V>KN%48@hXNppcN`_EgGbm34c7dsOpCj&DF z7l$O6VBiGGF)%PPGb)JYp2_8Am*ZpN;9_7Fk`ht_6AT<+1q@ueObhDIlsF17F>x`l zb4qb4F!S;93B#nDx0G-NE-`*6#l*-3(ZI|t&8-HLwyO+i_Z8BCamnVXMW62>#lJ5^y`^7aHH6EhD7k0?yIu{-L|{{6RZG4g$ft01vHn+x>pf#SoJogyqu%mSi9^*MJ)^Yron8-_+?vqxEbN4*iKYvcZES^c*_*q}8-2Hx+|GsQe_@#xn zzs`8H+e1-v*E}DI=RYqWVo8wqV&&}K)=q)*{%>slKM%ZkN^f`l#*dyK!XvXh zH@%tneEw>OdXL!)SI_l7a%`H{p@P!0NpdGL89Xms*?eNs$@RxI`f5|I+OIU|GGQpL z%uU(_jN1zzE=AtbIT$Ozq{+yj#>L4c2qu6sU~uyAY?Cv76X)q`?-{w` zJ50AL1BI0|lyqQ*+*YfNIk+Pt5GZUeWG)YL5iHOcnNR}j!_DtK%?EqRfU1>6lqFz> z%&l7XD`RF=Co|A&J0)kBl|WvQQaFOArl6(@|uqsAr0r37;wkY~VU0pne5dU{vw%B9&ry@sNOQZT)+ z2xjEM8nHlOP^`k-wLE<1s;$QlE(Cf-UtV7cW(bg{sjq{?Gt@VM@n8YZ%n6SBd%6~f zn(FTN0$sslC=64?qh=vyAq(SmIx$S}%Y1hZ=u{m(9R*l8!f2qIKxrjUj^l)xQQ1ux z4fMStr=loK70^wb`l2u+ul=wrl33vV3}~c*uz@N}m}||4vo^E-frR-v_yu5LrT*z_ z*^zsiZ-Bx|dP;^cBVoFL4gjS_n8gf5sX2+D5GpQ8E(RxVcnW7=R{P@}^I{Tvz)~h< zRR(zcGB70PrsOCB^~lQ0urTxT@yLnt3yDdH3$k-?a&vLAv5E*w3rH$TG08Ik0Blq7 A+W-In literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/TitlesLayout.hpp.75FC133FF2EF41D2.idx b/.cache/clangd/index/TitlesLayout.hpp.75FC133FF2EF41D2.idx new file mode 100644 index 0000000000000000000000000000000000000000..0416f1dc87f34542850a2441d8b82f30677cdf50 GIT binary patch literal 624 zcmWIYbaTsKVqkDi@vO*AElFfyU|)?o7jsF%d=Ocnci?VI zU|OWYBc|=wlNlZvM!Hz6emA*zw@jRSaiUfu7V_X_-%9ZI?Hoc_DrZ^!eP>{s9Z zir$%8^L_?S4j7??TaIW)lp0|!tJ2&5FZ zbMA`&cujzbkqaWi%)`qg4wKH4<2YevRCbe{iHVbenU#xG3`{U^LeyGlDDTeVTK8Fi zi5;e!kC#sbrn@LLt@t%irNw7&>l?4cG8uW8Sv6SoV1~}+WVdQ$i0uXn^I7sa!wg$% zy>#`(w&gP!nV1DQ1Vmw~mxu3Mwe|SHh0H+JqI?oC)j*y+pAr&JolgtKgZZ723+!i@ zNiaV%a)SK|6Nb@1)gX`F)3rF%RCm9(u{-L|{{6RZ0bL1l4#eX?KS8|?Gz8>jm}Z8e x)SN_6YJmBf0WMQqlw7P2lwo2{ZJfD(#YqDzW;Pa922k>W0yY?ffq@ml1OSiPv~B4Aww_iaA>+-OiI%6lklI&z`m< zYu2etaUo^=+E>>u-I4W9hiCKd6*C+Sa?JDNbF^P=n>6={k~mNM|7J@ACI^NY8SFh9 z)SFAqXHOLl+vvP*YS*s%?_xHUEG26jo|aXA-+WVNU(R+Wsh`S;K9|CErMgT!nw$TW z)o-7;J7?}rkBIfLW;7>&ypU6%H&t>u*kKZ#lm6$jvGy8Pm3tc1F>Ra~u9HT(Gt4 z_e0wiGy8V+v>yl&;VWGv*bl*2HQ*vuzqS?SsNT18qOp%d)Mbm zv)%hd*FPu-fA;@2H{aRvZ?n&9FVC|+8Gn^Ib=?`(Um+*!3uK#q^z1odIITu1zd%H| zcGo(OE!Q5#oLc_7EOgV{DeGQ!&rXk@_p9cj>*9#eznA~aw0h(3$o;98U-f&=^UsTC zHava8uWwk*#ZX+Cn^Xggw>(|FxS5N^IK`M0G#OOc1=(ekc{q54890D)K%leI=T_v5 zk9q=3>Og5pF-civK3+Z%m~{4!`oik@;raqh@<3@(Nl^`D0RaJdn6y)-(YkV9$=$pR zY8nvpR9R(Ml_5+9hN9H8;wC198yLC34%ipqnIE|Q;@1DXHAxo^rE)RysIqdiO2G^> zc6Gm&e)AR&P*_k=&=6+Wdq%GK4%6+*Kw%Db4sDpfU>*RP4RSrqY?#A=!XQ_}gqe$~ ztt}5fvj-X?$|A}QQ)Thl+xo^Uu}mf&Rdz*ob(q;eo+i6Kj5oJx*{_V5Rh=wA2iS5r z!Q2Jp1#*NTcwE|C1_&OXJf8}THAN-H$)~dInG!*-clQp59fva%nbDSXxwC3Z{B__|8>Zj~`sf3^ZF#QV}K$F*jbS`km;n95&cecOps4d0p^}-KP-zR7I;4c z3QGw~slrv)6wY_!W_bk^Ruoc{g9)pD`dW76p5_~%Fo!OO0nCu1)SN_6G!z#l7lV_h z5-d^}m{pxNPnEI1`P7w3MTr3(Squ!xxhXk{KxH!W(#%Xeyxg)Pe1f9lVghXJ99*0n QtSrJpQv4E%l8kZ;0A5_b0{{R3 literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/UsersLayout.hpp.1712702588294560.idx b/.cache/clangd/index/UsersLayout.hpp.1712702588294560.idx new file mode 100644 index 0000000000000000000000000000000000000000..66a84d75186065da61697f49be7d25b7a945e4c0 GIT binary patch literal 736 zcmWIYbaT7G#K7R3;#rZKT9U}Zz`!5~#Kk2=ne9OOI}lgQ>Fqnnb;v-#<$L$8?=iL> z3%eFHUEg-|k<%Ss&uuU6&;GVxuO<)k=LZK5%sX{1NJ(>TMb#nG;8U^xgR~6_71}$r zoio)w%_?#8HRCL>M_x^9K3od!BS>KyI zCpx=0NAa}P1c^P2JLJQEGZa_mChY>cB~Mo`ZsuY!PBA7XP9PTun0YvOgc&#>9G#Uu zw<2eJ)DvK0gGux8@`=EtvwzeVR?iRD7hqz9Nec)F$it+$wUzIi-zbmdW8&guVCInL z&;S!K>3g~shnni{_cAfDLu_MUX69n%VSpO7FTgWDaQnrr>`Y7?49u)ttfF87CS8=8 zR;bmc?c*B@(4^A<`JMU$OAB8=AvqA z%frv?8F`omI0X1%s$l+N?~FyXnJ>{g8ovE4vnK1)7l zmp)1cinbKvF-IJ2OJ;IhGnahqU5mu*NkCT{y~>tQx&)BEJT-+AwO z-&?pjJG(~$U@zTVTUA!GClCPS?CY%IE2=~QYXbmkd)-I#9AB-Who5ZWlgjk{d%Y>A z4L7rQziPjDzUW5lm9~s-m)GN-zk16xytQ+lpp5TQOV;Q+Qv)et(j>7Ve5^LQ)=lY!E`~!3MV%^Li*Y^D!P~JF}b|s&f!8Txx%JKYp^bEfE4@YMa^?#d4QG%Q`cv~-#5Omio{;BnlrAG`R;9ZOwl{^zE3 z@o~+ebv*q3@QmeLydwWCSHV12HIq5qV$m#Qc7|=aJ3hItGC1}Po9$z1L32=~e!aIN zJ@?xaJ-W_;w%*czyyfzg`^x!}?cXeaG4fHPb%AcjaF zAt8Q2+$HNgO*bY|h(>{iXr2+Iyf`;B!p|jB(4jy}v}z!-ApZ%D_QA*hPA=QUVnfnX z4|17Y@zf-A?HF1!F0$>Spuqd1NEExDIf#j67HeL<-f&j@N)3f56sU<>2P9PNAE0*c zKD2g1+(bc*0u@n30Fegx1s&d?5B_p)=%b)VK@5pu0({6_J!8_MhOdVyC{dscRWggK zf+5n#JX~%_%Xo8Z>QxF_6c~vy8VC*ak7zyT;r4e=j8cd|fi6U+@{LF|u@kPJ{&HmN zcdsu}P@y22M6(g-;kF@suyB)gnL;=UOvJ>ZA|n3?;LG+p?>&>cB-EES?w4}PKqXmu z6i%g3MXjucQ|r~SE1Tp@Dw7rmVn;;8*9|-lo58Tq2*lV2hJ_v=#uhLvq>mWGWmpIm zF&bf5h!QcnWmpIhF~-NR5F6s}74dl|UDbUe$|)igT6`Cx2agmP+&Iu%E; ztBvZH{=d>1v?er7IbEPGcqKwkuhYliR&bwexKIfkj)h=YC<0((^-cN1geem zdHRzT!3%b>OcE$y-Ya>1(nTTH-7g;QnDVcB?GE1D^|o)`oY`Q!reelk{nV?xM{P?u`!O-InGTQ+`{2bXEWMJWtWg%EdqbaqEr1#h>hMJzMs9%csI^>#kMH zyi%Whr_!YA;=-#!41SKk8P>hoqU3L@arf}UrB!U*>kGDMPC8t|ShCjFi&;HmlGCgW za<9D)|LHgL`&t&XzpEpeZ@%Fs^@LA_IUEA(B%+JYhtIyN2Q;B5HLZ9qkOOlIBPZAm*}ZFi|G)aj8Ri0@Fvw<@@Mkrt zTTfSg+Qi7iD=Z)^39|*}9H45DGhnJ=(kxtH%VEMiyrL|k>@XX6c*O+8L|`WH@QRCw ti^CknP?VaJ2y$_8QF5^|kY?gt`}C$L+s5jXO#FNd{2(a^;Da$37yu=U)HwhE literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/const.h.BA34DD522C225A5C.idx b/.cache/clangd/index/const.h.BA34DD522C225A5C.idx new file mode 100644 index 0000000000000000000000000000000000000000..436dc3f0752bdfd7520cac7e84554166a1e2e65a GIT binary patch literal 184 zcmWIYbaUIlz`)>~;#rZKT9U{DWD5duaY<389gsEx;)*%R9;eTEZoPEXS~m8`g&gVKX+bR@8anM28K0tg385}xk*3+7>ZKU ziuHiBv8(&F^qaSM7`Yf3I2a^AQXnw5YT2)hnN^)YVMY!{UWgz_S56{`U0jr0%nhWO Q82hg?B{bBo+Q`5F0CA)?)c^nh literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/data.cpp.92E1D4C612A67155.idx b/.cache/clangd/index/data.cpp.92E1D4C612A67155.idx new file mode 100644 index 0000000000000000000000000000000000000000..f4b842120f5885d2b3669a65a3a30759d8808ea2 GIT binary patch literal 6758 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 literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/data.h.FB9692DD59DD0CA9.idx b/.cache/clangd/index/data.h.FB9692DD59DD0CA9.idx new file mode 100644 index 0000000000000000000000000000000000000000..f72c8d30dc07e647c8ae6e3ab56434a3d155bdc4 GIT binary patch literal 3524 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 literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/dir.h.8134312F1E0EEB8F.idx b/.cache/clangd/index/dir.h.8134312F1E0EEB8F.idx new file mode 100644 index 0000000000000000000000000000000000000000..7daac4ae8a98ea8869c8c66669a8e4813f760764 GIT binary patch literal 2302 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 D24zpX literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/elm_ProgressBar.hpp.5BE7F064B955686E.idx b/.cache/clangd/index/elm_ProgressBar.hpp.5BE7F064B955686E.idx new file mode 100644 index 0000000000000000000000000000000000000000..ccf5285a153d1ddbcdb896247dab9b3db0c3e911 GIT binary patch literal 3448 zcmY*b3sh9s6@BjlBI6a_FwC1b!`%72ad7yih{&%8Q1`B&FUvcXh^iNelWyOOd4xjj5LxOi!Ni(P-7%3)mmGdV7sEV=e_nYl(pDvy}jQ( z@1Aq+*>_6Z`T1+7bKJa@ZePQymYP70 ze|AgB!87X)ADE}Bcze?qSGKr&JXtroYkGcgzeR7_7d)#d()-Q+9R+u*zS*-WCH=&^ zSH|uHXxe^Qw(ZOFNqNJ6^Gv(_l=)-B+q+3&-*JuYNdL`k&X4S} z=gxzdzkOsp`OmJ47sT}Sals#4e=cLD@8@0f^S36-Xa3cYSmPPHIn(_4v|sa07yr1_ zyRl(;78Iub;vvt-hNJ+2OqDsd+O*oG0yh=v1%C?yKF`{|>!W~BVg;G$m`Mec|N6p{ zPYxA5Lj|G-d4;qhN(GdcC-e^Ps@_laBmiW+L!YJs%6+NlKMj21h9Hm-kV{RaP8Co- zoPM^i-By(lN^Bro!YvjRP|i&ad(?NVC@GkP+c_4l3D>K@g{T|n8UIpD`usy_uC!1R z1?!E1QL6&3k2@GMTHLZ|oRH}@HD_tHKr|rd8S|o5K>4$Cbze+-U*i>s0J2Z(lT<*t(SCc` zg^vRsrSap@k<{Ze_bbD9BEOGg1YVD}_UC z#pTa-3M3fhOhcwk1(YjBn@e{aPJ$c;vRCptR6yCe{rPPNu70#NlsG^(>&&7GDA&$E zYIRMm-7XNVtoDIpt=d*2%5Mz6-eN58-4RNhuv!u%tqLeVeDCrft~aLc5=aEd*;2M$ z1(b8%Yafex{K0`x5(%<3+$yPna&KzFywSVAdrKfeAlFOvGgLr1Zr_Q0Z`A+vWGI;d zvPm#$RY1AWRQbZ1;hvKMF@c;YC7M-0c{pipK5HBr5Qq`vXervP0?IRv9gE%ByXlNT zLP0K<%A-|4nO3aH_|p;lpg?pW7fZ!4Dxh4L)zv@#3+p+7h*-5UZJ8P6%g4C!^|tz< zP-21AkwTPJHYkw8w9(rhZA{AG9Y-kqmc6MyG70xRRlpP*%t4W}q`s=5cu*!{$=f64R21hZI-9R~7TY@aQ{4qxucf z@YPXX{(9o8=s&PpF&})bG3g%>HA@PtQz?sJ5i%M9WqPKUF*IcsYSE%aQD&u9EuK%x z@^pC;S^#D4$K12A3zQYi(dWJ1sjBb&Y{>ThV;#D`(!o`bc5W2O+ded&nsq$Z^KLN@^knS zWeF_7Qu)6_L)k2GmH|fx9Tn=S*eM3U0>YjY8$}x8{)U$?O{DdH=BX>WftQL2W#QKF ziC+Hy9?^E;6N=|zEG!1liq|5IHVd@ku}EX}fmXZ~X|z?K6;DMP?G$LmOOZw!1zPb? zr14||t#~KWXqzwxif1AX$-TnMdnRf?*uIgCaB+LP8vEkRc zLxR&gxo2L4j`}KmwU{@$F(0D3Fn$$X7#giuFw(FYpS;oE=qMIt!Q?565n~K!g6Pwb zq+-$-;FssCe-i)Izh5PREFwK31N$Dx^xxHI;^3SgIJ#`kz^XkwVGimr;@UTtynEpI z;BR{aAOovU#th(Twl8JU(-Xc0_=MvIX()FAMuIdx;pNXJ)pQ|S=)j&+Rw9;|apH`7 zU1gaMpFa{#nM9>9EDU8vY7E19pv*)~VR(H|7D*$+(30U}7TNBvnH(!8OnOR{GbTN` z5%I?nY!v|NT|Oap>6awsI%q+t_xXmAe>eJU2j3cJk&`o|;;SI9Ao|EO}>_gU8tj z$}7m;v9Bth$0LUB%3(y0E7O;s8uu)Z$y9!NXK_zz={S$QEcd>)qVCb(AMm&*Z}SST XLD|08wICu1;Vpc$BmkAzfZ zQBWbyN2b%LgUy*a7lRKn3F-zuw#5aFPBbpdaGQor36o$ZamT~`z0I2RZ_fYa{O3FW z|9z(czt2~t?438muhp{+l3URokP zIq908=iOTLDY@L&v_U*1so8Rc(HgeV52?8 zlDjx|SHwRb**jV;T9gBWYfASzH=J*%&>uXNKYaYCeOu$z*L!dEjYd7`A8KtHOgle# zE%M~1qdm?E^D|5Dof&MGrLz}f|8AaHUsSuc`kgNk$4weZ8eQIYc$|Qc$PvHApTGha zMej*J`{rgPu4rBpDWDh%7s`b;767i8Gi~Pbt^F|q3Zrm}loHPZ!1sE)@}BqB>-ES& zVNno`EC9^?7V*n$>sf<L5rwIsCI8)9{U;*G?_XK&bOYjM39ECHa3>ymok1uj}CwFe} z>5-Ab7L&!y0>F;?YjyE=`2rE?D6C+`%mTojvF`c@tFjgeD4fDJ$u@xnfYXm`bd@ar zdWjxM6qW?Z$O6FU+XvRQwFJur6iwk=Id=*R05`_06yhD{+Vp5Vg=IlDvHr4aRUW?ciXO>yw^=Y7Spb;i zTyuSVuHiu>(wRA8iZ&4zIBFL9;R#>(W5rF+zpal1WT5-qvU?&6u)igF!{E1jB1Qxh zL1CxloWKIWX6f#Ol=pQ{1*E62Lv~DL0pOal@>*ZGrdd9EOt2~`&?-$cp{i-nC`~hg zs%g+>SoD}M)ifr`E?(Kq!-O$OQj)B|8>P-@H(YKfqz`^vNamWQWgHt|a1%UX-_8>$^yM{;;Xtk`OS@q>A28Ri_d3|xs4 zWRB4Yp5T>}FNF;PHRD;5)jT znNHmeextmY*)(4Jcx8VGuT&+~3Ua|DT}+q2P0&DEnHf?oaX=S2BgidjqKykI4wQo+ zK3~vr?9`BB@8~^dA$i=#^lo zz?E`jwpUA7TAd5MqaU6SF)?Ga0UVBrh(!aq022vI251x}GL{WM36nS+X8`rlo=;Tb zVNP_Fq_{&?uPW0+R{2Un$f{DQ)>bxR6JcJMIP8we;C@V;#3^c)bKBjM!E%_SkQ7my zk!Ol08Safq2FVb$-efv6UC1#CmZeai$59l9Owp}G<#yzG_;JS+0&|~;Y6BdPpX=(DXS_er^nu3b|5iuW~ZG8 zDTe3GnYE*BnU4qJ;J%mSs+`_BUxvGqhh{Im{nuLuGu|BLVKR$q50zFtAAH6Gr`np* ZT8W;9NblyBKlg4gyTzM06Wp5P{sX?o=C1$% literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/elm_TextBlock.hpp.B8CCDCBE3879D2C2.idx b/.cache/clangd/index/elm_TextBlock.hpp.B8CCDCBE3879D2C2.idx new file mode 100644 index 0000000000000000000000000000000000000000..c35e70003a85390f6a5fc1348d4ed810116ab691 GIT binary patch literal 2184 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 V%kFzeZZYw4GjPM~VPN1zFac>6YqbCX literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/file.cpp.5237F76D2447B003.idx b/.cache/clangd/index/file.cpp.5237F76D2447B003.idx new file mode 100644 index 0000000000000000000000000000000000000000..a0e56d544b2bf32224b9474fca139d7620b073f6 GIT binary patch literal 5404 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 literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/file.h.ECED60B58854FB92.idx b/.cache/clangd/index/file.h.ECED60B58854FB92.idx new file mode 100644 index 0000000000000000000000000000000000000000..18e999afb9bf0a34e6ca881a22e30dc607a76358 GIT binary patch literal 2402 zcmYk72~ZPP7{^~05H>8Z2}ihMIF!YR+>%f(MFc5W6cs3_MHH(XiUA~4s)$;xXf0Hk z0fj0aP!M!Rg$`B`wV;lba>+G91*}D+6%-KX*!qTt&`Ax1l&8+GS{L8#XwVkYw8SJ{OE9Gz?Oqn9b)?en zNki1ifuV@ty!|P|=N3HK-g}}@x#Lwt%igga-#u!&QIp#_l-(f9SGZY)pQkcHSIeJW z>3lhuE3Vj@J>9m>$^WZwpV|8O)}JoAFx@vY?35qi8BlO9O-)!ZGtP{D{Y@;&cSw9X zF`(gow9Bj{**k}9mW2%#^@#pcpIQ|>HaqnATuZ}^|N zzZKR#cTTWMy;T@6e9?7n*C~(qzthE*&ujizU+)@}Q7sxsSQ%cFQJ>Vh#bWffM&%1S zvoF`_vO{L-<*TQ4UX@BRD+*nLV}s)2<8)TlFO5Fj{Ik_cpZx1(%}QdsUXET$$bc|* zsIdIietm$@2zuB#juB!fP7i$DNCzcnO<{4=!4_H23Ggzf9-j?-x zB(tSRe5U_Py}W!gQGTF@S#^H(r9(DPa=SD1O!syg{4Q7;vj0(OmtXS_fr6;-Lw{M4 z_fB)Xe9zKa-eUd1nB?@tm|JQH8NKV_O(K6i5#ei(UkUs$48`amE!B_v3*Ro@wWZfk zm+-VljBK{diZkGLk6AIJJ&%4-6(m5j6xm@R23O7 z(o29yZ5~=|iUS_|1tqRlSOn69H|%dOus4AX=9D{VJftqfP)H2Z7`Z7tVJVxQjRg`4!_iK{x+;S4g4x zkZ(X57$Q=iROKI?5NEWudS0NA0|Z!VThfT62%|;Dc!G!FX(hSJjX1y+0>q@)_(KOR zhrBH68rw@Kl*~ znY5KAT%fqKu`>hiYw2HXv?mH$DP#rBiAWKiUq{`NYi{`o@AN`4q=zQVaCuvStr2G+ ze^a9C=l^_~I!qI8*ew-EMVtY5O4f)?Snu*l3Vj0QJxNbo9uCL3>hO+-+NURV2|3P} z8OzK$1Nn;B&B-<&am?d!`~sM+UU&H&>5&Em#aOCa^50)3Bd6p-Km#D>@j1957rxc_ z9Ml%sk8}E?I;ts#J$rCc45Pys!Y{y`M{<}$3P6r!7H)_JxUtMa4bgx!mRXcRhHi0} zEX7a+0LIZQxDXB4VwuGiq5)SdvzUSmm|~g56N&(wSZ1LF8IZ)CuslK$KoLi?2tqUf zh_668PwD{g1E0eXasfk}%i;&Qa9>zvp#vF^!!nB+$N(CaS-?OBys*q-1u{T|<&Q6P z#C0^kv-rn4+%D})2gC7Fj4)al2R8=9;S*qSgDHSCEVGz_420pGSh7F{vark&1$_Ze zxCjdqM8mmZnS}^s;0G6Bxq%`;4UT4!foMf+!UpzlC|R*FIe=YAS)+R9!2%)M4@;Z( aOM*#IT#J>oI33flmCm!7i{`#}q5lD<^7-`u literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/fs.cpp.2C750D58CF93396A.idx b/.cache/clangd/index/fs.cpp.2C750D58CF93396A.idx new file mode 100644 index 0000000000000000000000000000000000000000..fb70b75f9a7651766e36129d6a3e274329fa6d9f GIT binary patch literal 10148 zcmY*f2V7J~6MwUN%DwX)a2^LoFUK87S5cZ3)aZ#%v4aMpsIkXb5==eHe@9gfZLkINhm*v565fcU^ z%$PWLoQ&f*75O)3?(8XjF~=409G8$)IAY8fw?c)A!F6W>rVpBMAgroQ+xlz1`N6go z`+9Yr`$dXd`LZF=?cGBMT%Gm)ZEn_{g@*oLgHK7*>vXHWTPFEuHwRxmaC+aS-f=nF z9>M+l^?#XE^`LU~Z}ayFKNo9VQ+}9y@R$059cIj^&GcFuHR#WQ4Pkrx{Nr|hw^@`B zIVGd>*fAR_WRXW3?CV}e-P~|#cWp^@^thk_7Izx@Tbr!YB^PI{%extT{Cby|9Z#nIc5t3Hx>2#U zD1DOklCxL7aW`H#JvKLM=Ca>L1@3*^=f23?*w!`*9ILh_`Yb2glt zJ-Yv_uy0rI(rycgJ=^YYKJIe$oa^baWeKw;4_L6@X8N+aeO<3*%(WXmtL~BGefI{- z>3{2M!{5Yy^;g!&p@B{XFV@y?P&_VJUE!h?qMaw@?8DoX`)&@uKlSp{hz?U%{S|&M zX6?;WL8Cki12Uey8`R{LcsAkW_MndQ^5?uyYlbE9F^!j2oWB>g>Cu_B6APo(e}7h0 zR*!T8L(luY8rv=PrbpX0Z>RTFt$jU0H92GG6xp_Q)gwzrUwHdRx~sAd{k{o}>*Rb* zTfV8|ls(3~*UEf7`N*{cQvCxyT=U%D@YMQ9k>h@gYl}a*pwK2ARaYEaw0`&Y{kL~k zbUb%KINmE~9zPVru;~s*i|m)o*yJ#@bj|0L9k#`XCMv>K+|J+SbGY8!zl&F*;+Id` zOlwN-cWA2F^`mCTa?y`dr|JR<#!b06r(bcsy0T07`E$iZ#nvm9-i}VH8I|2(#~QQTsa_yWFniz1d64m_}~S{2Ak4lhu^B^oQujNndaR*LNrd1`nTZwCT5jEFRYvKj1+dZpf;vjystGAvGbP4Pac`36}WyxA&;cEpE<`Ac2b^B5yJO z7OMt!=ew&oUL`a6GZ5ZdpX{|pvt_Kn^(P_?z&C)i(Vcg9=6H467MJJ0j61QWyLqg@ zjU*!Gyt&e-;Wf&S{(OwdqQ9=}@ZR}mijteaabjC_Tg}H`Bu#z%ncFpIr1-%oeyF zL}V~O*v6>kwM4*1(IRjpZpemftN+MVa-R}21y{lQ<1cFF<*)t2r+xBZyTFYh{nfm> zz0sPtZqM_g%|8AAwmK|u!- z*z)_S(mS`5+&E&3!b)NN@fWqDgF{?wwtj4tz=f0M5)ewj;olD`()?lQjn|`QJrcM9 zMC3UL&xuIO2NijD@%Z?YZwg-sTr9C;GC$eI=)^mbh-l<3FI@@m1~my> zw8>e_zrvOSyYbyD>C6m-*%K$t`Nf&7e^C6p_+3_1q~9O&dl6mrq@iWW(+1=Djj8@M z5y(sstHH4v^sP)3YapZsdNX_<9PdlplaV?Z*;CDen2prg$i8)g#idxa6x+5Y0x=tV zW#dj12S1*%SGD#y#)5bQ+1)^%tf=m!|K$im%tt1w6!H^667+#L-mZMPSPd;+aM?I-O z>;Jsz?>0bTL58*Svg=NV-SwGpeW6OUAo_1X+$|W-;`IT7KR_7Mw-t5Yih5Cff>?n9 zD^L)1o90wve@jB89*iEgDvJNkvpo{Tq4J@YlzM`A7vy)L75iNq9Aj0q)g4ooH{#=T!U5g-&00dj$3*ddV_bvP__E=$6NfOIfXUA`Ovlk)7zUFK2$8=+*VT z3!!C4Wk(nKwIFtO>)eH*ZJ^u+F3g%ja3}m2-Mxi^5EyrWs`N+LRN{qdYyy*A5zoo^*7F`n|#Jb1Z$x*VSOChE6mHA>)U9 zX!l^2sbRb@-ioGxjUInh+{(M*OTKQ#hGrZ@H#ho8B0o$RX2oKC7KF24#jJk}!eg+a z!zljU4{3-W?{)m+-O#QfgaCD5R|n3m`Ad8aiq~L4cS@%bO;0=cKMy72Wq~0}x+E4O zyTvGo#isy?1!x+Lk02HzT_K}zW9h@n0jExMCnH9-i?pUwDu|~*ehSnS$Gr$ioOP$d zBvuL?OCh*5_lh?`aT8Q@e{{RwBX(i8$R0$n5gQtD*VfEOA{N?=jWkl3!pfd2oAP^* zQ1(*x($g8~tx8Or=DDqR8$o=Igy%>_*Onl@MZ#O8YTY)(RoHSB*3iWuh-KKa3~OkL z5yU6h>It@`bPjLo`o9Mmw|bND5@m@3oe|fDxJ3Js&^}~5FQu0oHA4`6+U( z?IDPVk?t_+L-FR5*VhmKySvy{5ZzR6l1$*O@|K`Zs!kFVq6(3q-m2abv>f>5EQ3`4 znz1x#l`6_f5I2C+2B~Ko!F40(slkGn2~L^P_AGGClD6l7Q;xJf7hH3t?Rj962lh-~ z9`wqCJ`CrBJ|8+Tyc_hprMM8pLKw>07a+|7WXmGI7-<$u@p7bDF2!j`orY|f{Ay&o z8aXnYj%?GVI0tESkOQ3uvg4q^IcONexyUJ(&9oryKu$ZPI3L;NBPS-m2Wj_6_3c4} z_ek~aMNWIA{r4lM{Zd?jv<1@s1!zD48pQM;Mox#N@`cE$kl}V0ipyUrW=4@b;i7cW zF+#5g<$BPuu%;ko3evH#Y(vUzNJobm5c1`L>I3>=gwX3z`}N44=7q+j4dpij&`8oy z2=YR(q#A?LKfFpg{KZI;{Owit5+dqUItlVo`AAS_Rc8qbRfS4WxGG$NRsp|?(Rt+7 zI}<<1lcI^2wIHtrE0#8E!MPT^8Eyo5BUsTiN|F@l8=)h`%N)PViod&JELopFg6v1O za0T%vaQF%QsC%>n*(6)8D>Q@u;_j>u%wGH{(U8zR;S(w^kSjyq>oAz6NqU_j{Y`fn z+PnIoQ%e7Gk2n&}4_NjAx1-rIBlU6UKQX;NBWllM`FU)~(p)u`S7S?>=JY)#%WH*6 zpOGV32FNm?9kbvb$nSv#-FgIZBevX#ZD{^<@oUgu$$mDDjF1kpbg*L`*Mj|8lJx(* zIRtjCy7{S7^EfiI!OCD)MyXJ@(5?(6sgfjFWC2(&057US5WffI_u$I#Dx_S6Tp9g- zK*}GGE2ZCyn2qL@YaGUtup9;XQBcy3+n1&P=^AAiPmH#;vvp*nyV|+7q6Fg*<@lgq z#*>ho2J_S4L3<10Wo&*Kd$3qO#O)tqZyHN_r9_JVTqOl@jPDqKdSe{7B)lSC%oI^K<*Q)Z1=Is`lKHhp~reAlJ9IAPOA@fxSoRtV zYwkC7k#qvR8d@``JXpIANT1tK!d(4te`e(rjYn8zj7uZpZ1^GF`eIAH%{i ztfEI^djD>#_|LuDbV`slVg)nfHCDdHYKEJ!tQjk)S%SDw=C)Ag$#AMnnJQCL{OW1< zY0-cFJeQcg30rN#&XnGCy2yev-R|jvtF3HYx$xA=ugL7(K#Cj4oE%-)I=TalVF+jN6aR3J4S z_EdShi#C-Pz9aVU!j`+RfsTJWc0=UY0gIDJ!(osgW=Bf?_SHZAlm1B|Gg1M{3b3Yp z62vA@Hi0!wRm20NEJ4=vwo2tlL|V!jG$u4dV8y>h4BB8il*;SCnq||iSi6dpe3gNEmzuUUY1Al(ksk7B>G-gbG9p08C3 zVyttl2jw-%)_w_HnbPaf^*Z#RqYESup_LF$BO{1aAgcm_;cAdoOK}5)H-M3az8Sb? zl74C3PJ9ot_aHEwiMUK8r$&-PJ(6W1f#EVFD?$pH`t zXX3#OAH|+WaZkFg=Usfc%H5&g7BYi%;9e))YTtn34X9`gep=q9u*v`67Gg>f$cxzi z^5-Ut&{+QBR-(a9W#`WF-b&zCf&;afUa3ejHr34-Cx1oqUy(H}TiqJtQ;e@(%_hsC z774Y;g*n!Ygl6Qz?hk3$G7Y;^$7tnErua|AO%Nvt6I#=sAWo4_Y2R8g66eY0nbVRR zHN1`DV_}XNcprrOpkZ9e#@cM`O2;M4$Ihj!G$M!(u&^wI~GA_s))vpq#9GL zlEv%>w!DFzS+aeGt)5{WjY(5Z)z0IaZtWuaiovQF0;s;_eP^DENjd)m;ZixaEXNK^ z!&7Ya6uVFj-;O=~dR&5R57Cf;tuoj?K{XMYnTn&#qEe8Tf;G)gy{7y9Z+YqRy`;ap z-n}!OhoVJCBVkX@0rK@-(B5VB1gGDe(#iz)gQOu7beRxL$GLby|D?V)3hb-EhiX*(TdJi#jrUc|u%EpB z2(f89w%U&UC?y>eugrR|+`L(3#;1@UM{KCh%{P;u54QLFDPM z<;P@dhZ5w=@Oj+jJPwiKu=BVl!_~M;wY0q&hgGxoL(eLk8Yf;ec@U+Fa-%6?~X z&JX#qkVK%ABoJ_+vqo3}igGZgd3|Z*z@844e;1MdXTbanIMP|!btd+9qlM22QWY?0 z48C-F1<_aID?x#pKnd!m=_WxDnuu1EdF_IsdD*@bWEow8z)KLy4621rwGhm9)C<_` z0#-8G)?l+5tfaIZd1%k&qrcxSCI-vR7sa)EcO{<5xVa?>2NM zp$oaiI_9wIf*|H1T`n?Gs?-J6Z?4?F?NocR4T=e)X%qzUBFHX+IkWa6XfA>?!<7(O z2_q@N1n~vPUVu6C<^^b8NQ+pfkn9vPr&K0ICZsuqoEdIFvIb<%Qgj2-G$3b&Q?V>n zdL~Q7npC!S1@RD;9m3{xZ!%%cA?(cXIV?LTJ;R;Dnsd@LQ-x(!*qlb2EFi3@!p;=W zyOdCtc-5bj^hkBg?i94yM=>aiK}AE`?eD+qY&DLDcDW5)`fvm!M?ikc_-o3eH9j*~p7dsX$8ic1u|WKJ3Cf z>*#T57f3-V4;=D9a@NTQuY74mCJkxRP$#B%HF8>wf*Ia}hVMZ$*+Bb|Za?Zy@y~yF z{q$z*0rDC{l809^gi@CiZ);sUkFPN`+{LQ9*qVlQ)A3pF7Q4Q>L{`T`5FUaJ<5L#a zW?>!8OXP%$g$iuLR>yN}`5fC*MU*FG8d{!{=ro*uIW6_zP`FMG1!s`_jFf>*NN7Us zX-{&^$HGszJ!MR_#R}&Mw#w@y59C4LJeW?M5yai#wHu-sPDf7ZsIN3ij(emlZZFd9 zWh?GZLdq{;o%faz#owyGZ9U|e9w5}Wz=1{JG_p92v}}c}!}jagp@p3Hutg!(QhN{g z3LCZT*ZbvU#p?}vNs&Fw5Y~zc=f}nSp)EH|q{KooR@2`9YxHw7emT67^lrq;Mr@>EZ zp(Zy9Y*vXa7?ta>Sv|I(RQ7Iv?5iUIi)+YKJOH}~>>yz}7PxK3p;U2(?X8OPx@&g` zwKX!04UGs{{vcZ_^=}zCEMw0q)DIG||GtKrZjClg;6ab=-$dJZ*d!%AF%h-hx2^fh zMAUY-KqV!r*=eL?@mPn|>!dG-h1jeRE2;k>E?YNduN9sW|9;2v-=%B14$JGX4Glzd zL^)R&f9M&Z+5(wuflNWCHu1MOe}|9<&xzxDm0t3?6s8K3pw+;y1}$Bt^yE%5gz2G| z=7)Q02FE0Id|FS=*p=X32_2bR4dBxNAv7A~*#|tEp$l8)naDd61=Hkbx=kr=A{)9P z2;vf~Si*{IrrVTVCibASN9tKvaTMFousnBP8t1$3^Oqzn3EBh$HQQ7@bh!?Gl*aVd zN{-E@=VJS4&C#s4E;kk9fz?FGZ|M5M#ET!e2u;m6le^T zpl-%)5)@&Kkf0g}uYut-bam71&RAcyd_`QbQQAlzR+eI)rMNeZ06n!5BDOr7GiP$K zRW5d*f-3i4r+#IlX(U7_Lyl$at(hh%GLWU*(t;)F-0b){ zVdN8wULKCaN2K5Ik_|RS4&scI!5lZ3{Ta#r9K`;NpD|&&D}h~{10C%32KTPM9$tO{ Z{vDiMTy<`)PL4j_ojp57b+QZM{tx82-}V3i literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/fs.h.B7E897F33D9D7EE5.idx b/.cache/clangd/index/fs.h.B7E897F33D9D7EE5.idx new file mode 100644 index 0000000000000000000000000000000000000000..d74e01762a71fb220285e6581c3b03e1356d6a8b GIT binary patch literal 2726 zcmYk72~d;Q7RPT8fe$X21Va`KAt4DMkbo=^3d$bgDN9jCtrS5~E2s!m;XRcO0$Q!? zwFETILj~NGip&UQaYX?u#b*_2eNYr1ZmqHuL+iUA%rSm5$=vzp_nmvrJ@mw9y(LDCArU)d1Ewsq^iubykgU)pC^{p z_{;?(}UfMRuoj<=Xsnzhj;Gnngra{XZT(hI{Ot7A>CJo7pr z6KXEcD?Quxms9;@5j{JxwoNcCB< zAyzk%R>%vup#IOkWquhk^(TCIe{MHxe)7))Vg#&0s7C+_fhGIx2n{d(0mfz|_C zL@RAxMnCChM5%jyd;1(tzhUp}y4w-lBsty_dA%dL`n%rE-GW6)3qx(+8PpASF9`jM zXIkj>d*;Qf2h{&+zn8G*VBGr|Q5ECkysaB|8;5fE>(@$dryf0(6%^du;ri3P2u?`Y z8U=O`IBD)CwcpQrsPoM4ZB)^sqFlY2|rzfMsT zm1=bC<*^AJ=key=V#f_f2lHL+9|ufa|Kak!>md2HU1^LvbHhj z#!$qyzxH@+G#$TM?W!;`Y<~U8xg*+}%rKeRs^TjxI?qa-Z<3_2wQzJ|xF}`ez_9#d~n)Rr777Z|CY7m#Ll?1tFZ@M`W@9r3ZJ#K#bt56@)N5H zK3|e3G#q4gsx+rOW{=g*x+3Z?UA8N{UYizjzM`#CY)}}~@M&U8niZCqMI9e7-!Rtx z%W#}cT@^Fo#Bji)gJ*w~-Riki?pJVZP_tVzIkW8Nel|+a+LXwffl&3{lPiX@w;+t1 z=99}y9;GYg%14y7ISQ39l#GFk&*d-H2pAZ710XY(StE*Vh=Oei(Dk=!dHHc0GmJg~ zfY0O$5M^P3{Al1y-M@d$dvTwI(Odu&l!Bw*Viu!|S2a+?#V8N}7s|y-4+xx0)@+C^ z;9=wpfE(o|)B`%JR{tVS#VU*x07xmR2vL?Zr>n?%8{bsqXYn~kz5sA2j`>uQQ)Lb< zZCd%bHf9?}K>!FSfhD4>Or|5m56@5ka*VYbBS!!vl!RQsDF)7001_W4JngjJbh3l!hs9K}ct zfFtF|qLZ961*9ddOOGNW9sI$drhH+$|9_h2M zDk6JO9xRZEC>y^S?W*ZN_g6!z$>mh z396sIDlx`Np-5=|;R-3m3bEHmrF%&hz>ZjH=VKQL@vu@FC=G|B#7dc=48uLaO1YsN zgSjMqtlaLit(A0YN$eCz3DW%S7To1~`}CKf{I zDO`FY(=!2R7zQK=Jp@383qoYt`XGbxiA)mQ9@*Tgn*op^M^e4 z@sf8$cBkB#Ag3jzB+y5ap0*}Eo?f`pU(=5lERcb6`B9eN;CN+$v6rX2o9jFe|3Xlu6951J literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/fsfile.c.867FA10C150715C4.idx b/.cache/clangd/index/fsfile.c.867FA10C150715C4.idx new file mode 100644 index 0000000000000000000000000000000000000000..4cf7d01337a32ae4380ce638d60eadc71cfe5916 GIT binary patch literal 3438 zcmYjS2~-nV7OgKKse~dSfdBzn0tAArLQ0lE1cU&J$R;Q#14ERewwEt{E&axp-qv?@PHGk~rs3+%-x6WH` zp*o((q^qJvQ=a*nZBPy>fBSat`kAs32e*u%?`2Vo*Nl98`1{-Z!p!jncZf<$i-D-N)vSv9peR8jBu2BoTbx_EQVy=6EA)ez)js`0dGI&<4&zDwo5$*9gx<@n zY2s(*z~u-R)>t{2((d({;{5y4|LG<-En-*r81)Nx}JP{^#tM$JzkXAI-f1R~w;$Nz1`SJ6ma|aV- z2miU}WINNd?2m~&MY~h=(=mCm-*)Uk)XPA@{gJw`@1(9xuD5?W`lpwz1IgPITb`W~ z>>As%pVeh^@G_GdwqL0#w7ITxqCrE z-3NSP?5@h1z!pM+E6tUV@M(MkV;az~kol1CB=!FCrcQMrfdxSVgU&FMnA6S8FeY=( zmm>~8GaZUN`Xq(Gd?CSy;lq=dGE8~19$YjYjJ%qIE*kz=OJFics0NH`z>zFrEa6~G zHp6X^hGHl@R9DtzeT={YAte{j6-dOmSb#Bc;OguF35lUWWW>QBHG%m-f>2*bNG$a& zzl1rPN9j9vyT!Q)4+ty(65{cAjzolu;1Py&Y}Nyor^w7NfYSzPMrX|m24~UiLy#hO zk)QS)($n43Pb&^7^^p2&6D7mk!~C?$l1c7Ke&~3#3RtsZBj>Acs9rqZ-C;O~AcdGv zGXrNIf(*ujwP;0reJrzF%!8y%Mka?Ml`+b+ND_FHHCUW%!XQY7J;PaB9nwT-;)GHo zNOPJwi$c`^s|Iv!9bgTF)xb#?yH*1)3fBNy4PYT0suqTrS4quj1SzJ8S(HTHG;bCq zkq_oWrzDD^MX`_=hyz8@G#E-ODYWBxtGZjHN01S;2qVNM$Yffw5fYRjb1iZmQGe`p z`n7-PXrCM0l5LUgLXnD$iyRP%AS;1IC2&Fb%#)slH4|n&Fn&jlqX{~mAmtpn4qD7v ztb<}iG4l}f-JRzTBClNxgoRnkSjt1o1Q}xxV~P-}1Z*qKB|*!ut#FZm(##Y06d*ka zQi@9jlxAUgn1E6t2~QHB1nr*6QY!afE6k|K`Mbz3G5L@vBFAfE;>q5BwL5S zAu`hdY-pQcN0fv5Ma9nFGK|*2WhDqwf_UVnE4}2lf`23%hq2jZIZ?4?liB_hssMHs zz=?{j62Qv(Q@9q`*8(weN|5!yvL4v#Vo5#lqi`c28UYvKtt*EVKi;=2fYCJoyaDi$ zA^+kNRhUPF#t>s2V~3JNW|;ez8HNn@XODVsrV01J;wZQZD=Pj{ZmAWDw&C@fSF%af zUg%WJ6+57YKxXJvGxd;5Rpi)++lHm>uw|pTQ8q|Wf=tKLO{oJ4@B&lhfgp?VVl6s7 z6}hfPxT+mq6mPD#4b^dJc$$ubt@u{$7OOJ#=4UNE9k3__hcHH=5TpgiLI*_>kw%nl z1!skhErm$Yv902)(y^`Qtk*$10A~l#;?tuKKD<-(c0h5W+0oi`O9$GTt6N&T;Ia}J zDS;&_fx|!A-CoI?FX%(XnF=-~NG3m1x6_%WY)YOoewj|6D*>(qhR9*!>Ek_}gAXsk zsTz;P({ELs+qQl$dWDgYNLf!5(} z%{LkCcHwmuba;OK1Qt*%5(lC)V6)nK`%=v+nn~-dp?2f#%+TZj9 zw0wR6gNe6|7o%nP?Fh&XMWK+}Vh8n9XFkC3n9a=QP^3!0tOOiHBgk4{P)m&oO_74? zfgBY{(~HhZ;6dRgfHwg)!qIK~3fsQJGqAcc1DP`lKTnaJuE{<>Z*9JZ=EXxNOOcVl!raNm(%RNeXk~1|H#6n)xO45L I4jeJ|f7$X|nE(I) literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/fsfile.h.35B524E0BEF369EF.idx b/.cache/clangd/index/fsfile.h.35B524E0BEF369EF.idx new file mode 100644 index 0000000000000000000000000000000000000000..0a4a0068fa6600443efa056c4672cbb73e816b78 GIT binary patch literal 2786 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 J70p)y{tqhwRv!QW literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/fstype.h.DEBE4E158EC53C0F.idx b/.cache/clangd/index/fstype.h.DEBE4E158EC53C0F.idx new file mode 100644 index 0000000000000000000000000000000000000000..0999c49a3d8621344bd2e9904e017b0e23183e56 GIT binary patch literal 2320 zcmYL}4Nz276vyvAaDD8)clW*B$H#slyR3XIxiu*hSd3_rND2}$g*x~VDjEs9I-;Rc zgMuR#O6sTqIg+Dks3T62GFYajQ8Q+uhB~4snT}1Gt(hO4d&d(y!=Ii1|D5w4m-{<; zS(%w)7$IZc$*L$VUNAkB5Te3QV1d8ncliB-j*yB^*XL%>JNmrTopYi5&@aKunHNgy zG76#&g-xE=^;hymGymXf%#W9PYNmAoo&x}ebYxjweMfI(+?KA^eV2M>2Yb!`P6=tR zT3OTk^!}tR=hIF%wm2R{A8!sjm%S||HG0v#+9?&z?6ZSM?7ZAm=q~?k(D=IX`muS< zQE_d${Fi^LG>_i)I47+$In(j?5q((W*0cII=A7DB6@K*a)6Trlq6?fmsoUP>w@(Ga_0T?t$;F8U*NY1x(TS18dzY`55LTreIn zl4e%uK7Ne~F%Z*en#cv?g2pSwPsQbL8;KpxEmj|E<}z?@4b}Z=e-)0JW+a25AY30# zxeOFcn7wSn)F-90s1OPdFjKR}<^Kni$6ab$J8Q0y*r4C3cbd5j^xH2C+n}4#F`o)i z&>yeGM{&Xa6*p6kAKc+xqzEApYqA!>1>>Fb#G=|QmseBbgxIFqG%gt5&fb;qu(xCr zCE*Y|R7V6Cj2E7|x5neh+)RlCv0HUVal!ao`>N4ZZ{2UALL|fqa)N~m#+6xRhFf{1 z+o=!%v7#!GTre&;w&LK4-1Y;MxFNPiTJ2mgj#=Hk_S)q0UkQSl-%&!S-k_JB9So`b z`C_+cM1MOK20=HKsm2An8%&$)I<{4QPlYgu6V*g37mN>NuX|KM^LwZuLTrdOxVT^( zI&?zyiC|Tb3Lc1!ic#f)ap&Uw!Ff-_$5e1ZY*I{4E*SS^)g+dbeFCwO4YwK`Trl<* z&k9Jeu#i}tfs=}VFOmv2!xU}g6Kn=2+Q=o?3`(?-N3a=;Xd{PUGYHW}{=jDNp^e;u z&7eaYc>|llhBk5rHiHc9(GOE9`x<&ObP{!l4h1h9Vh7cXIjlz9z-FwW-RT)Jba>Os zsW8MY+RgYVWDlwtcvy|Zg%~(#XiL=Mu_WQiNK{MEh9Nx#&nSdR3_)x`_P}P~p^aT& zGvLrp=&H9K@Hv;kTS}s2!c(nz@ZHV)Nx^EcO`^$!m#1RsnDPFh7i++lW!aAZ8Uz+* zGg@)>uw!1^_8WKBg-TQr6$R0fs7fw# z4nx>Zz#-GloGkydvZNKNHMw?*4 z(JbQy!7TvQYz1KT)%u*mo<-+@Z$5UJM+?TWOfo&D75%^+wHZX)O3LJv} zX0X|UKpS@hdn7CdwEe~JPG?&#;GY@ru`ebj{3FnqJ)e*5b*_;^WW_{e^a)W0zWxUg CNUoaz literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/ldn.cpp.393680BBDDA86121.idx b/.cache/clangd/index/ldn.cpp.393680BBDDA86121.idx new file mode 100644 index 0000000000000000000000000000000000000000..b21627a0c2187d43d7a4142a47d69ded45a37449 GIT binary patch literal 8148 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 literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/ldn.h.1D557AF101A575C7.idx b/.cache/clangd/index/ldn.h.1D557AF101A575C7.idx new file mode 100644 index 0000000000000000000000000000000000000000..847968119b7bd7ce2185801e212edcf7295d1a83 GIT binary patch literal 4290 zcmYk730PBC7RN6S2zli3f=LL3BrJijDT|OlkxjJLdt7aWu7nY2y@<+-qswT@L6%$;J>Y> z+~%)~Og%dFEZ>GnHn#zj(tq*=J99bhT+wPiD zlIS-7xb5jf-t8x2Ow%SrE$Dl+bzk3es#9EC!x2gWuUy82u>lU_DglRvkEp8b1bMy5VpP2ejx$c~Jboz;vTW&5r zu5U}ddc9-lmU&m}`CXN^FU~b@>zbCoz!JBvZp)!f-*<0%@O9!wbMyVCM$5PMMU_=s zo2Ny-Tazw%`DE6SSBG^AXIyylsy*uT5c86oMJFE}Zh58 z?N(ph)qnYPe$0V6VV0J$4Kdrz|9E_R@LRhT%gnX4UI*hN3--^KbQn_G%st1xn;kZP zv+ee>MW5b0;oV!;asSe(za8!F4_Wus`jy(;sFYhZ{J8L2gFW~3I(LV>y;N~4qVI#_ zewM@G37X8|Sr0BqJ9n?F@A98@vM=ahgkbNV_N9GOQ1|rG`^jAoLh9|No?rdDA@=3W zp89p6(pfE|WffPq`L4Y4tZn|3v>|NgV%=`Oq z6+Y+FEf18NuDd4XIz> zJ}P>{ao=aQzxO=NEL~VM?S_Pq)rw_xw||^!CnIi3BE(7J6rv$4oKHe*1e;wg_s#|p zdk3C*O+|z#mngkxh*S(9mE$)wU%{o*4=5SXHd6XwZG4LEaTtRjcL5 zIORY+LN=SNB&>`f*@Gc_Vdj|Ko^zx09EreyBu!EfVOf^A1km;p`fC^GT=e7_KS(e_ zIYKWQOc43%FYlF%4fJ9d#lZeV80Cf>HSzq>rDW92qdBy^(qkN)*MT4uy80V*) ztNM>WN76C-WOlNgu)O_1c?}iCgEj_i2;`YySRd&YsS^#ZzZY!Y_j;;p5YHIF9peRuJDASi)W(PMBt=IAKi1DhH0WO0vHiZg+8E6dGiJ|XvlQ0s_a~I`@#ni^Ig*9} zIc&}#>-1dKm6c|@4om0AFbqhOrMVN<(T3;)VS2?apG?lwPtW0*u~1;NDq1HRtU#t7 zdMI-G4GTwdaQ!59l8Uf$3Goer^-hnR$(VaVuX7{{15(%&t(ZXke$~|;d${!n^Eomc z1I#k>|5fl)g~i}$ur1)pM0X-+C0b52SV1tmdB(hdJuTpwWGGP32nNxh`%c@dd8d2( z-sG7uaF6sF=_?v^?;U&KL)kFPYzfiA;WjuJ)S|Ioj`GE(loDfSm5iw2_C!b`RHCs4 zd>#|C&#mU#3OVtD9h7!TxoE7{!#}j~YTlE&YMxAi`aM_=rD(8%ngTb^+2dYc#gj;I zyF0n7M1$_Syah9o^=>Vr zKj%m^jyI7_g!=>6L!AFq!>RZ4ni3j#k_7{b=i;43g9#$9zJKn6c3rWto8}djDY@QHL*I;U4T;K z+sD=AJm*OWBsVEUgKknXV`gb5Q0~}yJTzQ zC^$=9`Yo;nPMEh!l>6G9PWN<@?qh9FZCqC712jAQ%49F>F<^o(AL z2c8o=7!N7FFPz}XcuMg&a)KY@Cq;g6fCaH_i#K3DFdrC?hdJ zrnp2II|Z3y65n+sB@L6w!w=CuFO#b$D|)AxDwp zjt38+2ni?=u~md2B%lz)oe+T_Q}m(SJM8i1YqdL?;pXN>=f>k=PO#`Kez>N!THoqv zoO=PL7cY&MVZ-=_KmnAPSO7j-AX8G}P_KU4tf{H|trarq7@Z?l&k07x=!gtMlEPYw zQLGXP3dK`$qKpp}L{n&D0r*CNOks%yU=ENeBvD2_f=uCv-yW$5GDRZFm;+=ALj0=3 z55H9ybUmgICgjez%kUH;7$KTc5$nd|2QsB0R)QdeE-3&p8u14*#U9ECJ=la24`qCk zL8hcbxn#y$Q)#iKCDThM!e2&+Hut`_=~(qf$(Ygcri3^$274hS-ulyI{W;qDGr{^Z H&ieDe(n99s literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/pu_Include.hpp.C523922F5EC060FC.idx b/.cache/clangd/index/pu_Include.hpp.C523922F5EC060FC.idx new file mode 100644 index 0000000000000000000000000000000000000000..b0c8ec756a2ee99d7084662b952ec6a13234f371 GIT binary patch literal 1072 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 literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/render_SDL2.hpp.18A6D5991D9EFEE8.idx b/.cache/clangd/index/render_SDL2.hpp.18A6D5991D9EFEE8.idx new file mode 100644 index 0000000000000000000000000000000000000000..e5ba05e89192aee896e5575bef4a4ef9edcbb143 GIT binary patch literal 934 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 literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/sdl2_Types.hpp.14E8D52331FEA768.idx b/.cache/clangd/index/sdl2_Types.hpp.14E8D52331FEA768.idx new file mode 100644 index 0000000000000000000000000000000000000000..54941a3a2d217f3142e55cadbd28fc15f2b79951 GIT binary patch literal 758 zcmWIYbaQ*h#K7R3;#rZKT9U}Zz`!5~#Kk2=nMZ*14MqlriaBd1Y|J}sz~l1ORqesW z>@Gi7fh&5q&U)x*sVQ|bxmupPfBcj{N$!QGeW$A}F6=1|`P_MN(SjNKI;{ON*kZPF z%*yYYw*J_}<9rPJjJ(=zSZvYR({PmaoBdygd42^STrGn*9ST1kRa(My^Vc`Q$Lms_ z8m!2ER{xQAd&|z5!Bw{`GEHMVCL5@T-8GT?G__>b{7L`bE?)aF``G;hWj4FNDu{Sw zt`v^@(j(HBUL(uDWl>IrR_ynVU(?>MNqr}}Z`sr0%G@N7U#dBJY83mmn3t}9paBQwvmrzQ;x^S^ literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/threads.cpp.3D4AF726B9B95CFB.idx b/.cache/clangd/index/threads.cpp.3D4AF726B9B95CFB.idx new file mode 100644 index 0000000000000000000000000000000000000000..195e416bbd5f058e792eec502a0844a7b1e3fe90 GIT binary patch literal 1834 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 literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/ui_Container.hpp.DBA564B6F57F0254.idx b/.cache/clangd/index/ui_Container.hpp.DBA564B6F57F0254.idx new file mode 100644 index 0000000000000000000000000000000000000000..c44e358c71f87051ec93b64375c16eb01e6bdc4c GIT binary patch literal 1922 zcmYk7e@qi+7{{+Kl^@+pdv~RG*On{4Tt!5w8@Mux{IIYx%T`dA;T#(X+lZJftr%e0 z)Me4kxsACWxJ9#JWX{AyXXe-znNo2isFOfQ6vDvqhYlrkVI+)Uw&z~+Seo!{?)$lW z-sgSq`;^ME($dx#j$2n(*1WxbM~$B2I061bJAw^o;QMhM$2A}B{IJImcG0~v-pk!x zt9y^sJ%6diHdHF#9vRHpF#cQ9MD>Mr;l69_Nu+ai!1+z)tdQ|%<+Tq|?=Ig|y`?{3 zF4*_!s>Z>#j;nVJO$9~fKYYJtKGC{i_Sxa8;i^a1PwGwIALIY>R2&|#m>yd@Z;ij& z{Mu~X%JI|R9z3_z`q9|f{uKIl*the_(DY{+!4pdH+^N71qid^2qhpVLa=Oyq7(UoN z5uY?iekp2547F^peV=e#M#(eQLqGKyjYP6=qQWZz6D}5Z1)o*D3t7?0N78r_1K20~ zl9(VK87%Jn`ptT$k???RD{L+%hB_syJfeX3F32k^>5S(2fRjN25jZ6 z0u#h{r`rZ^{M+s4NjzY$;!S3P`1V)*rOuA7iWs6#;KT$&f|&^y#~Rm(y1aL}6jHh7 zC7vvS=Up~eDieG@bf$6lk3#FKJTU?GD4s+nh)cE&zjaA}JjfFr;AAD)&IIw~{bjox zbkB|DJ`V!_|LZ{|epcSfQBmU&rVf_UIi zINV|Hxxfu;}X#WR;g-Xg80Tn zL06!?=@w6-0B0(hDig#lLxov}m*em8BpPr)4kR-{%mwRT3H3!qQmHqvG~%nKqFSTY zVhdC(kxFDt2^GuKG6&{0JHOX(y=8NPj*2d`%ZgDztTV6}V_l3f*jk3s#`uD*WfyIX zEi|WP7Hw#5o7xy@u3RdY@kLUxLalJ%?y+U4tECzX;5RX_AeVkAU+J08U4Xi9$_Q~M z@T`_-v@y(JYe_~MLkzZ-V6-v3U~9=m8$$~l(-Mm|G_Xm1F0!#4DM!W#QZZM}b>Kl^ ztaWiL&R76X0hZIUj5gK)Tgx!o)??{a`SXDkl8#qN0^r zP554*-$XSj(yzK)&0KV~M$KJx^_2Q_epe zxG+vK9H2JFSiluMDpuU07j;B*P=^(59BjB-n`*T8ytjGb{P~d)m=x{q2fs!fhwH=L zi{pp$4YoGiSOm8Owl>sg!#p?Eq(aGuhI?jx-t{S|;h_YaZ=!L1=#TU`6M T`rt#v&&NE!xBo3q>jdt92^C8E literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/ui_Dialog.hpp.BA5E55C427BB5263.idx b/.cache/clangd/index/ui_Dialog.hpp.BA5E55C427BB5263.idx new file mode 100644 index 0000000000000000000000000000000000000000..a333316d3b51b5c1adb3af6398ecb583eca76c91 GIT binary patch literal 4508 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 literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/ui_Overlay.hpp.177672D215C52C40.idx b/.cache/clangd/index/ui_Overlay.hpp.177672D215C52C40.idx new file mode 100644 index 0000000000000000000000000000000000000000..44f18c487f4b6ca5b6d01251fb1ee992b3129dea GIT binary patch literal 1660 zcmY*Y4@{J082`Ta=seDskNf-Gecy5Mo?IP>a5xGFrez5`XqjM+Ky#8JWAdlCTXB(1 z90N;>qAh1CCgJ*{EVGQ3`~fTxb)@Yec2~&@5|eBySmsl z`^UG_p3mEk?VPI{cNQL-QZKt+Z+t#k2!`vQo`EjjdUtqiwwf^BJWtp=aNE>$MURzqw!c1fys56yJF9)QC#y>&VgcG^ za#=Yb{eJ10l993(fu=w!CPn6e^as&EZE#;rxryk3UZgC#hXd03yo#+UudE14WIoWU zMRjsOx}!2Q@LXl&fSn`&ZTHx-I3Qi>UNROqa`TWxtU$ZXZkYqpAL=i(E6X12u@eHc z?2&UhAiZVpLrO_><9jkO0L>_~azOgCB=3;FccRZk?gHBH^m{oVeY}qyG-Ry!R3gbh zrM4)XRTQ&!zx0e0-v;KVL4HMA;?Q{4T2c&g>UVb=r!PU8W z#9$I6i_v1{ASCkXiIUhjVHng=k+l-+5}gHV%~rS#X$Wg}!Z11s!kUdRtn{W=EW6eI5v7vNZDZ&dD%st3 zhV@ZNcFPRUqmn|EWV}Zzxu`1{2Lm;#%#9_$%EuPQt?pw>;#P$$5VvX*Sx4+S35$GO3O z@}r=R8&p$uUDX0ejt&%1gJ CCj8O> literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/ui_Types.hpp.D33AC0C2311B451E.idx b/.cache/clangd/index/ui_Types.hpp.D33AC0C2311B451E.idx new file mode 100644 index 0000000000000000000000000000000000000000..88e3fa21cc8570d7ea039ad9aeb21eb6c23f734d GIT binary patch literal 3832 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 WmnD6y;pL+d+Z#n@#{6u73-~`_y~>0D literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/util.cpp.7798728B5E2F0E42.idx b/.cache/clangd/index/util.cpp.7798728B5E2F0E42.idx new file mode 100644 index 0000000000000000000000000000000000000000..0b7254ca30f7415f3ba1bd8af6d0dca6a104ed00 GIT binary patch literal 5358 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 literal 0 HcmV?d00001 diff --git a/.cache/clangd/index/util.h.4B818D27750FB9A3.idx b/.cache/clangd/index/util.h.4B818D27750FB9A3.idx new file mode 100644 index 0000000000000000000000000000000000000000..74af23724f1f79c69a5d89f621ce2022b6de4711 GIT binary patch literal 5730 zcmYk93tUZE8^+g8lYKfn`{;HqIi-uPy0{Fb8=}kUVoEoJQioJXC5bUpA&F2b&A26F zK7>rB57W2}F=i4%O78Q~#Edk^h*-zZT6^t%{)Gkj`c5}S$R{Bn zYk@i=P8%UK82_Yaq|JXZ0HG7Q2xV<6EnTqap{wM=`_Om0+rHmDQQyC|K3D%%T2yw# zfD^afw_B9R)+(M|T-=cv)q7{rGwoto$cd7yu6GUbO$mKPSMv{;-Ao-axjr_n^xT`N zo6mWBTNsQ@?0Wk{QTZbI`N~!Ib}CoA`o+|D+yC@!f*vj%aVN23^n;?}=;l6`DJPr1 zc>+!9Te~&ih#AP-!eB(X6LoD3l!hULR7`JoFqoqy{-)#*!YN?eUTDs=0L-qD0 zT5-Oy2hvY|*RAz=q%9gZ#_D~@4)^wxX{%ltj7#6Q?n9&9(_{a5nCz*Za(p_JKX$qMbZOAqkq_eizYkW$vU~GxPoLka zvR0)`wleu z*>hRt!GrVmxVKqfsekk`n{`|jdc#u|v7vWu=b*}8o9($Bd#8FI&CXo3_`}Zu!*7pS zyP!w!;jKdx-qy|Alrv9$?$waI_UybdN0v84hBV#UcW=}fMYQi{ht!6t$@0SNvLhYy z0-ZZImN%!?MXz}j8)njT>Px+{=C;27^|iFU>2y{!ob~g%v&o|L;*+c54OiET>+KTE zZTH@@GFrbUTK8=CmW!)KZIe!GSY3an>8K&LwU|wR`#5hsxmilp8)K zo*Si&-AM-FNm@%|B^Qox4_~iW+b_Pc>slDjx3o8Wu2rAJpLjB`W2WkU>cT9=)Q%JP zm%p2}v%AN|JZg8=-d);d@viNn+hxk4f<3Os8b-EGopi~kvw4f^#HD?%#W&h#cN=X> zI{MgS^3|@Sm#+2+#YKA`g>EsLVEjbq&a6GT&zfxIKU!7CoXNVL6*uV@w-qg2p1TtL zs-&A<*-x#gYQCGBdpsyX^?uS7|FjpGJ$2i96HE4F-1;js!fjdkos`7iKl9Fr&+hQ* z8$A3cQQMISY539d)a0vu8y3dHXRvXTDN+bVcnyh@A4r)eLEz7U{2cI&Sr6 ziC15Gq*J(OL{?RmResCW6^Ht2xs045N5kn$_+7^<%3>_tLPcS-*G(@ddHPh9dH?$1 zZ`|J}aspuwRz-+BgrG!5i%+W|G8%&GaE;0%;NM< zUmyG#hhj)1UJ^f)3KAJ67goeWmHHNw4RB@kt*-J1B)`h z6>(_!r(Oa?0hUN)#zhOg45-^!VB>$yfJdW96&Wj&QK41VF|%-$!jT5Dpz)lHL#dyt zL`kA>6}b*tN?Q3^`d^D(*|iEDIg%n4tc9G4MiFH}QutRtoKx~>3Wp5$c03VSR)w~jfo7`&b5rp@UY|1LL8y5 zWM7G|2@+XKrqgbNPJM8zwjbcYp+%n(k&;O3{`EY*P~T#`)zW<;)`$iHu@L$*9nXupU*>AMKgy7p@$d@u`(U zMqJ1YK_Wv2O(UCYxA@>0tp~1d99m4uq)JoGs36f0k+A&>P)B9sn|1Cy@+Aou)k_nCMiSKP)0>#QNN73 z6g$iLbs&!-NW_cvl2M@%;nYn_@JgNj!Z(aZBS}QcN@Y|us=SUI{vk@eE{aEAkjMmf zf}Dy*m031NweO$(GKNRCB%)-Maw-~C%IEBF75m0@1sL+V8!8Q#yE(EFS zW^*V5M}*T5E(te9BI5zV=4GkA(3>;%)Eo{ak|L`a$!f;#;~Ns0ia*}7vA6uceQ0}S z4v*|e%#<~iQ_*PWmG|{wIu)hyJQ_nHCaj5!ibkYHS(#-u!*wo?!b!x9b(2z|5n=bb zE~z4Qj%&>mqihoK(ecrvLL&&_t8}V6rE_j^K^l)Hkc0#4AfrMP!m?eC1r0M^dpM0l zU*d?c>^M=J84_9WUc!z4=&WVF-t*e!JhCTM%vduy6^(8?Cti-fkno=z9t|fEbJko= zMI(|fYFoMF@6)+F3MG+=>_j;g8W9$R4tQ|?RQKfZD1=1ZS$7!~jY!?z{Llu2kbE9Z zCJ|@WSw@9MgcW`7v&N&x|5yQ!d`QHRb(B#dksu)=e%5eranAT64y|EGCeb+2nhFwG z4Mx^;@YX$-$ZZrot2Xf{m?T_TS7Ry~z3l(9t75u-@MaEug(Je&g-OB`NTe7joS1*A zT0(uw_ig1+7AX=e36@epA`@1)k5ZovbM6y=znw!1NMfaQr7abDp6D~E$vE=2zlJtd z@@O1Ma4cs?g*H;a#Nl3JU3v#^5uMr1qtPTHXXP>~G$K5i9dqw4tWB%hBSx7dGFoS} z9u*p)XC+B5tZlZ=ABTA~f+UPtV;L2VB4PD^#p?VzpoT|IBx1>0%Bg5X{vB9-Br!dq zhC@qmMA#FRScQ+1>@)N={WdC+v%{`@bMprtxsob+te%t#ts*Swy;J_;s1W6U#b_Rh zSm{{lQR(kC>`>hJ%NbLS^T?kh>{vS~6`Bw(@}-2r|=U~xQ!B<9#r~mtvth{iDa_j>~I+sGFhO|^7`Da?=s@Ip5ss&i7b^a zwW8Ah057OX=39;rJI^CGk{HAeGNhuhDBTHq%;XBQOFRlA5f9cwMnz*$+vik7Zw-mQ z%%QyghKm?c5u>ls@bX|EUx~u$3Wsv~Q!%0#oRMm;5EkWh_|<~n?Z#Zy(#rq1IVgFc z?!ZBGGQ3$Mw=UbizE!J}N8?E|_N={(3LO^~?P;*$@JUm3Cx=pSMA+bIl4B4>MuZbF_Q4nB5z$d^d1ON(L)am5 zDkS0|+->*GO+B{fM)z_k{Zlu2j3kdyB9T&8SX7#NZn_@ZPl1ex!XIoXkRPKB6lHP=|{UmV@-9 z%jOehtK4NcUC3w`GP*!0fOxn%!8^!@zbi~>O!rgbd@-XaW*h-DfcJ2oupZ=r@vu$! z4s75$Y!jvf8(0oENe~Wf061(DZUY;r4Hp@Ti4ANZHEa_~0~_cJ+l0)(hV|mw0*Ju? zU>MF51Opq`3)_Udz=mzWw!m620EmSL2ws7G@X&~X-Wvx6;(aV(q$P|q6ae1BdBR$d z2gbrS;VZC#tFTR&3T$90Y!i+G`;?X0u+cl#%+%(R5z*#T=bcF{9S%D2ig>6DpU;{;An-CP( zKu*{u)C4x*61E8{fena+TO?!zHeeA>6C?s#`%wM226Yd<##^OUsFnR&rFK-i^nXg` zlKK9vO5svIeFB!kbqPm7UEn8d6Lta{mNUY;1f<0 zbb|EAl)^%rip}{0@Z}Z9^Zi|_2djIx@egPY*ItGgOKzUh0c#U%%u23x~b=aREcv#p_{@|RP`HuuhbLcdSg zVn!dHgMb{k34$9?6fgtNMd$)-U<;fkTmd%l1WpSW0RzAgI8XQiY~TiL6J`J#SOMFF y6Tk*Oz|{pTfB}@IPKhH3l%5u!Zb^PgA|kxz!!JlH`JMR312L`Nt>K2Ql9;;GRd|~yRdo!f=!oQBbKTukn-sOFIj`fpd=VCur zhHvS?8sDtDd&A;mt{JMbIy>C^gu7y~*?)Zj1d!>%7HhRH^B$xfQ>0zg(QU`BOo97SgzT zeyfk*y?ld~W73t<8sFI4Hku#OQpdU<>zS3Ek>~byaMyre&@P*o*69g--2TCNE2n(1 zBeA&q>ZEd(EJF8cL6h};uTW#%o(F+p>*6!Urp?rgIGVV!cHozRT@{?=Nvmfct&E%Y zY3n)ezNFofsEqzLN6*GD=1S{7_2o%tUgIpaUw-)QKF8^S<|U;wihjT0ISzFNIBdVX zbVpQ5)QpNlf%k`&7GJphvAJfW?vqcmVlL{uu8wd&Ty1NUtR+%u3P~{t9{21<%A5SE zsj=_$HpmC8O?Q9a73!z)8NOg)$)p9RN_xu><%|{F0(1-X z{`Wsay#8@4Z^J6*dR1 zBPs~nFaX>E5W8VZ#Yzv3v&9~qo003V!E0-yfaQ%P2y_Kz%7sYiNVllk-VtycQI1$b z7I3pb%Z<LLpe9c~ytk)$EXRu=DHS&HaPkYs`x$rr*thNnzfqs*3FT?<-IB05kQs85K9mUHA{ zB5{&aP;yD=CRMC31vn`nBm|P+Se7EY$(<2BUN+u}F~0)D6<|orccd@!S`+4r@hwA9 zs0O2QwQ#jILDMDI+dWToOE6O-7&n3|Bl{Itz5-8zhYn=iY^1_;F=HWc3PDEHAi5t= zKbVjr2rIi~vHu?@*%(Ckf@&{F2m#Trf%6)47(57SgCHfbCuIt}|687TTTz?D9^z)a zJzSH-!JD64-{y5?%|vYIUC_A;(vjq)+d63A@LldTR_?ZCJgQb zPA3RSCn>TW@BCe2#S(n;sPR#wQYv~vv+vk26R7(v|ojXe{R z-X>!gX97PHw3%3T0ly2hi3XPik#8rzIGTzX%fPe@oQMYy{StIv!Z@Nj?fu2xIUxh7 zY#cOUl!SN$Bhx5r2IT`gAJiBj`M98&WQhi9}+|pyPm!Ga);< z`+CZJ*4%V#uouTmozd)NTW76zr29nm6l1C88C*g zm98Djpd+ApWVDbPkkl|4PMQmTW`_q3CYD_w>0)Zg;F}w3AOCQ@ijUi&wyPe)7QQh& zVHA>wr;M~v+)~pZJaZII0Z9r-8TJgAoB`ep&Iavl7$v+Ad&v2T~cUeZZ5&bp$YXKwsYpt(k49bGpS+I!FbO+dX zKtMDh`VMH_0U5y-PscY0a`Z1?cN74-05q9{eZc8sW{j^6pPv8WvZxN5IK_C%IAV)< z%NxJOdj*Q^N$l(+-Y#UL#PQ{n~kjgx42 za3;DHBNXQ@h)Epc-i7h)$}ir-N=rdl%J?xQm><~|d+Pzd{x(qE2I@?tAAsruP$v>L ze<87uBqjZ+uusiH#8|XYbK$7jr5H4enby#&qR~2|x4aLlJpt$hXb^*kuAW(XcCZ=` zptP^L??|KR%>I0Sl6~K6Y>kvBm5>@ibT066nYV&%Ha)d|V9NkzlN-s$GA5^hI0du_ zu1%;Mi2B6&h?U5lU}{$SZui1lmra_`iPED zfVlOMaqfzLMg}8_8fgsF7&`mm%I!hLmjc<7T|L|>C8vU$qDDq1ii(U`7Olud3z@lq hFVWGqlgJtY+LBW&13`HAlxPsHG(C#0Ke2^D#%VihnPP2|Ba5M@RX_)oF2)9$na| zQhCs_p6e2Oo||`MRKB#|;}0)C=bW3WSrY5Dk7v#_vsM4j9k_NfZhz^GuY0sh?iHom zW^LuLStBZTwQ)<3+eH55M>=m8zOgmuICxLx*o7IdXWsI-7QKbS@-Xm=1GzvT%+1Ly%D~CaBq`0uD9kA2l%AOQex(`@g8)nc4=0Z-11B3J z16aZIOIOxyjT3U`VUU0+;OFI+Vc_IqWsu?ln$Ys}Ma9qkYZme_2*DKaaqFa^Avyg)~CvOr8IN=+-) z0j3<7Zx}hjzEJ4CHt})vjqNZ$0EIzrhY7=64ipBt7$&T7W`g8aec3t|9${WFURk*1 z!hCXks&LN;^ULz9z)au~77!JXf%!x4sJ7IyXYVF4@(A;@@bkbFDcu%qxw!7YY$hII zZar>Om|J;-dCYihVNQgZ4|EeKkYH~5X!2?1%|-JMg7ijlry%t52J^ + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..e6bbd32 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..d59c8e2 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,23 @@ +{ + "configurations": [ + { + "name": "DKP aarch64", + "includePath": [ + "${env:DEVKITPRO}/devkitA64/aarch64-none-elf/include/**", + "${env:DEVKITPRO}/devkitARM/arm-none-eabi/include/**", + "${env:DEVKITPRO}/devkitA64/lib/gcc/aarch64-none-elf/13.2.0/include/**", + "${env:DEVKITPRO}/libnx/include/**", + "${env:DEVKITPRO}/portlibs/switch/include/**", + "${workspaceFolder}/include/**", + "${workspaceFolder}/lib/Plutonium/include/**", + "/opt/homebrew/opt/lz4/include/**" + ], + "defines": ["SWITCH", "__SWITCH__", "DEBUG", "__BSD_VISIBLE"], + "compilerPath": "${env:DEVKITPRO}/devkitA64/bin/aarch64-none-elf-g++", + "cStandard": "c17", + "cppStandard": "c++14", + "intelliSenseMode": "linux-gcc-arm64" + } + ], + "version": 4 +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..67b7939 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,101 @@ +{ + "files.associations": { + "string.h": "c", + "stdlib.h": "c", + "switch.h": "c", + "psm.h": "c", + "vector": "cpp", + "any": "cpp", + "array": "cpp", + "atomic": "cpp", + "barrier": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "cfenv": "cpp", + "charconv": "cpp", + "chrono": "cpp", + "cinttypes": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "codecvt": "cpp", + "compare": "cpp", + "complex": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "coroutine": "cpp", + "csetjmp": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cuchar": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "forward_list": "cpp", + "list": "cpp", + "map": "cpp", + "set": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "exception": "cpp", + "expected": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "regex": "cpp", + "source_location": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "format": "cpp", + "fstream": "cpp", + "future": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "latch": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "numbers": "cpp", + "ostream": "cpp", + "ranges": "cpp", + "scoped_allocator": "cpp", + "semaphore": "cpp", + "shared_mutex": "cpp", + "span": "cpp", + "spanstream": "cpp", + "sstream": "cpp", + "stacktrace": "cpp", + "stdexcept": "cpp", + "stdfloat": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "syncstream": "cpp", + "thread": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp", + "valarray": "cpp", + "variant": "cpp", + "filesystem": "cpp", + "plutonium": "cpp" + } +} \ No newline at end of file diff --git a/Iridium_Icon256.png b/Iridium_Icon256.png new file mode 100644 index 0000000000000000000000000000000000000000..5ba7b0cef6cd5733ff8464d7feec3328a7c6b012 GIT binary patch literal 23661 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 SERjXH*i}2nOO-ahkNy|K;%xo^ literal 0 HcmV?d00001 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c894e4d --- /dev/null +++ b/Makefile @@ -0,0 +1,203 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITPRO)/libnx/switch_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +# EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm". +# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional) +# +# NO_ICON: if set to anything, do not use icon. +# NO_NACP: if set to anything, no .nacp file is generated. +# APP_TITLE is the name of the app stored in the .nacp file (Optional) +# APP_AUTHOR is the author of the app stored in the .nacp file (Optional) +# APP_VERSION is the version of the app stored in the .nacp file (Optional) +# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional) +# ICON is the filename of the icon (.jpg), relative to the project folder. +# If not set, it attempts to use one of the following (in this order): +# - .jpg +# - icon.jpg +# - /default_icon.jpg +#--------------------------------------------------------------------------------- +TARGET := NXST +BUILD := build +SOURCES := source source/fs lib/Plutonium/source +INCLUDES := include include/fs lib/Plutonium/include +EXEFS_SRC := exefs_src +APP_TITLE := NXST +APP_AUTHOR := DragonSpirit +APP_VERSION := 01.28.2024 +ICON := icon.jpg + + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE + +CFLAGS += -g -O2 -ffunction-sections \ + $(ARCH) $(DEFINES) + +CFLAGS += $(INCLUDE) -D__SWITCH__ + +CXXFLAGS:= $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +LIBS := -lpu -lz -lminizip -lfreetype -lSDL2_mixer -lopusfile -lopus -lmodplug -lmpg123 -lvorbisidec -logg -lSDL2_ttf -lSDL2_gfx -lSDL2_image -lSDL2 -lEGL -lGLESv2 -lglapi -ldrm_nouveau -lwebp -lpng -ljpeg `sdl2-config --libs` `freetype-config --libs` -lnx + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) $(LIBNX) $(CURDIR)/lib/Plutonium + + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES_BIN := $(addsuffix .o,$(BINFILES)) +export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +export OFILES := $(OFILES_BIN) $(OFILES_SRC) +export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(ICON)),) + icons := $(wildcard *.jpg) + ifneq (,$(findstring $(TARGET).jpg,$(icons))) + export APP_ICON := $(TOPDIR)/$(TARGET).jpg + else + ifneq (,$(findstring icon.jpg,$(icons))) + export APP_ICON := $(TOPDIR)/icon.jpg + endif + endif +else + export APP_ICON := $(TOPDIR)/$(ICON) +endif + +ifeq ($(strip $(NO_ICON)),) + export NROFLAGS += --icon=$(APP_ICON) +endif + +ifeq ($(strip $(NO_NACP)),) + export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp +endif + +ifneq ($(APP_TITLEID),) + export NACPFLAGS += --titleid=$(APP_TITLEID) +endif + +ifneq ($(ROMFS),) + export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS) +endif + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +all: $(BUILD) + +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).pfs0 $(TARGET).nso $(TARGET).nro $(TARGET).nacp $(TARGET).elf + + +#--------------------------------------------------------------------------------- +send: $(BUILD) + @nxlink $(TARGET).nro + +debug: $(BUILD) + @nxlink -s $(TARGET).nro + + +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(OUTPUT).pfs0 $(OUTPUT).nro + +$(OUTPUT).pfs0 : $(OUTPUT).nso + +$(OUTPUT).nso : $(OUTPUT).elf + +ifeq ($(strip $(NO_NACP)),) +$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp +else +$(OUTPUT).nro : $(OUTPUT).elf +endif + +$(OUTPUT).elf : $(OFILES) + +$(OFILES_SRC) : $(HFILES_BIN) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o %_bin.h : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/NXST.lst b/NXST.lst new file mode 100644 index 0000000..3ad15de --- /dev/null +++ b/NXST.lst @@ -0,0 +1,2 @@ +-CSn +/Users/n.fedorov/dev/NXST/NXST.elf diff --git a/cleanup b/cleanup new file mode 100755 index 0000000..344a357 --- /dev/null +++ b/cleanup @@ -0,0 +1,10 @@ +rm build/ -r || true + +# TRY to remove Iridium.nsp, ignore if it fails + +rm Iridium.nro || true +rm Iridium.nacp || true +rm Iridium.elf || true +rm Iridium.lst || true + + diff --git a/compile_commands.json b/compile_commands.json new file mode 100644 index 0000000..3f01e6a --- /dev/null +++ b/compile_commands.json @@ -0,0 +1,428 @@ +[ + { + "directory": "/Users/n.fedorov/dev/NXST", + "arguments": [ + "aarch64-none-elf-g++", + "-MMD", + "-MP", + "-MF", + "/Users/n.fedorov/dev/NXST/build/Main.d", + "-g", + "-O2", + "-ffunction-sections", + "-march=armv8-a+crc+crypto", + "-mtune=cortex-a57", + "-mtp=soft", + "-fPIE", + "-I/Users/n.fedorov/dev/NXST/include", + "-I/Users/n.fedorov/dev/NXST/include/fs", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/opt/devkitpro/portlibs/switch/include", + "-I/opt/devkitpro/libnx/include", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/Users/n.fedorov/dev/NXST/build", + "-D__SWITCH__", + "-fno-rtti", + "-fno-exceptions", + "-std=gnu++17", + "-c", + "/Users/n.fedorov/dev/NXST/source/Main.cpp", + "-o", + "Main.o" + ], + "file": "/Users/n.fedorov/dev/NXST/source/Main.cpp" + }, + { + "directory": "/Users/n.fedorov/dev/NXST", + "arguments": [ + "aarch64-none-elf-g++", + "-MMD", + "-MP", + "-MF", + "/Users/n.fedorov/dev/NXST/build/MainApplication.d", + "-g", + "-O2", + "-ffunction-sections", + "-march=armv8-a+crc+crypto", + "-mtune=cortex-a57", + "-mtp=soft", + "-fPIE", + "-I/Users/n.fedorov/dev/NXST/include", + "-I/Users/n.fedorov/dev/NXST/include/fs", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/opt/devkitpro/portlibs/switch/include", + "-I/opt/devkitpro/libnx/include", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/Users/n.fedorov/dev/NXST/build", + "-D__SWITCH__", + "-fno-rtti", + "-fno-exceptions", + "-std=gnu++17", + "-c", + "/Users/n.fedorov/dev/NXST/source/MainApplication.cpp", + "-o", + "MainApplication.o" + ], + "file": "/Users/n.fedorov/dev/NXST/source/MainApplication.cpp" + }, + { + "directory": "/Users/n.fedorov/dev/NXST", + "arguments": [ + "aarch64-none-elf-g++", + "-MMD", + "-MP", + "-MF", + "/Users/n.fedorov/dev/NXST/build/TitlesLayout.d", + "-g", + "-O2", + "-ffunction-sections", + "-march=armv8-a+crc+crypto", + "-mtune=cortex-a57", + "-mtp=soft", + "-fPIE", + "-I/Users/n.fedorov/dev/NXST/include", + "-I/Users/n.fedorov/dev/NXST/include/fs", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/opt/devkitpro/portlibs/switch/include", + "-I/opt/devkitpro/libnx/include", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/Users/n.fedorov/dev/NXST/build", + "-D__SWITCH__", + "-fno-rtti", + "-fno-exceptions", + "-std=gnu++17", + "-c", + "/Users/n.fedorov/dev/NXST/source/TitlesLayout.cpp", + "-o", + "TitlesLayout.o" + ], + "file": "/Users/n.fedorov/dev/NXST/source/TitlesLayout.cpp" + }, + { + "directory": "/Users/n.fedorov/dev/NXST", + "arguments": [ + "aarch64-none-elf-g++", + "-MMD", + "-MP", + "-MF", + "/Users/n.fedorov/dev/NXST/build/UsersLayout.d", + "-g", + "-O2", + "-ffunction-sections", + "-march=armv8-a+crc+crypto", + "-mtune=cortex-a57", + "-mtp=soft", + "-fPIE", + "-I/Users/n.fedorov/dev/NXST/include", + "-I/Users/n.fedorov/dev/NXST/include/fs", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/opt/devkitpro/portlibs/switch/include", + "-I/opt/devkitpro/libnx/include", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/Users/n.fedorov/dev/NXST/build", + "-D__SWITCH__", + "-fno-rtti", + "-fno-exceptions", + "-std=gnu++17", + "-c", + "/Users/n.fedorov/dev/NXST/source/UsersLayout.cpp", + "-o", + "UsersLayout.o" + ], + "file": "/Users/n.fedorov/dev/NXST/source/UsersLayout.cpp" + }, + { + "directory": "/Users/n.fedorov/dev/NXST", + "arguments": [ + "aarch64-none-elf-g++", + "-MMD", + "-MP", + "-MF", + "/Users/n.fedorov/dev/NXST/build/data.d", + "-g", + "-O2", + "-ffunction-sections", + "-march=armv8-a+crc+crypto", + "-mtune=cortex-a57", + "-mtp=soft", + "-fPIE", + "-I/Users/n.fedorov/dev/NXST/include", + "-I/Users/n.fedorov/dev/NXST/include/fs", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/opt/devkitpro/portlibs/switch/include", + "-I/opt/devkitpro/libnx/include", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/Users/n.fedorov/dev/NXST/build", + "-D__SWITCH__", + "-fno-rtti", + "-fno-exceptions", + "-std=gnu++17", + "-c", + "/Users/n.fedorov/dev/NXST/source/data.cpp", + "-o", + "data.o" + ], + "file": "/Users/n.fedorov/dev/NXST/source/data.cpp" + }, + { + "directory": "/Users/n.fedorov/dev/NXST", + "arguments": [ + "aarch64-none-elf-g++", + "-MMD", + "-MP", + "-MF", + "/Users/n.fedorov/dev/NXST/build/fs.d", + "-g", + "-O2", + "-ffunction-sections", + "-march=armv8-a+crc+crypto", + "-mtune=cortex-a57", + "-mtp=soft", + "-fPIE", + "-I/Users/n.fedorov/dev/NXST/include", + "-I/Users/n.fedorov/dev/NXST/include/fs", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/opt/devkitpro/portlibs/switch/include", + "-I/opt/devkitpro/libnx/include", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/Users/n.fedorov/dev/NXST/build", + "-D__SWITCH__", + "-fno-rtti", + "-fno-exceptions", + "-std=gnu++17", + "-c", + "/Users/n.fedorov/dev/NXST/source/fs.cpp", + "-o", + "fs.o" + ], + "file": "/Users/n.fedorov/dev/NXST/source/fs.cpp" + }, + { + "directory": "/Users/n.fedorov/dev/NXST", + "arguments": [ + "aarch64-none-elf-g++", + "-MMD", + "-MP", + "-MF", + "/Users/n.fedorov/dev/NXST/build/ldn.d", + "-g", + "-O2", + "-ffunction-sections", + "-march=armv8-a+crc+crypto", + "-mtune=cortex-a57", + "-mtp=soft", + "-fPIE", + "-I/Users/n.fedorov/dev/NXST/include", + "-I/Users/n.fedorov/dev/NXST/include/fs", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/opt/devkitpro/portlibs/switch/include", + "-I/opt/devkitpro/libnx/include", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/Users/n.fedorov/dev/NXST/build", + "-D__SWITCH__", + "-fno-rtti", + "-fno-exceptions", + "-std=gnu++17", + "-c", + "/Users/n.fedorov/dev/NXST/source/ldn.cpp", + "-o", + "ldn.o" + ], + "file": "/Users/n.fedorov/dev/NXST/source/ldn.cpp" + }, + { + "directory": "/Users/n.fedorov/dev/NXST", + "arguments": [ + "aarch64-none-elf-g++", + "-MMD", + "-MP", + "-MF", + "/Users/n.fedorov/dev/NXST/build/threads.d", + "-g", + "-O2", + "-ffunction-sections", + "-march=armv8-a+crc+crypto", + "-mtune=cortex-a57", + "-mtp=soft", + "-fPIE", + "-I/Users/n.fedorov/dev/NXST/include", + "-I/Users/n.fedorov/dev/NXST/include/fs", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/opt/devkitpro/portlibs/switch/include", + "-I/opt/devkitpro/libnx/include", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/Users/n.fedorov/dev/NXST/build", + "-D__SWITCH__", + "-fno-rtti", + "-fno-exceptions", + "-std=gnu++17", + "-c", + "/Users/n.fedorov/dev/NXST/source/threads.cpp", + "-o", + "threads.o" + ], + "file": "/Users/n.fedorov/dev/NXST/source/threads.cpp" + }, + { + "directory": "/Users/n.fedorov/dev/NXST", + "arguments": [ + "aarch64-none-elf-g++", + "-MMD", + "-MP", + "-MF", + "/Users/n.fedorov/dev/NXST/build/util.d", + "-g", + "-O2", + "-ffunction-sections", + "-march=armv8-a+crc+crypto", + "-mtune=cortex-a57", + "-mtp=soft", + "-fPIE", + "-I/Users/n.fedorov/dev/NXST/include", + "-I/Users/n.fedorov/dev/NXST/include/fs", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/opt/devkitpro/portlibs/switch/include", + "-I/opt/devkitpro/libnx/include", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/Users/n.fedorov/dev/NXST/build", + "-D__SWITCH__", + "-fno-rtti", + "-fno-exceptions", + "-std=gnu++17", + "-c", + "/Users/n.fedorov/dev/NXST/source/util.cpp", + "-o", + "util.o" + ], + "file": "/Users/n.fedorov/dev/NXST/source/util.cpp" + }, + { + "directory": "/Users/n.fedorov/dev/NXST", + "arguments": [ + "aarch64-none-elf-g++", + "-MMD", + "-MP", + "-MF", + "/Users/n.fedorov/dev/NXST/build/dir.d", + "-g", + "-O2", + "-ffunction-sections", + "-march=armv8-a+crc+crypto", + "-mtune=cortex-a57", + "-mtp=soft", + "-fPIE", + "-I/Users/n.fedorov/dev/NXST/include", + "-I/Users/n.fedorov/dev/NXST/include/fs", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/opt/devkitpro/portlibs/switch/include", + "-I/opt/devkitpro/libnx/include", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/Users/n.fedorov/dev/NXST/build", + "-D__SWITCH__", + "-fno-rtti", + "-fno-exceptions", + "-std=gnu++17", + "-c", + "/Users/n.fedorov/dev/NXST/source/fs/dir.cpp", + "-o", + "dir.o" + ], + "file": "/Users/n.fedorov/dev/NXST/source/fs/dir.cpp" + }, + { + "directory": "/Users/n.fedorov/dev/NXST", + "arguments": [ + "aarch64-none-elf-g++", + "-MMD", + "-MP", + "-MF", + "/Users/n.fedorov/dev/NXST/build/file.d", + "-g", + "-O2", + "-ffunction-sections", + "-march=armv8-a+crc+crypto", + "-mtune=cortex-a57", + "-mtp=soft", + "-fPIE", + "-I/Users/n.fedorov/dev/NXST/include", + "-I/Users/n.fedorov/dev/NXST/include/fs", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/opt/devkitpro/portlibs/switch/include", + "-I/opt/devkitpro/libnx/include", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/Users/n.fedorov/dev/NXST/build", + "-D__SWITCH__", + "-fno-rtti", + "-fno-exceptions", + "-std=gnu++17", + "-c", + "/Users/n.fedorov/dev/NXST/source/fs/file.cpp", + "-o", + "file.o" + ], + "file": "/Users/n.fedorov/dev/NXST/source/fs/file.cpp" + }, + { + "directory": "/Users/n.fedorov/dev/NXST", + "arguments": [ + "aarch64-none-elf-g++", + "-MMD", + "-MP", + "-MF", + "/Users/n.fedorov/dev/NXST/build/zip.d", + "-g", + "-O2", + "-ffunction-sections", + "-march=armv8-a+crc+crypto", + "-mtune=cortex-a57", + "-mtp=soft", + "-fPIE", + "-I/Users/n.fedorov/dev/NXST/include", + "-I/Users/n.fedorov/dev/NXST/include/fs", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/opt/devkitpro/portlibs/switch/include", + "-I/opt/devkitpro/libnx/include", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/Users/n.fedorov/dev/NXST/build", + "-D__SWITCH__", + "-fno-rtti", + "-fno-exceptions", + "-std=gnu++17", + "-c", + "/Users/n.fedorov/dev/NXST/source/fs/zip.cpp", + "-o", + "zip.o" + ], + "file": "/Users/n.fedorov/dev/NXST/source/fs/zip.cpp" + }, + { + "directory": "/Users/n.fedorov/dev/NXST", + "arguments": [ + "aarch64-none-elf-gcc", + "-MMD", + "-MP", + "-MF", + "/Users/n.fedorov/dev/NXST/build/fsfile.d", + "-g", + "-O2", + "-ffunction-sections", + "-march=armv8-a+crc+crypto", + "-mtune=cortex-a57", + "-mtp=soft", + "-fPIE", + "-I/Users/n.fedorov/dev/NXST/include", + "-I/Users/n.fedorov/dev/NXST/include/fs", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/opt/devkitpro/portlibs/switch/include", + "-I/opt/devkitpro/libnx/include", + "-I/Users/n.fedorov/dev/NXST/lib/Plutonium/include", + "-I/Users/n.fedorov/dev/NXST/build", + "-D__SWITCH__", + "-c", + "/Users/n.fedorov/dev/NXST/source/fs/fsfile.c", + "-o", + "fsfile.o" + ], + "file": "/Users/n.fedorov/dev/NXST/source/fs/fsfile.c" + } +] diff --git a/icon.jpg b/icon.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a060b1d670840494fcee93a37de6711f6a875132 GIT binary patch literal 5728 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 +#include +#include + +namespace ui { + + class MainApplication : public pu::ui::Application { + + public: + using Application::Application; + PU_SMART_CTOR(MainApplication) + + void OnLoad() override; + + // Layout instance + UsersLayout::Ref usersLayout; + TitlesLayout::Ref titlesLayout; + }; +} \ No newline at end of file diff --git a/include/TitlesLayout.hpp b/include/TitlesLayout.hpp new file mode 100644 index 0000000..747a1a2 --- /dev/null +++ b/include/TitlesLayout.hpp @@ -0,0 +1,19 @@ +#include +#include +#include + +namespace ui { + class TitlesLayout : public pu::ui::Layout { + private: + + pu::ui::elm::Menu::Ref titlesMenu; + + public: + + void InitTitles(); + + void onInput(u64 Down, u64 Up, u64 Held, pu::ui::TouchPoint Pos); + + PU_SMART_CTOR(TitlesLayout) + }; +} \ No newline at end of file diff --git a/include/UsersLayout.hpp b/include/UsersLayout.hpp new file mode 100644 index 0000000..f714f6a --- /dev/null +++ b/include/UsersLayout.hpp @@ -0,0 +1,22 @@ +#include +#include + +namespace ui { + + class UsersLayout : public pu::ui::Layout { + private: + + pu::ui::elm::Menu::Ref usersMenu; + + public: + + UsersLayout(); + + void onInput(u64 Down, u64 Up, u64 Held, pu::ui::TouchPoint Pos); + + int32_t GetCurrentIndex(); + + PU_SMART_CTOR(UsersLayout) + + }; +} diff --git a/include/const.h b/include/const.h new file mode 100644 index 0000000..8dda9ed --- /dev/null +++ b/include/const.h @@ -0,0 +1,2 @@ +#define BACKGROUND_COLOR COLOR("00FFFFFF") +#define COLOR(hex) pu::ui::Color::FromHex(hex) \ No newline at end of file diff --git a/include/data.h b/include/data.h new file mode 100644 index 0000000..17336de --- /dev/null +++ b/include/data.h @@ -0,0 +1,91 @@ +#pragma once +#include + +#include +#include +#include + +#define BLD_MON 02 +#define BLD_DAY 23 +#define BLD_YEAR 2023 + +namespace data +{ + //Loads user + title info + void init(); + void exit(); + bool loadUsersTitles(bool clearUsers); + void sortUserTitles(); + + //Draws some stats to the upper left corner + void dispStats(); + + //Global stuff for all titles/saves + typedef struct + { + NacpStruct nacp; + std::string title, safeTitle, author;//Shortcuts sorta. + bool fav; + } titleInfo; + + //Holds stuff specific to user's titles/saves + typedef struct + { + //Makes it easier to grab id + uint64_t tid; + FsSaveDataInfo saveInfo; + PdmPlayStatistics playStats; + } userTitleInfo; + + //Class to store user info + titles + class user + { + public: + user() = default; + user(const AccountUid& _id, const std::string& _backupName, const std::string& _safeBackupName); + + //Sets ID + void setUID(const AccountUid& _id); + + //Returns user ID + AccountUid getUID() const { return userID; } + u128 getUID128() const { return uID128; } + + //Returns username + std::string getUsername() const { return username; } + std::string getUsernameSafe() const { return userSafe; } + + std::vector titleInfo; + void addUserTitleInfo(const uint64_t& _tid, const FsSaveDataInfo *_saveInfo, const PdmPlayStatistics *_stats); + + private: + AccountUid userID; + u128 uID128; + std::string username, userSafe; + //User icon + }; + + //User vector + extern std::vector users; + //Title data/info map + extern std::unordered_map titles; + + //Sets/Retrieves current user/title + void setUserIndex(unsigned _sUser); + data::user *getCurrentUser(); + unsigned getCurrentUserIndex(); + + void setTitleIndex(unsigned _sTitle); + data::userTitleInfo *getCurrentUserTitleInfo(); + unsigned getCurrentUserTitleInfoIndex(); + + //Gets pointer to info that also has title + nacp + data::titleInfo *getTitleInfoByTID(const uint64_t& tid); + + //More shortcut functions + std::string getTitleNameByTID(const uint64_t& tid); + std::string getTitleSafeNameByTID(const uint64_t& tid); + int getTitleIndexInUser(const data::user& u, const uint64_t& tid); + extern SetLanguage sysLang; + +} \ No newline at end of file diff --git a/include/fs.h b/include/fs.h new file mode 100644 index 0000000..a582ba5 --- /dev/null +++ b/include/fs.h @@ -0,0 +1,54 @@ +#pragma once +#include + +#include +#include + +#include "fs/fstype.h" +#include "fs/file.h" +#include "fs/dir.h" +#include "fs/fsfile.h" +#include "fs/zip.h" + +#define BUFF_SIZE 0x4000 +#define ZIP_BUFF_SIZE 0x20000 +#define TRANSFER_BUFFER_LIMIT 0xC00000 + +namespace fs +{ + copyArgs *copyArgsCreate(const std::string& src, const std::string& dst, const std::string& dev, zipFile z, unzFile unz, bool _cleanup, bool _trimZipPath, uint8_t _trimPlaces); + void copyArgsDestroy(copyArgs *c); + + void init(); + bool mountSave(const FsSaveDataInfo& _m); + inline bool unmountSave() { return fsdevUnmountDevice("sv") == 0; } + bool commitToDevice(const std::string& dev); + std::string getWorkDir(); + void setWorkDir(const std::string& _w); + + //Loads paths to filter from backup/deletion + void loadPathFilters(const uint64_t& tid); + bool pathIsFiltered(const std::string& _path); + void freePathFilters(); + + void createSaveData(FsSaveDataType _type, uint64_t _tid, AccountUid _uid, threadInfo *t); + void createSaveDataThreaded(FsSaveDataType _type, uint64_t _tid, AccountUid _uid); + bool extendSaveData(const data::userTitleInfo *tinfo, uint64_t extSize, threadInfo *t); + void extendSaveDataThreaded(const data::userTitleInfo *tinfo, uint64_t extSize); + uint64_t getJournalSize(const data::userTitleInfo *tinfo); + uint64_t getJournalSizeMax(const data::userTitleInfo *tinfo); + + //Always threaded + void wipeSave(); + + void createNewBackup(void *a); + void overwriteBackup(void *a); + void restoreBackup(void *a); + void deleteBackup(void *a); + + void dumpAllUserSaves(void *a); + void dumpAllUsersAllSaves(void *a); + + void logOpen(); + void logWrite(const char *fmt, ...); +} diff --git a/include/fs/dir.h b/include/fs/dir.h new file mode 100644 index 0000000..8dc83b3 --- /dev/null +++ b/include/fs/dir.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include "type.h" + +namespace fs +{ + void mkDir(const std::string& _p); + void mkDirRec(const std::string& _p); + void delDir(const std::string& _p); + bool dirNotEmpty(const std::string& _dir); + bool isDir(const std::string& _path); + + //threadInfo is optional. Only for updating task status. + void copyDirToDir(const std::string& src, const std::string& dst, threadInfo *t); + void copyDirToDirThreaded(const std::string& src, const std::string& dst); + void copyDirToDirCommit(const std::string& src, const std::string& dst, const std::string& dev, threadInfo *t); + void copyDirToDirCommitThreaded(const std::string& src, const std::string& dst, const std::string& dev); + void getDirProps(const std::string& path, unsigned& dirCount, unsigned& fileCount, uint64_t& totalSize); + + class dirItem + { + public: + dirItem(const std::string& pathTo, const std::string& sItem); + std::string getItm() const { return itm; } + std::string getName() const; + std::string getExt() const; + bool isDir() const { return dir; } + + private: + std::string itm; + bool dir = false; + }; + + //Just retrieves a listing for _path and stores it in item vector + class dirList + { + public: + dirList() = default; + dirList(const std::string& _path); + void reassign(const std::string& _path); + void rescan(); + + std::string getItem(int index) const { return item[index].getItm(); } + std::string getItemExt(int index) const { return item[index].getExt(); } + bool isDir(int index) const { return item[index].isDir(); } + unsigned getCount() const { return item.size(); } + fs::dirItem *getDirItemAt(unsigned int _ind) { return &item[_ind]; } + + private: + std::string path; + std::vector item; + }; +} diff --git a/include/fs/file.h b/include/fs/file.h new file mode 100644 index 0000000..08ed43a --- /dev/null +++ b/include/fs/file.h @@ -0,0 +1,64 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "fs.h" +#include "data.h" + +namespace fs +{ + //Copy args are optional and only used if passed and threaded + void copyFile(const std::string& src, const std::string& dst, threadInfo *t); + void copyFileThreaded(const std::string& src, const std::string& dst); + void copyFileCommit(const std::string& src, const std::string& dst, const std::string& dev, threadInfo *t); + void copyFileCommitThreaded(const std::string& src, const std::string& dst, const std::string& dev); + void fileDrawFunc(void *a); + + //deletes file + void delfile(const std::string& _p); + + //Dumps all titles for current user + void dumpAllUserSaves(); + + void getShowFileProps(const std::string& _path); + void getShowDirProps(const std::string& _path); + + bool fileExists(const std::string& _path); + //Returns file size + size_t fsize(const std::string& _f); + + class dataFile + { + public: + dataFile(const std::string& _path); + ~dataFile(); + void close(){ fclose(f); } + + bool isOpen() const { return opened; } + + bool readNextLine(bool proc); + //Finds where variable name ends. When a '(' or '=' is hit. Strips spaces + void procLine(); + std::string getLine() const { return line; } + std::string getName() const { return name; } + //Reads until ';', ',', or '\n' is hit and returns as string. + std::string getNextValueStr(); + int getNextValueInt(); + + private: + FILE *f; + std::string line, name; + size_t lPos = 0; + bool opened = false; + }; + + void logOpen(); + void logWrite(const char *fmt, ...); + void logClose(); +} diff --git a/include/fs/fsfile.h b/include/fs/fsfile.h new file mode 100644 index 0000000..c84be82 --- /dev/null +++ b/include/fs/fsfile.h @@ -0,0 +1,100 @@ +#pragma once + +#include +#include + +//Bare minimum wrapper around switch fs for JKSV +#define FS_SEEK_SET 0 +#define FS_SEEK_CUR 1 +#define FS_SEEK_END 2 + +#ifdef __cplusplus +extern "C" +{ +#endif +typedef struct +{ + FsFile _f; + Result error; + s64 offset, fsize; +} FSFILE; + +int fsremove(const char *_p); +Result fsDelDirRec(const char *_p); + +char *getDeviceFromPath(char *dev, size_t _max, const char *path); +char *getFilePath(char *pathOut, size_t _max, const char *path); + +bool fsMkDir(const char *_p); + +/*Opens file. Device is fetched from path. Libnx romfs doesn't work with this. +Mode needs to be: + FsOpenMode_Read + FsOpenMode_Write + FsOpenMode_Append +*/ +bool fsfcreate(const char *_p, int64_t crSize); + +FSFILE *fsfopen(const char *_p, uint32_t mode); + +/*Same as above, but FsFileSystem _s is used. Path cannot have device in it*/ +FSFILE *fsfopenWithSystem(FsFileSystem *_s, const char *_p, uint32_t mode); + +//Closes _f +inline void fsfclose(FSFILE *_f) +{ + if(_f != NULL) + { + fsFileClose(&_f->_f); + free(_f); + } +} + +//Seeks like stdio +inline void fsfseek(FSFILE *_f, int offset, int origin) +{ + switch(origin) + { + case FS_SEEK_SET: + _f->offset = offset; + break; + + case FS_SEEK_CUR: + _f->offset += offset; + break; + + case FS_SEEK_END: + _f->offset = offset + _f->fsize; + break; + } +} + +//Returns offset +inline size_t fsftell(FSFILE *_f) { return _f->offset; } + +//Writes buf to file. Automatically resizes _f to fit buf +size_t fsfwrite(const void *buf, size_t sz, size_t count, FSFILE *_f); + +//Reads to buff +inline size_t fsfread(void *buf, size_t sz, size_t count, FSFILE *_f) +{ + uint64_t read = 0; + _f->error = fsFileRead(&_f->_f, _f->offset, buf, sz * count, 0, &read); + _f->offset += read; + return read; +} + +//Gets byte from file +inline char fsfgetc(FSFILE *_f) +{ + char ret = 0; + uint64_t read = 0; + _f->error = fsFileRead(&_f->_f, _f->offset++, &ret, 1, 0, &read); + return ret; +} + +//Writes byte to file +inline void fsfputc(int ch, FSFILE *_f) { fsfwrite(&ch, 1, 1, _f); } +#ifdef __cplusplus +} +#endif diff --git a/include/fs/fstype.h b/include/fs/fstype.h new file mode 100644 index 0000000..347f05d --- /dev/null +++ b/include/fs/fstype.h @@ -0,0 +1,46 @@ +#pragma once + +#include "data.h" +#include "type.h" +#include "ldn.h" + +namespace fs +{ + typedef struct + { + std::string src, dst, dev; + zipFile z; + unzFile unz; + LDN::LDNCommunicate *comm; + bool cleanup = false, trimZipPath = false; + uint8_t trimZipPlaces = 0; + uint64_t offset = 0; + threadStatus *thrdStatus; + Mutex arglck = 0; + void argLock() { mutexLock(&arglck); } + void argUnlock() { mutexUnlock(&arglck); } + } copyArgs; + + typedef struct + { + FsSaveDataType type; + uint64_t tid; + AccountUid account; + uint16_t index; + } svCreateArgs; + + typedef struct + { + const data::userTitleInfo *tinfo; + uint64_t extSize; + } svExtendArgs; + + typedef struct + { + std::string path; + bool origin = false; + unsigned dirCount = 0; + unsigned fileCount = 0; + uint64_t totalSize = 0; + } dirCountArgs; +} diff --git a/include/fs/ldn.h b/include/fs/ldn.h new file mode 100644 index 0000000..16b74fb --- /dev/null +++ b/include/fs/ldn.h @@ -0,0 +1,94 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "type.h" + +#define SAVE_DATA_SERVER_PORT 25789 +#define SOCKET_BUFFER_SIZE 4096 +#define LENGTH_OF_LISTEN_QUEUE 20 + +enum LDN_COMMUNICATE_TYPE { + UPDATE_FILE, + UPDATE_ABORT, + UPDATE_OK, + UPDATE_DONE, +}; + +struct LZ4_readFile_s { + LZ4F_dctx *dctxPtr; + int socket; + LZ4_byte *srcBuf; + size_t srcBufNext; + size_t srcBufSize; + size_t srcBufMaxSize; +}; + +struct LZ4_writeFile_s { + LZ4F_cctx *cctxPtr; + int socket; + LZ4_byte *dstBuf; + size_t maxWriteSize; + size_t dstBufMaxSize; + LZ4F_errorCode_t errCode; +}; + +namespace LDN { + typedef struct { + // point to server's socket fd; + int serverFD; + // point to communicate socket fd, send meta data + int commFD; + // for client to bind with server, communicate create file socket fd + struct sockaddr_in serverAddr; + } LDNCommunicate; + + typedef struct { + LDNCommunicate *comm; + unsigned int filesize = 0, writeLimit = 0; + std::string fullPath; + std::mutex bufferLock; + std::condition_variable cond; + std::vector sharedBuffer; + bool bufferIsFull = false; + std::string dst, dev; + LZ4_writeFile_s* lz4fWrite; + } LDNfcopyArgs; + + typedef struct { + u32 type; + size_t fsz; + } commMeta; + + void destroyLDN(); + + LDN::LDNCommunicate *createCommunicate(void); + + void destroyCommunicate(LDNCommunicate *comm); + + Result createLDNServer(LDNCommunicate *comm); + + Result createLDNClient(LDNCommunicate *comm); + + int bindClient(int serverFD); + + int bindServer(sockaddr_in *serverAddr); + + bool waitForOK(int socketfd); + bool waitForDONE(int socketfd); + void sendOK(int socket_fd); + void sendDONE(int socket_fd); + void sendAbort(int socket_fd); + void reciveMeta(commMeta *meta, int socketfd); + void sendMeta(commMeta *meta, int socketfd); + void copySaveFileToRemote(const std::string &local, threadInfo *t); + void copyRemoteSaveFile(threadInfo *t); +}; \ No newline at end of file diff --git a/include/fs/zip.h b/include/fs/zip.h new file mode 100644 index 0000000..4f8afb5 --- /dev/null +++ b/include/fs/zip.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +#include + +#include "type.h" + +namespace fs +{ + //threadInfo is optional and only used when threaded versions are used + void copyDirToZip(const std::string& src, zipFile dst, bool trimPath, int trimPlaces, threadInfo *t); + void copyDirToZipThreaded(const std::string& src, zipFile dst, bool trimPath, int trimPlaces); + void copyZipToDir(unzFile src, const std::string& dst, const std::string& dev, threadInfo *t); + void copyZipToDirThreaded(unzFile src, const std::string& dst, const std::string& dev); + uint64_t getZipTotalSize(unzFile unz); + bool zipNotEmpty(unzFile unz); +} diff --git a/include/threads.h b/include/threads.h new file mode 100644 index 0000000..a384904 --- /dev/null +++ b/include/threads.h @@ -0,0 +1,44 @@ +#include +#include "type.h" + +namespace threads { + + //pad data cause i don't know where else to put it + extern PadState pad; + extern HidTouchScreenState touchState; + + static inline void updateInput() { + touchState = {0}; + padUpdate(&pad); + hidGetTouchScreenStates(&touchState, 1); + } + + inline uint64_t padKeysDown() { return padGetButtonsDown(&pad); } + + inline uint64_t padKeysHeld() { return padGetButtons(&pad); } + + inline uint64_t padKeysUp() { return padGetButtonsUp(&pad); } + + threadInfo *newThread(ThreadFunc func, void *args, funcPtr _drawFunc); + + class threadProcMngr { + public: + ~threadProcMngr(); + + //Draw function is used and called to draw on overlay + threadInfo *newThread(ThreadFunc func, void *args, funcPtr _drawFunc); + + void update(); + + void draw(); + + bool empty() { return threads.empty(); } + + private: + std::vector threads; + uint8_t lgFrame = 0, clrShft = 0; + bool clrAdd = true; + unsigned frameCount = 0; + Mutex threadLock = 0; + }; +} diff --git a/include/type.h b/include/type.h new file mode 100644 index 0000000..4f73986 --- /dev/null +++ b/include/type.h @@ -0,0 +1,29 @@ +#pragma once +#include +#include +#include +#include + +//Misc stuff for new menu code +typedef void (*funcPtr)(void *); + +class threadStatus +{ + public: + void setStatus(const char *fmt, ...); + void getStatus(std::string& statusOut); + + private: + Mutex statusLock = 0; + std::string status; +}; + +typedef struct +{ + bool running = false, finished = false; + Thread thrd; + ThreadFunc thrdFunc; + void *argPtr = NULL; + funcPtr drawFunc = NULL;//Draw func is passed threadInfo pointer too + threadStatus *status; +} threadInfo; diff --git a/include/util.h b/include/util.h new file mode 100644 index 0000000..72548cc --- /dev/null +++ b/include/util.h @@ -0,0 +1,152 @@ +#pragma once + +#include "data.h" +//#include "ui.h" +#include "fs/file.h" +//#include "gfx.h" + +namespace util +{ + enum + { + DATE_FMT_YMD, + DATE_FMT_YDM, + DATE_FMT_HOYSTE, + DATE_FMT_JHK, + DATE_FMT_ASC + }; + + typedef enum + { + CPU_SPEED_204MHz = 204000000, + CPU_SPEED_306MHz = 306000000, + CPU_SPEED_408MHz = 408000000, + CPU_SPEED_510MHz = 510000000, + CPU_SPEED_612MHz = 612000000, + CPU_SPEED_714MHz = 714000000, + CPU_SPEED_816MHz = 816000000, + CPU_SPEED_918MHz = 918000000, + CPU_SPEED_1020MHz = 1020000000, //Default + CPU_SPEED_1122MHz = 1122000000, + CPU_SPEED_1224MHz = 1224000000, + CPU_SPEED_1326MHz = 1326000000, + CPU_SPEED_1428MHz = 1428000000, + CPU_SPEED_1581MHz = 1581000000, + CPU_SPEED_1683MHz = 1683000000, + CPU_SPEED_1785MHz = 1785000000 + } cpuSpds; + + typedef enum + { + GPU_SPEED_0MHz = 0, + GPU_SPEED_76MHz = 76800000, + GPU_SPEED_153MHz = 153600000, + GPU_SPEED_203MHz = 230400000, + GPU_SPEED_307MHz = 307200000, //Handheld 1 + GPU_SPEED_384MHz = 384000000, //Handheld 2 + GPU_SPEED_460MHz = 460800000, + GPU_SPEED_537MHz = 537600000, + GPU_SPEED_614MHz = 614400000, + GPU_SPEED_768MHz = 768000000, //Docked + GPU_SPEED_844MHz = 844800000, + GPU_SPEED_921MHZ = 921600000 + } gpuSpds; + + typedef enum + { + RAM_SPEED_0MHz = 0, + RAM_SPEED_40MHz = 40800000, + RAM_SPEED_68MHz = 68000000, + RAM_SPEED_102MHz = 102000000, + RAM_SPEED_204MHz = 204000000, + RAM_SPEED_408MHz = 408000000, + RAM_SPEED_665MHz = 665600000, + RAM_SPEED_800MHz = 800000000, + RAM_SPEED_1065MHz = 1065600000, + RAM_SPEED_1331MHz = 1331200000, + RAM_SPEED_1600MHz = 1600000000 + } ramSpds; + + //Returns string with date S+ time + std::string getDateTime(int fmt); + + //Removes last folder from '_path' + void removeLastFolderFromString(std::string& _path); + size_t getTotalPlacesInPath(const std::string& _path); + void trimPath(std::string& _path, uint8_t _places); + + inline bool isASCII(const uint32_t& t) + { + return t > 30 && t < 127; + } + + std::string safeString(const std::string& s); + + std::string getStringInput(SwkbdType _type, const std::string& def, const std::string& head, size_t maxLength, unsigned dictCnt, const std::string dictWords[]); + + std::string getExtensionFromString(const std::string& get); + std::string getFilenameFromPath(const std::string& get); + + std::string generateAbbrev(const uint64_t& tid); + + //removes char from C++ string + void stripChar(char _c, std::string& _s); + + void replaceStr(std::string& _str, const std::string& _find, const std::string& _rep); + + //For future external translation support. Replaces [button] with button chars + void replaceButtonsInString(std::string& rep); + + inline u128 accountUIDToU128(AccountUid uid) + { + return ((u128)uid.uid[0] << 64 | uid.uid[1]); + } + + inline AccountUid u128ToAccountUID(u128 id) + { + AccountUid ret; + ret.uid[0] = id >> 64; + ret.uid[1] = id; + return ret; + } + + inline std::string getIDStr(const uint64_t& _id) + { + char tmp[18]; + sprintf(tmp, "%016lX", _id); + return std::string(tmp); + } + + inline std::string getIDStrLower(const uint64_t& _id) + { + char tmp[18]; + sprintf(tmp, "%08X", (uint32_t)_id); + return std::string(tmp); + } + + inline std::string generatePathByTID(const uint64_t& tid) + { + return fs::getWorkDir() + data::getTitleSafeNameByTID(tid) + "/"; + } + + std::string getSizeString(const uint64_t& _size); + + inline void createTitleDirectoryByTID(const uint64_t& tid) + { + std::string makePath = fs::getWorkDir() + data::getTitleSafeNameByTID(tid); + mkdir(makePath.c_str(), 777); + } + + Result accountDeleteUser(AccountUid *uid); + + void sysBoost(); + void sysNormal(); + + inline bool isApplet() + { + AppletType type = appletGetAppletType(); + return type == AppletType_LibraryApplet; + } + + void checkForUpdate(void *a); +} \ No newline at end of file diff --git a/lib b/lib new file mode 160000 index 0000000..b56564b --- /dev/null +++ b/lib @@ -0,0 +1 @@ +Subproject commit b56564b70d038c59eef875f2c3cf436859c827f2 diff --git a/source/.DS_Store b/source/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4cf2dcae4bd9ca356c5b5178e1017bf154424ed9 GIT binary patch literal 6148 zcmeH~F%H5o3`K3|P>H1@V-^m;4WbH8&uWIwhEDnJFO02QDDRA5F5 z#5vxsX7o&a6e>Uk=AnRn9}?V{gQe0x9SA-GfDOuSSojDS;a)h^^03>!4ui +#include +#include + +static int nxlink_sock = -1; + +extern "C" void userAppInit() { + appletInitialize(); + hidInitialize(); + nsInitialize(); + setsysInitialize(); + setInitialize(); + accountInitialize(AccountServiceType_Administrator); + pmshellInitialize(); + socketInitializeDefault(); + pdmqryInitialize(); + nxlink_sock = nxlinkStdio(); + printf("userAppInit\n"); +} + +extern "C" void userAppExit() { + if (nxlink_sock != -1) { + close(nxlink_sock); + } + appletExit(); + hidExit(); + nsExit(); + setsysExit(); + setExit(); + accountExit(); + pmshellExit(); + socketExit(); + pdmqryExit(); +} + +// Main entrypoint +int main() { + printf("main\n"); + // First create our renderer, where one can customize SDL or other stuff's + // initialization. + auto renderer_opts = pu::ui::render::RendererInitOptions( + SDL_INIT_EVERYTHING, pu::ui::render::RendererHardwareFlags); + renderer_opts.UseImage(pu::ui::render::IMGAllFlags); + renderer_opts.UseAudio(pu::ui::render::MixerAllFlags); + renderer_opts.UseTTF(); + + auto renderer = pu::ui::render::Renderer::New(renderer_opts); + + data::init(); + fs::init(); + // Create our main application from the renderer + auto main = ui::MainApplication::New(renderer); + + main->Prepare(); + + main->Show(); + + return 0; +} diff --git a/source/MainApplication.cpp b/source/MainApplication.cpp new file mode 100644 index 0000000..c2fa9de --- /dev/null +++ b/source/MainApplication.cpp @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#include + +namespace ui { + MainApplication *mainApp; + + void MainApplication::OnLoad() { + mainApp = this; + this->usersLayout = UsersLayout::New(); + this->titlesLayout = TitlesLayout::New(); + this->usersLayout->SetOnInput( + std::bind(&UsersLayout::onInput, this->usersLayout, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4)); + this->titlesLayout->SetOnInput(std::bind(&TitlesLayout::onInput, this->titlesLayout,std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4)); + this->LoadLayout(this->usersLayout); + } +} \ No newline at end of file diff --git a/source/TitlesLayout.cpp b/source/TitlesLayout.cpp new file mode 100644 index 0000000..52822c2 --- /dev/null +++ b/source/TitlesLayout.cpp @@ -0,0 +1,71 @@ +#include +#include +#include +#include + +static std::vector accSids, devSids, bcatSids, cacheSids; + +//Sort save create tids alphabetically by title from data +static struct +{ + bool operator()(const uint64_t& tid1, const uint64_t& tid2) + { + std::string tid1Title = data::getTitleNameByTID(tid1); + std::string tid2Title = data::getTitleNameByTID(tid2); + + uint32_t pointA = 0, pointB = 0; + for(unsigned i = 0, j = 0; i < tid1Title.length(); ) + { + ssize_t tid1Cnt = decode_utf8(&pointA, (const uint8_t *)&tid1Title.c_str()[i]); + ssize_t tid2Cnt = decode_utf8(&pointB, (const uint8_t *)&tid2Title.c_str()[j]); + + pointA = tolower(pointA), pointB = tolower(pointB); + if(pointA != pointB) + return pointA < pointB; + + i += tid1Cnt, j += tid2Cnt; + } + return false; + } +} sortCreateTIDs; + +namespace ui { + extern MainApplication *mainApp; + void TitlesLayout::InitTitles() { + this->titlesMenu = pu::ui::elm::Menu::New(0, 0, 1280, COLOR("#67000000"), COLOR("#170909FF"), 94, 7); + const data::user *u = data::getCurrentUser(); + for(const data::userTitleInfo& t : u->titleInfo) { + auto titleItem = pu::ui::elm::MenuItem::New(data::getTitleNameByTID(t.tid).c_str()); + titleItem->SetColor(COLOR("#FFFFFFFF")); + titlesMenu->AddItem(titleItem); + } + + this->Add(this->titlesMenu); + + this->SetBackgroundColor(BACKGROUND_COLOR); + } + + void TitlesLayout::onInput(u64 Down, u64 Up, u64 Held, pu::ui::TouchPoint Pos) { + if (Down & HidNpadButton_Plus) { + mainApp->Close(); + return; + } + + if (Down & HidNpadButton_A) { + printf("current game index is %i\n", this->titlesMenu->GetSelectedIndex()); + data::setTitleIndex(this->titlesMenu->GetSelectedIndex()); + int opt = mainApp->CreateShowDialog("", "What do you want?", { "Transfer", "Receive" }, true); + printf("opt is %d\n", opt); + switch (opt) { + case 0: { + // Transfert selected + break; + } + case 1: { + // Receive selected + break; + } + } + } + } +} diff --git a/source/UsersLayout.cpp b/source/UsersLayout.cpp new file mode 100644 index 0000000..7c5629c --- /dev/null +++ b/source/UsersLayout.cpp @@ -0,0 +1,39 @@ +#include +#include +#include + +namespace ui { + extern MainApplication *mainApp; + + UsersLayout::UsersLayout() : Layout::Layout() { + this->usersMenu = pu::ui::elm::Menu::New(0, 0, 1280, COLOR("#67000000"), COLOR("#170909FF"), 94, + 7); + this->usersMenu->SetScrollbarColor(COLOR("#170909FF")); + + for (data::user &u: data::users) { + auto username = pu::ui::elm::MenuItem::New(u.getUsername() + ": " + std::to_string(u.titleInfo.size())); + username->SetColor(COLOR("#FFFFFFFF")); + this->usersMenu->AddItem(username); + } + this->SetBackgroundColor(BACKGROUND_COLOR); + this->Add(this->usersMenu); + } + + int32_t UsersLayout::GetCurrentIndex() { + return this->usersMenu->GetSelectedIndex(); + } + + void UsersLayout::onInput(u64 Down, u64 Up, u64 Held, pu::ui::TouchPoint Pos) { + if (Down & HidNpadButton_Plus) { + mainApp->Close(); + return; + } + + if (Down & HidNpadButton_A) { + printf("current index is %i\n", this->usersMenu->GetSelectedIndex()); + data::setUserIndex(this->usersMenu->GetSelectedIndex()); + mainApp->titlesLayout->InitTitles(); + mainApp->LoadLayout(mainApp->titlesLayout); + } + } +} diff --git a/source/data.cpp b/source/data.cpp new file mode 100644 index 0000000..9048f8d --- /dev/null +++ b/source/data.cpp @@ -0,0 +1,352 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "data.h" +#include "fs/file.h" +#include "util.h" +#include "type.h" + +//FsSaveDataSpaceId_All doesn't work for SD +static const unsigned saveOrder[] = {0, 1, 2, 3, 4, 100, 101}; + +int selUser = 0, selData = 0; + +//User vector +std::vector data::users; + +//For other save types +static bool sysBCATPushed = false, tempPushed = false; +std::unordered_map data::titles; + +//Sorts titles by sortType +static struct { + bool operator()(const data::userTitleInfo &a, const data::userTitleInfo &b) { + std::string titleA = data::getTitleNameByTID(a.tid); + std::string titleB = data::getTitleNameByTID(b.tid); + uint32_t pointA, pointB; + for (unsigned i = 0, j = 0; i < titleA.length();) { + ssize_t aCnt = decode_utf8(&pointA, (const uint8_t *) &titleA.data()[i]); + ssize_t bCnt = decode_utf8(&pointB, (const uint8_t *) &titleB.data()[j]); + pointA = tolower(pointA), pointB = tolower(pointB); + if (pointA != pointB) + return pointA < pointB; + + i += aCnt; + j += bCnt; + } + + return false; + } +} sortTitles; + +//Returns -1 for new +static int getUserIndex(const AccountUid &id) { + u128 nId = util::accountUIDToU128(id); + for (unsigned i = 0; i < data::users.size(); i++) + if (data::users[i].getUID128() == nId) return i; + + return -1; +} + +static inline bool accountSystemSaveCheck(const FsSaveDataInfo &_inf) { + if (_inf.save_data_type == FsSaveDataType_System && util::accountUIDToU128(_inf.uid) != 0) + return false; + + return true; +} + +//Minimal init/test to avoid loading and creating things I don't need +static bool testMount(const FsSaveDataInfo &_inf) { + bool ret = false; + + if ((ret = fs::mountSave(_inf))) + fs::unmountSave(); + + return ret; +} + +static inline void addTitleToList(const uint64_t &tid) { + uint64_t outSize = 0; + NsApplicationControlData *ctrlData = new NsApplicationControlData; + NacpLanguageEntry *ent; + Result ctrlRes = nsGetApplicationControlData(NsApplicationControlSource_Storage, tid, ctrlData, + sizeof(NsApplicationControlData), &outSize); + Result nacpRes = nacpGetLanguageEntry(&ctrlData->nacp, &ent); + size_t iconSize = outSize - sizeof(ctrlData->nacp); + + if (R_SUCCEEDED(ctrlRes) && !(outSize < sizeof(ctrlData->nacp)) && R_SUCCEEDED(nacpRes) && iconSize > 0) { + //Copy nacp + memcpy(&data::titles[tid].nacp, &ctrlData->nacp, sizeof(NacpStruct)); + + //Setup 'shortcuts' to strings + NacpLanguageEntry *ent; + nacpGetLanguageEntry(&data::titles[tid].nacp, &ent); + if (strlen(ent->name) == 0) + data::titles[tid].title = ctrlData->nacp.lang[SetLanguage_ENUS].name; + else + data::titles[tid].title = ent->name; + + data::titles[tid].author = ent->author; + + if ((data::titles[tid].safeTitle = util::safeString(ent->name)) == "") + data::titles[tid].safeTitle = util::getIDStr(tid); + } else { + memset(&data::titles[tid].nacp, 0, sizeof(NacpStruct)); + data::titles[tid].title = util::getIDStr(tid); + data::titles[tid].author = "Someone?"; + data::titles[tid].safeTitle = util::getIDStr(tid); + } + delete ctrlData; +} + +static inline bool titleIsLoaded(const uint64_t &tid) { + auto findTid = data::titles.find(tid); + + return findTid == data::titles.end() ? false : true; +} + +static void loadUserAccounts() { + s32 total = 0; + AccountUid *uids = new AccountUid[8]; + if (R_SUCCEEDED(accountListAllUsers(uids, 8, &total))) { + for (int i = 0; i < total; i++) + data::users.emplace_back(uids[i], "", ""); + } + delete[] uids; +} + +//This can load titles installed without having save data +static void loadTitlesFromRecords() { + NsApplicationRecord nsRecord; + int32_t entryCount = 0, recordOffset = 0; + while (R_SUCCEEDED(nsListApplicationRecord(&nsRecord, 1, recordOffset++, &entryCount)) && entryCount > 0) { + if (!titleIsLoaded(nsRecord.application_id)) + addTitleToList(nsRecord.application_id); + } +} + +bool data::loadUsersTitles(bool clearUsers) { + static unsigned systemUserCount = 4; + FsSaveDataInfoReader it; + FsSaveDataInfo info; + s64 total = 0; + + //Clear titles + for (data::user &u: data::users) + u.titleInfo.clear(); + if (clearUsers) { + systemUserCount = 4; + data::users.clear(); + + loadUserAccounts(); + sysBCATPushed = false; + tempPushed = false; + + users.emplace_back(util::u128ToAccountUID(3), "Device", "Device"); + users.emplace_back(util::u128ToAccountUID(2), "BCAT", "BCAT"); + users.emplace_back(util::u128ToAccountUID(5), "Cache", "Cache"); + users.emplace_back(util::u128ToAccountUID(0), "System", "System"); + } + + for (unsigned i = 0; i < 7; i++) { + if (R_FAILED(fsOpenSaveDataInfoReader(&it, (FsSaveDataSpaceId) saveOrder[i]))) + continue; + + while (R_SUCCEEDED(fsSaveDataInfoReaderRead(&it, &info, 1, &total)) && total != 0) { + uint64_t tid = 0; + if (info.save_data_type == FsSaveDataType_System || info.save_data_type == FsSaveDataType_SystemBcat) + tid = info.system_save_data_id; + else + tid = info.application_id; + + if (!titleIsLoaded(tid)) + addTitleToList(tid); + + //Don't bother with this stuff + if (!accountSystemSaveCheck(info) || !testMount(info)) + continue; + + switch (info.save_data_type) { + case FsSaveDataType_Bcat: + info.uid = util::u128ToAccountUID(2); + break; + + case FsSaveDataType_Device: + info.uid = util::u128ToAccountUID(3); + break; + + case FsSaveDataType_SystemBcat: + info.uid = util::u128ToAccountUID(4); + if (!sysBCATPushed) { + ++systemUserCount; + sysBCATPushed = true; + users.emplace_back(util::u128ToAccountUID(4), "System BCAT", + "System BCAT"); + } + break; + + case FsSaveDataType_Cache: + info.uid = util::u128ToAccountUID(5); + break; + + case FsSaveDataType_Temporary: + info.uid = util::u128ToAccountUID(6); + if (!tempPushed) { + ++systemUserCount; + tempPushed = true; + users.emplace_back(util::u128ToAccountUID(6), "Temporary", + "Temporary"); + } + break; + } + + int u = getUserIndex(info.uid); + if (u == -1) { + users.emplace(data::users.end() - systemUserCount, info.uid, "", ""); + u = getUserIndex(info.uid); + } + + PdmPlayStatistics playStats; + if (info.save_data_type == FsSaveDataType_Account || info.save_data_type == FsSaveDataType_Device) + pdmqryQueryPlayStatisticsByApplicationIdAndUserAccountId(info.application_id, info.uid, false, + &playStats); + else + memset(&playStats, 0, sizeof(PdmPlayStatistics)); + users[u].addUserTitleInfo(tid, &info, &playStats); + } + fsSaveDataInfoReaderClose(&it); + } + + //Get reference to device save user + unsigned devPos = getUserIndex(util::u128ToAccountUID(3)); + data::user &dev = data::users[devPos]; + for (unsigned i = 0; i < devPos; i++) { + //Not needed but makes this easier to read + data::user &u = data::users[i]; + u.titleInfo.insert(u.titleInfo.end(), dev.titleInfo.begin(), dev.titleInfo.end()); + } + + data::sortUserTitles(); + + return true; +} + +void data::sortUserTitles() { + + for (data::user &u: data::users) + std::sort(u.titleInfo.begin(), u.titleInfo.end(), sortTitles); +} + +void data::init() { + data::loadUsersTitles(true); +} + +void data::exit() { + /*Still needed for planned future revisions*/ +} + +void data::setUserIndex(unsigned _sUser) { + selUser = _sUser; +} + +data::user *data::getCurrentUser() { + return &users[selUser]; +} + +unsigned data::getCurrentUserIndex() { + return selUser; +} + +void data::setTitleIndex(unsigned _sTitle) { + selData = _sTitle; +} + +data::userTitleInfo *data::getCurrentUserTitleInfo() { + return &users[selUser].titleInfo[selData]; +} + +unsigned data::getCurrentUserTitleInfoIndex() { + return selData; +} + +data::titleInfo *data::getTitleInfoByTID(const uint64_t &tid) { + if (titles.find(tid) != titles.end()) + return &titles[tid]; + return NULL; +} + +std::string data::getTitleNameByTID(const uint64_t &tid) { + return titles[tid].title; +} + +std::string data::getTitleSafeNameByTID(const uint64_t &tid) { + return titles[tid].safeTitle; +} + +int data::getTitleIndexInUser(const data::user &u, const uint64_t &tid) { + for (unsigned i = 0; i < u.titleInfo.size(); i++) { + if (u.titleInfo[i].tid == tid) + return i; + } + return -1; +} + +data::user::user(const AccountUid &_id, const std::string &_backupName, const std::string &_safeBackupName) { + userID = _id; + uID128 = util::accountUIDToU128(_id); + + AccountProfile prof; + AccountProfileBase base; + + if (R_SUCCEEDED(accountGetProfile(&prof, userID)) && R_SUCCEEDED(accountProfileGet(&prof, NULL, &base))) { + username = base.nickname; + userSafe = util::safeString(username); + if (userSafe.empty()) { + char tmp[32]; + sprintf(tmp, "Acc%08X", (uint32_t) uID128); + userSafe = tmp; + } + + uint32_t jpgSize = 0; + accountProfileGetImageSize(&prof, &jpgSize); + uint8_t *jpegData = new uint8_t[jpgSize]; + accountProfileLoadImage(&prof, jpegData, jpgSize, &jpgSize); + delete[] jpegData; + + accountProfileClose(&prof); + } else { + username = _backupName.empty() ? util::getIDStr((uint64_t) uID128) : _backupName; + userSafe = _safeBackupName.empty() ? util::getIDStr((uint64_t) uID128) : _safeBackupName; + } + titles.reserve(64); +} + +void data::user::setUID(const AccountUid &_id) { + userID = _id; + uID128 = util::accountUIDToU128(_id); +} + +void data::user::addUserTitleInfo(const uint64_t &tid, const FsSaveDataInfo *_saveInfo, const PdmPlayStatistics *_stats) { + data::userTitleInfo newInfo; + newInfo.tid = tid; + memcpy(&newInfo.saveInfo, _saveInfo, sizeof(FsSaveDataInfo)); + memcpy(&newInfo.playStats, _stats, sizeof(PdmPlayStatistics)); + titleInfo.push_back(newInfo); +} + +void data::dispStats() { + data::user *cu = data::getCurrentUser(); + data::userTitleInfo *d = data::getCurrentUserTitleInfo(); + + //Easiest/laziest way to do this + std::string stats = std::to_string(users.size()) + "\n"; + for (data::user &u: data::users) { + stats += u.getUsername() + ": " + std::to_string(u.titleInfo.size()) + "\n"; + } +} diff --git a/source/fs.cpp b/source/fs.cpp new file mode 100644 index 0000000..13df28e --- /dev/null +++ b/source/fs.cpp @@ -0,0 +1,519 @@ +#include + +#include "fs.h" +#include "threads.h" +#include "util.h" + +static std::string wd = "sdmc:/NXST/"; + +static FSFILE *debLog; + +static FsFileSystem sv; + +static std::vector pathFilter; + +void fs::init() { + mkDirRec(wd); + fs::logOpen(); +} + +bool fs::mountSave(const FsSaveDataInfo &_m) { + Result svOpen; + FsSaveDataAttribute attr = {0}; + switch (_m.save_data_type) { + case FsSaveDataType_System: + case FsSaveDataType_SystemBcat: { + attr.uid = _m.uid; + attr.system_save_data_id = _m.system_save_data_id; + attr.save_data_type = _m.save_data_type; + svOpen = fsOpenSaveDataFileSystemBySystemSaveDataId(&sv, (FsSaveDataSpaceId) _m.save_data_space_id, &attr); + } + break; + + case FsSaveDataType_Account: { + attr.uid = _m.uid; + attr.application_id = _m.application_id; + attr.save_data_type = _m.save_data_type; + attr.save_data_rank = _m.save_data_rank; + attr.save_data_index = _m.save_data_index; + svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId) _m.save_data_space_id, &attr); + } + break; + + case FsSaveDataType_Device: { + attr.application_id = _m.application_id; + attr.save_data_type = FsSaveDataType_Device; + svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId) _m.save_data_space_id, &attr); + } + break; + + case FsSaveDataType_Bcat: { + attr.application_id = _m.application_id; + attr.save_data_type = FsSaveDataType_Bcat; + svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId) _m.save_data_space_id, &attr); + } + break; + + case FsSaveDataType_Cache: { + attr.application_id = _m.application_id; + attr.save_data_type = FsSaveDataType_Cache; + attr.save_data_index = _m.save_data_index; + svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId) _m.save_data_space_id, &attr); + } + break; + + case FsSaveDataType_Temporary: { + attr.application_id = _m.application_id; + attr.save_data_type = _m.save_data_type; + svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId) _m.save_data_space_id, &attr); + } + break; + + default: + svOpen = 1; + break; + } + + return R_SUCCEEDED(svOpen) && fsdevMountDevice("sv", sv) != -1; +} + +bool fs::commitToDevice(const std::string &dev) { + bool ret = true; + Result res = fsdevCommitDevice(dev.c_str()); + if (R_FAILED(res)) { + fs::logWrite("Error committing file to device -> 0x%X\n", res); + ret = false; + } + return ret; +} + +std::string fs::getWorkDir() { return wd; } + +void fs::setWorkDir(const std::string &_w) { wd = _w; } + + +void fs::loadPathFilters(const uint64_t &tid) { + char path[256]; + // sprintf(path, "sdmc:/config/JKSV/0x%016lX_filter.txt", tid); + if (fs::fileExists(path)) { + fs::dataFile filter(path); + while (filter.readNextLine(false)) + pathFilter.push_back(filter.getLine()); + } +} + +bool fs::pathIsFiltered(const std::string &_path) { + if (pathFilter.empty()) + return false; + + for (std::string &_p: pathFilter) { + if (_path == _p) + return true; + } + + return false; +} + +void fs::freePathFilters() { + pathFilter.clear(); +} + +void fs::createSaveData(FsSaveDataType _type, uint64_t _tid, AccountUid _uid, threadInfo *t) { + data::titleInfo *tinfo = data::getTitleInfoByTID(_tid); + if (t) + t->status->setStatus("Creating Save Data for #%s#...", tinfo->title.c_str()); + + uint16_t cacheIndex = 0; + std::string indexStr; + if (_type == FsSaveDataType_Cache && + !(indexStr = util::getStringInput(SwkbdType_NumPad, "0", "Enter cache index", 2, 0, NULL)).empty()) + cacheIndex = strtoul(indexStr.c_str(), NULL, 10); + else if (_type == FsSaveDataType_Cache && indexStr.empty()) { + if (t) + t->finished = true; + return; + } + + FsSaveDataAttribute attr; + memset(&attr, 0, sizeof(FsSaveDataAttribute)); + attr.application_id = _tid; + attr.uid = _uid; + attr.system_save_data_id = 0; + attr.save_data_type = _type; + attr.save_data_rank = 0; + attr.save_data_index = cacheIndex; + + FsSaveDataCreationInfo crt; + memset(&crt, 0, sizeof(FsSaveDataCreationInfo)); + int64_t saveSize = 0, journalSize = 0; + switch (_type) { + case FsSaveDataType_Account: + saveSize = tinfo->nacp.user_account_save_data_size; + journalSize = tinfo->nacp.user_account_save_data_journal_size; + break; + + case FsSaveDataType_Device: + saveSize = tinfo->nacp.device_save_data_size; + journalSize = tinfo->nacp.device_save_data_journal_size; + break; + + case FsSaveDataType_Bcat: + saveSize = tinfo->nacp.bcat_delivery_cache_storage_size; + journalSize = tinfo->nacp.bcat_delivery_cache_storage_size; + break; + + case FsSaveDataType_Cache: + saveSize = 32 * 1024 * 1024; + if (tinfo->nacp.cache_storage_journal_size > tinfo->nacp.cache_storage_data_and_journal_size_max) + journalSize = tinfo->nacp.cache_storage_journal_size; + else + journalSize = tinfo->nacp.cache_storage_data_and_journal_size_max; + break; + + default: + if (t) + t->finished = true; + return; + break; + } + crt.save_data_size = saveSize; + crt.journal_size = journalSize; + crt.available_size = 0x4000; + crt.owner_id = _type == FsSaveDataType_Bcat ? 0x010000000000000C : tinfo->nacp.save_data_owner_id; + crt.flags = 0; + crt.save_data_space_id = FsSaveDataSpaceId_User; + + FsSaveDataMetaInfo meta; + memset(&meta, 0, sizeof(FsSaveDataMetaInfo)); + if (_type != FsSaveDataType_Bcat) { + meta.size = 0x40060; + meta.type = FsSaveDataMetaType_Thumbnail; + } + + Result res = 0; + if (R_SUCCEEDED(res = fsCreateSaveDataFileSystem(&attr, &crt, &meta))) { + util::createTitleDirectoryByTID(_tid); + data::loadUsersTitles(false); + } else { + fs::logWrite("SaveCreate Failed -> %X\n", res); + } +} + +static void createSaveData_t(void *a) { + threadInfo *t = (threadInfo *) a; + fs::svCreateArgs *crt = (fs::svCreateArgs *) t->argPtr; + fs::createSaveData(crt->type, crt->tid, crt->account, t); + delete crt; + t->finished = true; +} + +void fs::createSaveDataThreaded(FsSaveDataType _type, uint64_t _tid, AccountUid _uid) { + fs::svCreateArgs *send = new fs::svCreateArgs; + send->type = _type; + send->tid = _tid; + send->account = _uid; + threads::newThread(createSaveData_t, send, NULL); +} + +bool fs::extendSaveData(const data::userTitleInfo *tinfo, uint64_t extSize, threadInfo *t) { + if (t) + t->status->setStatus("Extending Save Data for #%s#...", data::getTitleNameByTID(tinfo->tid).c_str()); + + uint64_t journal = fs::getJournalSizeMax(tinfo); + uint64_t saveID = tinfo->saveInfo.save_data_id; + FsSaveDataSpaceId space = (FsSaveDataSpaceId) tinfo->saveInfo.save_data_space_id; + Result res = 0; + if (R_FAILED((res = fsExtendSaveDataFileSystem(space, saveID, extSize, journal)))) { + int64_t totalSize = 0; + fs::mountSave(tinfo->saveInfo); + fsFsGetTotalSpace(fsdevGetDeviceFileSystem("sv"), "/", &totalSize); + fs::unmountSave(); + + fs::logWrite("Extend Failed: %uMB to %uMB -> %X\n", totalSize / 1024 / 1024, extSize / 1024 / 1024, res); +// ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataExtendFailed", 0)); + return false; + } + return true; +} + +static void extendSaveData_t(void *a) { + threadInfo *t = (threadInfo *) a; + fs::svExtendArgs *e = (fs::svExtendArgs *) t->argPtr; + fs::extendSaveData(e->tinfo, e->extSize, t); + delete e; + t->finished = true; +} + +void fs::extendSaveDataThreaded(const data::userTitleInfo *tinfo, uint64_t extSize) { + fs::svExtendArgs *send = new fs::svExtendArgs; + send->tinfo = tinfo; + send->extSize = extSize; + threads::newThread(extendSaveData_t, send, NULL); +} + +uint64_t fs::getJournalSize(const data::userTitleInfo *tinfo) { + uint64_t ret = 0; + data::titleInfo *t = data::getTitleInfoByTID(tinfo->tid); + switch (tinfo->saveInfo.save_data_type) { + case FsSaveDataType_Account: + ret = t->nacp.user_account_save_data_journal_size; + break; + + case FsSaveDataType_Device: + ret = t->nacp.device_save_data_journal_size; + break; + + case FsSaveDataType_Bcat: + ret = t->nacp.bcat_delivery_cache_storage_size; + break; + + case FsSaveDataType_Cache: + if (t->nacp.cache_storage_journal_size > 0) + ret = t->nacp.cache_storage_journal_size; + else + ret = t->nacp.cache_storage_data_and_journal_size_max; + break; + + default: + ret = BUFF_SIZE; + break; + } + return ret; +} + +uint64_t fs::getJournalSizeMax(const data::userTitleInfo *tinfo) { + uint64_t ret = 0; + data::titleInfo *extend = data::getTitleInfoByTID(tinfo->tid); + switch (tinfo->saveInfo.save_data_type) { + case FsSaveDataType_Account: + if (extend->nacp.user_account_save_data_journal_size_max > extend->nacp.user_account_save_data_journal_size) + ret = extend->nacp.user_account_save_data_journal_size_max; + else + ret = extend->nacp.user_account_save_data_journal_size; + break; + + case FsSaveDataType_Bcat: + ret = extend->nacp.bcat_delivery_cache_storage_size; + break; + + case FsSaveDataType_Cache: + if (extend->nacp.cache_storage_data_and_journal_size_max > extend->nacp.cache_storage_journal_size) + ret = extend->nacp.cache_storage_data_and_journal_size_max; + else + ret = extend->nacp.cache_storage_journal_size; + break; + + case FsSaveDataType_Device: + if (extend->nacp.device_save_data_journal_size_max > extend->nacp.device_save_data_journal_size) + ret = extend->nacp.device_save_data_journal_size_max; + else + ret = extend->nacp.device_save_data_journal_size; + break; + + default: + //will just fail + ret = 0; + break; + } + return ret; +} + +static void wipeSave_t(void *a) { + threadInfo *t = (threadInfo *) a; + t->status->setStatus("Resetting save data..."); + fs::delDir("sv:/"); + fs::commitToDevice("sv"); + t->finished = true; +} + +void fs::wipeSave() { + threads::newThread(wipeSave_t, NULL, NULL); +} + +void fs::createNewBackup(void *a) { + if (!fs::dirNotEmpty("sv:/")) { +// ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popSaveIsEmpty", 0)); + return; + } + + uint64_t held = threads::padKeysHeld(); + + data::user *u = data::getCurrentUser(); + data::userTitleInfo *d = data::getCurrentUserTitleInfo(); + data::titleInfo *t = data::getTitleInfoByTID(d->tid); + + std::string out; + + const std::string dict[] = + { + util::getDateTime(util::DATE_FMT_YMD), + util::getDateTime(util::DATE_FMT_YDM), + util::getDateTime(util::DATE_FMT_HOYSTE), + util::getDateTime(util::DATE_FMT_JHK), + util::getDateTime(util::DATE_FMT_ASC), + u->getUsernameSafe(), + t->safeTitle, + util::generateAbbrev(d->tid), + ".zip" + }; + std::string defaultText = u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD); + out = util::getStringInput(SwkbdType_QWERTY, defaultText, "Enter a new name", 64, 9, dict); + out = util::safeString(out); + + if (!out.empty()) { + std::string ext = util::getExtensionFromString(out); + std::string path = util::generatePathByTID(d->tid) + out; + + fs::mkDir(path); + path += "/"; + fs::copyDirToDirThreaded("sv:/", path); +// ui::fldRefreshMenu(); + } +} + +void fs::overwriteBackup(void *a) { + threadInfo *t = (threadInfo *) a; + std::string *dst = (std::string *) t->argPtr; + bool saveHasFiles = fs::dirNotEmpty("sv:/"); + if (fs::isDir(*dst) && saveHasFiles) { + fs::delDir(*dst); + fs::mkDir(*dst); + dst->append("/"); + fs::copyDirToDirThreaded("sv:/", *dst); + } + delete dst; + t->finished = true; +} + +void fs::restoreBackup(void *a) { + threadInfo *t = (threadInfo *) a; + std::string *restore = (std::string *) t->argPtr; + data::user *u = data::getCurrentUser(); + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + if ((utinfo->saveInfo.save_data_type != FsSaveDataType_System)) { + bool saveHasFiles = fs::dirNotEmpty("sv:/"); + if (saveHasFiles) { + std::string autoFolder = util::generatePathByTID(utinfo->tid) + "/AUTO - " + u->getUsernameSafe() + " - " + + util::getDateTime(util::DATE_FMT_YMD) + "/"; + fs::mkDir(autoFolder.substr(0, autoFolder.length() - 1)); + fs::copyDirToDirThreaded("sv:/", autoFolder); + } + + if (fs::isDir(*restore)) { + restore->append("/"); + if (fs::dirNotEmpty(*restore)) { + t->status->setStatus("Calculating save data size..."); + unsigned dirCount = 0, fileCount = 0; + uint64_t saveSize = 0; + int64_t availSize = 0; + fs::getDirProps(*restore, dirCount, fileCount, saveSize); + fsFsGetTotalSpace(fsdevGetDeviceFileSystem("sv"), "/", &availSize); + if ((int) saveSize > availSize) { + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + fs::unmountSave(); + fs::extendSaveData(utinfo, saveSize + 0x500000, t); + fs::mountSave(utinfo->saveInfo); + } + + fs::wipeSave(); + fs::copyDirToDirCommitThreaded(*restore, "sv:/", "sv"); + } +// else +// ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popFolderIsEmpty", 0)); + } else { + std::string dstPath = "sv:/" + util::getFilenameFromPath(*restore); + fs::copyFileCommitThreaded(*restore, dstPath, "sv"); + } + } + + delete restore; + t->finished = true; +} + +void fs::deleteBackup(void *a) { + threadInfo *t = (threadInfo *) a; + std::string *deletePath = (std::string *) t->argPtr; + std::string backupName = util::getFilenameFromPath(*deletePath); + + t->status->setStatus("Deleting..."); + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + + if (fs::isDir(*deletePath)) { + *deletePath += "/"; + fs::delDir(*deletePath); +// ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupDeleted", 0), backupName.c_str()); + } else { + fs::delfile(*deletePath); +// ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupDeleted", 0), backupName.c_str()); + } +// ui::fldRefreshMenu(); + delete deletePath; + t->finished = true; +} + +void fs::dumpAllUserSaves(void *a) { + threadInfo *t = (threadInfo *) a; + fs::copyArgs *c = fs::copyArgsCreate("", "", "", NULL, NULL, false, false, 0); + t->argPtr = c; + data::user *u = data::getCurrentUser(); + + for (unsigned i = 0; i < u->titleInfo.size(); i++) { + bool saveMounted = fs::mountSave(u->titleInfo[i].saveInfo); + util::createTitleDirectoryByTID(u->titleInfo[i].tid); + if (saveMounted && fs::dirNotEmpty("sv:/")) { + fs::loadPathFilters(u->titleInfo[i].tid); + std::string dst = util::generatePathByTID(u->titleInfo[i].tid) + u->getUsernameSafe() + " - " + + util::getDateTime(util::DATE_FMT_YMD) + "/"; + fs::mkDir(dst.substr(0, dst.length() - 1)); + fs::copyDirToDir("sv:/", dst, t); + fs::freePathFilters(); + } + fs::unmountSave(); + } + fs::copyArgsDestroy(c); + t->finished = true; +} + +void fs::dumpAllUsersAllSaves(void *a) { + threadInfo *t = (threadInfo *) a; + fs::copyArgs *c = fs::copyArgsCreate("", "", "", NULL, NULL, false, false, 0); + t->argPtr = c; + unsigned curUser = 0; + while (data::users[curUser].getUID128() != 2) { + data::user *u = &data::users[curUser++]; + for (unsigned i = 0; i < u->titleInfo.size(); i++) { + bool saveMounted = fs::mountSave(u->titleInfo[i].saveInfo); + util::createTitleDirectoryByTID(u->titleInfo[i].tid); + if (saveMounted && fs::dirNotEmpty("sv:/")) { + fs::loadPathFilters(u->titleInfo[i].tid); + std::string dst = util::generatePathByTID(u->titleInfo[i].tid) + u->getUsernameSafe() + " - " + + util::getDateTime(util::DATE_FMT_YMD) + "/"; + fs::mkDir(dst.substr(0, dst.length() - 1)); + fs::copyDirToDir("sv:/", dst, t); + fs::freePathFilters(); + } + fs::unmountSave(); + } + } + fs::copyArgsDestroy(c); + t->finished = true; +} + +void fs::logOpen() { + std::string logPath = wd + "log.txt"; + debLog = fsfopen(logPath.c_str(), FsOpenMode_Write); + fsfclose(debLog); +} + +void fs::logWrite(const char *fmt, ...) { + std::string logPath = wd + "log.txt"; + debLog = fsfopen(logPath.c_str(), FsOpenMode_Append | FsOpenMode_Write); + char tmp[256]; + va_list args; + va_start(args, fmt); + vsprintf(tmp, fmt, args); + va_end(args); + fsfwrite(tmp, 1, strlen(tmp), debLog); + fsfclose(debLog); +} + diff --git a/source/fs/dir.cpp b/source/fs/dir.cpp new file mode 100644 index 0000000..20b3164 --- /dev/null +++ b/source/fs/dir.cpp @@ -0,0 +1,266 @@ +#include +#include + +#include "fs.h" +#include "util.h" +#include + +static struct +{ + bool operator()(const fs::dirItem& a, const fs::dirItem& b) + { + if(a.isDir() != b.isDir()) + return a.isDir(); + + for(unsigned i = 0; i < a.getItm().length(); i++) + { + char charA = tolower(a.getItm()[i]); + char charB = tolower(b.getItm()[i]); + if(charA != charB) + return charA < charB; + } + return false; + } +} sortDirList; + +void fs::mkDir(const std::string& _p) +{ + mkdir(_p.c_str(), 777); +} + +void fs::mkDirRec(const std::string& _p) +{ + //skip first slash + size_t pos = _p.find('/', 0) + 1; + while((pos = _p.find('/', pos)) != _p.npos) + { + fs::mkDir(_p.substr(0, pos).c_str()); + ++pos; + } +} + +void fs::delDir(const std::string& path) +{ + dirList list(path); + for(unsigned i = 0; i < list.getCount(); i++) + { + if(pathIsFiltered(path + list.getItem(i))) + continue; + + if(list.isDir(i)) + { + std::string newPath = path + list.getItem(i) + "/"; + delDir(newPath); + + std::string delPath = path + list.getItem(i); + // rmdir(delPath.c_str()); + } + else + { + std::string delPath = path + list.getItem(i); + std::remove(delPath.c_str()); + } + } + // rmdir(path.c_str()); +} + +bool fs::dirNotEmpty(const std::string& _dir) +{ + fs::dirList tmp(_dir); + return tmp.getCount() > 0; +} + +bool fs::isDir(const std::string& _path) +{ + struct stat s; + return stat(_path.c_str(), &s) == 0 && S_ISDIR(s.st_mode); +} + +void fs::copyDirToDir(const std::string& src, const std::string& dst, threadInfo *t) +{ + if(t) + t->status->setStatus("Opening '#%s#'..."); + + fs::dirList *list = new fs::dirList(src); + for(unsigned i = 0; i < list->getCount(); i++) + { + if(pathIsFiltered(src + list->getItem(i))) + continue; + + if(list->isDir(i)) + { + std::string newSrc = src + list->getItem(i) + "/"; + std::string newDst = dst + list->getItem(i) + "/"; + fs::mkDir(newDst.substr(0, newDst.length() - 1)); + fs::copyDirToDir(newSrc, newDst, t); + } + else + { + std::string fullSrc = src + list->getItem(i); + std::string fullDst = dst + list->getItem(i); + + if(t) + t->status->setStatus("Copying '#%s#'..."); + + fs::copyFile(fullSrc, fullDst, t); + } + } + delete list; +} + +static void copyDirToDir_t(void *a) +{ + threadInfo *t = (threadInfo *)a; + fs::copyArgs *in = (fs::copyArgs *)t->argPtr; + fs::copyDirToDir(in->src, in->dst, t); + if(in->cleanup) + fs::copyArgsDestroy(in); + t->finished = true; +} + +void fs::copyDirToDirThreaded(const std::string& src, const std::string& dst) +{ + fs::copyArgs *send = fs::copyArgsCreate(src, dst, "", NULL, NULL, true, false, 0); + threads::newThread(copyDirToDir_t, send, fs::fileDrawFunc); +} + +void fs::copyDirToDirCommit(const std::string& src, const std::string& dst, const std::string& dev, threadInfo *t) +{ + if(t) + t->status->setStatus("Opening '#%s#'..."); + + fs::dirList *list = new fs::dirList(src); + for(unsigned i = 0; i < list->getCount(); i++) + { + if(pathIsFiltered(src + list->getItem(i))) + continue; + + if(list->isDir(i)) + { + std::string newSrc = src + list->getItem(i) + "/"; + std::string newDst = dst + list->getItem(i) + "/"; + fs::mkDir(newDst.substr(0, newDst.length() - 1)); + fs::copyDirToDirCommit(newSrc, newDst, dev, t); + } + else + { + std::string fullSrc = src + list->getItem(i); + std::string fullDst = dst + list->getItem(i); + + if(t) + t->status->setStatus("Copying '#%s#'..."); + + fs::copyFileCommit(fullSrc, fullDst, dev, t); + } + } + delete list; +} + +static void copyDirToDirCommit_t(void *a) +{ + threadInfo *t = (threadInfo *)a; + fs::copyArgs *in = (fs::copyArgs *)t->argPtr; + fs::copyDirToDirCommit(in->src, in->dst, in->dev, t); + if(in->cleanup) + fs::copyArgsDestroy(in); + t->finished = true; +} + +void fs::copyDirToDirCommitThreaded(const std::string& src, const std::string& dst, const std::string& dev) +{ + fs::copyArgs *send = fs::copyArgsCreate(src, dst, dev, NULL, NULL, true, false, 0); + threads::newThread(copyDirToDirCommit_t, send, fs::fileDrawFunc); +} + +void fs::getDirProps(const std::string& path, unsigned& dirCount, unsigned& fileCount, uint64_t& totalSize) +{ + fs::dirList *d = new fs::dirList(path); + for(unsigned i = 0; i < d->getCount(); i++) + { + if(d->isDir(i)) + { + ++dirCount; + std::string newPath = path + d->getItem(i) + "/"; + fs::getDirProps(newPath, dirCount, fileCount, totalSize); + } + else + { + ++fileCount; + std::string filePath = path + d->getItem(i); + totalSize += fs::fsize(filePath); + } + } + delete d; +} + +fs::dirItem::dirItem(const std::string& pathTo, const std::string& sItem) +{ + itm = sItem; + + std::string fullPath = pathTo + sItem; + struct stat s; + if(stat(fullPath.c_str(), &s) == 0 && S_ISDIR(s.st_mode)) + dir = true; +} + +std::string fs::dirItem::getName() const +{ + size_t extPos = itm.find_last_of('.'), slPos = itm.find_last_of('/'); + if(extPos == itm.npos) + return ""; + + return itm.substr(slPos + 1, extPos); +} + +std::string fs::dirItem::getExt() const +{ + return util::getExtensionFromString(itm); +} + +fs::dirList::dirList(const std::string& _path) +{ + DIR *d; + struct dirent *ent; + path = _path; + d = opendir(path.c_str()); + + while((ent = readdir(d))) + item.emplace_back(path, ent->d_name); + + closedir(d); + + std::sort(item.begin(), item.end(), sortDirList); +} + +void fs::dirList::reassign(const std::string& _path) +{ + DIR *d; + struct dirent *ent; + path = _path; + + d = opendir(path.c_str()); + + item.clear(); + + while((ent = readdir(d))) + item.emplace_back(path, ent->d_name); + + closedir(d); + + std::sort(item.begin(), item.end(), sortDirList); +} + +void fs::dirList::rescan() +{ + item.clear(); + DIR *d; + struct dirent *ent; + d = opendir(path.c_str()); + + while((ent = readdir(d))) + item.emplace_back(path, ent->d_name); + + closedir(d); + + std::sort(item.begin(), item.end(), sortDirList); +} diff --git a/source/fs/file.cpp b/source/fs/file.cpp new file mode 100644 index 0000000..4911d7d --- /dev/null +++ b/source/fs/file.cpp @@ -0,0 +1,383 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fs.h" +#include "util.h" +#include "data.h" +#include + +static std::string wd = "sdmc:/JKSV/"; + +typedef struct +{ + std::mutex bufferLock; + std::condition_variable cond; + std::vector sharedBuffer; + std::string dst, dev; + bool bufferIsFull = false; + unsigned int filesize = 0, writeLimit = 0; +} fileCpyThreadArgs; + +static void writeFile_t(void *a) +{ + fileCpyThreadArgs *in = (fileCpyThreadArgs *)a; + size_t written = 0; + std::vector localBuffer; + std::FILE *out = std::fopen(in->dst.c_str(), "wb"); + + while(written < in->filesize) + { + std::unique_lock buffLock(in->bufferLock); + in->cond.wait(buffLock, [in]{ return in->bufferIsFull;}); + localBuffer.clear(); + localBuffer.assign(in->sharedBuffer.begin(), in->sharedBuffer.end()); + in->sharedBuffer.clear(); + in->bufferIsFull = false; + buffLock.unlock(); + in->cond.notify_one(); + written += fwrite(localBuffer.data(), 1, localBuffer.size(), out); + } + fclose(out); +} + +static void writeFileCommit_t(void *a) +{ + fileCpyThreadArgs *in = (fileCpyThreadArgs *)a; + size_t written = 0, journalCount = 0; + std::vector localBuffer; + FILE *out = fopen(in->dst.c_str(), "wb"); + + while(written < in->filesize) + {` + std::unique_lock buffLock(in->bufferLock); + in->cond.wait(buffLock, [in]{ return in->bufferIsFull; }); + localBuffer.clear(); + localBuffer.assign(in->sharedBuffer.begin(), in->sharedBuffer.end()); + in->sharedBuffer.clear(); + in->bufferIsFull = false; + buffLock.unlock(); + in->cond.notify_one(); + + written += fwrite(localBuffer.data(), 1, localBuffer.size(), out); + + journalCount += written; + if(journalCount >= in->writeLimit) + { + journalCount = 0; + fclose(out); + fs::commitToDevice(in->dev.c_str()); + out = fopen(in->dst.c_str(), "ab"); + } + } + fclose(out); +} + +fs::copyArgs *fs::copyArgsCreate(const std::string& src, const std::string& dst, const std::string& dev, zipFile z, unzFile unz, bool _cleanup, bool _trimZipPath, uint8_t _trimPlaces) +{ + copyArgs *ret = new copyArgs; + ret->src = src; + ret->dst = dst; + ret->dev = dev; + ret->z = z; + ret->unz = unz; + ret->cleanup = _cleanup; + ret->offset = 0; + ret->trimZipPath = _trimZipPath; + ret->trimZipPlaces = _trimPlaces; + return ret; +} + +void fs::copyArgsDestroy(copyArgs *c) +{ + // delete c->prog; + delete c; + c = NULL; +} + +fs::dataFile::dataFile(const std::string& _path) +{ + f = fopen(_path.c_str(), "r"); + if(f != NULL) + opened = true; +} + +fs::dataFile::~dataFile() +{ + fclose(f); +} + +bool fs::dataFile::readNextLine(bool proc) +{ + bool ret = false; + char tmp[1024]; + while(fgets(tmp, 1024, f)) + { + if(tmp[0] != '#' && tmp[0] != '\n' && tmp[0] != '\r') + { + line = tmp; + ret = true; + break; + } + } + util::stripChar('\n', line); + util::stripChar('\r', line); + if(proc) + procLine(); + + return ret; +} + +void fs::dataFile::procLine() +{ + size_t pPos = line.find_first_of("(=,"); + if(pPos != line.npos) + { + lPos = pPos; + name.assign(line.begin(), line.begin() + lPos); + } + else + name = line; + + util::stripChar(' ', name); + ++lPos; +} + +std::string fs::dataFile::getNextValueStr() +{ + std::string ret = ""; + //Skip all spaces until we hit actual text + size_t pos1 = line.find_first_not_of(", ", lPos); + //If reading from quotes + if(line[pos1] == '"') + lPos = line.find_first_of('"', ++pos1); + else + lPos = line.find_first_of(",;\n", pos1);//Set lPos to end of string we want. This should just set lPos to the end of the line if it fails, which is ok + + ret = line.substr(pos1, lPos++ - pos1); + + util::replaceStr(ret, "\\n", "\n"); + + return ret; +} + +int fs::dataFile::getNextValueInt() +{ + int ret = 0; + std::string no = getNextValueStr(); + if(no[0] == '0' && tolower(no[1]) == 'x') + ret = strtoul(no.c_str(), NULL, 16); + else + ret = strtoul(no.c_str(), NULL, 10); + + return ret; +} + +void fs::copyFile(const std::string& src, const std::string& dst, threadInfo *t) +{ + fs::copyArgs *c = NULL; + size_t filesize = fs::fsize(src); + if(t) + { + c = (fs::copyArgs *)t->argPtr; + c->offset = 0; + } + + FILE *fsrc = fopen(src.c_str(), "rb"); + if(!fsrc) + { + fclose(fsrc); + return; + } + + fileCpyThreadArgs thrdArgs; + thrdArgs.dst = dst; + thrdArgs.filesize = filesize; + + uint8_t *buff = new uint8_t[BUFF_SIZE]; + std::vector transferBuffer; + Thread writeThread; + threadCreate(&writeThread, writeFile_t, &thrdArgs, NULL, 0x40000, 0x2E, 2); + threadStart(&writeThread); + size_t readIn = 0; + uint64_t readCount = 0; + while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0) + { + transferBuffer.insert(transferBuffer.end(), buff, buff + readIn); + readCount += readIn; + + if(c) + c->offset = readCount; + + if(transferBuffer.size() >= TRANSFER_BUFFER_LIMIT || readCount == filesize) + { + std::unique_lock buffLock(thrdArgs.bufferLock); + thrdArgs.cond.wait(buffLock, [&thrdArgs]{ return thrdArgs.bufferIsFull == false; }); + thrdArgs.sharedBuffer.assign(transferBuffer.begin(), transferBuffer.end()); + transferBuffer.clear(); + thrdArgs.bufferIsFull = true; + buffLock.unlock(); + thrdArgs.cond.notify_one(); + } + } + threadWaitForExit(&writeThread); + threadClose(&writeThread); + fclose(fsrc); + delete[] buff; +} + + +static void copyFileThreaded_t(void *a) +{ + threadInfo *t = (threadInfo *)a; + fs::copyArgs *in = (fs::copyArgs *)t->argPtr; + + t->status->setStatus("Copy file", in->src.c_str()); + + fs::copyFile(in->src, in->dst, t); + if(in->cleanup) + fs::copyArgsDestroy(in); + t->finished = true; +} + +void fs::copyFileThreaded(const std::string& src, const std::string& dst) +{ + fs::copyArgs *send = fs::copyArgsCreate(src, dst, "", NULL, NULL, true, false, 0); + threads::newThread(copyFileThreaded_t, send, fs::fileDrawFunc); +} + +void fs::copyFileCommit(const std::string& src, const std::string& dst, const std::string& dev, threadInfo *t) +{ + fs::copyArgs *c = NULL; + size_t filesize = fs::fsize(src); + if(t) + { + c = (fs::copyArgs *)t->argPtr; + c->offset = 0; + // c->prog->setMax(filesize); + // c->prog->update(0); + } + + FILE *fsrc = fopen(src.c_str(), "rb"); + if(!fsrc) + { + fclose(fsrc); + return; + } + + fileCpyThreadArgs thrdArgs; + thrdArgs.dst = dst; + thrdArgs.dev = dev; + thrdArgs.filesize = filesize; + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + uint64_t journalSpace = fs::getJournalSize(utinfo); + thrdArgs.writeLimit = (journalSpace - 0x100000) < TRANSFER_BUFFER_LIMIT ? journalSpace - 0x100000 : TRANSFER_BUFFER_LIMIT; + + Thread writeThread; + threadCreate(&writeThread, writeFileCommit_t, &thrdArgs, NULL, 0x040000, 0x2E, 2); + + uint8_t *buff = new uint8_t[BUFF_SIZE]; + size_t readIn = 0; + uint64_t readCount = 0; + std::vector transferBuffer; + threadStart(&writeThread); + while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0) + { + transferBuffer.insert(transferBuffer.end(), buff, buff + readIn); + readCount += readIn; + if(c) + c->offset = readCount; + + if(transferBuffer.size() >= thrdArgs.writeLimit || readCount == filesize) + { + std::unique_lock buffLock(thrdArgs.bufferLock); + thrdArgs.cond.wait(buffLock, [&thrdArgs]{ return thrdArgs.bufferIsFull == false; }); + thrdArgs.sharedBuffer.assign(transferBuffer.begin(), transferBuffer.end()); + transferBuffer.clear(); + thrdArgs.bufferIsFull = true; + buffLock.unlock(); + thrdArgs.cond.notify_one(); + } + } + threadWaitForExit(&writeThread); + threadClose(&writeThread); + + fclose(fsrc); + fs::commitToDevice(dev); + delete[] buff; +} + +static void copyFileCommit_t(void *a) +{ + threadInfo *t = (threadInfo *)a; + fs::copyArgs *in = (fs::copyArgs *)t->argPtr; + + t->status->setStatus("Copy file", in->src.c_str()); + + fs::copyFileCommit(in->src, in->dst, in->dev, t); + if(in->cleanup) + fs::copyArgsDestroy(in); + + t->finished = true; +} + +void fs::copyFileCommitThreaded(const std::string& src, const std::string& dst, const std::string& dev) +{ + fs::copyArgs *send = fs::copyArgsCreate(src, dst, dev, NULL, NULL, true, false, 0); + threads::newThread(copyFileCommit_t, send, fs::fileDrawFunc); +} + +void fs::fileDrawFunc(void *a) +{ + threadInfo *t = (threadInfo *)a; + if(!t->finished && t->argPtr) + { + copyArgs *c = (copyArgs *)t->argPtr; + std::string tmp; + t->status->getStatus(tmp); + c->argLock(); + // c->prog->update(c->offset); + // c->prog->draw(tmp); + c->argUnlock(); + } +} + +void fs::delfile(const std::string& path) +{ + remove(path.c_str()); +} + +void fs::getShowFileProps(const std::string& _path) +{ + size_t size = fs::fsize(_path); + // ui::showMessage(ui::getUICString("fileModeFileProperties", 0), _path.c_str(), util::getSizeString(size).c_str()); +} + +bool fs::fileExists(const std::string& path) +{ + bool ret = false; + FILE *test = fopen(path.c_str(), "rb"); + if(test != NULL) + ret = true; + fclose(test); + return ret; +} + +size_t fs::fsize(const std::string& _f) +{ + size_t ret = 0; + FILE *get = fopen(_f.c_str(), "rb"); + if(get != NULL) + { + fseek(get, 0, SEEK_END); + ret = ftell(get); + } + fclose(get); + return ret; +} diff --git a/source/fs/fsfile.c b/source/fs/fsfile.c new file mode 100644 index 0000000..d0b7d52 --- /dev/null +++ b/source/fs/fsfile.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include + +#include "fs/fsfile.h" + +char *getDeviceFromPath(char *dev, size_t _max, const char *path) +{ + memset(dev, 0, _max); + char *c = strchr(path, ':'); + if(c - path > _max) + return NULL; + + //probably not good? idk + memcpy(dev, path, c - path); + + return dev; +} + +char *getFilePath(char *pathOut, size_t _max, const char *path) +{ + memset(pathOut, 0, _max); + char *c = strchr(path, '/'); + size_t pLength = strlen(c); + if(pLength > _max) + return NULL; + + memcpy(pathOut, c, pLength); + + return pathOut; +} + +bool fsMkDir(const char *_p) +{ + char devStr[16]; + char path[FS_MAX_PATH]; + if(!getDeviceFromPath(devStr, 16, _p) || !getFilePath(path, FS_MAX_PATH, _p)) + return false; + + Result res = fsFsCreateDirectory(fsdevGetDeviceFileSystem(devStr), path); + return res == 0; +} + +int fsremove(const char *_p) +{ + char devStr[16]; + char path[FS_MAX_PATH]; + if(!getDeviceFromPath(devStr, 16, _p) || !getFilePath(path, FS_MAX_PATH, _p)) + return -1; + + Result res = fsFsDeleteFile(fsdevGetDeviceFileSystem(devStr), path); + return res; +} + +Result fsDelDirRec(const char *_p) +{ + char devStr[16]; + char path[FS_MAX_PATH]; + if(!getDeviceFromPath(devStr, 16, _p) || ! getFilePath(path, FS_MAX_PATH, _p)) + return 1; + + return fsFsDeleteDirectoryRecursively(fsdevGetDeviceFileSystem(devStr), path); +} + +bool fsfcreate(const char *_p, int64_t crSize) +{ + char devStr[16]; + char filePath[FS_MAX_PATH]; + if(!getDeviceFromPath(devStr, 16, _p) || !getFilePath(filePath, FS_MAX_PATH, _p)) + return false; + + FsFileSystem *s = fsdevGetDeviceFileSystem(devStr); + if(s == NULL) + return false; + + Result res = fsFsCreateFile(s, filePath, crSize, 0); + if(R_SUCCEEDED(res)) + res = fsdevCommitDevice(devStr); + + return R_SUCCEEDED(res) ? true : false; +} + +FSFILE *fsfopen(const char *_p, uint32_t mode) +{ + char devStr[16]; + char filePath[FS_MAX_PATH]; + if(!getDeviceFromPath(devStr, 16, _p) || !getFilePath(filePath, FS_MAX_PATH, _p)) + return NULL; + + FsFileSystem *s = fsdevGetDeviceFileSystem(devStr); + if(s == NULL) + return NULL; + + if(mode == FsOpenMode_Write) + { + fsFsDeleteFile(s, filePath); + fsFsCreateFile(s, filePath, 0, 0); + } + + FSFILE *ret = malloc(sizeof(FSFILE)); + ret->error = fsFsOpenFile(s, filePath, mode, &ret->_f); + if(R_FAILED(ret->error)) + { + free(ret); + return NULL; + } + fsFileGetSize(&ret->_f, &ret->fsize); + ret->offset = (mode & FsOpenMode_Append) ? ret->fsize : 0; + + return ret; +} + +FSFILE *fsfopenWithSystem(FsFileSystem *_s, const char *_p, uint32_t mode) +{ + if(mode & FsOpenMode_Write) + { + fsFsDeleteFile(_s, _p); + fsFsCreateFile(_s, _p, 0, 0); + } + else if(mode & FsOpenMode_Append) + fsFsCreateFile(_s, _p, 0, 0); + + FSFILE *ret = malloc(sizeof(FSFILE)); + ret->error = fsFsOpenFile(_s, _p, mode, &ret->_f); + if(R_FAILED(ret->error)) + { + free(ret); + return NULL; + } + fsFileGetSize(&ret->_f, &ret->fsize); + ret->offset = (mode & FsOpenMode_Append) ? ret->fsize : 0; + + return ret; +} + +size_t fsfwrite(const void *buf, size_t sz, size_t count, FSFILE *_f) +{ + size_t fullSize = sz * count; + if(_f->offset + fullSize > _f->fsize) + { + s64 newSize = (_f->fsize + fullSize) - (_f->fsize - _f->offset); + fsFileSetSize(&_f->_f, newSize); + _f->fsize = newSize; + } + _f->error = fsFileWrite(&_f->_f, _f->offset, buf, fullSize, FsWriteOption_Flush); + _f->offset += fullSize; + + return fullSize; +} diff --git a/source/fs/zip.cpp b/source/fs/zip.cpp new file mode 100644 index 0000000..1795b2b --- /dev/null +++ b/source/fs/zip.cpp @@ -0,0 +1,251 @@ +#include +#include +#include +#include +#include + +#include "fs.h" +#include "util.h" +#include "threads.h" + +typedef struct +{ + std::mutex buffLock; + std::condition_variable cond; + std::vector sharedBuffer; + std::string dst, dev; + bool bufferIsFull = false; + unzFile unz; + unsigned int fileSize, writeLimit = 0; +} unzThrdArgs; + +static void writeFileFromZip_t(void *a) +{ + unzThrdArgs *in = (unzThrdArgs *)a; + std::vector localBuffer; + unsigned int written = 0, journalCount = 0; + + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + uint64_t journalSpace = fs::getJournalSize(utinfo); + + FILE *out = fopen(in->dst.c_str(), "wb"); + while(written < in->fileSize) + { + std::unique_lock buffLock(in->buffLock); + in->cond.wait(buffLock, [in]{ return in->bufferIsFull; }); + localBuffer.clear(); + localBuffer.assign(in->sharedBuffer.begin(), in->sharedBuffer.end()); + in->sharedBuffer.clear(); + in->bufferIsFull = false; + buffLock.unlock(); + in->cond.notify_one(); + + written += fwrite(localBuffer.data(), 1, localBuffer.size(), out); + journalCount += written; + if(journalCount >= in->writeLimit) + { + journalCount = 0; + fclose(out); + fs::commitToDevice(in->dev); + out = fopen(in->dst.c_str(), "ab"); + } + } + fclose(out); +} + +void fs::copyDirToZip(const std::string& src, zipFile dst, bool trimPath, int trimPlaces, threadInfo *t) +{ + fs::copyArgs *c = NULL; + if(t) + { + t->status->setStatus("threadStatusOpeningFolder"); + c = (fs::copyArgs *)t->argPtr; + } + + fs::dirList *list = new fs::dirList(src); + for(unsigned i = 0; i < list->getCount(); i++) + { + std::string itm = list->getItem(i); + if(fs::pathIsFiltered(src + itm)) + continue; + + if(list->isDir(i)) + { + std::string newSrc = src + itm + "/"; + fs::copyDirToZip(newSrc, dst, trimPath, trimPlaces, t); + } + else + { + time_t raw; + time(&raw); + tm *locTime = localtime(&raw); + zip_fileinfo inf = { (unsigned)locTime->tm_sec, (unsigned)locTime->tm_min, (unsigned)locTime->tm_hour, + (unsigned)locTime->tm_mday, (unsigned)locTime->tm_mon, (unsigned)(1900 + locTime->tm_year), 0, 0, 0 }; + + std::string filename = src + itm; + size_t zipNameStart = 0; + if(trimPath) + util::trimPath(filename, trimPlaces); + else + zipNameStart = filename.find_first_of('/') + 1; + + if(t) + t->status->setStatus("threadStatusAddingFileToZip"); + + int zipOpenFile = zipOpenNewFileInZip64(dst, filename.substr(zipNameStart, filename.npos).c_str(), &inf, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION, 0); + if(zipOpenFile == ZIP_OK) + { + std::string fullSrc = src + itm; + if(c) + { + c->offset = 0; + // c->prog->setMax(fs::fsize(fullSrc)); + // c->prog->update(0); + } + + FILE *fsrc = fopen(fullSrc.c_str(), "rb"); + size_t readIn = 0; + uint8_t *buff = new uint8_t[ZIP_BUFF_SIZE]; + while((readIn = fread(buff, 1, ZIP_BUFF_SIZE, fsrc)) > 0) + { + zipWriteInFileInZip(dst, buff, readIn); + if(c) + c->offset += readIn; + } + delete[] buff; + fclose(fsrc); + } + } + } +} + +void copyDirToZip_t(void *a) +{ + threadInfo *t = (threadInfo *)a; + fs::copyArgs *c = (fs::copyArgs *)t->argPtr; + + fs::copyDirToZip(c->src, c->z, c->trimZipPath, c->trimZipPlaces, t); + + if(c->cleanup) + { + zipClose(c->z, NULL); + delete c; + } + t->finished = true; +} + +void fs::copyDirToZipThreaded(const std::string& src, zipFile dst, bool trimPath, int trimPlaces) +{ + fs::copyArgs *send = fs::copyArgsCreate(src, "", "", dst, NULL, true, false, 0); + threads::newThread(copyDirToZip_t, send, fs::fileDrawFunc); +} + +void fs::copyZipToDir(unzFile src, const std::string& dst, const std::string& dev, threadInfo *t) +{ + fs::copyArgs *c = NULL; + if(t) + c = (fs::copyArgs *)t->argPtr; + + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + uint64_t journalSize = getJournalSize(utinfo), writeCount = 0; + char filename[FS_MAX_PATH]; + uint8_t *buff = new uint8_t[BUFF_SIZE]; + int readIn = 0; + unz_file_info64 info; + do + { + unzGetCurrentFileInfo64(src, &info, filename, FS_MAX_PATH, NULL, 0, NULL, 0); + if(unzOpenCurrentFile(src) == UNZ_OK) + { + if(t) + t->status->setStatus("threadStatusDecompressingFile"); + + if(c) + { + // c->prog->setMax(info.uncompressed_size); + // c->prog->update(0); + c->offset = 0; + } + + std::string fullDst = dst + filename; + fs::mkDirRec(fullDst.substr(0, fullDst.find_last_of('/') + 1)); + + unzThrdArgs unzThrd; + unzThrd.dst = fullDst; + unzThrd.fileSize = info.uncompressed_size; + unzThrd.dev = dev; + unzThrd.writeLimit = (journalSize - 0x100000) < TRANSFER_BUFFER_LIMIT ? (journalSize - 0x100000) : TRANSFER_BUFFER_LIMIT; + + Thread writeThread; + threadCreate(&writeThread, writeFileFromZip_t, &unzThrd, NULL, 0x8000, 0x2B, 2); + threadStart(&writeThread); + + std::vector transferBuffer; + uint64_t readCount = 0; + while((readIn = unzReadCurrentFile(src, buff, BUFF_SIZE)) > 0) + { + transferBuffer.insert(transferBuffer.end(), buff, buff + readIn); + readCount += readIn; + + if(c) + c->offset += readIn; + + if(transferBuffer.size() >= unzThrd.writeLimit || readCount == info.uncompressed_size) + { + std::unique_lock buffLock(unzThrd.buffLock); + unzThrd.cond.wait(buffLock, [&unzThrd]{ return unzThrd.bufferIsFull == false; }); + unzThrd.sharedBuffer.assign(transferBuffer.begin(), transferBuffer.end()); + transferBuffer.clear(); + unzThrd.bufferIsFull = true; + unzThrd.cond.notify_one(); + } + } + threadWaitForExit(&writeThread); + threadClose(&writeThread); + fs::commitToDevice(dev); + } + } + while(unzGoToNextFile(src) != UNZ_END_OF_LIST_OF_FILE); + delete[] buff; +} + +static void copyZipToDir_t(void *a) +{ + threadInfo *t = (threadInfo *)a; + fs::copyArgs *c = (fs::copyArgs *)t->argPtr; + fs::copyZipToDir(c->unz, c->dst, c->dev, t); + if(c->cleanup) + { + unzClose(c->unz); + delete c; + } + t->finished = true; +} + +void fs::copyZipToDirThreaded(unzFile src, const std::string& dst, const std::string& dev) +{ + fs::copyArgs *send = fs::copyArgsCreate("", dst, dev, NULL, src, true, false, 0); + threads::newThread(copyZipToDir_t, send, fs::fileDrawFunc); +} + +uint64_t fs::getZipTotalSize(unzFile unz) +{ + uint64_t ret = 0; + if(unzGoToFirstFile(unz) == UNZ_OK) + { + unz_file_info64 finfo; + char filename[FS_MAX_PATH]; + do + { + unzGetCurrentFileInfo64(unz, &finfo, filename, FS_MAX_PATH, NULL, 0, NULL, 0); + ret += finfo.uncompressed_size; + } while(unzGoToNextFile(unz) != UNZ_END_OF_LIST_OF_FILE); + unzGoToFirstFile(unz); + } + return ret; +} + +bool fs::zipNotEmpty(unzFile unz) +{ + return unzGoToFirstFile(unz) == UNZ_OK; +} diff --git a/source/ldn.cpp b/source/ldn.cpp new file mode 100644 index 0000000..5001df0 --- /dev/null +++ b/source/ldn.cpp @@ -0,0 +1,543 @@ +#include "ldn.h" + +#include +#include +#include +#include +#include +#include + +#include "fs.h" +#include "file.h" +#include "util.h" + +static const u8 sec_data[0x10] = {0x04, 0xb9, 0x9d, 0x4d, 0x58, 0xbc, + 0x65, 0xe1, 0x77, 0x13, 0xc2, 0xb8, + 0xd1, 0xb8, 0xec, 0xf6}; + +Result create_network(const LdnSecurityConfig *sec_config, + const LdnUserConfig *user_config, + const LdnNetworkConfig *netconfig, const void *advert, + size_t advert_size) { + Result rc = 0; + + rc = ldnOpenAccessPoint(); + if (R_FAILED(rc)) { + return rc; + } + + rc = ldnCreateNetwork(sec_config, user_config, netconfig); + if (R_FAILED(rc)) { + goto error_close; + } + + rc = ldnSetAdvertiseData(advert, advert_size); + if (R_FAILED(rc)) + goto error_close; + + return rc; +error_close: + ldnCloseAccessPoint(); + return rc; +} + +Result connect_network(const LdnScanFilter *filter, + const LdnSecurityConfig *sec_config, + const LdnUserConfig *user_config, const void *advert, + size_t advert_size) { + Result rc = 0; + s32 total_out = 0; + LdnNetworkInfo netinfo_list[0x18]; + + rc = ldnOpenStation(); + + if (R_SUCCEEDED(rc)) { + rc = ldnScan(0, filter, netinfo_list, 0x18, &total_out); + } + + // In an actual app you'd display the output netinfo_list and let the user + // select which one to connect to, however in this example we'll just + // connect to the first one. + + if (R_SUCCEEDED(rc) && !total_out) { + rc = MAKERESULT(Module_Libnx, LibnxError_NotFound); + } + + if (R_SUCCEEDED(rc)) { // Handle this / parse it with any method you want. + if (netinfo_list[0].advertise_data_size != advert_size || + memcmp(netinfo_list[0].advertise_data, advert, advert_size) != 0) { + rc = MAKERESULT(Module_Libnx, LibnxError_NotFound); + } + } + + if (R_SUCCEEDED(rc)) { + rc = ldnConnect(sec_config, user_config, 0, 0, &netinfo_list[0]); + } + + if (R_FAILED(rc)) + ldnCloseStation(); + + return rc; +} + +static void leave_network(void) { + Result rc = 0; + LdnState state; + + rc = ldnGetState(&state); + if (R_SUCCEEDED(rc)) { + if (state == LdnState_AccessPointOpened || + state == LdnState_AccessPointCreated) { + if (state == LdnState_AccessPointCreated) { + rc = ldnDestroyNetwork(); + } + rc = ldnCloseAccessPoint(); + } + + if (state == LdnState_StationOpened || state == LdnState_StationConnected) { + if (state == LdnState_StationConnected) { + rc = ldnDisconnect(); + } + rc = ldnCloseStation(); + } + } +} + +void LDN::destroyLDN() { + leave_network(); + ldnExit(); +} + +LDN::LDNCommunicate* LDN::createCommunicate(void) +{ + LDN::LDNCommunicate* comm = new LDN::LDNCommunicate; + comm->serverFD = -1; + comm->commFD = -1; + return comm; +} + +void LDN::destroyCommunicate(LDNCommunicate *comm) { + if (comm->commFD >= 0) + close(comm->commFD); + if (comm->serverFD >= 0) + close(comm->serverFD); + delete comm; +} + +Result LDN::createLDNServer(LDNCommunicate *comm) { + Result rc; + LdnSecurityConfig sec_config = {0}; + LdnUserConfig user_config = {0}; + LdnNetworkConfig netconfig = {0}; + LdnState state; + data::user *user = data::getCurrentUser(); + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + /* + * Use Title ID to the advert, so if advert not match + * LDN connect between client and server will bind fail + */ + std::string advertStr = std::to_string(utinfo->tid); + int serverSocket; + + // send nickname to make sure + strncpy(user_config.nickname, user->getUsername().c_str(), 0x20 - 1); + + netconfig.local_communication_id = -1; + netconfig.participant_max = 2; // Adjust as needed. + + sec_config.type = 1; + sec_config.data_size = sizeof(sec_data); + memcpy(sec_config.data, sec_data, sizeof(sec_data)); + + rc = ldnInitialize(LdnServiceType_User); + if (R_FAILED(rc)) { + goto out; + } + + rc = ldnGetState(&state); + if (!R_SUCCEEDED(rc) || state != LdnState_Initialized) { + goto ldn_out; + } + + rc = create_network(&sec_config, &user_config, &netconfig, advertStr.c_str(), + advertStr.length()); + if (R_FAILED(rc)) { + goto ldn_out; + } + + return rc; + +ldn_out: + ldnExit(); +out: + return rc; +} + +Result LDN::createLDNClient(LDNCommunicate *comm) { + Result rc; + LdnUserConfig user_config = {0}; + LdnSecurityConfig sec_config = {0}; + LdnNetworkConfig netconfig = {0}; + LdnScanFilter filter = {0}; + LdnState state; + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + /* + * Use Title ID to the advert, so if advert not match + * LDN connect between client and server will bind fail + */ + std::string advertStr = std::to_string(utinfo->tid); + data::user *user = data::getCurrentUser(); + + strncpy(user_config.nickname, user->getUsername().c_str(), 0x20 - 1); + + rc = ldnInitialize(LdnServiceType_User); + if (R_FAILED(rc)) { + goto out; + } + + netconfig.local_communication_id = -1; + netconfig.participant_max = 2; // Adjust as needed. + + sec_config.type = 1; + sec_config.data_size = sizeof(sec_data); + memcpy(sec_config.data, sec_data, sizeof(sec_data)); + + filter.local_communication_id = -1; + filter.userdata_filter = netconfig.userdata_filter; + filter.flags = + LdnScanFilterFlags_LocalCommunicationId | LdnScanFilterFlags_UserData; + + rc = ldnGetState(&state); + if (!R_SUCCEEDED(rc) || state != LdnState_Initialized) { + goto ldnOut; + } + + rc = connect_network(&filter, &sec_config, &user_config, advertStr.c_str(), + advertStr.length()); + +out: + return rc; +ldnOut: + ldnExit(); + return rc; +} + +int LDN::bindClient(int serverFD) { + struct sockaddr_in clientAddr; + socklen_t length = sizeof(clientAddr); + int cSocket = + accept(serverFD, (struct sockaddr *)&clientAddr, &length); + if (cSocket < 0) { + return -1; + } + + return cSocket; +} + +int LDN::bindServer(struct sockaddr_in *serverAddr) { + /// sockfd + int sock_cli = socket(AF_INET, SOCK_STREAM, 0); + int ret; + if ((ret = connect(sock_cli, (struct sockaddr *)serverAddr, + sizeof(*serverAddr))) < 0) { + close(sock_cli); + return -1; + } + + return sock_cli; +} + +static void reciveBuf(char *buf, ssize_t size, int socketfd) { + ssize_t offset = 0, ssize; + while (offset < size) { + ssize = + size - offset < SOCKET_BUFFER_SIZE ? size - offset : SOCKET_BUFFER_SIZE; + ssize_t done = recv(socketfd, buf + offset, ssize, 0); + if (done == -1) { + break; + } + offset += done; + } +} + +static void sendBuf(const char *buf, ssize_t size, int socketfd) { + ssize_t offset = 0, ssize; + while (offset < size) { + ssize = + size - offset < SOCKET_BUFFER_SIZE ? size - offset : SOCKET_BUFFER_SIZE; + ssize_t done = send(socketfd, buf + offset, ssize, 0); + if (done == -1) { + break; + } + offset += done; + } +} + +bool LDN::waitForOK(int socketfd) { + commMeta meta; + reciveBuf((char *)&meta, sizeof(meta), socketfd); + if (meta.type == UPDATE_OK) + return true; + return false; +} + +bool LDN::waitForDONE(int socketfd) { + commMeta meta; + reciveBuf((char *)&meta, sizeof(meta), socketfd); + if (meta.type == UPDATE_DONE) + return true; + return false; +} + +void LDN::sendOK(int socket_fd) { + commMeta meta; + meta.type = UPDATE_OK; + + sendBuf((char *)&meta, sizeof(meta), socket_fd); +} + +void LDN::sendDONE(int socket_fd) { + commMeta meta; + meta.type = UPDATE_DONE; + + sendBuf((char *)&meta, sizeof(meta), socket_fd); +} + +void LDN::sendAbort(int socket_fd) { + commMeta meta; + meta.type = UPDATE_ABORT; + + sendBuf((char *)&meta, sizeof(meta), socket_fd); +} + +void LDN::reciveMeta(commMeta *meta, int socketfd) { + bzero(meta, sizeof(commMeta)); + reciveBuf((char *)meta, sizeof(commMeta), socketfd); + sendOK(socketfd); +} + +void LDN::sendMeta(commMeta *meta, int socketfd) { + sendBuf((char *)meta, sizeof(commMeta), socketfd); + waitForOK(socketfd); +} + +static void copySaveFileToRemote_t(void *a) { + LDN::LDNfcopyArgs *in = (LDN::LDNfcopyArgs *)a; + LDN::LDNCommunicate *comm = in->comm; + size_t written = 0; + std::vector localBuffer; + + int fSocket = LDN::bindClient(comm->serverFD); + if (fSocket < 0) + return; + + while (written < in->filesize) { + std::unique_lock buffLock(in->bufferLock); + in->cond.wait(buffLock, [in] { return in->bufferIsFull; }); + localBuffer.clear(); + localBuffer.assign(in->sharedBuffer.begin(), in->sharedBuffer.end()); + in->sharedBuffer.clear(); + in->bufferIsFull = false; + buffLock.unlock(); + in->cond.notify_one(); + + written += send(fSocket, localBuffer.data(), localBuffer.size(), 0); + } + + close(fSocket); +} + +void LDN::copySaveFileToRemote(const std::string &local, threadInfo *t) { + fs::copyArgs *c = NULL; + c = (fs::copyArgs *)t->argPtr; + LDN::LDNCommunicate *comm = c->comm; + commMeta cm; + std::string zipPath = fs::getWorkDir() + "tempSave.zip"; + + //Trim this to unzip direct in direct sv:/ + int zipTrim = util::getTotalPlacesInPath("sv:/"); + + t->status->setStatus("LDNStatus"); + + + zipFile zip = zipOpen64(zipPath.c_str(), 0); + fs::copyDirToZip(local, zip, true, zipTrim, t); + zipClose(zip, NULL); + + + size_t filesize = fs::fsize(zipPath); + t->status->setStatus("LDNStatus"); + c->offset = 0; + + FILE *fsrc = fopen(zipPath.c_str(), "rb"); + if(!fsrc) + { + sendAbort(comm->commFD); + fclose(fsrc); + return; + } + + cm.type = UPDATE_FILE; + cm.fsz = filesize; + sendMeta(&cm, comm->commFD); + + LDNfcopyArgs thrdArgs; + thrdArgs.comm = comm; + thrdArgs.filesize = filesize; + + uint8_t *buff = new uint8_t[BUFF_SIZE]; + std::vector transferBuffer; + Thread writeThread; + threadCreate(&writeThread, copySaveFileToRemote_t, &thrdArgs, NULL, + 0x40000, 0x2E, 2); + threadStart(&writeThread); + size_t readIn = 0; + uint64_t readCount = 0; + + while ((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0) { + transferBuffer.insert(transferBuffer.end(), buff, buff + readIn); + readCount += readIn; + + if (c) + c->offset = readCount; + + if (transferBuffer.size() >= TRANSFER_BUFFER_LIMIT || + readCount == filesize) { + std::unique_lock buffLock(thrdArgs.bufferLock); + thrdArgs.cond.wait( + buffLock, [&thrdArgs] { return thrdArgs.bufferIsFull == false; }); + thrdArgs.sharedBuffer.assign(transferBuffer.begin(), + transferBuffer.end()); + transferBuffer.clear(); + thrdArgs.bufferIsFull = true; + buffLock.unlock(); + thrdArgs.cond.notify_one(); + } + } + threadWaitForExit(&writeThread); + threadClose(&writeThread); + fclose(fsrc); + fs::delfile(zipPath); + delete[] buff; + + t->status->setStatus("LDNStatus"); + // wait for client recived sure + // otherwise, may lost package + LDN::sendDONE(comm->commFD); + LDN::waitForDONE(comm->commFD); +} + +static void copyRemoteFileWrite_t(void *a) { + LDN::LDNfcopyArgs *in = (LDN::LDNfcopyArgs *)a; + size_t written = 0; + std::vector localBuffer; + FILE *out = fopen(in->dst.c_str(), "wb"); + + while (written < in->filesize) { + std::unique_lock buffLock(in->bufferLock); + in->cond.wait(buffLock, [in] { return in->bufferIsFull; }); + localBuffer.clear(); + localBuffer.assign(in->sharedBuffer.begin(), in->sharedBuffer.end()); + in->sharedBuffer.clear(); + in->bufferIsFull = false; + buffLock.unlock(); + in->cond.notify_one(); + written += fwrite(localBuffer.data(), 1, localBuffer.size(), out); + } + fclose(out); +} + +static void copyRemoteSaveFileCommit(LDN::commMeta *meta, threadInfo *t) { + fs::copyArgs *c = (fs::copyArgs *)t->argPtr; + LDN::LDNCommunicate *comm = c->comm; + + std::string fullPath = fs::getWorkDir() + "tempSave.zip"; + size_t filesize = meta->fsz; + + c->offset = 0; + + int fSocket = LDN::bindServer(&comm->serverAddr); + if (fSocket < 0) + return; + + t->status->setStatus("LDNStatus"); + LDN::LDNfcopyArgs thrdArgs; + thrdArgs.dst = fullPath; + thrdArgs.filesize = filesize; + + uint8_t *buff = new uint8_t[BUFF_SIZE]; + std::vector transferBuffer; + Thread writeThread; + threadCreate(&writeThread, copyRemoteFileWrite_t, &thrdArgs, NULL, 0x40000, + 0x2E, 2); + threadStart(&writeThread); + size_t readIn = 0; + uint64_t readCount = 0; + while ((readIn = recv(fSocket, buff, BUFF_SIZE, 0)) > 0) { + transferBuffer.insert(transferBuffer.end(), buff, buff + readIn); + readCount += readIn; + + if (c) + c->offset = readCount; + + if (transferBuffer.size() >= TRANSFER_BUFFER_LIMIT || + readCount == filesize) { + std::unique_lock buffLock(thrdArgs.bufferLock); + thrdArgs.cond.wait( + buffLock, [&thrdArgs] { return thrdArgs.bufferIsFull == false; }); + thrdArgs.sharedBuffer.assign(transferBuffer.begin(), + transferBuffer.end()); + transferBuffer.clear(); + thrdArgs.bufferIsFull = true; + buffLock.unlock(); + thrdArgs.cond.notify_one(); + } + } + threadWaitForExit(&writeThread); + threadClose(&writeThread); + + t->status->setStatus("LDNStatus"); + + unzFile unz = unzOpen64(fullPath.c_str()); + if(unz && fs::zipNotEmpty(unz)) { + t->status->setStatus("threadStatusCalculatingSaveSize"); + uint64_t saveSize = fs::getZipTotalSize(unz); + int64_t availSize = 0; + fsFsGetTotalSpace(fsdevGetDeviceFileSystem("sv"), "/", &availSize); + if ((int)saveSize > availSize) { + data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo(); + fs::unmountSave(); + fs::extendSaveData(utinfo, saveSize + 0x500000, t); + fs::mountSave(utinfo->saveInfo); + } + + fs::delDir("sv:/"); + fs::commitToDevice("sv"); + // fs::copyZipToDir(unz, "sv:/", "sv", t); + } + + // if (unz) + // unzClose(unz); + close(fSocket); + + delete[] buff; + fs::delfile(fullPath); + + LDN::waitForDONE(comm->commFD); + LDN::sendDONE(comm->commFD); +} + +void LDN::copyRemoteSaveFile(threadInfo *t) { + fs::copyArgs *c = (fs::copyArgs *)t->argPtr; + LDN::LDNCommunicate *comm = (LDN::LDNCommunicate *)c->comm; + LDN::commMeta meta; + + t->status->setStatus("LDNStatus"); + reciveMeta(&meta, comm->commFD); + if (meta.type == UPDATE_ABORT) + return; + + if (meta.type == UPDATE_FILE) { + copyRemoteSaveFileCommit(&meta, t); + } +} \ No newline at end of file diff --git a/source/threads.cpp b/source/threads.cpp new file mode 100644 index 0000000..7a29759 --- /dev/null +++ b/source/threads.cpp @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include +#include +#include "threads.h" +#include "util.h" + +static threads::threadProcMngr *threadMngr; + +threads::threadProcMngr::~threadProcMngr() +{ + for(threadInfo *t : threads) + { + threadWaitForExit(&t->thrd); + threadClose(&t->thrd); + delete t->status; + delete t; + } +} + +threadInfo *threads::threadProcMngr::newThread(ThreadFunc func, void *args, funcPtr _drawfunc) +{ + threadInfo *t = new threadInfo; + t->status = new threadStatus; + t->running = false; + t->finished = false; + t->thrdFunc = func; + t->drawFunc = _drawfunc; + t->argPtr = args; + + mutexLock(&threadLock); + threads.push_back(t); + mutexUnlock(&threadLock); + return threads[threads.size() - 1]; +} + +void threads::threadProcMngr::update() +{ + if(!threads.empty()) + { + Result res = 0; + threadInfo *t = threads[0]; + if(!t->running && R_SUCCEEDED((res = threadCreate(&t->thrd, t->thrdFunc, t, NULL, 0x80000, 0x2B, 1)))) + { + threadStart(&t->thrd); + t->running = true; + } + else if(!t->running && R_FAILED(res))//Should kill the thread that failed. + t->finished = true; + else if(t->finished) + { + threadWaitForExit(&t->thrd); + threadClose(&t->thrd); + delete t->status; + delete t; + mutexLock(&threadLock); + threads.erase(threads.begin()); + mutexUnlock(&threadLock); + } + } +} + +threadInfo *threads::newThread(ThreadFunc func, void *args, funcPtr _drawFunc) +{ + return threadMngr->newThread(func, args, _drawFunc); +} diff --git a/source/util.cpp b/source/util.cpp new file mode 100644 index 0000000..f8dd4fb --- /dev/null +++ b/source/util.cpp @@ -0,0 +1,351 @@ +#include +#include +#include +#include +#include + +#include "fs/file.h" +#include "data.h" +#include "util.h" +#include "type.h" + +static const uint32_t verboten[] = { L',', L'/', L'\\', L'<', L'>', L':', L'"', L'|', L'?', L'*', L'™', L'©', L'®'}; + +static bool isVerboten(const uint32_t& t) +{ + for(unsigned i = 0; i < 13; i++) + { + if(t == verboten[i]) + return true; + } + + return false; +} + +void util::replaceStr(std::string& _str, const std::string& _find, const std::string& _rep) +{ + size_t pos = 0; + while((pos = _str.find(_find)) != _str.npos) + _str.replace(pos, _find.length(), _rep); +} + +//Used to split version tag git +static void getVersionFromTag(const std::string& tag, unsigned& _year, unsigned& _month, unsigned& _day) +{ + _month = strtoul(tag.substr(0, 2).c_str(), NULL, 10); + _day = strtoul(tag.substr(3, 5).c_str(), NULL, 10); + _year = strtoul(tag.substr(6, 10).c_str(), NULL, 10); +} + +//Missing swkbd config funcs for now +typedef enum +{ + SwkbdPosStart = 0, + SwkbdPosEnd = 1 +} SwkbdInitPos; + +typedef struct +{ + uint16_t read[0x32 / sizeof(uint16_t)]; + uint16_t word[0x32 / sizeof(uint16_t)]; +} dictWord; + +void swkbdDictWordCreate(dictWord *w, const char *read, const char *word) +{ + memset(w, 0, sizeof(*w)); + + utf8_to_utf16(w->read, (uint8_t *)read, (sizeof(w->read) / sizeof(uint16_t)) - 1); + utf8_to_utf16(w->word, (uint8_t *)word, (sizeof(w->word) / sizeof(uint16_t)) - 1); +} + +uint32_t replaceChar(uint32_t c) +{ + switch(c) + { + case L'é': + return 'e'; + break; + } + + return c; +} + +static inline void replaceCharCStr(char *_s, char _find, char _rep) +{ + size_t strLength = strlen(_s); + for(unsigned i = 0; i < strLength; i++) + { + if(_s[i] == _find) + _s[i] = _rep; + } +} + +std::string util::getDateTime(int fmt) +{ + char ret[128]; + + time_t raw; + time(&raw); + tm *Time = localtime(&raw); + + switch(fmt) + { + case DATE_FMT_YMD: + sprintf(ret, "%04d.%02d.%02d @ %02d.%02d.%02d", Time->tm_year + 1900, Time->tm_mon + 1, Time->tm_mday, Time->tm_hour, Time->tm_min, Time->tm_sec); + break; + + case DATE_FMT_YDM: + sprintf(ret, "%04d.%02d.%02d @ %02d.%02d.%02d", Time->tm_year + 1900, Time->tm_mday, Time->tm_mon + 1, Time->tm_hour, Time->tm_min, Time->tm_sec); + break; + + case DATE_FMT_HOYSTE: + sprintf(ret, "%02d.%02d.%04d", Time->tm_mday, Time->tm_mon + 1, Time->tm_year + 1900); + break; + + case DATE_FMT_JHK: + sprintf(ret, "%04d%02d%02d_%02d%02d", Time->tm_year + 1900, Time->tm_mon + 1, Time->tm_mday, Time->tm_hour, Time->tm_min); + break; + + case DATE_FMT_ASC: + strcpy(ret, asctime(Time)); + replaceCharCStr(ret, ':', '_'); + replaceCharCStr(ret, '\n', 0x00); + break; + } + + return std::string(ret); +} + +//void util::copyDirListToMenu(const fs::dirList& d, ui::menu& m) +//{ +// m.reset(); +// m.addOpt(NULL, "."); +// m.addOpt(NULL, ".."); +// for(unsigned i = 0; i < d.getCount(); i++) +// { +// if(d.isDir(i)) +// m.addOpt(NULL, "D " + d.getItem(i)); +// else +// m.addOpt(NULL, "F " + d.getItem(i)); +// } +//} + +void util::removeLastFolderFromString(std::string& _path) +{ + unsigned last = _path.find_last_of('/', _path.length() - 2); + _path.erase(last + 1, _path.length()); +} + +size_t util::getTotalPlacesInPath(const std::string& _path) +{ + //Skip device + size_t pos = _path.find_first_of('/'), ret = 0; + while((pos = _path.find_first_of('/', ++pos)) != _path.npos) + ++ret; + return ret; +} + +void util::trimPath(std::string& _path, uint8_t _places) +{ + size_t pos = _path.find_first_of('/'); + for(int i = 0; i < _places; i++) + pos = _path.find_first_of('/', ++pos); + _path = _path.substr(++pos, _path.npos); +} + +std::string util::safeString(const std::string& s) +{ + std::string ret = ""; + for(unsigned i = 0; i < s.length(); ) + { + uint32_t tmpChr = 0; + ssize_t untCnt = decode_utf8(&tmpChr, (uint8_t *)&s.data()[i]); + + i += untCnt; + + tmpChr = replaceChar(tmpChr); + + if(isVerboten(tmpChr)) + ret += ' '; + else if(!isASCII(tmpChr)) + return ""; //return empty string so titledata::init defaults to titleID + else + ret += (char)tmpChr; + } + + //Check for spaces at end + while(ret[ret.length() - 1] == ' ' || ret[ret.length() - 1] == '.') + ret.erase(ret.length() - 1, 1); + + return ret; +} + +static inline std::string getTimeString(const uint32_t& _h, const uint32_t& _m) +{ + char tmp[32]; + sprintf(tmp, "%02d:%02d", _h, _m); + return std::string(tmp); +} + +std::string util::getStringInput(SwkbdType _type, const std::string& def, const std::string& head, size_t maxLength, unsigned dictCnt, const std::string dictWords[]) +{ + SwkbdConfig swkbd; + swkbdCreate(&swkbd, dictCnt); + swkbdConfigSetBlurBackground(&swkbd, true); + swkbdConfigSetInitialText(&swkbd, def.c_str()); + swkbdConfigSetHeaderText(&swkbd, head.c_str()); + swkbdConfigSetGuideText(&swkbd, head.c_str()); + swkbdConfigSetInitialCursorPos(&swkbd, SwkbdPosEnd); + swkbdConfigSetType(&swkbd, _type); + swkbdConfigSetStringLenMax(&swkbd, maxLength); + swkbdConfigSetKeySetDisableBitmask(&swkbd, SwkbdKeyDisableBitmask_Backslash | SwkbdKeyDisableBitmask_Percent); + swkbdConfigSetDicFlag(&swkbd, 1); + + if(dictCnt > 0) + { + dictWord words[dictCnt]; + for(unsigned i = 0; i < dictCnt; i++) + swkbdDictWordCreate(&words[i], dictWords[i].c_str(), dictWords[i].c_str()); + + swkbdConfigSetDictionary(&swkbd, (SwkbdDictWord *)words, dictCnt); + } + + char out[maxLength + 1]; + memset(out, 0, maxLength + 1); + swkbdShow(&swkbd, out, maxLength + 1); + swkbdClose(&swkbd); + + return std::string(out); +} + +std::string util::getExtensionFromString(const std::string& get) +{ + size_t ext = get.find_last_of('.'); + if(ext != get.npos) + return get.substr(ext + 1, get.npos); + else + return ""; +} + +std::string util::getFilenameFromPath(const std::string& get) +{ + size_t nameStart = get.find_last_of('/'); + if(nameStart != get.npos) + return get.substr(nameStart + 1, get.npos); + else + return ""; +} + +std::string util::generateAbbrev(const uint64_t& tid) +{ + data::titleInfo *tmp = data::getTitleInfoByTID(tid); + size_t titleLength = tmp->safeTitle.length(); + + char temp[titleLength + 1]; + memset(temp, 0, titleLength + 1); + memcpy(temp, tmp->safeTitle.c_str(), titleLength); + + std::string ret; + char *tok = strtok(temp, " "); + while(tok) + { + if(isASCII(tok[0])) + ret += tok[0]; + tok = strtok(NULL, " "); + } + return ret; +} + +void util::stripChar(char _c, std::string& _s) +{ + size_t pos = 0; + while((pos = _s.find(_c)) != _s.npos) + _s.erase(pos, 1); +} + +void util::replaceButtonsInString(std::string& rep) +{ + replaceStr(rep, "[A]", "\ue0e0"); + replaceStr(rep, "[B]", "\ue0e1"); + replaceStr(rep, "[X]", "\ue0e2"); + replaceStr(rep, "[Y]", "\ue0e3"); + replaceStr(rep, "[L]", "\ue0e4"); + replaceStr(rep, "[R]", "\ue0e5"); + replaceStr(rep, "[ZL]", "\ue0e6"); + replaceStr(rep, "[ZR]", "\ue0e7"); + replaceStr(rep, "[SL]", "\ue0e8"); + replaceStr(rep, "[SR]", "\ue0e9"); + replaceStr(rep, "[DPAD]", "\ue0ea"); + replaceStr(rep, "[DUP]", "\ue0eb"); + replaceStr(rep, "[DDOWN]", "\ue0ec"); + replaceStr(rep, "[DLEFT]", "\ue0ed"); + replaceStr(rep, "[DRIGHT]", "\ue0ee"); + replaceStr(rep, "[+]", "\ue0ef"); + replaceStr(rep, "[-]", "\ue0f0"); +} + +void util::sysBoost() +{ + if(R_FAILED(clkrstInitialize())) + return; + + ClkrstSession cpu, gpu, ram; + clkrstOpenSession(&cpu, PcvModuleId_CpuBus, 3); + clkrstOpenSession(&gpu, PcvModuleId_GPU, 3); + clkrstOpenSession(&ram, PcvModuleId_EMC, 3); + + clkrstSetClockRate(&cpu, util::CPU_SPEED_1785MHz); + clkrstSetClockRate(&gpu, util::GPU_SPEED_76MHz); + clkrstSetClockRate(&ram, util::RAM_SPEED_1600MHz); + + clkrstCloseSession(&cpu); + clkrstCloseSession(&gpu); + clkrstCloseSession(&ram); + clkrstExit(); +} + +void util::sysNormal() +{ + if(R_FAILED(clkrstInitialize())) + return; + + ClkrstSession cpu, gpu, ram; + clkrstOpenSession(&cpu, PcvModuleId_CpuBus, 3); + clkrstOpenSession(&gpu, PcvModuleId_GPU, 3); + clkrstOpenSession(&ram, PcvModuleId_EMC, 3); + + clkrstSetClockRate(&cpu, util::CPU_SPEED_1020MHz); + clkrstSetClockRate(&gpu, util::GPU_SPEED_76MHz); + clkrstSetClockRate(&ram, util::RAM_SPEED_1331MHz); + + clkrstCloseSession(&cpu); + clkrstCloseSession(&gpu); + clkrstCloseSession(&ram); + clkrstExit(); + +} + +std::string util::getSizeString(const uint64_t& _size) +{ + char sizeStr[32]; + if(_size >= 0x40000000) + sprintf(sizeStr, "%.2fGB", (float)_size / 1024.0f / 1024.0f / 1024.0f); + else if(_size >= 0x100000) + sprintf(sizeStr, "%.2fMB", (float)_size / 1024.0f / 1024.0f); + else if(_size >= 0x400) + sprintf(sizeStr, "%.2fKB", (float)_size / 1024.0f); + else + sprintf(sizeStr, "%lu Bytes", _size); + return std::string(sizeStr); +} + +Result util::accountDeleteUser(AccountUid *uid) +{ + Service *account = accountGetServiceSession(); + struct + { + AccountUid uid; + } in = {*uid}; + + return serviceDispatchIn(account, 203, in); +}