diff --git a/mymenu.py b/mymenu.py new file mode 100644 index 0000000..177346c --- /dev/null +++ b/mymenu.py @@ -0,0 +1,190 @@ +import os, sys, ConfigParser, zipfile +import wx +import Wii + +queue = [] + +global logdata +logdata = '' +def log(text): + global logdata + #logdata.append(text + '\n') + logdata = logdata + text + 'n' +def debug(text): + log("[DEBUG] " + text) +def error(text): + log("[ERROR] " + text) + wx.MessageBox(text, 'Error', wx.OK | wx.ICON_ERROR) + +class MyMenu(wx.App): + def OnInit(self): + self.completed = 0 + self.selected = -1 + frame = wx.Frame(None, -1, "MyMenu 1.5", (300, 200), (400, 250)) + panel = wx.Panel(frame) + panel.Show(True) + + wx.StaticText(panel, -1, "MyMenu (c) 2009 Xuzz. Powered by the Wii.py framework.", (15, 230)) + + wx.StaticText(panel, -1, "Source:", (5, 10), (60, 27)) + self.src = wx.TextCtrl(panel, -1, "", (65, 5), (245, 30)) + browsebtn = wx.Button(panel, -1, "Browse", (315, 5), (80, 30)) + self.Bind(wx.EVT_BUTTON, self.browse, browsebtn) + + addbtn = wx.Button(panel, -1, "Add", (315, 45), (80, 30)) + self.Bind(wx.EVT_BUTTON, self.add, addbtn) + rmbtn = wx.Button(panel, -1, "Remove", (315, 80), (80, 30)) + self.Bind(wx.EVT_BUTTON, self.remove, rmbtn) + + upbtn = wx.Button(panel, -1, "Up", (315, 115), (80, 30)) + self.Bind(wx.EVT_BUTTON, self.up, upbtn) + downbtn = wx.Button(panel, -1, "Down", (315, 150), (80, 30)) + self.Bind(wx.EVT_BUTTON, self.down, downbtn) + + self.list = wx.ListCtrl(panel, -1, (5, 45), (300, 140), wx.LC_REPORT | wx.SUNKEN_BORDER) + self.list.Show(True) + self.list.InsertColumn(0, "MyMenu Scripts", 0, 290) + + gobtn = wx.Button(panel, -1, "Create CSM", (5, 200), (90, 30)) + self.Bind(wx.EVT_BUTTON, self.go, gobtn) + self.progress = wx.Gauge(panel, -1, 100, (100, 200), (295, 30)) + self.progress.SetValue(0) + + frame.Show(True) + + log("GUI Started...") + + return True + def progress(self, val): + self.progress.SetValue(self.completed * 100 + val + 50) + def doMyMenu(self, arc, mym): + self.progress(0) + try: + debug("Opening zip file %s..." % mym) + myZip = zipfile.ZipFile(mym, 'r') + debug("Loading INI...") + myScript = ConfigParser.ConfigParser() + myScript.readfp(myZip.open("mym.ini")) + except: + error("Invalid MyScript, skipping...") + debug("Loaded successfully.") + self.progress(10) + sections = myScript.sections() + + def go(self, evt): + self.progress.SetRange(len(queue) * 100 + 50) + src = self.src.GetText() + try: + arc = Wii.U8.load(Wii.WAD.loadFile(src)[0]) + except: + try: + arc = Wii.U8.loadFile(src) + except: + error("File selected is not a WAD or a U8 file.") + return + try: #basic sanity checking + assert arc['layout'] == None + assert arc['layout/common'] == None + except: + error("Invalid source selected!") + return + + self.progress(0) + + for elem in queue: + arc = self.doMyMenu(arc, elem) + self.completed += 1 + + dlg = wx.FileDialog(None, "Save Completed File...", "", "", "Custom System Menu Files (*.csm)|*.csm|All Files (*.*)|*.*", wx.SAVE) + if dlg.ShowModal() == wx.ID_OK: + dst = dlg.GetPath() + if(dst.find('.') == -1): + dst = dst + '.csm' + arc.dumpFile(dst) + dlg.Destroy() + def add(self, evt): + dlg = wx.FileDialog(None, "Browse for Source...", "", "", "MyMenu Scripts (*.mym)|*.mym|All Files (*.*)|*.*", wx.OPEN) + if dlg.ShowModal() == wx.ID_OK: + queue.append(dlg.GetPath()) + log("Added " + dlg.GetPath() + " to queue.") + self.setList() + self.list.Select(len(queue) - 1) + dlg.Destroy() + def getSelected(self): + i = self.list.GetFirstSelected() + self.selected = i + return i + def setList(self): + self.list.DeleteAllItems() + for elem in queue: + self.list.InsertStringItem(0, elem) + def remove(self, evt): + if(self.getSelected() == -1): + return + log("Removing " + queue[self.selected] + " from queue.") + queue.pop(self.selected) + self.setList() + self.list.Select(min(len(queue) - 1, self.selected)) + def browse(self, evt): + dlg = wx.FileDialog(None, "Browse for Source...", "", "", "Theme Bases (*.csm)|*.csm|Theme Bases (*.app)|*.app|Wii WAD files (*.wad)|*.wad|All Files (*.*)|*.*", wx.OPEN) + if dlg.ShowModal() == wx.ID_OK: + self.src.SetValue(dlg.GetPath()) + log("Source selected: " + dlg.GetPath()) + dlg.Destroy() + def up(self, evt): + global queue + if(self.getSelected() == -1): + return + if(self.selected == 0): + return + tmp1 = queue[self.selected - 1] + tmp2 = queue[self.selected] + queue[self.selected - 1] = tmp2 + queue[self.selected] = tmp1 + self.setList() + self.list.Select(self.selected - 1) + self.getSelected() + def down(self, evt): + global queue + if(self.getSelected() == -1): + return + if(self.selected == len(queue) - 1): + return + tmp1 = queue[self.selected + 1] + tmp2 = queue[self.selected] + queue[self.selected + 1] = tmp2 + queue[self.selected] = tmp1 + self.setList() + self.list.Select(self.selected + 1) + self.getSelected() + +mymenu = MyMenu() +mymenu.MainLoop() + +""" + cont = {} + numcont = 0 + numelse = 0 + for sec in sections: + if(sec[:4] == 'cont'): + numcont += 1 + for sec in sections: + if(sec[:4] == 'sdta' or sec[:4] == 'simg' or sec[:4] == 'cdta' or sec[:4] == 'cimg'): + numelse += 1 + thiscont = 0 + for i, sec in enumerate(sections): + if(sec[:4] == 'cont'): + self.progress(10 + (20 / (numcont / thiscont)) + thiscont += 1 + + + self.progress(30) + for i, sec in enumerate(sections): + if(sec[:4] == 'sdta'): + + elif(sec[:4] == 'simg'): + + elif(sec[:4] == 'cdta'): + + elif(sec[:4] == 'cimg'): +""" diff --git a/nus_downloader.py b/nus_downloader.py new file mode 100644 index 0000000..f07f45d --- /dev/null +++ b/nus_downloader.py @@ -0,0 +1,397 @@ +#---------------------------------------------------------------------- +# NUS WAD Packer 1.0.1 - a (sorta) simple GUI for NUS downloading. +# (c) 2009 Xuzz (icefire) and Xuzz Productions. +# +# Wii.py (c) Xuzz, SquidMan, megazig, TheLemonMan, Omega|, and Matt_P. +#---------------------------------------------------------------------- + +import os, wx, shutil, sys, threading +import Wii + +def readableTitleID(lower): + out = struct.unpack("4s", struct.pack(">I", lower)) + return out[0] + +def getName(titleid): + upper = (titleid >> 32) + lower = (titleid & 0xFFFFFFFF) + if(upper == 0x00000001): + if(lower > 0x02 and lower < 0x100): + return "IOS%d" % lower + elif(lower == 0x02): + return "SystemMenu" + elif(lower == 0x100): + return "BC" + elif(lower == 0x101): + return "MIOS" + else: + return "Unknown System Title (%08x)" % lower + elif(upper == 0x00010002 or upper == 0x00010008): + read = readableTitleID(lower) + + if(read[3] == "K"): + rgn = "Korea" + elif(read[3] == "A"): + rgn = "All Regions" + elif(read[3] == "P"): + rgn = "Europe/PAL" + elif(read[3] == "E"): + rgn = "North America" + elif(read[3] == "J"): + rgn = "Japan" + else: + rgn = "Unknown Region" + + if(read[:3] == "HAB"): + return "Wii Shop Channel (%s)" % rgn + if(read[:3] == "HAL"): + return "EULA (%s)" % rgn + if(read[:3] == "HAA"): + return "Photo Channel (%s)" % rgn + if(read[:3] == "HAC"): + return "Mii Channel (%s)" % rgn + if(read[:3] == "HAE"): + return "Wii Message Board (%s)" % rgn + if(read[:3] == "HAF"): + return "Weather Channel (%s)" % rgn + if(read[:3] == "HAG"): + return "News Channel (%s)" % rgn + if(read[:3] == "HAK"): + return "Region Select (%s)" % rgn + if(read[:3] == "HAY"): + return "Photo Channel 1.1 (%s)" % rgn + + + if(upper == 0x00010002): + return "Channel '%s'" % read + if(upper == 0x00010008): + return "Hidden Channel '%s'" % read + else: + return "Other (%08x-%08x)" % (upper, lower) + +queue = [] + +class Downloader(wx.App): + def OnInit(self): + self.selected = -1 + frame = wx.Frame(None, -1, "NUS WAD Packer", (150, 150), (600, 650))#, wx.SYSTEM_MENU | wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.CLOSE_BOX) + panel = wx.Panel(frame) + panel.Show(True) + + wx.StaticText(panel, -1, "NUS WAD Packer (c) 2009 Xuzz. Powered by the Wii.py framework.", (5, 5)) + + wx.StaticText(panel, -1, "Title ID:", (5, 35)) + self.titleid = wx.TextCtrl(panel, -1, "", (60, 30), (150, -1)) + wx.StaticText(panel, -1, "Version:", (216, 35)) + self.version = wx.TextCtrl(panel, -1, "", (270, 30), (50, -1)) + + wx.StaticText(panel, -1, "Output:", (5, 70)) + self.out = wx.TextCtrl(panel, -1, "", (60, 65), (150, -1)) + browsebtn = wx.Button(panel, -1, "Browse", (216, 65), (105, 27)) + self.Bind(wx.EVT_BUTTON, self.browse, browsebtn) + + wx.StaticText(panel, -1, "Output Format:", (330, 35)) + selectbox = ['WAD', 'Enc Contents', 'Dec Contents'] + self.outputtype = wx.ComboBox(panel, -1, "", (330, 65), (125, 27), choices = selectbox, style = wx.CB_READONLY) + self.outputtype.SetStringSelection(selectbox[0]) + + wx.StaticBox(panel, -1, "Scripting", (460, 5), (130, 86)) + loadbtn = wx.Button(panel, -1, "Load Script", (470, 25), (110, 25)) + self.Bind(wx.EVT_BUTTON, self.load, loadbtn) + savescriptbtn = wx.Button(panel, -1, "Save Script", (470, 55), (110, 25)) + self.Bind(wx.EVT_BUTTON, self.savescript, savescriptbtn) + + addbtn = wx.Button(panel, -1, "Add", (5, 100), (75, -1)) + self.Bind(wx.EVT_BUTTON, self.add, addbtn) + savebtn = wx.Button(panel, -1, "Save", (250, 100), (75, -1)) + self.Bind(wx.EVT_BUTTON, self.save, savebtn) + + rmbtn = wx.Button(panel, -1, "Remove", (85, 100), (75, -1)) + self.Bind(wx.EVT_BUTTON, self.remove, rmbtn) + + upbtn = wx.Button(panel, -1, "Up", (440, 100), (75, -1)) + self.Bind(wx.EVT_BUTTON, self.up, upbtn) + downbtn = wx.Button(panel, -1, "Down", (520, 100), (75, -1)) + self.Bind(wx.EVT_BUTTON, self.down, downbtn) + + + self.list = wx.ListCtrl(panel, -1, (5, 140), (590, 250), wx.LC_REPORT | wx.SUNKEN_BORDER) + self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.select, self.list) + self.list.Show(True) + self.list.InsertColumn(0, "Title ID") + self.list.InsertColumn(1, "Version") + self.list.InsertColumn(2, "Output") + self.list.InsertColumn(3, "Format") + + + wx.StaticText(panel, -1, "Message Log:", (5, 400)) + self.output = wx.TextCtrl(panel, -1, "", (5, 420), (590, 170), wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_DONTWRAP) + font = wx.Font(8, wx.MODERN, wx.NORMAL, wx.NORMAL) + self.output.SetFont(font) + self.output.AppendText("NUS WAD Packer started and ready...\n\n") + + + downloadbtn = wx.Button(panel, -1, "Download", (5, 600), (120, -1)) + self.Bind(wx.EVT_BUTTON, self.go, downloadbtn) + self.progress = wx.Gauge(panel, -1, 100, (135, 605), (460, -1)) + self.progress.SetValue(0) + + frame.Show(True) + + return True + def getSelected(self): + i = self.list.GetFirstSelected() + self.selected = i + return i + def select(self, evt): + if(self.getSelected() == -1): + return + item = queue[self.selected] + self.titleid.SetValue(item[0]) + self.version.SetValue(item[1]) + self.out.SetValue(item[2]) + self.outputtype.SetValue(item[3]) + def setList(self): + self.list.DeleteAllItems() + for i, elem in enumerate(queue): + self.list.InsertStringItem(i, elem[0]) + self.list.SetStringItem(i, 1, elem[1]) + self.list.SetStringItem(i, 2, elem[2]) + self.list.SetStringItem(i, 3, elem[3]) + def add(self, evt): + titleid = self.titleid.GetValue() + if(len(titleid) != 16 and not titleid.isdigit()): + self.dialog("Title ID must be 16 numbers long! No dashes.") + return + ver = self.version.GetValue() + if(not ver.isdigit() and ver != ""): + self.dialog("Version must be all numbers!") + return + out = self.out.GetValue() + fmt = self.outputtype.GetValue() + if(not os.path.isdir(os.path.dirname(out)) and fmt == "WAD"): + out = os.path.expanduser("~/" + getName(int(titleid, 16))) + if(ver != ""): + out += "v" + str(ver) + out += ".wad" + elif(not os.path.isdir(os.path.dirname(out))): + out = os.path.expanduser("~/" + getName(int(titleid, 16))) + if(ver != ""): + out += "v" + str(ver) + queue.append((titleid, ver, out, fmt)) + self.setList() + self.list.Select(len(queue) - 1) + def dialog(self, message): + wx.MessageBox(message, "Error") + def save(self, evt): + if(self.getSelected() == -1): + return + titleid = self.titleid.GetValue() + if(len(titleid) != 16 and titleid.isdigit()): + self.dialog("Title ID must be 16 numbers long! No dashes.") + return + ver = self.version.GetValue() + if(ver.isdigit()): + self.dialog("Version must be all numbers!") + return + out = self.out.GetValue() + fmt = self.outputtype.GetValue() + if(not os.path.isdir(os.path.dirname(out)) and fmt == "WAD"): + out = os.path.expanduser("~/" + getName(int(titleid, 16))) + if(ver != ""): + out += "v" + str(ver) + out += ".wad" + elif(not os.path.isdir(os.path.dirname(out))): + out = os.path.expanduser("~/" + getName(int(titleid, 16))) + if(ver != ""): + out += + "v" + str(ver) + queue[self.selected] = (titleid, ver, out, fmt) + self.setList() + self.list.Select(self.selected) + def remove(self, evt): + if(self.getSelected() == -1): + return + queue.pop(self.selected) + self.setList() + self.list.Select(min(len(queue) - 1, self.selected)) + def browse(self, evt): + if(self.outputtype.GetValue() == "WAD"): + dlg = wx.FileDialog(None, "Browse For Destination...", "", "", "Wii WAD files (*.wad)|*.wad|All Files (*.*)|*.*", wx.SAVE) + if dlg.ShowModal() == wx.ID_OK: + self.out.SetValue(dlg.GetPath()) + dlg.Destroy() + else: + dlg = wx.DirDialog(None, "Browse For Destination...", "") + if dlg.ShowModal() == wx.ID_OK: + self.out.SetValue(dlg.GetPath()) + dlg.Destroy() + def up(self, evt): + global queue + if(self.getSelected() == -1): + return + if(self.selected == 0): + return + tmp1 = queue[self.selected - 1] + tmp2 = queue[self.selected] + queue[self.selected - 1] = tmp2 + queue[self.selected] = tmp1 + self.setList() + self.list.Select(self.selected - 1) + self.getSelected() + def down(self, evt): + global queue + if(self.getSelected() == -1): + return + if(self.selected == len(queue) - 1): + return + tmp1 = queue[self.selected + 1] + tmp2 = queue[self.selected] + queue[self.selected + 1] = tmp2 + queue[self.selected] = tmp1 + self.setList() + self.list.Select(self.selected + 1) + self.getSelected() + def load(self, evt): + dlg = wx.FileDialog(None, "Open Script...", "", "", "Wii NUS Packer/Wiiimposter scripts (*.nus)|*.nus|All Files (*.*)|*.*", wx.OPEN) + if(dlg.ShowModal() == wx.ID_OK): + script = dlg.GetPath() + else: + dlg.Destroy() + return + dlg.Destroy() + stuff = open(script).read().split() + for i, arg in enumerate(stuff): + if(len(arg) == 16 and len(stuff) != i + 1 and stuff[i + 1].isdigit()): + tmp = (arg, str(int(stuff[i + 1], 16)), os.path.expanduser("~/" + getName(int(arg, 16)) + "v" + str(int(stuff[i + 1], 16)) + ".wad"), "WAD") + queue.append(tmp) + self.setList() + self.output.AppendText("Script loaded from %s.\n" % script) + def savescript(self, evt): + dlg = wx.FileDialog(None, "Save Script...", "", "", "Wii NUS Packer/Wiiimposter scripts (*.nus)|*.nus|All Files (*.*)|*.*", wx.SAVE) + if dlg.ShowModal() == wx.ID_OK: + script = dlg.GetPath() + else: + dlg.Destroy() + return + dlg.Destroy() + fd = open(script, "wb") + for i, elem in enumerate(queue): + fd.write("%08x%08x %04x\n" % (int(elem[0][:8], 16), int(elem[0][8:], 16), int(elem[1]))) + self.output.AppendText("Script written to %s.\n" % script) + def go(self, evt): + self.progress.SetValue(0) + self.progress.SetRange(len(queue) * 3) + if(os.path.isdir("tmp")): + shutil.rmtree("tmp") + olddir = os.getcwd() + for i, elem in enumerate(queue): + os.chdir(olddir) + try: + titleid = int(elem[0], 16) + if(len(elem[1]) > 0): + ver = int(elem[1]) + else: + ver = 0 + except: + self.output.AppendText("Invalid title %s" % elem[0]) + if(elem[1] != ""): + self.output.AppendText(" version %s" % elem[1]) + self.output.AppendText(", skipping...\n\n") + continue + + outfile = elem[2] + fmt = elem[3] + + self.output.AppendText("Downloading %08x-%08x (%s)" % (titleid >> 32, titleid & 0xFFFFFFF, getName(titleid),)) + if(ver != 0): + self.output.AppendText(" version %u" % ver) + self.output.AppendText("...") + + self.progress.SetValue(i * 3 + 1) + if(fmt == "Dec Contents"): + dlthread = download(titleid, ver, True) + else: + dlthread = download(titleid, ver) + dlthread.start() + while(dlthread.is_alive()): + wx.Yield() + + self.progress.SetValue(i * 3 + 2) + + if(os.path.exists("tmp/tik") == False): + self.output.AppendText("not found!\n\n") + continue + self.output.AppendText("done!\n") + if(fmt == "WAD"): + if(os.path.isdir(os.path.dirname(outfile))): + self.output.AppendText("Packing WAD to %s..." % outfile) + dlthread = pack("tmp", outfile) + dlthread.start() + while(dlthread.is_alive()): + wx.Yield() + else: + if(os.path.isdir("/".join(outfile.split("/")[:-1]))): + if(not os.path.isdir(outfile)): + os.mkdir(outfile) + self.output.AppendText("Copying files to %s..." % outfile) + for file in os.listdir("tmp"): + shutil.copy("tmp/" + file, outfile) + wx.Yield() + self.output.AppendText("done!\n") + + self.progress.SetValue(i * 3 + 3) + + self.output.AppendText("Title Info:\n") + self.output.AppendText(str(Wii.TMD.loadFile("tmp/tmd"))) + self.output.AppendText(str(Wii.Ticket.loadFile("tmp/tik"))) + + self.output.AppendText("\n") + + os.chdir(olddir) + os.chdir(olddir) + self.output.AppendText("Queue Downloaded!\n\n") + +class download(threading.Thread): + def __init__(self, titleid, ver, decrypt = True): + threading.Thread.__init__(self) + self.titleid = titleid + self.ver = ver + self.decrypt = decrypt + def run(self): + try: + if(self.ver != 0): + Wii.NUS.download(self.titleid, self.ver).dumpDir("tmp", decrypt = self.decrypt) + else: + Wii.NUS.download(self.titleid).dumpDir("tmp", decrypt = self.decrypt) + except: + pass + +class pack(threading.Thread): + def __init__(self, dir, outfile): + threading.Thread.__init__(self) + self.outfile = outfile + self.dir = dir + def run(self): + try: + Wii.WAD.loadDir(self.dir).dumpFile(self.outfile, fakesign = False) + except: + pass + +tb = '' +def excepthook(type, value, traceb): + import traceback + class dummy: + def write(self, text): + global tb + tb += text + dummyf = dummy() + traceback.print_exception(type, value, traceb, file=dummyf) + wx.MessageBox('NUS WAD Packer has encountered a fatal error. Please inform the author of the following traceback:\n\n%s' % tb, 'Fatal Error', wx.OK | wx.ICON_ERROR) + clean() + sys.exit(1) + +if(__name__ == '__main__'): + dl = Downloader(redirect = False) + dl.MainLoop() + if(os.path.isdir(os.getcwd() + "/tmp")): + shutil.rmtree(os.getcwd() + "/tmp")