From 19067967bc1b4d2b05cf754318f615b0489f1e94 Mon Sep 17 00:00:00 2001 From: giantpune Date: Sat, 25 Jul 2009 09:39:01 +0000 Subject: [PATCH] change the onscreen keyboard to filebrowser for custom paths no button to create a new file and a little bug with the scrolling, but better than typing stuff in. added channel launcher. currently doesnt show the actual name, only the u32 and ID. also, it is only showing 0x00010001 channels, so no Mii, weather, or other crappy channels, just the good stuff. fixed bug that showed the MacOS hidden files as extra homebrew entries. --- Languages/czech.lang | 2 +- Languages/danish.lang | 2 +- Languages/dutch.lang | 2 +- Languages/english.lang | 2 +- Languages/finnish.lang | 2 +- Languages/french.lang | 2 +- Languages/german.lang | 2 +- Languages/hungarian.lang | 2 +- Languages/italian.lang | 2 +- Languages/japanese.lang | 2 +- Languages/korean.lang | 2 +- Languages/norwegian.lang | 2 +- Languages/polish.lang | 2 +- Languages/portuguese_br.lang | 2 +- Languages/portuguese_pt.lang | 2 +- Languages/russian.lang | 2 +- Languages/schinese.lang | 2 +- Languages/spanish.lang | 2 +- Languages/swedish.lang | 2 +- Languages/tchinese.lang | 2 +- Languages/turkish.lang | 2 +- Makefile | 2 +- gui.pnps | 2 +- source/homebrewboot/HomebrewBrowse.cpp | 31 +- source/homebrewboot/HomebrewFiles.cpp | 4 +- source/images/addressbar_textbox.png | Bin 1785 -> 3888 bytes source/images/bg_browser.png | Bin 1746 -> 4399 bytes source/images/bg_browser_selection.png | Bin 5922 -> 5132 bytes source/libwiigui/gui_filebrowser.cpp | 29 +- source/menu.cpp | 5 +- source/prompts/TitleBrowser.cpp | 194 ++++++++ source/prompts/TitleBrowser.h | 15 + source/{ => prompts}/filebrowser.cpp | 641 ++++++++++++++++--------- source/{ => prompts}/filebrowser.h | 1 + source/settings/Settings.cpp | 30 +- source/testfilebrowser.cpp | 134 ------ source/wad/title.c | 460 ++++++++++++++++++ source/wad/title.h | 55 +++ 38 files changed, 1240 insertions(+), 405 deletions(-) create mode 100644 source/prompts/TitleBrowser.cpp create mode 100644 source/prompts/TitleBrowser.h rename source/{ => prompts}/filebrowser.cpp (51%) rename source/{ => prompts}/filebrowser.h (95%) delete mode 100644 source/testfilebrowser.cpp diff --git a/Languages/czech.lang b/Languages/czech.lang index de8b1d35..502358df 100644 --- a/Languages/czech.lang +++ b/Languages/czech.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-18 15:18+0200\n" "Last-Translator: David Jelinek (djelinek@hotmail.com) \n" "Language-Team: Last version on http://startgolf.tym.cz/czech.lang \n" diff --git a/Languages/danish.lang b/Languages/danish.lang index f011518f..dd52e0c3 100644 --- a/Languages/danish.lang +++ b/Languages/danish.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-18 15:18+0200\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/Languages/dutch.lang b/Languages/dutch.lang index 1116f37e..0cdb4250 100644 --- a/Languages/dutch.lang +++ b/Languages/dutch.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-18 15:18+0200\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/Languages/english.lang b/Languages/english.lang index 7a2f33bb..52392574 100644 --- a/Languages/english.lang +++ b/Languages/english.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-18 15:18+0200\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/Languages/finnish.lang b/Languages/finnish.lang index 04fc2ef9..98da7f9d 100644 --- a/Languages/finnish.lang +++ b/Languages/finnish.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-18 15:18+0200\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/Languages/french.lang b/Languages/french.lang index 8b63ca75..95446ae4 100644 --- a/Languages/french.lang +++ b/Languages/french.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-18 15:18+0200\n" "Last-Translator: Kin8\n" "Language-Team: Badablek, Amour, ikya, OuahOuah, dj_skual & Kin8\n" diff --git a/Languages/german.lang b/Languages/german.lang index ed8e7a3c..c1b7a270 100644 --- a/Languages/german.lang +++ b/Languages/german.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-18 15:18+0200\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/Languages/hungarian.lang b/Languages/hungarian.lang index cd1637f7..ee024472 100644 --- a/Languages/hungarian.lang +++ b/Languages/hungarian.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-18 15:18+0200\n" "Last-Translator: Tusk\n" "Language-Team: \n" diff --git a/Languages/italian.lang b/Languages/italian.lang index e56d202f..f603c41d 100644 --- a/Languages/italian.lang +++ b/Languages/italian.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-20 20:00+0200\n" "Last-Translator: Cambo \n" "Language-Team: FoxeJoe & Cambo\n" diff --git a/Languages/japanese.lang b/Languages/japanese.lang index ba672bd5..1ca8518b 100644 --- a/Languages/japanese.lang +++ b/Languages/japanese.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-18 15:18+0200\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/Languages/korean.lang b/Languages/korean.lang index 3ccb22e6..f170f52a 100644 --- a/Languages/korean.lang +++ b/Languages/korean.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-18 15:18+0200\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/Languages/norwegian.lang b/Languages/norwegian.lang index 8573e55a..1d5de30d 100644 --- a/Languages/norwegian.lang +++ b/Languages/norwegian.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-18 15:18+0200\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/Languages/polish.lang b/Languages/polish.lang index 33ba9e90..3aa1af88 100644 --- a/Languages/polish.lang +++ b/Languages/polish.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-18 15:18+0200\n" "Last-Translator: ziom666 (zadania_prog@vp.pl)\n" "Language-Team: \n" diff --git a/Languages/portuguese_br.lang b/Languages/portuguese_br.lang index f7152b61..fba7f4dd 100644 --- a/Languages/portuguese_br.lang +++ b/Languages/portuguese_br.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-18 15:18+0200\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/Languages/portuguese_pt.lang b/Languages/portuguese_pt.lang index d3cbc409..34ebcec8 100644 --- a/Languages/portuguese_pt.lang +++ b/Languages/portuguese_pt.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-20 16:40\n" "Last-Translator: Sky8000\n" "Language-Team: \n" diff --git a/Languages/russian.lang b/Languages/russian.lang index 302cd4a5..13f87eed 100644 --- a/Languages/russian.lang +++ b/Languages/russian.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-18 15:18+0200\n" "Last-Translator: Kir\n" "Language-Team: Kir\n" diff --git a/Languages/schinese.lang b/Languages/schinese.lang index 32665bc3..cc9a4ef7 100644 --- a/Languages/schinese.lang +++ b/Languages/schinese.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-18 15:18+0200\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/Languages/spanish.lang b/Languages/spanish.lang index 952a65b5..df71b81d 100644 --- a/Languages/spanish.lang +++ b/Languages/spanish.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-18 15:18+0200\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/Languages/swedish.lang b/Languages/swedish.lang index 25a293b7..a947ec79 100644 --- a/Languages/swedish.lang +++ b/Languages/swedish.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-21 20:18+0200\n" "Last-Translator: Katsurou\n" "Language-Team: \n" diff --git a/Languages/tchinese.lang b/Languages/tchinese.lang index 199fefbf..e0f28c24 100644 --- a/Languages/tchinese.lang +++ b/Languages/tchinese.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-18 15:18+0200\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/Languages/turkish.lang b/Languages/turkish.lang index 286926de..c865e606 100644 --- a/Languages/turkish.lang +++ b/Languages/turkish.lang @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: USB Loader GX\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-23 19:22+0200\n" +"POT-Creation-Date: 2009-07-24 23:13-0400\n" "PO-Revision-Date: 2009-07-18 15:18+0200\n" "Last-Translator: \n" "Language-Team: \n" diff --git a/Makefile b/Makefile index 73a1e3de..9ec65392 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ INCLUDES := source CFLAGS = -g -O2 -save-temps -Wall $(MACHDEP) $(INCLUDE) CXXFLAGS = -Xassembler -aln=$@.lst $(CFLAGS) -LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map,--section-start,.init=0x80c00000 +LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map,--section-start,.init=0x80b00000 #--------------------------------------------------------------------------------- # any extra libraries we wish to link with the project diff --git a/gui.pnps b/gui.pnps index 3d1ccac3..a5e72cd6 100644 --- a/gui.pnps +++ b/gui.pnps @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/source/homebrewboot/HomebrewBrowse.cpp b/source/homebrewboot/HomebrewBrowse.cpp index edf692d2..d5cbbcf9 100644 --- a/source/homebrewboot/HomebrewBrowse.cpp +++ b/source/homebrewboot/HomebrewBrowse.cpp @@ -11,6 +11,7 @@ #include "language/gettext.h" #include "libwiigui/gui.h" +#include "prompts/TitleBrowser.h" #include "prompts/PromptWindows.h" #include "prompts/ProgressWindow.h" #include "homebrewboot/HomebrewFiles.h" @@ -104,6 +105,10 @@ int MenuHomebrewBrowse() snprintf(imgPath, sizeof(imgPath), "%swifi1.png", CFG.theme_path); GuiImageData wifiImgData(imgPath, wifi1_png); + + snprintf(imgPath, sizeof(imgPath), "%sbrowser.png", CFG.theme_path); + GuiImageData channelImgData(imgPath, browser_png); + GuiImage background(&bgData); @@ -294,6 +299,17 @@ int MenuHomebrewBrowse() wifiBtn.SetEffectGrow(); wifiBtn.SetAlpha(80); wifiBtn.SetTrigger(&trigA); + + GuiImage channelBtnImg(&channelImgData); + channelBtnImg.SetWidescreen(CFG.widescreen); + GuiButton channelBtn(channelBtnImg.GetWidth(), channelBtnImg.GetHeight()); + channelBtn.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + channelBtn.SetPosition(425, 400); + channelBtn.SetImage(&channelBtnImg); + channelBtn.SetSoundOver(&btnSoundOver); + channelBtn.SetSoundClick(&btnClick); + channelBtn.SetEffectGrow(); + channelBtn.SetTrigger(&trigA); GuiWindow w(screenwidth, screenheight); @@ -385,6 +401,7 @@ int MenuHomebrewBrowse() w.Append(&backBtn); w.Append(&homo); w.Append(&wifiBtn); + w.Append(&channelBtn); w.Append(&GoRightBtn); w.Append(&GoLeftBtn); @@ -835,7 +852,19 @@ int MenuHomebrewBrowse() CloseConnection(); ResumeNetworkWait(); } - + + else if(channelBtn.GetState() == STATE_CLICKED) { + w.SetState(STATE_DISABLED); + //10001 are the channels that are installed as channels, not including shop channel/mii channel etc + u32 num = 0x00010001; + TitleBrowser(num); + //if they didn't boot a channel reset this window + w.SetState(STATE_DEFAULT); + channelBtn.ResetState(); + + + } + if(IsNetworkInit()) { wifiBtn.SetAlpha(255); } diff --git a/source/homebrewboot/HomebrewFiles.cpp b/source/homebrewboot/HomebrewFiles.cpp index 51465c36..4fea3226 100644 --- a/source/homebrewboot/HomebrewFiles.cpp +++ b/source/homebrewboot/HomebrewFiles.cpp @@ -45,8 +45,8 @@ bool HomebrewFiles::LoadPath(const char * folderpath) temp[i] = filename[strlen(filename)-4+i]; } - if(strncasecmp(temp, ".dol", 4) == 0 || strncasecmp(temp, ".elf", 4) == 0 - && filecount < MAXHOMEBREWS) { + if((strncasecmp(temp, ".dol", 4) == 0 || strncasecmp(temp, ".elf", 4) == 0) + && filecount < MAXHOMEBREWS && filename[0]!='.') { strncpy(FileInfo[filecount].FilePath, folderpath, sizeof(FileInfo[filecount].FilePath)); strncpy(FileInfo[filecount].FileName, filename, sizeof(FileInfo[filecount].FileName)); diff --git a/source/images/addressbar_textbox.png b/source/images/addressbar_textbox.png index 856be7662b3911adbf635db49ee8cec1652227e2..77007f5bf5c1b2a866eef3e94b3e6fcaf6528906 100644 GIT binary patch literal 3888 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 AG5`Po diff --git a/source/images/bg_browser.png b/source/images/bg_browser.png index f7796934839c3d5490cb28861884dec9ceb08a8d..a2c03f38fae651dafa66fb0fdd6edcb49f38fb76 100644 GIT binary patch literal 4399 zcma)9cU;rUvR?%0RXPaLlp?(vI)q-OnV_hEKq%7DPy~WV69f??6hTnw2-1R)jtEEz zO=>98jELYBqzD9F&OOif&bja1bM7C%-I>qK?#z6@`kD8J+9utSfNfV8qk$oTlbgaL9WFY$q7XY-D9#H7Ti|)QbzJcz(egei&sDNL9 zubanBR{(;ib8Qf|Hme*OyK_HuP2*ANroPtf)B@JJi72+za}t6y%qH=I1yk%+?JWBG z6udq8@#M+Ls3dkPN&5S=lT^!s&yu5`$KUTgSO|OWHQu!QY2c`SLX%Ljm0LSV)kaO9 zVWeQCgrYCiuq>?|MJwV5n5k=B1Oth}WMD5sUH!aJ8&wM+3m&DT25sg! zZL+81j+wsbW;u|d?vb?xrCuj8H)P%(JvzCM7<0ya0(P6(Kk00kq+m z>1qHqJ&?7Ej}ZqHVZgCRSU4Em%K~f$n=tk7=PQ{B5+tOuYSghJ5dEkt)KdObFqkyI z7|xjUJe#u938!pr>5h;rZuuxhrjJ|w0OY5#ld9b!2ICkjaX95<4C8gFFRhfvLe9=h zM=OKne%b&m1Vs!VNy^mnpwuW)-bc^QZcw;iqszawo9I@(~>CT!mrtVU9tiqdbRQKmrZ3OMoW7{Sfp7L!IL0;fe3S*B@J zXvptbb%+Y3m6+C@d&Baxlgn9NE)H%aDLj5Eg;j<*EFRjaB62DLDldwCc*3~)h3&|x z5rYvQYvEPN(i}x29^th2(=J{$RFHH@f%82v%el*Mmlc+ImjySk(B?X8`@h(;SroJG z^)%sLVO~*Op>)lZ*Rgw^Z9Q93V9TPEa#{Cf0miz@Dz1c8@m4luAezJ2wD9G#$D=&% zobJ0GRiA_2u*^Q@w?GfUM*3C_KchdB|3K0+#Ii?s$0NkJbGWFu5Zp+vs!X#Y?$Jc< zZd+LuxwT9}7E_k59b5tYYBZ}m0x{*si{kV?gn>l zu%w_DLwW42D5cJG)dN#^Zc8*~68RbvHOfj0AW#Jp1z4^1R=S%O)l#Pa-jg5;8iH6c zdMo1o9NRbXMRDFDMKi3NtAkfr208;?Zd7hnZn)O0T)AGHThy%IXnzpJsMBpC>L6-} zNWq=VCD=^a%ofuYbC_$WZdXc|c@^>&H0mK+eTp|S^IEQ<^2~gT=R%qZ`=`TYh_*!U z{o-vydN^e*y$B_q9>=BrPRZX_olmA4|J@3D^{qCv(CM)gdf{Fwc3A!Sn85=BrX-Ip zhb56E?=J7I=jSNT37#`G|6;z8ZEcP%5-(CSQ#0!x=pT4CFrKB9qaimTPskzUOytZr zI9?9EEQu+>ymmFNS-xCkzkzA;iMb51FNE7&zFKSWGWX@#@y3^p#Vo~Gi!_V!ym7?a zSKl%3F{KUMuT~~0@s${FOt=%mnG@0QuJY|hT60?XoA3uj4JwAXDaLZX%X|@mbpdRu zmsIDnaZfh1!r%SKSd~G*2bl*a6_zlped3)Sxi&eYh6qjsHZXcCJ~6@cZl5$-Q#yyY zYqqC(*(7M&|LQ{M$aZc{ZBEB}3BGDWdBbBPZsuvf;#2WFdxgNEw>{90Rx86=bWb14 zdd*ivSVAqM5cLFMnHw^xu$L3B8VZqRyH4LYHFq=vo-S!FsjJM%&)Hw^S7~eLY3Q?j z>zj8yW*!%*6VyM#O>@gXXwPfm$%Bj`nA;$mR2TFHL#aGqf~v=VZ7 z1{yf8x38C>HEP=?2+0g9564eJ9VGZIHjO0ALmz!jZBhymd8be)xq`hXTKcfbjKOR+M>UTl`?i3$ zyoPGCT=b*VhyJ={g63%$#23UTx7&Rct}!)7?|c#)WcVLbz4xkpSaH%`iWZ|=^x5{Z z*n|XC4Z;=X);f^T3&|+YJ3p}AU)zg+sPg37)8qA19j6u^VG3hSVN!hXPt6sckQ#OW z5IpS?`^odMmnbXLU*E?_c#m0@ufx!l5zXg9&Apn7LY_qYKyE!!8iKWz7Hl{ZFa z>zyX{e1=$YGm2tFB4-R#Y5gB+XegDcKg-dOf)4v&AC3q3T%pJ95UsBRx(vSs_; zV|w-OXc}U3Fe&$OZg_iVe@s+W(|IY z74{mIU8Q>6`%BOl^`o>=%kIV}joFo02QTbKXmfp-+wLlFo(gXEM{~$`j^pvMJc!0@ z^H!+u?z`RXd5+nL08t{YuWGEN zUCNl~!K2je6ej4&l&qA#SccfOybGET$f8yNarLkmI_NTZE|2r**->95Cx=YL-q_j% zZa8ze0KJJ$YxTZUNc_^a#$AQ)>geKcc^|AGckRcegY|ag43h8L^LZxAuht1?F4t*!tTsZ$1Eqoy8}YZRxZo4C&YEBIWZ4ETNk}B zUO!|~v|^(v)bUuvSr8s6>(fSx8K+XduSthfXLVq-r`RO>f}ONJ<)zWqHGXw4kQH*? z*fKKunmhH0gHVj_Yf3W_Cj&C0;XCLn4L;_fgO)+=$O`X>H^IldIMa@ z!@!8$52ZHWWTd1*+{lK6AOyIBLy`gl=a3M89c^uGBYVk29F~Db!}f_Sj-bx$>O^%@ z(`h<7y4JF_{bJVW;Wg4VCna>5n(UBK04w4v}kLd^c=DM*8rqgzrvwZ z2BgKoj#3-R&+Fgjl35U5uCr5lvYLk?KRg>3`Im`j7Le+^6bK8S?5GGOdJ4*_6zDhlF^#Z>Iwfs9u6+UPLw|g?9c05%N z%(;M>{{I613zXj(ag5EYq72#b_bb-{)8(s&Do#L_{ZB;w?*EInkLGLqO^#?b?XZ<6 zq>Y>S|I!!VVCwmeU%c@JnD!X?4^LrJ^BXFe$xC!7ntwSle<1Xahldf-3;{Ahe}V7+ zRQxN~e-?wX-+T}TNSKqfqm=eZslue$Q>feL3zy@$Ea?rzT{Q@YC6!)Cy8L&ykw|0! z?pPz3_!Ii=$rchqaJo8?YP~tco8R0%DN%SR>)%nbwtohX#~;s3Pv1{}q((WUd+TcV z`1p7Vgy4IQQdp=(y6`Yuk%!o=WlC0OX=hhmUCpAVruNjxo-8eSN##6{qK>rm$Jo``)7mjSN*pDWN&;2L`RD9~hv87YQs2 z$I~bJ<0ORm^*dXI7OTVy>(NBr%@8_JBt`#QXQ}m$@4+1I464!{5;QX|b^2DN42FH~A zq*MjZ+{E-3nbD5iypH5rJBZ7CoBpVb#C2 z)yc$oc8~6}&y5C#Gh^oMt@)Yy*`{#y)vjF^Gfb2i7VKB?ob>u%(YYNGp8Dr?jTycy zoqhG{)%bhQn+vCLx=TsPFQ2|OXyuo{tx;R=FkEPNGM+PUp4@W(`%C)2s(6}J3CUz; ztZBKh;`(d-Wy_W=+PHC}MqjcvA4Bb`n>lXm?Ccl6eJd-etNR!G>r#4V#hpFn1uZMx zR)$pV-LXT$*Uv91k>P>-LU}WD^Tl)L&i(r3{Q65TEb3nT`((Q@u>bLoua_QDV4o@y?x?9c!L)^<7ba{P=OAOA;$%Ltoa`sF1Z`;ZnWFg62Jl;FM=! zIFVISViIF_LRjWJ8$0`28HNcrFI))N;q#2MPcVKt14HGVtRXzi0#WyFfsf&+rrEsAj8lAlz>t!>|h>(Qm|lP0P;Z8K}IC1!96hVd(!HwyJ{I2 zQZBBP_OW1SIK;`v-~hC#i5W%#O$G4~6p~fHnjXJoY&bL%q5-QC3`boMKlOd@!z~dE z3akC@CLCg95b-0deO}YH^p!1tFU(!a#PFqy6Wuc$d|mV?Q zH0A&U2pS03!y+NOm|;PI8YC#O1|CFT!}0|+_ocU)u`_IXb%htG-r*sJfe43yLfocl zTlDPqx1PDVe1siu!(`pd#1Q+MNTZpeXEQUj8b8GAIj|#GpZ>nLVXGy>gwW-A20-;( z>X7t+a4RU#fIKMmKyb_5TQ)iVS)gzU2c`{>DYz6vlZ*m$`bq|(9S=0@fo8!pE`|%H zAZ`CGAr>Gx1Ca`$7C@8O5Bq{B9fkl4VNwz+FqRzjr@XH|{P7EeLl|+%0;iu@o|frv zi&}ddWabP=`mLCCu<+??5e9|+-DNvY3CmPpzkWT8kKx3dSFg62)}0oX*&i1d7iGzy zuz7b`#dLLxItweSPuijk3X=`)TG-q3`=KJy|Wv@IX;rUH#(2hYx3)nC+{4v2WYKiFGfYr)~cE^V+p(FBlkZS=rh3 zZQH*6@a3<5-;eSCjqi0^{Bcu=R;{(6p=I87CnAP!YoTzfr zKbG})Y>ADxzW!s2I#VkvsZgz{85I>4UjMf}Vz{6_>+G}KjF^}hm-O`X{r6jsU5~Vv zPycJ`B_-GV^6B9(f=o{;e@Sfo!*Id;U&p^&>5t!j`t<48p+ipV_>bTH_s5i1@IMQ~ rh4e`(CrkJLp90PDt-pgC7#U30#XOYS+-MD~q!>J1{an^LB{Ts5rzcAK diff --git a/source/images/bg_browser_selection.png b/source/images/bg_browser_selection.png index 54e7d9d0c999f86e6bef8e0a043a321e3a50ff02..2bdc02dbb83c944f69e960bb9c6d0c5198af20bd 100644 GIT binary patch literal 5132 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 scrollbarImg->SetAlignment(ALIGN_RIGHT, ALIGN_TOP); - scrollbarImg->SetPosition(0, 30); + scrollbarImg->SetPosition(0, 2); + scrollbarImg->SetSkew(0,0,0,0,0,-30,0,-30); arrowDown = new GuiImageData(scrollbar_arrowdown_png); arrowDownImg = new GuiImage(arrowDown); @@ -59,6 +60,7 @@ GuiFileBrowser::GuiFileBrowser(int w, int h) arrowUpBtn->SetParent(this); arrowUpBtn->SetImage(arrowUpImg); arrowUpBtn->SetAlignment(ALIGN_RIGHT, ALIGN_TOP); + arrowUpBtn->SetPosition(12,-12); arrowUpBtn->SetSelectable(false); arrowUpBtn->SetClickable(false); arrowUpBtn->SetHoldable(true); @@ -70,6 +72,7 @@ GuiFileBrowser::GuiFileBrowser(int w, int h) arrowDownBtn->SetParent(this); arrowDownBtn->SetImage(arrowDownImg); arrowDownBtn->SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + arrowDownBtn->SetPosition(12,12); arrowDownBtn->SetSelectable(false); arrowDownBtn->SetClickable(false); arrowDownBtn->SetHoldable(true); @@ -81,8 +84,8 @@ GuiFileBrowser::GuiFileBrowser(int w, int h) scrollbarBoxBtn->SetParent(this); scrollbarBoxBtn->SetImage(scrollbarBoxImg); scrollbarBoxBtn->SetAlignment(ALIGN_RIGHT, ALIGN_TOP); - scrollbarBoxBtn->SetMinY(0); - scrollbarBoxBtn->SetMaxY(136); + scrollbarBoxBtn->SetMinY(-10); + scrollbarBoxBtn->SetMaxY(156); scrollbarBoxBtn->SetSelectable(false); scrollbarBoxBtn->SetClickable(false); scrollbarBoxBtn->SetHoldable(true); @@ -103,7 +106,7 @@ GuiFileBrowser::GuiFileBrowser(int w, int h) fileListBg[i] = new GuiImage(bgFileSelectionEntry); fileListFolder[i] = new GuiImage(fileFolder); - fileList[i] = new GuiButton(512,30); + fileList[i] = new GuiButton(350,30); fileList[i]->SetParent(this); fileList[i]->SetLabel(fileListText[i]); fileList[i]->SetLabelOver(fileListTextOver[i]); @@ -228,7 +231,7 @@ void GuiFileBrowser::Update(GuiTrigger * t) browser.numEntries > FILEBROWSERSIZE ) { - scrollbarBoxBtn->SetPosition(0,0); + scrollbarBoxBtn->SetPosition(20,-10); positionWiimote = t->wpad.ir.y - 60 - scrollbarBoxBtn->GetTop(); if(positionWiimote < scrollbarBoxBtn->GetMinY()) @@ -236,7 +239,7 @@ void GuiFileBrowser::Update(GuiTrigger * t) else if(positionWiimote > scrollbarBoxBtn->GetMaxY()) positionWiimote = scrollbarBoxBtn->GetMaxY(); - browser.pageIndex = (positionWiimote * browser.numEntries)/136.0 - selectedItem; + browser.pageIndex = (positionWiimote * browser.numEntries)/166.0 - selectedItem; if(browser.pageIndex <= 0) { @@ -248,6 +251,8 @@ void GuiFileBrowser::Update(GuiTrigger * t) } listChanged = true; focus = false; + + } if(arrowDownBtn->GetState() == STATE_HELD && arrowDownBtn->GetStateChan() == t->chan) @@ -255,12 +260,14 @@ void GuiFileBrowser::Update(GuiTrigger * t) t->wpad.btns_h |= WPAD_BUTTON_DOWN; if(!this->IsFocused()) ((GuiWindow *)this->GetParent())->ChangeFocus(this); + } else if(arrowUpBtn->GetState() == STATE_HELD && arrowUpBtn->GetStateChan() == t->chan) { t->wpad.btns_h |= WPAD_BUTTON_UP; if(!this->IsFocused()) ((GuiWindow *)this->GetParent())->ChangeFocus(this); + } // pad/joystick navigation @@ -385,15 +392,15 @@ void GuiFileBrowser::Update(GuiTrigger * t) } else { - position = 136*(browser.pageIndex + FILEBROWSERSIZE/2.0) / (browser.numEntries*1.0); + position = -10+(166*(browser.pageIndex + FILEBROWSERSIZE/2.0) / (browser.numEntries*1.0)); if(browser.pageIndex/(FILEBROWSERSIZE/2.0) < 1) - position = 0; + position = -10; else if((browser.pageIndex+FILEBROWSERSIZE)/(FILEBROWSERSIZE*1.0) >= (browser.numEntries)/(FILEBROWSERSIZE*1.0)) - position = 136; + position = 156; } - scrollbarBoxBtn->SetPosition(0,position+36); + scrollbarBoxBtn->SetPosition(12,position+26); listChanged = false; diff --git a/source/menu.cpp b/source/menu.cpp index 86afa313..2c20a481 100644 --- a/source/menu.cpp +++ b/source/menu.cpp @@ -25,7 +25,9 @@ #include "homebrewboot/HomebrewBrowse.h" #include "homebrewboot/BootHomebrew.h" #include "prompts/PromptWindows.h" +#include "prompts/filebrowser.h" #include "prompts/ProgressWindow.h" +#include "prompts/TitleBrowser.h" #include "prompts/gameinfo.h" #include "mload/mload.h" #include "patches/patchcode.h" @@ -472,7 +474,7 @@ int MenuDiscList() homebrewBtnImg.SetWidescreen(CFG.widescreen); GuiButton homebrewBtn(homebrewBtnImg.GetWidth(), homebrewBtnImg.GetHeight()); homebrewBtn.SetAlignment(ALIGN_LEFT, ALIGN_TOP); - homebrewBtn.SetPosition(425, 400); + homebrewBtn.SetPosition(THEME.homebrew_x,THEME.homebrew_y); homebrewBtn.SetImage(&homebrewBtnImg); homebrewBtn.SetSoundOver(&btnSoundOver); homebrewBtn.SetSoundClick(&btnClick); @@ -618,7 +620,6 @@ int MenuDiscList() { w.Append(&gamecntTxt); } - w.Append(&sdcardBtn); w.Append(&poweroffBtn); w.Append(&gameInfo); diff --git a/source/prompts/TitleBrowser.cpp b/source/prompts/TitleBrowser.cpp new file mode 100644 index 00000000..384841cf --- /dev/null +++ b/source/prompts/TitleBrowser.cpp @@ -0,0 +1,194 @@ +/**************************************************************************** + * TitleBrowser + * USB Loader GX 2009 + * + * TitleBrowser.cpp + ***************************************************************************/ +#include "language/gettext.h" +#include "libwiigui/gui.h" +#include "libwiigui/gui_customoptionbrowser.h" +#include "prompts/PromptWindows.h" +#include "filelist.h" +#include "settings/cfg.h" +#include "sys.h" +#include "menu.h" + +#include "../wad/title.h" + +/*** Extern functions ***/ +extern void ResumeGui(); +extern void HaltGui(); + +/*** Extern variables ***/ +extern GuiWindow * mainWindow; +extern u8 shutdown; +extern u8 reset; + + +/******************************************************************************** +* TitleBrowser- opens a browser with a list of installed Titles +* relies on code from any title deleter. +*********************************************************************************/ +int TitleBrowser(u32 type) +{ + + u32 num_titles; + u32 titles[100] ATTRIBUTE_ALIGN(32); + s32 ret = -1; + + + // Get count of titles of our requested type + ret = getTitles_TypeCount(type, &num_titles); + if (ret < 0){ + //printf("\tError! Can't get count of titles! (ret = %d)\n", ret); + //exit(1); + } + + // Die if we can't handle this many + if (num_titles > 100){ + //printf("\tError! Too many titles! (%u)\n", num_titles); + //exit(1); + } + + // Get titles of our requested type + ret = getTitles_Type(type, titles, num_titles); + if (ret < 0){ + //printf("\tError! Can't get list of titles! (ret = %d)\n", ret); + //exit(1); + } + + + customOptionList options3(num_titles); + //write the titles on the option browser + u32 i = 0; + while (i < num_titles){ + + char name[256]; + char text[15]; + //set the title's name, number, ID to text + sprintf(text, "%s", titleText(type, titles[i])); + getTitle_Name(name, TITLE_ID(type, titles[i]), text); + + //set the text to the option browser + options3.SetName(i, "%s",name); + options3.SetValue(i, "%s (%08x)",text,titles[i]); + + //move on to the next title + i++; + } + + bool exit = false; + + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + + char imgPath[100]; + + snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path); + GuiImageData btnOutline(imgPath, button_dialogue_box_png); + snprintf(imgPath, sizeof(imgPath), "%sgamesettings_background.png", CFG.theme_path); + GuiImageData settingsbg(imgPath, settings_background_png); + + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + GuiTrigger trigHome; + trigHome.SetButtonOnlyTrigger(-1, WPAD_BUTTON_HOME | WPAD_CLASSIC_BUTTON_HOME, 0); + GuiTrigger trigB; + trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + + GuiText titleTxt("Title Launcher", 28, (GXColor){0, 0, 0, 255}); + titleTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); + titleTxt.SetPosition(12,40); + titleTxt.SetMaxWidth(356, GuiText::SCROLL); + + GuiImage settingsbackground(&settingsbg); + GuiButton settingsbackgroundbtn(settingsbackground.GetWidth(), settingsbackground.GetHeight()); + settingsbackgroundbtn.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + settingsbackgroundbtn.SetPosition(0, 0); + settingsbackgroundbtn.SetImage(&settingsbackground); + + GuiText cancelBtnTxt(tr("Back"), 22, (GXColor){THEME.prompttxt_r, THEME.prompttxt_g, THEME.prompttxt_b, 255}); + cancelBtnTxt.SetMaxWidth(btnOutline.GetWidth()-30); + GuiImage cancelBtnImg(&btnOutline); + if (Settings.wsprompt == yes){ + cancelBtnTxt.SetWidescreen(CFG.widescreen); + cancelBtnImg.SetWidescreen(CFG.widescreen); + } + GuiButton cancelBtn(&cancelBtnImg,&cancelBtnImg, 2, 3, 180, 400, &trigA, &btnSoundOver, &btnClick,1); + cancelBtn.SetScale(0.9); + cancelBtn.SetLabel(&cancelBtnTxt); + cancelBtn.SetTrigger(&trigB); + + u8 scrollbaron = 0; + if(num_titles > 9) + scrollbaron = 1; + + GuiCustomOptionBrowser optionBrowser3(396, 280, &options3, CFG.theme_path, "bg_options_gamesettings.png", bg_options_settings_png, num_titles>9?1:0, 200); + optionBrowser3.SetPosition(0, 90); + optionBrowser3.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); + + HaltGui(); + GuiWindow w(screenwidth, screenheight); + w.Append(&settingsbackgroundbtn); + w.Append(&titleTxt); + w.Append(&cancelBtn); + w.Append(&optionBrowser3); + + mainWindow->Append(&w); + + ResumeGui(); + + while(!exit) + { + VIDEO_WaitVSync(); + + if(shutdown == 1) + Sys_Shutdown(); + if(reset == 1) + Sys_Reboot(); + + ret = optionBrowser3.GetClickedOption(); + + if(ret > -1) {//if a click happened + char name[256]; + char text[15]; + + sprintf(text, "%s", titleText(type, titles[ret])); + getTitle_Name(name, TITLE_ID(type, titles[ret]), text); + + char temp[100]; + //prompt to boot selected title + snprintf(temp, sizeof(temp), "%s : %s",text,name); + int choice = WindowPrompt("Boot?", temp, tr("OK"), tr("Cancel")); + if(choice) {//if they say yes + + WII_Initialize(); + WII_LaunchTitle(TITLE_ID(type,titles[ret])); + //this really shouldn't be needed because the title will be booted + exit = true; + break; + } + else{ + //if they said no to booting the title + ret = -1; + optionBrowser3.ResetState(); + } + } + + if (cancelBtn.GetState() == STATE_CLICKED) + { + //break the loop and end the function + exit = true; + ret = -10; + } + } + + HaltGui(); + mainWindow->Remove(&w); + ResumeGui(); + + return ret; +} + + + diff --git a/source/prompts/TitleBrowser.h b/source/prompts/TitleBrowser.h new file mode 100644 index 00000000..b6f12793 --- /dev/null +++ b/source/prompts/TitleBrowser.h @@ -0,0 +1,15 @@ +/**************************************************************************** + * TitleBrowser + * USB Loader GX 2009 + * + * TitleBrowser.h + ***************************************************************************/ + +#ifndef _TITLEBROWSER_H_ +#define _TITLEBROWSER_H_ + +///opens a window with a custom option browser in it populated with +//! type is the type of chnnel to put in the list +int TitleBrowser(u32 type); + +#endif diff --git a/source/filebrowser.cpp b/source/prompts/filebrowser.cpp similarity index 51% rename from source/filebrowser.cpp rename to source/prompts/filebrowser.cpp index 790fc448..bc71b180 100644 --- a/source/filebrowser.cpp +++ b/source/prompts/filebrowser.cpp @@ -1,225 +1,239 @@ -/**************************************************************************** - * libwiigui Template +/**************************************************************************** + * libwiigui Template * Tantric 2009 * - * modified by dimok - * - * filebrowser.cpp - * - * Generic file routines - reading, writing, browsing - ***************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include - -#include "filebrowser.h" -#include "menu.h" - -BROWSERINFO browser; -BROWSERENTRY * browserList = NULL; // list of files/folders in browser - -/**************************************************************************** - * ResetBrowser() - * Clears the file browser memory, and allocates one initial entry - ***************************************************************************/ -void ResetBrowser() -{ - browser.numEntries = 0; - browser.selIndex = 0; - browser.pageIndex = 0; - - // Clear any existing values - if(browserList != NULL) - { - free(browserList); - browserList = NULL; - } - // set aside space for 1 entry - browserList = (BROWSERENTRY *)malloc(sizeof(BROWSERENTRY)); - memset(browserList, 0, sizeof(BROWSERENTRY)); -} - -/**************************************************************************** - * UpdateDirName() - * Update curent directory name for file browser - ***************************************************************************/ -int UpdateDirName() -{ - int size=0; - char * test; - char temp[1024]; - - /* current directory doesn't change */ - if (strcmp(browserList[browser.selIndex].filename,".") == 0) - { - return 0; - } - /* go up to parent directory */ - else if (strcmp(browserList[browser.selIndex].filename,"..") == 0) - { - /* determine last subdirectory namelength */ - sprintf(temp,"%s",browser.dir); - test = strtok(temp,"/"); - while (test != NULL) - { - size = strlen(test); - test = strtok(NULL,"/"); - } - - /* remove last subdirectory name */ - size = strlen(browser.dir) - size - 1; - browser.dir[size] = 0; - - return 1; - } - /* Open a directory */ - else - { - /* test new directory namelength */ - if ((strlen(browser.dir)+1+strlen(browserList[browser.selIndex].filename)) < MAXPATHLEN) - { - /* update current directory name */ - sprintf(browser.dir, "%s/%s",browser.dir, browserList[browser.selIndex].filename); - return 1; - } - else - { - return -1; - } - } -} - -/**************************************************************************** - * FileSortCallback - * - * Quick sort callback to sort file entries with the following order: - * . - * .. - * - * - ***************************************************************************/ -int FileSortCallback(const void *f1, const void *f2) -{ - /* Special case for implicit directories */ - if(((BROWSERENTRY *)f1)->filename[0] == '.' || ((BROWSERENTRY *)f2)->filename[0] == '.') - { - if(strcmp(((BROWSERENTRY *)f1)->filename, ".") == 0) { return -1; } - if(strcmp(((BROWSERENTRY *)f2)->filename, ".") == 0) { return 1; } - if(strcmp(((BROWSERENTRY *)f1)->filename, "..") == 0) { return -1; } - if(strcmp(((BROWSERENTRY *)f2)->filename, "..") == 0) { return 1; } - } - - /* If one is a file and one is a directory the directory is first. */ - if(((BROWSERENTRY *)f1)->isdir && !(((BROWSERENTRY *)f2)->isdir)) return -1; - if(!(((BROWSERENTRY *)f1)->isdir) && ((BROWSERENTRY *)f2)->isdir) return 1; - - return stricmp(((BROWSERENTRY *)f1)->filename, ((BROWSERENTRY *)f2)->filename); -} - -/*************************************************************************** - * Browse subdirectories - **************************************************************************/ -int -ParseDirectory() -{ - DIR_ITER *dir = NULL; - char fulldir[MAXPATHLEN]; - char filename[MAXPATHLEN]; - struct stat filestat; - - // reset browser - ResetBrowser(); - - // open the directory - sprintf(fulldir, "%s%s", browser.rootdir, browser.dir); // add currentDevice to path - dir = diropen(fulldir); - - // if we can't open the dir, try opening the root dir - if (dir == NULL) - { - sprintf(browser.dir,"/"); - dir = diropen(browser.rootdir); - if (dir == NULL) - { - return -1; - } - } - - // index files/folders - int entryNum = 0; - - while(dirnext(dir,filename,&filestat) == 0) - { - if(strcmp(filename,".") != 0) - { - BROWSERENTRY * newBrowserList = (BROWSERENTRY *)realloc(browserList, (entryNum+1) * sizeof(BROWSERENTRY)); - - if(!newBrowserList) // failed to allocate required memory - { - ResetBrowser(); - entryNum = -1; - break; - } - else - { - browserList = newBrowserList; - } - memset(&(browserList[entryNum]), 0, sizeof(BROWSERENTRY)); // clear the new entry - - strncpy(browserList[entryNum].filename, filename, MAXJOLIET); - - if(strcmp(filename,"..") == 0) - { - sprintf(browserList[entryNum].displayname, ".."); - } - else - { - strcpy(browserList[entryNum].displayname, filename); // crop name for display - } - - browserList[entryNum].length = filestat.st_size; - browserList[entryNum].isdir = (filestat.st_mode & _IFDIR) == 0 ? 0 : 1; // flag this as a dir - - entryNum++; - } - } - - // close directory - dirclose(dir); - - // Sort the file list - qsort(browserList, entryNum, sizeof(BROWSERENTRY), FileSortCallback); - - browser.numEntries = entryNum; - return entryNum; -} - -/**************************************************************************** - * BrowserChangeFolder - * - * Update current directory and set new entry list if directory has changed - ***************************************************************************/ -int BrowserChangeFolder() -{ - if(!UpdateDirName()) - return -1; - - ParseDirectory(); - - return browser.numEntries; + * modified by dimok + * + * filebrowser.cpp + * + * Generic file routines - reading, writing, browsing + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "filebrowser.h" +#include "menu.h" + +#include "language/gettext.h" +#include "PromptWindows.h" +#include "libwiigui/gui.h" +#include "sys.h" + +/*** Extern variables ***/ +extern GuiWindow * mainWindow; +extern u8 shutdown; +extern u8 reset; + +/*** Extern functions ***/ +extern void ResumeGui(); +extern void HaltGui(); + +BROWSERINFO browser; +BROWSERENTRY * browserList = NULL; // list of files/folders in browser + +/**************************************************************************** + * ResetBrowser() + * Clears the file browser memory, and allocates one initial entry + ***************************************************************************/ +void ResetBrowser() +{ + browser.numEntries = 0; + browser.selIndex = 0; + browser.pageIndex = 0; + + // Clear any existing values + if(browserList != NULL) + { + free(browserList); + browserList = NULL; + } + // set aside space for 1 entry + browserList = (BROWSERENTRY *)malloc(sizeof(BROWSERENTRY)); + memset(browserList, 0, sizeof(BROWSERENTRY)); } -/**************************************************************************** - * BrowseDevice - * Displays a list of files on the selected device - ***************************************************************************/ -int BrowseDevice(int device) -{ +/**************************************************************************** + * UpdateDirName() + * Update curent directory name for file browser + ***************************************************************************/ +int UpdateDirName() +{ + int size=0; + char * test; + char temp[1024]; + + /* current directory doesn't change */ + if (strcmp(browserList[browser.selIndex].filename,".") == 0) + { + return 0; + } + /* go up to parent directory */ + else if (strcmp(browserList[browser.selIndex].filename,"..") == 0) + { + /* determine last subdirectory namelength */ + sprintf(temp,"%s",browser.dir); + test = strtok(temp,"/"); + while (test != NULL) + { + size = strlen(test); + test = strtok(NULL,"/"); + } + + /* remove last subdirectory name */ + size = strlen(browser.dir) - size - 1; + browser.dir[size] = 0; + + return 1; + } + /* Open a directory */ + else + { + /* test new directory namelength */ + if ((strlen(browser.dir)+1+strlen(browserList[browser.selIndex].filename)) < MAXPATHLEN) + { + /* update current directory name */ + sprintf(browser.dir, "%s/%s",browser.dir, browserList[browser.selIndex].filename); + return 1; + } + else + { + return -1; + } + } +} + +/**************************************************************************** + * FileSortCallback + * + * Quick sort callback to sort file entries with the following order: + * . + * .. + * + * + ***************************************************************************/ +int FileSortCallback(const void *f1, const void *f2) +{ + /* Special case for implicit directories */ + if(((BROWSERENTRY *)f1)->filename[0] == '.' || ((BROWSERENTRY *)f2)->filename[0] == '.') + { + if(strcmp(((BROWSERENTRY *)f1)->filename, ".") == 0) { return -1; } + if(strcmp(((BROWSERENTRY *)f2)->filename, ".") == 0) { return 1; } + if(strcmp(((BROWSERENTRY *)f1)->filename, "..") == 0) { return -1; } + if(strcmp(((BROWSERENTRY *)f2)->filename, "..") == 0) { return 1; } + } + + /* If one is a file and one is a directory the directory is first. */ + if(((BROWSERENTRY *)f1)->isdir && !(((BROWSERENTRY *)f2)->isdir)) return -1; + if(!(((BROWSERENTRY *)f1)->isdir) && ((BROWSERENTRY *)f2)->isdir) return 1; + + return stricmp(((BROWSERENTRY *)f1)->filename, ((BROWSERENTRY *)f2)->filename); +} + +/*************************************************************************** + * Browse subdirectories + **************************************************************************/ +int +ParseDirectory() +{ + DIR_ITER *dir = NULL; + char fulldir[MAXPATHLEN]; + char filename[MAXPATHLEN]; + struct stat filestat; + + // reset browser + ResetBrowser(); + + // open the directory + sprintf(fulldir, "%s%s", browser.rootdir, browser.dir); // add currentDevice to path + dir = diropen(fulldir); + + // if we can't open the dir, try opening the root dir + if (dir == NULL) + { + sprintf(browser.dir,"/"); + dir = diropen(browser.rootdir); + if (dir == NULL) + { + return -1; + } + } + + // index files/folders + int entryNum = 0; + + while(dirnext(dir,filename,&filestat) == 0) + { + if(strcmp(filename,".") != 0) + { + BROWSERENTRY * newBrowserList = (BROWSERENTRY *)realloc(browserList, (entryNum+1) * sizeof(BROWSERENTRY)); + + if(!newBrowserList) // failed to allocate required memory + { + ResetBrowser(); + entryNum = -1; + break; + } + else + { + browserList = newBrowserList; + } + memset(&(browserList[entryNum]), 0, sizeof(BROWSERENTRY)); // clear the new entry + + strncpy(browserList[entryNum].filename, filename, MAXJOLIET); + + if(strcmp(filename,"..") == 0) + { + sprintf(browserList[entryNum].displayname, ".."); + } + else + { + strcpy(browserList[entryNum].displayname, filename); // crop name for display + } + + browserList[entryNum].length = filestat.st_size; + browserList[entryNum].isdir = (filestat.st_mode & _IFDIR) == 0 ? 0 : 1; // flag this as a dir + + entryNum++; + } + } + + // close directory + dirclose(dir); + + // Sort the file list + qsort(browserList, entryNum, sizeof(BROWSERENTRY), FileSortCallback); + + browser.numEntries = entryNum; + return entryNum; +} + +/**************************************************************************** + * BrowserChangeFolder + * + * Update current directory and set new entry list if directory has changed + ***************************************************************************/ +int BrowserChangeFolder() +{ + if(!UpdateDirName()) + return -1; + + ParseDirectory(); + + return browser.numEntries; +} + +/**************************************************************************** + * BrowseDevice + * Displays a list of files on the selected device + ***************************************************************************/ +int BrowseDevice(int device) +{ sprintf(browser.dir, "/"); switch(device) { @@ -229,7 +243,190 @@ int BrowseDevice(int device) case USB: sprintf(browser.rootdir, "USB:"); break; - } - ParseDirectory(); // Parse root directory - return browser.numEntries; -} + } + ParseDirectory(); // Parse root directory + return browser.numEntries; +} + + +/**************************************************************************** + * MenuBrowseDevice + ***************************************************************************/ + +int BrowseDevice(char * var, int force) +{ + + int result=-1; + int i; + char currentdir[90]; + int curDivice = -1; + int forced =force; + + if(forced>-1){ + if(BrowseDevice(forced) > 0) + { + curDivice = forced; + goto main; + } + } + + else if((!strcasecmp(bootDevice, "USB:"))&&(BrowseDevice(USB) > 0)) + { + curDivice = USB; + goto main; + } + else if((!strcasecmp(bootDevice, "SD:"))&&(BrowseDevice(SD) > 0)) + { + curDivice = SD; + goto main; + } + else { + WindowPrompt(tr("Error"),0,tr("Ok")); + return -1; + } + +main: + int menu = MENU_NONE; + +/* + GuiText titleTxt("Browse Files", 28, (GXColor){0, 0, 0, 230}); + titleTxt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); + titleTxt.SetPosition(70,20); +*/ + GuiTrigger trigA; + trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); + GuiTrigger trigB; + trigB.SetButtonOnlyTrigger(-1, WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, PAD_BUTTON_B); + + GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM, Settings.sfxvolume); + GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, SOUND_PCM, Settings.sfxvolume); + + GuiImageData btnOutline(button_dialogue_box_png); + GuiText ExitBtnTxt("Cancel", 24, (GXColor){0, 0, 0, 255}); + GuiImage ExitBtnImg(&btnOutline); + if (Settings.wsprompt == yes){ + ExitBtnTxt.SetWidescreen(CFG.widescreen); + ExitBtnImg.SetWidescreen(CFG.widescreen); + }GuiButton ExitBtn(btnOutline.GetWidth(), btnOutline.GetHeight()); + ExitBtn.SetAlignment(ALIGN_RIGHT, ALIGN_BOTTOM); + ExitBtn.SetPosition(-55, -35); + ExitBtn.SetLabel(&ExitBtnTxt); + ExitBtn.SetImage(&ExitBtnImg); + ExitBtn.SetTrigger(&trigA); + ExitBtn.SetTrigger(&trigB); + ExitBtn.SetEffectGrow(); + + GuiText okBtnTxt(tr("Ok"), 22, (GXColor){THEME.prompttxt_r, THEME.prompttxt_g, THEME.prompttxt_b, 255}); + GuiImage okBtnImg(&btnOutline); + if (Settings.wsprompt == yes){ + okBtnTxt.SetWidescreen(CFG.widescreen); + okBtnImg.SetWidescreen(CFG.widescreen); + } + GuiButton okBtn(&okBtnImg,&okBtnImg, 0, 4, 45, -35, &trigA, &btnSoundOver, &btnClick,1); + okBtn.SetLabel(&okBtnTxt); + + GuiFileBrowser fileBrowser(396, 248); + fileBrowser.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); + fileBrowser.SetPosition(0, 120); + + GuiImageData Address(addressbar_textbox_png); + snprintf(currentdir, sizeof(currentdir), "%s%s", browser.rootdir, browser.dir); + GuiText AdressText(currentdir, 20, (GXColor) {0, 0, 0, 255}); + AdressText.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); + AdressText.SetPosition(20, 0); + AdressText.SetMaxWidth(Address.GetWidth()-40, GuiText::SCROLL); + GuiImage AdressbarImg(&Address); + GuiButton Adressbar(Address.GetWidth(), Address.GetHeight()); + Adressbar.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); + Adressbar.SetPosition(0, fileBrowser.GetTop()-45); + Adressbar.SetImage(&AdressbarImg); + Adressbar.SetLabel(&AdressText); + + //save var in case they cancel and return it to them + snprintf(currentdir, sizeof(currentdir), "%s", var); + sprintf(var,"%s", browser.rootdir); + + HaltGui(); + GuiWindow w(screenwidth, screenheight); + w.Append(&ExitBtn); +// w.Append(&titleTxt); + w.Append(&fileBrowser); + w.Append(&Adressbar); + w.Append(&okBtn); +// w.Append(&deviceBtn);//i got codedump when i tried to make an extra button so i took this one out for now till i find the dump + mainWindow->Append(&w); + ResumeGui(); + + while(menu == MENU_NONE) + { + VIDEO_WaitVSync(); + + if(shutdown == 1) + Sys_Shutdown(); + + if(reset == 1) + Sys_Reboot(); + + for(i=0; iGetState() == STATE_CLICKED) + { + fileBrowser.fileList[i]->ResetState(); + // check corresponding browser entry + if(browserList[browser.selIndex].isdir) + { + if(BrowserChangeFolder()) + { + fileBrowser.ResetState(); + fileBrowser.fileList[0]->SetState(STATE_SELECTED); + fileBrowser.TriggerUpdate(); + sprintf(var,"%s", browser.rootdir); + int len=strlen(browser.rootdir); + for (unsigned int i=len;iSetState(STATE_DISABLED); + mainWindow->SetState(STATE_DEFAULT); + } + } + } + + if(ExitBtn.GetState() == STATE_CLICKED) + { + snprintf(var,sizeof(currentdir),"%s", currentdir); + break; + } + if(okBtn.GetState() == STATE_CLICKED) + { + /*int e=0; + for(unsigned int d=0;dRemove(&w); + ResumeGui(); + + //} + + return result; +} + diff --git a/source/filebrowser.h b/source/prompts/filebrowser.h similarity index 95% rename from source/filebrowser.h rename to source/prompts/filebrowser.h index c4357047..6036fb1e 100644 --- a/source/filebrowser.h +++ b/source/prompts/filebrowser.h @@ -51,5 +51,6 @@ void ResetBrowser(); int ParseDirectory(); int BrowserChangeFolder(); int BrowseDevice(int device); +int BrowseDevice(char * var, int force =-1); #endif diff --git a/source/settings/Settings.cpp b/source/settings/Settings.cpp index 80f50925..d596dd38 100644 --- a/source/settings/Settings.cpp +++ b/source/settings/Settings.cpp @@ -9,6 +9,7 @@ #include "prompts/PromptWindows.h" #include "prompts/DiscBrowser.h" #include "settings/SettingsPrompts.h" +#include "prompts/filebrowser.h" #include "cheats/cheatmenu.h" #include "fatmounter.h" #include "menu.h" @@ -976,7 +977,7 @@ int MenuSettings() w.Remove(&optionBrowser2); w.Remove(&backBtn); char entered[20] = ""; - int result = OnScreenKeyboard(entered, 20,0); + int result = OnScreenKeyboard(entered, 20,0); w.Append(&optionBrowser2); w.Append(&backBtn); if ( result == 1 ) { @@ -1278,7 +1279,8 @@ int MenuSettings() w.Remove(&backBtn); char entered[43] = ""; strncpy(entered, Settings.covers_path, sizeof(entered)); - int result = OnScreenKeyboard(entered,43,0); + int result = BrowseDevice(entered); + //int result = OnScreenKeyboard(entered,43,0); w.Append(&optionBrowser2); w.Append(&backBtn); if ( result == 1 ) @@ -1304,7 +1306,8 @@ int MenuSettings() w.Remove(&backBtn); char entered[43] = ""; strncpy(entered, Settings.disc_path, sizeof(entered)); - int result = OnScreenKeyboard(entered, 43,0); + int result = BrowseDevice(entered); + //int result = OnScreenKeyboard(entered, 43,0); w.Append(&optionBrowser2); w.Append(&backBtn); if ( result == 1 ) @@ -1330,7 +1333,8 @@ int MenuSettings() w.Remove(&backBtn); char entered[43] = ""; strncpy(entered, CFG.theme_path, sizeof(entered)); - int result = OnScreenKeyboard(entered, 43,0); + int result = BrowseDevice(entered); + //int result = OnScreenKeyboard(entered, 43,0); HaltGui(); w.RemoveAll(); if ( result == 1 ) @@ -1387,7 +1391,8 @@ int MenuSettings() w.Remove(&backBtn); char entered[43] = ""; strncpy(entered, Settings.titlestxt_path, sizeof(entered)); - int result = OnScreenKeyboard(entered,43,0); + int result = BrowseDevice(entered); + //int result = OnScreenKeyboard(entered,43,0); w.Append(&optionBrowser2); w.Append(&backBtn); if ( result == 1 ) @@ -1418,7 +1423,8 @@ int MenuSettings() w.Remove(&backBtn); char entered[43] = ""; strncpy(entered, Settings.update_path, sizeof(entered)); - int result = OnScreenKeyboard(entered,43,0); + int result = BrowseDevice(entered); + //int result = OnScreenKeyboard(entered,43,0); w.Append(&optionBrowser2); w.Append(&backBtn); if ( result == 1 ) @@ -1440,7 +1446,8 @@ int MenuSettings() w.Remove(&backBtn); char entered[43] = ""; strncpy(entered, Settings.Cheatcodespath, sizeof(entered)); - int result = OnScreenKeyboard(entered,43,0); + int result = BrowseDevice(entered); + //int result = OnScreenKeyboard(entered,43,0); w.Append(&optionBrowser2); w.Append(&backBtn); if ( result == 1 ) @@ -1462,7 +1469,8 @@ int MenuSettings() w.Remove(&backBtn); char entered[43] = ""; strncpy(entered, Settings.TxtCheatcodespath, sizeof(entered)); - int result = OnScreenKeyboard(entered,43,0); + int result = BrowseDevice(entered); + //int result = OnScreenKeyboard(entered,43,0); w.Append(&optionBrowser2); w.Append(&backBtn); if ( result == 1 ) @@ -1484,7 +1492,8 @@ int MenuSettings() w.Remove(&backBtn); char entered[43] = ""; strncpy(entered, Settings.dolpath, sizeof(entered)); - int result = OnScreenKeyboard(entered,43,0); + int result = BrowseDevice(entered); + //int result = OnScreenKeyboard(entered,43,0); w.Append(&optionBrowser2); w.Append(&backBtn); if ( result == 1 ) @@ -1510,7 +1519,8 @@ int MenuSettings() w.Remove(&backBtn); char entered[43] = ""; strncpy(entered, Settings.homebrewapps_path, sizeof(entered)); - int result = OnScreenKeyboard(entered,43,0); + int result = BrowseDevice(entered); + //int result = OnScreenKeyboard(entered,43,0); w.Append(&optionBrowser2); w.Append(&backBtn); if ( result == 1 ) diff --git a/source/testfilebrowser.cpp b/source/testfilebrowser.cpp deleted file mode 100644 index 391c1ccd..00000000 --- a/source/testfilebrowser.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include -#include - -#include "language/gettext.h" -#include "prompts/PromptWindows.h" -#include "libwiigui/gui.h" -#include "filebrowser.h" -#include "menu.h" -#include "sys.h" - -/*** Extern variables ***/ -extern GuiWindow * mainWindow; -extern u8 shutdown; -extern u8 reset; - -/*** Extern functions ***/ -extern void ResumeGui(); -extern void HaltGui(); - -/**************************************************************************** - * MenuBrowseDevice - ***************************************************************************/ -int MenuBrowseDevice() -{ - int i; - char currentdir[50]; - - // populate initial directory listing - if(BrowseDevice(SD) <= 0) - { - int choice = WindowPrompt("Error", - "Unable to load device.", - "Retry", - "Change Settings"); - - if(choice) { - return MENU_DISCLIST; - } - } - - int menu = MENU_NONE; - - GuiText titleTxt("Browse Files", 28, (GXColor){0, 0, 0, 230}); - titleTxt.SetAlignment(ALIGN_LEFT, ALIGN_TOP); - titleTxt.SetPosition(70,20); - - GuiTrigger trigA; - trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A); - GuiTrigger trigPlus; - trigPlus.SetButtonOnlyTrigger(-1, WPAD_BUTTON_PLUS | WPAD_CLASSIC_BUTTON_PLUS, 0); - GuiTrigger trigMinus; - trigMinus.SetButtonOnlyTrigger(-1, WPAD_BUTTON_MINUS | WPAD_CLASSIC_BUTTON_MINUS, 0); - - GuiFileBrowser fileBrowser(552, 248); - fileBrowser.SetAlignment(ALIGN_CENTRE, ALIGN_TOP); - fileBrowser.SetPosition(0, 100); - - GuiImageData btnOutline(button_dialogue_box_png); - GuiText ExitBtnTxt("Exit", 24, (GXColor){0, 0, 0, 255}); - GuiImage ExitBtnImg(&btnOutline); - GuiButton ExitBtn(btnOutline.GetWidth(), btnOutline.GetHeight()); - ExitBtn.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM); - ExitBtn.SetPosition(100, -35); - ExitBtn.SetLabel(&ExitBtnTxt); - ExitBtn.SetImage(&ExitBtnImg); - ExitBtn.SetTrigger(&trigA); - ExitBtn.SetEffectGrow(); - - GuiImageData Address(addressbar_textbox_png); - snprintf(currentdir, sizeof(currentdir), "%s%s", browser.rootdir, browser.dir); - GuiText AdressText(currentdir, 20, (GXColor) {0, 0, 0, 255}); - AdressText.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE); - AdressText.SetPosition(20, 0); - AdressText.SetMaxWidth(Address.GetWidth()-40, GuiText::SCROLL); - GuiImage AdressbarImg(&Address); - GuiButton Adressbar(Address.GetWidth(), Address.GetHeight()); - Adressbar.SetAlignment(ALIGN_LEFT, ALIGN_TOP); - Adressbar.SetPosition(60, fileBrowser.GetTop()-45); - Adressbar.SetImage(&AdressbarImg); - Adressbar.SetLabel(&AdressText); - - HaltGui(); - GuiWindow w(screenwidth, screenheight); - w.Append(&ExitBtn); - w.Append(&titleTxt); - w.Append(&fileBrowser); - w.Append(&Adressbar); - mainWindow->Append(&w); - ResumeGui(); - - while(menu == MENU_NONE) - { - VIDEO_WaitVSync(); - - if(shutdown == 1) - Sys_Shutdown(); - - if(reset == 1) - Sys_Reboot(); - - for(i=0; iGetState() == STATE_CLICKED) - { - fileBrowser.fileList[i]->ResetState(); - // check corresponding browser entry - if(browserList[browser.selIndex].isdir) - { - if(BrowserChangeFolder()) - { - fileBrowser.ResetState(); - fileBrowser.fileList[0]->SetState(STATE_SELECTED); - fileBrowser.TriggerUpdate(); - AdressText.SetTextf("%s%s", browser.rootdir, browser.dir); - } else { - menu = MENU_DISCLIST; - break; - } - } else { - mainWindow->SetState(STATE_DISABLED); - mainWindow->SetState(STATE_DEFAULT); - } - } - } - - if(ExitBtn.GetState() == STATE_CLICKED) - menu = MENU_DISCLIST; - } - HaltGui(); - mainWindow->Remove(&w); - ResumeGui(); - - return menu; -} diff --git a/source/wad/title.c b/source/wad/title.c index 0d05bd92..a2c10e99 100644 --- a/source/wad/title.c +++ b/source/wad/title.c @@ -2,9 +2,14 @@ #include #include #include +#include #include #include "utils.h" +#include "../settings/cfg.h" +#include "fatmounter.h" + +#define MAX_TITLES 256 s32 Title_GetList(u64 **outbuf, u32 *outlen) @@ -254,3 +259,458 @@ out: return ret; } + + +/*------------------------------------------------------------- + taken from anytitledeleter + name.c -- functions for determining the name of a title + + Copyright (C) 2009 MrClick + +-------------------------------------------------------------*/ +// Max number of entries in the database +#define MAX_DB 1024 + +// Max name length +#define MAX_LINE 80 + +// Contains all title ids (e.g.: "HAC") +static char **__db_i; +// Contains all title names (e.g.: "Mii Channel") +static char **__db; +// Contains the number of entries in the database +static u32 __db_cnt = 0; + +s32 loadDatabase(){ + FILE *fdb; + + char dbfile[100]; + snprintf(dbfile,sizeof(dbfile),"SD:/database.txt"); + // Init SD card access, open database file and check if it worked + //fatInitDefault(); + SDCard_Init(); + fdb = fopen(dbfile, "r"); + if (fdb == NULL) + return -1; + + // Allocate memory for the database + __db_i = calloc(MAX_DB, sizeof(char*)); + __db = calloc(MAX_DB, sizeof(char*)); + + // Define the line buffer. Each line in the db file will be stored here first + char line[MAX_LINE]; + line[sizeof(line)] = 0; + + // Generic char buffer and counter variable + char byte; + u32 i = 0; + + // Read each character from the file + do { + byte = fgetc(fdb); + // In case a line was longer than MAX_LINE + if (i == -1){ + // Read bytes till a new line is hit + if (byte == 0x0A) + i = 0; + // In case were still good with the line length + } else { + // Add the new byte to the line buffer + line[i] = byte; + i++; + // When a new line is hit or MAX_LINE is reached + if (byte == 0x0A || i == sizeof(line) - 1) { + // Terminate finished line to create a string + line[i] = 0; + // When the line is not a comment or not to short + if (line[0] != '#' && i > 5){ + + // Allocate and copy title id to database + __db_i[__db_cnt] = calloc(4, sizeof(char*)); + memcpy(__db_i[__db_cnt], line, 3); + __db_i[__db_cnt][3] = 0; + // Allocate and copy title name to database + __db[__db_cnt] = calloc(i - 4, sizeof(char*)); + memcpy(__db[__db_cnt], line + 4, i - 4); + __db[__db_cnt][i - 5] = 0; + + // Check that the next line does not overflow the database + __db_cnt++; + if (__db_cnt == MAX_DB) + break; + } + // Set routine to ignore all bytes in the line when MAX_LINE is reached + if (byte == 0x0A) i = 0; else i = -1; + } + } + } while (!feof(fdb)); + + // Close database file; we are done with it + fclose(fdb); + + return 0; +} + + +void freeDatabase(){ + u32 i = 0; + for(; i < __db_cnt; i++){ + free(__db_i[i]); + free(__db[i]); + } + free(__db_i); + free(__db); +} + + +s32 getDatabaseCount(){ + return __db_cnt; +} + +s32 __convertWiiString(char *str, u8 *data, u32 cnt){ + u32 i = 0; + for(; i < cnt; data += 2){ + u16 *chr = (u16*)data; + if (*chr == 0) + break; + // ignores all but ASCII characters + else if (*chr >= 0x20 && *chr <= 0x7E) + str[i] = *chr; + else + str[i] = '.'; + i++; + } + str[i] = 0; + + return 0; +} + +s32 getNameDB(char* name, char* id){ + // Return fixed values for special entries + if (strncmp(id, "IOS", 3) == 0){ + sprintf(name, "Operating System %s", id); + return 0; + } + if (strncmp(id, "MIOS", 3) == 0){ + sprintf(name, "Gamecube Compatibility Layer"); + return 0; + } + if (strncmp(id, "SYSMENU", 3) == 0){ + sprintf(name, "System Menu"); + return 0; + } + if (strncmp(id, "BC", 2) == 0){ + sprintf(name, "BC"); + return 0; + } + + // Create an ? just in case the function aborts prematurely + sprintf(name, "?"); + + u32 i; + u8 db_found = 0; + // Compare each id in the database to the title id + for (i = 0; i < __db_cnt; i++) + if (strncmp(id, __db_i[i], 3) == 0){ + db_found = 1; + break; + } + + if (db_found == 0) + // Return -1 if no mathcing entry was found + return -1; + else { + // Get name from database once a matching id was found + sprintf(name, __db[i]); + return 0; + } +} + + +s32 getNameBN(char* name, u64 id){ + // Terminate the name string just in case the function exits prematurely + name[0] = 0; + + // Create a string containing the absolute filename + char file[256] __attribute__ ((aligned (32))); + sprintf(file, "/title/%08x/%08x/data/banner.bin", (u32)(id >> 32), (u32)id); + + // Bring the Wii into the title's userspace + if (ES_SetUID(id) < 0){ + // Should that fail repeat after setting permissions to system menu mode +// Identify_SysMenu(); +// if (ES_SetUID(id) < 0) +// return -1; + } + + // Try to open file + s32 fh = ISFS_Open(file, ISFS_OPEN_READ); + + // If a title does not have a banner.bin bail out + if (fh == -106) + return -2; + + // If it fails try to open again after identifying as SU + if (fh == -102){ +// Identify_SU(); +// fh = ISFS_Open(file, ISFS_OPEN_READ); + } + // If the file won't open + else if (fh < 0) + return fh; + + // Seek to 0x20 where the name is stored + ISFS_Seek(fh, 0x20, 0); + + // Read a chunk of 256 bytes from the banner.bin + u8 *data = memalign(32, 0x100); + if (ISFS_Read(fh, data, 0x100) < 0){ + ISFS_Close(fh); + free(data); + return -3; + } + + + // Prepare the strings that will contain the name of the title + char name1[0x41] __attribute__ ((aligned (32))); + char name2[0x41] __attribute__ ((aligned (32))); + name1[0x40] = 0; + name2[0x40] = 0; + + __convertWiiString(name1, data + 0x00, 0x40); + __convertWiiString(name2, data + 0x40, 0x40); + free(data); + + // Assemble name + sprintf(name, "%s", name1); + if (strlen(name2) > 1) + sprintf(name, "%s (%s)", name, name2); + + // Close the banner.bin + ISFS_Close(fh); + + // Job well done + return 1; +} + + +s32 getName00(char* name, u64 id){ + // Create a string containing the absolute filename + char file[256] __attribute__ ((aligned (32))); + sprintf(file, "/title/%08x/%08x/content/00000000.app", (u32)(id >> 32), (u32)id); + + s32 fh = ISFS_Open(file, ISFS_OPEN_READ); + + + + // If the title does not have 00000000.app bail out + if (fh == -106) + return fh; + + // In case there is some problem with the permission + if (fh == -102){ + // Identify as super user +// Identify_SU(); +// fh = ISFS_Open(file, ISFS_OPEN_READ); + } + else if (fh < 0) + return fh; + + // Jump to start of the name entries + ISFS_Seek(fh, 0x9C, 0); + + // Read a chunk of 0x22 * 0x2B bytes from 00000000.app + u8 *data = memalign(32, 2048); + s32 r = ISFS_Read(fh, data, 0x22 * 0x2B); + //printf("%s %d\n", file, r);wait_anyKey(); + if (r < 0){ + ISFS_Close(fh); + free(data); + return -4; + } + + // Take the entries apart + char str[0x22][0x2B]; + u8 i = 0; + // Convert the entries to ASCII strings + for(; i < 0x22; i++) + __convertWiiString(str[i], data + (i * 0x2A), 0x2A); + + // Clean up + ISFS_Close(fh); + free(data); + + // Assemble name + // Only the English name is returned + // There are 6 other language names in the str array + sprintf(name, "%s", str[2]); + if (strlen(str[3]) > 1) + sprintf(name, "%s (%s)", name, str[3]); + + // Job well done + return 2; +} + + +s32 printContent(u64 tid){ + char dir[256] __attribute__ ((aligned (32))); + sprintf(dir, "/title/%08x/%08x/content", (u32)(tid >> 32), (u32)tid); + + u32 num = 64; + + static char list[8000] __attribute__((aligned(32))); + + ISFS_ReadDir(dir, list, &num); + + char *ptr = list; + u8 br = 0; + for (; strlen(ptr) > 0; ptr += strlen(ptr) + 1){ + printf(" %-12.12s", ptr); + br++; if (br == 4) { br = 0; printf("\n"); } + } + if (br != 0) + printf("\n"); + + return num; +} + + +s32 getTitle_Name(char* name, u64 id, char *tid){ + char buf[256] __attribute__ ((aligned (32))); + + s32 r = -1; + // Determine the title's name database/banner/00000000.app + r = getNameDB(buf, tid); + if (r < 0) + r = getNameBN(buf, id); + if (r < 0) + r = getName00(buf, id); + + switch (r){ + // In case a name was found in the database + case 0: sprintf(name, "%s", buf); + break; + // In case a name was found in the banner.bin + case 1: sprintf(name, "*%s*", buf); + break; + // In case a name was found in the 00000000.app + case 2: sprintf(name, "+%s+", buf); + break; + // In case no proper name was found return a ? + default: sprintf(name, "Unknown Title"); + break; + } + + return 0; +} + +char *titleText(u32 kind, u32 title){ + static char text[10]; + + if (kind == 1){ + // If we're dealing with System Titles, use custom names + switch (title){ + case 1: + strcpy(text, "BOOT2"); + break; + case 2: + strcpy(text, "SYSMENU"); + break; + case 0x100: + strcpy(text, "BC"); + break; + case 0x101: + strcpy(text, "MIOS"); + break; + default: + sprintf(text, "IOS%u", title); + break; + } + } else { + // Otherwise, just convert the title to ASCII + int i =32, j = 0; + do { + u8 temp; + i -= 8; + temp = (title >> i) & 0x000000FF; + if (temp < 32 || temp > 126) + text[j] = '.'; + else + text[j] = temp; + j++; + } while (i > 0); + text[4] = 0; + } + return text; +} + + +/*------------------------------------------------------------- + from any title deleter +titles.c -- functions for grabbing all titles of a certain type + +Copyright (C) 2008 tona +-------------------------------------------------------------*/ + +u32 __titles_init = 0; +u32 __num_titles; +static u64 __title_list[MAX_TITLES] ATTRIBUTE_ALIGN(32); + +s32 __getTitles() { + s32 ret; + ret = ES_GetNumTitles(&__num_titles); + if (ret <0) + return ret; + if (__num_titles > MAX_TITLES) + return -1; + ret = ES_GetTitles(__title_list, __num_titles); + if (ret <0) + return ret; + __titles_init = 1; + return 0; +} + +s32 getTitles_TypeCount(u32 type, u32 *count) { + s32 ret = 0; + u32 type_count; + if (!__titles_init) + ret = __getTitles(); + if (ret <0) + return ret; + int i; + type_count = 0; + for (i=0; i < __num_titles; i++) { + u32 upper; + upper = __title_list[i] >> 32; + if(upper == type) + type_count++; + } + *count = type_count; + return ret; +} + +s32 getTitles_Type(u32 type, u32 *titles, u32 count) { + s32 ret = 0; + u32 type_count; + if (!__titles_init) + ret = __getTitles(); + if (ret <0) + return ret; + int i; + type_count = 0; + for (i=0; type_count < count && i < __num_titles; i++) { + u32 upper, lower; + upper = __title_list[i] >> 32; + lower = __title_list[i] & 0xFFFFFFFF; + if(upper == type) { + titles[type_count]=lower; + type_count++; + } + } + if (type_count < count) + return -2; + __titles_init = 0; + return 0; +} + + diff --git a/source/wad/title.h b/source/wad/title.h index 619156ac..03a68af2 100644 --- a/source/wad/title.h +++ b/source/wad/title.h @@ -1,3 +1,25 @@ +/*------------------------------------------------------------- + from any title deleter and wad manager 1.4 +title.h -- + +Copyright (C) 2008 tona and/or waninkoko +-------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include + +// Turn upper and lower into a full title ID +#define TITLE_ID(x,y) (((u64)(x) << 32) | (y)) +// Get upper or lower half of a title ID +#define TITLE_UPPER(x) ((u32)((x) >> 32)) +// Turn upper and lower into a full title ID +#define TITLE_LOWER(x) ((u32)(x)) + +#define MAX_TITLES 100 + #ifndef _TITLE_H_ #define _TITLE_H_ @@ -16,6 +38,39 @@ s32 Title_GetVersion(u64, u16 *); s32 Title_GetSysVersion(u64, u64 *); s32 Title_GetSize(u64, u32 *); s32 Title_GetIOSVersions(u8 **, u32 *); + +// Load the database from SD card +s32 loadDatabase(); + +// Free the database on exit +void freeDatabase(); + +// Get the number of entries in the database +s32 getDatabaseCount(); + +// Get the name of a title +s32 getTitle_Name(char *name, u64 id, char *tid); + +// Get the name of a title from the database located on the SD card +s32 getNameDB(char *name, char* id); + +// Get the name of a title from its banner.bin in NAND +s32 getNameBN(char *name, u64 id); + +// Get the name of a title from its 00000000.app in NAND +s32 getName00(char *name, u64 id); + +// Get string representation of lower title id +char *titleText(u32 kind, u32 title); + +// Converts a 16 bit Wii string to a printable 8 bit string +s32 __convertWiiString(char *str, u8 *data, u32 cnt); + +// Get the number of titles on the Wii of a given type +s32 getTitles_TypeCount(u32 type, u32 *count); + +// Get the list of titles of this type +s32 getTitles_Type(u32 type, u32 *titles, u32 count); #ifdef __cplusplus }