From f5a8145c4b2941ed5418b50d18304687d474331f Mon Sep 17 00:00:00 2001 From: Xuzz Date: Mon, 29 Jun 2009 17:55:30 -0700 Subject: [PATCH 1/7] TPL preview fixes for wx apps, RGBA8 is great *within* tpl.py but it fails on the wii :P --- TPL.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/TPL.py b/TPL.py index 0270f1b..8f7710c 100644 --- a/TPL.py +++ b/TPL.py @@ -513,22 +513,21 @@ class TPL(): Again, only a single texture is supported.""" import wx - class imp(wx.Panel): - def __init__(self, parent, id, im): - wx.Panel.__init__(self, parent, id) + class imp(wx.Dialog): + def __init__(self, title, im): w = img.GetWidth() h = img.GetHeight() - wx.StaticBitmap(self, -1, im, ( ((max(w, 300) - w) / 2), ((max(h, 200) - h) / 2) ), (w, h)) + + wx.Dialog.__init__(self, None, -1, title, size = (max(w, 300), max(h, 200))) + wx.StaticBitmap(self, -1, im, ( ((max(w, 300) - w) / 2), ((max(h, 200) - h) / 2) ), (w, h)) self.toImage("tmp.png") img = wx.Image("tmp.png", wx.BITMAP_TYPE_ANY).ConvertToBitmap() w = img.GetWidth() h = img.GetHeight() - app = wx.App(redirect = False) - frame = wx.Frame(None, -1, "TPL (" + str(w) + ", " + str(h) + ")", size = (max(w, 300), max(h, 200))) - image = imp(frame, -1, img) - frame.Show(True) - app.MainLoop() + dialog = imp("TPL (" + str(w) + ", " + str(h) + ")", img) + dialog.ShowModal() + dialog.Destroy() os.unlink("tmp.png") def RGBA8(self, (x, y), data): out = [0 for i in range(x * y)] From 56deb8d8fc8c06ed34b593b1034f1e429483ead8 Mon Sep 17 00:00:00 2001 From: Xuzz Date: Mon, 29 Jun 2009 18:07:56 -0700 Subject: [PATCH 2/7] simple IMD5 code --- tests/imd5sign.py | Bin 0 -> 102 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/imd5sign.py diff --git a/tests/imd5sign.py b/tests/imd5sign.py new file mode 100644 index 0000000000000000000000000000000000000000..2d51a8466f124a7fbeeafb2833d53d7c79c067ec GIT binary patch literal 102 zcmebDbundNU~mIsFt`#w?WkN;oOWuvyWpYIS*Dq}1^GoK3gMZVTu^3lWic05T7Hp2 mYEEjdLS~) Date: Mon, 29 Jun 2009 18:10:46 -0700 Subject: [PATCH 3/7] fixed stupidist thing ever - the imd5 siging code *had an IMD5 header*. Really. Please forget that moment... --- tests/imd5sign.py | Bin 102 -> 71 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/imd5sign.py b/tests/imd5sign.py index 2d51a8466f124a7fbeeafb2833d53d7c79c067ec..101fb2cac28dc0a67672107f73c9072c7bb53b56 100644 GIT binary patch delta 7 OcmYdupQzx*$OQlht^u$B delta 37 ncmZ=yQ}Fb4F=b$2a06m6xDr3@s9aT?c51u3;Gxr5rW4!%memRv From 3ff63e05a4979d7022697834a0a2ae240b2480b5 Mon Sep 17 00:00:00 2001 From: Xuzz Date: Mon, 29 Jun 2009 18:36:23 -0700 Subject: [PATCH 4/7] bit of re-organization, now has place for wip code :) --- experimental/breff.py | 564 ++++++++++++++++++++++++++++++++++++++++++ experimental/thp.py | 182 ++++++++++++++ 2 files changed, 746 insertions(+) create mode 100755 experimental/breff.py create mode 100644 experimental/thp.py diff --git a/experimental/breff.py b/experimental/breff.py new file mode 100755 index 0000000..ef17c7d --- /dev/null +++ b/experimental/breff.py @@ -0,0 +1,564 @@ +#!/usr/bin/python + +import sys, struct + +from Struct import Struct + +def nullterm(str_plus): + z = str_plus.find('\0') + if z != -1: + return str_plus[:z] + else: + return str_plus + +class BREFF(object): + class BREFF_REFF_Section2(Struct): + __endian__ = Struct.BE + def __format__(self): + self.unknown01 = Struct.uint32 + self.unknown02 = Struct.uint32 + self.unk03p1 = Struct.uint16 + self.unk03p2 = Struct.uint16 + self.unk04p1 = Struct.int16 + self.unk04p2 = Struct.uint16 + self.unknown05 = Struct.uint32 + self.unknown06 = Struct.float + self.unknown07 = Struct.uint32 + self.unknown08 = Struct.uint32 + self.unknown09 = Struct.uint32 + self.unknown10 = Struct.float + self.unknown11 = Struct.float + self.unknown12 = Struct.uint32 + self.unknown13 = Struct.float + self.unknown14 = Struct.uint32 + self.unknown15 = Struct.uint32 + self.unk16p1 = Struct.uint16 + self.unk16p2 = Struct.uint16 + self.unknown17 = Struct.float + self.unknown18 = Struct.float + self.unknown19 = Struct.uint32 + self.unknown20 = Struct.float + self.unknown21 = Struct.float + self.unknown22 = Struct.float + self.unknown23 = Struct.float + self.unknown24 = Struct.float + self.unknown25 = Struct.float + self.unknown26 = Struct.uint32 + self.unknown27 = Struct.uint32 + self.unknown28 = Struct.uint32 + self.unknown29 = Struct.uint32 + self.unknown30 = Struct.uint32 + self.unknown31 = Struct.float + self.unknown32 = Struct.uint32 + self.unknown33 = Struct.uint32 + self.unknown34 = Struct.uint32 + self.unknown35 = Struct.uint32 + self.unknown36 = Struct.uint32 + self.unknown37 = Struct.float + self.unknown38 = Struct.float + self.unknown39 = Struct.float + self.unknown40 = Struct.float + self.unknown41 = Struct.float + self.unknown42 = Struct.uint32 + self.unknown43 = Struct.uint32 + self.unknown44 = Struct.float + self.unknown45 = Struct.uint32 + self.unknown46 = Struct.uint32 + self.unknown47 = Struct.uint32 + self.unknown48 = Struct.uint32 + self.unknown49 = Struct.uint32 + self.unknown50 = Struct.uint32 + self.unknown51 = Struct.uint32 + self.unknown52 = Struct.uint32 + self.unknown53 = Struct.uint32 + self.unknown54 = Struct.uint32 + self.unknown55 = Struct.uint32 + self.unknown56 = Struct.uint32 + self.unknown57 = Struct.uint32 + self.unknown58 = Struct.uint32 + self.unknown59 = Struct.uint32 + self.unknown60 = Struct.uint32 + self.unknown61 = Struct.uint32 + self.unknown62 = Struct.uint32 + self.unknown63 = Struct.uint32 + self.unknown64 = Struct.uint32 + self.unknown65 = Struct.uint32 + self.unknown66 = Struct.uint32 + self.unknown67 = Struct.uint32 + self.unknown68 = Struct.uint32 + self.unknown69 = Struct.uint32 + self.unknown70 = Struct.uint32 + self.unknown71 = Struct.uint32 + self.unknown72 = Struct.uint32 + self.unknown73 = Struct.uint32 + self.unknown74 = Struct.uint32 + self.unknown75 = Struct.uint32 + self.unknown76 = Struct.uint32 + self.unknown77 = Struct.uint32 + self.unknown78 = Struct.uint32 + self.unknown79 = Struct.uint32 + self.unknown80 = Struct.uint32 + self.unknown81 = Struct.uint32 + self.unknown82 = Struct.uint32 + self.unknown83 = Struct.uint32 + self.unknown84 = Struct.uint32 + self.unknown85 = Struct.uint32 + self.unknown86 = Struct.uint32 + self.unknown87 = Struct.uint32 + self.unknown88 = Struct.uint32 + self.unknown89 = Struct.uint32 + self.unknown90 = Struct.uint32 + self.unknown91 = Struct.uint32 + self.unknown92 = Struct.uint32 + self.unknown93 = Struct.uint32 + self.unknown94 = Struct.uint32 + self.unknown95 = Struct.uint32 + self.unknown96 = Struct.uint32 + self.unknown97 = Struct.uint32 + self.unknown98 = Struct.uint32 + self.unknown99 = Struct.uint32 + self.unknownA0 = Struct.uint32 + self.unknownA1 = Struct.uint32 + self.unknownA2 = Struct.uint32 + self.unknownA3 = Struct.uint32 + self.unknownA4 = Struct.uint32 + self.unknownA5 = Struct.uint32 + self.unknownA6 = Struct.uint32 + self.unknownA7 = Struct.uint32 + self.unknownA8 = Struct.uint32 + self.unknownA9 = Struct.uint32 + self.unknownB0 = Struct.uint32 + self.unknownB1 = Struct.uint32 + self.unknownB2 = Struct.uint32 + def __str__(self): + return_string = "Unknown01: %08x\talways 00000128 ?\n" % self.unknown01 + return_string += "Unknown02: %08x\talways 80000xxx ?\n" % self.unknown02 + return_string += "Unknown03: %04x\t%04x\n" % (self.unk03p1 , self.unk03p2) + return_string += "Unknown04: %.2d\t%04x\n" % (self.unk04p1 , self.unk04p2) + return_string += "Unknown05: %08x\n" % self.unknown05 + return_string += "Unknown06: %.9f\n" % self.unknown06 + return_string += "Unknown07: %08x\n" % self.unknown07 + return_string += "Unknown08: %08x\n" % self.unknown08 + return_string += "Unknown09: %08x\n" % self.unknown09 + return_string += "Unknown10: %.9f\n" % self.unknown10 + return_string += "Unknown11: %.9f\n" % self.unknown11 + return_string += "Unknown12: %08x\n" % self.unknown12 + return_string += "Unknown13: %.9f\n" % self.unknown13 + return_string += "Unknown14: %08x\n" % self.unknown14 + return_string += "Unknown15: %08x\n" % self.unknown15 + return_string += "Unknown16: %04x\t%04x\n" % (self.unk16p1, self.unk16p2) + return_string += "Unknown17: %.9f\n" % self.unknown17 + return_string += "Unknown18: %.9f\n" % self.unknown18 + return_string += "Unknown19: %08x\n" % self.unknown19 + return_string += "Unknown20: %.9f\n" % self.unknown20 + return_string += "Unknown21: %.9f\n" % self.unknown21 + return_string += "Unknown22: %08x\n" % self.unknown22 + return_string += "Unknown23: %08x\n" % self.unknown23 + return_string += "Unknown24: %.20f\n" % self.unknown24 + return_string += "Unknown25: %.9f\n" % self.unknown25 + return_string += "Unknown26: %08x\n" % self.unknown26 + return_string += "Unknown27: %08x\n" % self.unknown27 + return_string += "Unknown28: %08x\n" % self.unknown28 + return_string += "Unknown29: %08x\n" % self.unknown29 + return_string += "Unknown30: %08x\n" % self.unknown30 + return_string += "Unknown31: %.9f\n" % self.unknown31 + return_string += "Unknown32: %08x\n" % self.unknown32 + return_string += "Unknown33: %08x\n" % self.unknown33 + return_string += "Unknown34: %08x\n" % self.unknown34 + return_string += "Unknown35: %08x\n" % self.unknown35 + return_string += "Unknown36: %08x\n" % self.unknown36 + return_string += "Unknown37: %.9f\n" % self.unknown37 + return_string += "Unknown38: %.9f\n" % self.unknown38 + return_string += "Unknown39: %.9f\n" % self.unknown39 + return_string += "Unknown40: %.9f\n" % self.unknown40 + return_string += "Unknown41: %.9f\n" % self.unknown41 + return_string += "Unknown42: %08x\n" % self.unknown42 + return_string += "Unknown43: %08x\n" % self.unknown43 + return_string += "Unknown44: %.9f\n" % self.unknown44 + return_string += "Unknown45: %08x\n" % self.unknown45 + return_string += "Unknown46: %08x\n" % self.unknown46 + return_string += "Unknown47: %08x\n" % self.unknown47 + return_string += "Unknown48: %08x\n" % self.unknown48 + return_string += "Unknown49: %08x\n" % self.unknown49 + return_string += "Unknown50: %08x\n" % self.unknown50 + return_string += "Unknown51: %08x\n" % self.unknown51 + return_string += "Unknown52: %08x\n" % self.unknown52 + return_string += "Unknown53: %08x\n" % self.unknown53 + return_string += "Unknown54: %08x\n" % self.unknown54 + return_string += "Unknown55: %08x\n" % self.unknown55 + return_string += "Unknown56: %08x\n" % self.unknown56 + return_string += "Unknown57: %08x\n" % self.unknown57 + return_string += "Unknown58: %08x\n" % self.unknown58 + return_string += "Unknown59: %08x\n" % self.unknown59 + return_string += "Unknown60: %08x\n" % self.unknown60 + return_string += "Unknown61: %08x\n" % self.unknown61 + return_string += "Unknown62: %08x\n" % self.unknown62 + return_string += "Unknown63: %08x\n" % self.unknown63 + return_string += "Unknown64: %08x\n" % self.unknown64 + return_string += "Unknown65: %08x\n" % self.unknown65 + return_string += "Unknown66: %08x\n" % self.unknown66 + return_string += "Unknown67: %08x\n" % self.unknown67 + return_string += "Unknown68: %08x\n" % self.unknown68 + return_string += "Unknown69: %08x\n" % self.unknown69 + return_string += "Unknown70: %08x\n" % self.unknown70 + return_string += "Unknown71: %08x\n" % self.unknown71 + return_string += "Unknown72: %08x\n" % self.unknown72 + return_string += "Unknown73: %08x\n" % self.unknown73 + return_string += "Unknown74: %08x\n" % self.unknown74 + return_string += "Unknown75: %08x\n" % self.unknown75 + return_string += "Unknown76: %08x\n" % self.unknown76 + return_string += "Unknown77: %08x\n" % self.unknown77 + return_string += "Unknown78: %08x\n" % self.unknown78 + return_string += "Unknown79: %08x\n" % self.unknown79 + return_string += "Unknown80: %08x\n" % self.unknown80 + return_string += "Unknown81: %08x\n" % self.unknown81 + return_string += "Unknown82: %08x\n" % self.unknown82 + return_string += "Unknown83: %08x\n" % self.unknown83 + return_string += "Unknown84: %08x\n" % self.unknown84 + return_string += "Unknown85: %08x\n" % self.unknown85 + return_string += "Unknown86: %08x\n" % self.unknown86 + return_string += "Unknown87: %08x\n" % self.unknown87 + return_string += "Unknown88: %08x\n" % self.unknown88 + return_string += "Unknown89: %08x\n" % self.unknown89 + return_string += "Unknown90: %08x\n" % self.unknown90 + return_string += "Unknown91: %08x\n" % self.unknown91 + return_string += "Unknown92: %08x\n" % self.unknown92 + return_string += "Unknown93: %08x\n" % self.unknown93 + return_string += "Unknown94: %08x\n" % self.unknown94 + return_string += "Unknown95: %08x\n" % self.unknown95 + return_string += "Unknown96: %08x\n" % self.unknown96 + return_string += "Unknown97: %08x\n" % self.unknown97 + return_string += "Unknown98: %08x\n" % self.unknown98 + return_string += "Unknown99: %08x\n" % self.unknown99 + return_string += "UnknownA0: %08x\n" % self.unknownA0 + return_string += "UnknownA1: %08x\n" % self.unknownA1 + return_string += "UnknownA2: %08x\n" % self.unknownA2 + return_string += "UnknownA3: %08x\n" % self.unknownA3 + return_string += "UnknownA4: %08x\n" % self.unknownA4 + return_string += "UnknownA5: %08x\n" % self.unknownA5 + return_string += "UnknownA6: %08x\n" % self.unknownA6 + return_string += "UnknownA7: %08x\n" % self.unknownA7 + return_string += "UnknownA8: %08x\n" % self.unknownA8 + return_string += "UnknownA9: %08x\n" % self.unknownA9 + return_string += "UnknownB0: %08x\n" % self.unknownB0 + return_string += "UnknownB1: %08x\n" % self.unknownB1 + return_string += "UnknownB2: %08x\n" % self.unknownB2 + return return_string + + class BREFF_REFF_StringSection1(Struct): + __endian__ = Struct.BE + def __format__(self): + self.offset = Struct.uint32 + self.length = Struct.uint32 + def __str__(self): + return_string = "Offset: %08x\n" % self.offset + return_string += "Length: %08x\n" % self.length + return return_string + + class BREFF_REFF(Struct): + __endian__ = Struct.BE + def __format__(self): + self.magic = Struct.string(4) + self.length = Struct.uint32 + self.chunk_cnt = Struct.uint32 + def __str__(self): + return_string = "Magic: %s\n" % self.magic + return_string += "Length: %08x\n" % self.length + return_string += "Chunk Count: %08x\n" % self.chunk_cnt + return return_string + + class BREFF_Header(Struct): + __endian__ = Struct.BE + def __format__(self): + self.magic = Struct.string(4) + self.version = Struct.uint32 + self.length = Struct.uint32 + self.header_size = Struct.uint16 + self.chunk_cnt = Struct.uint16 + def __str__(self): + return_string = "Magic: %s\n" % self.magic + return_string += "Version: %08x\n" % self.version + return_string += "Length: %08x\n" % self.length + return_string += "Header Size: %04x\n" % self.header_size + return_string += "Chunk Count: %04x\n" % self.chunk_cnt + return return_string + + def __init__(self, data): + self.data = [] + if data != None: + self.Unpack(data) + + def Unpack(self, data): + pos = 0 + header = self.BREFF_Header() + header.unpack(data[pos:pos+len(header)]) + pos += len(header) + print header + assert header.magic == "REFF" + assert header.version == 0xfeff0004 + reff = self.BREFF_REFF() + reff.unpack(data[pos:pos+len(reff)]) + pos += len(reff) + print reff + assert reff.magic == "REFF" + + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown: %08x" % unknown + str_length = Struct.uint16(data[pos:pos+2], endian='>') + pos += 2 + print "String Length with null added: %04x" % str_length + unknown = Struct.uint16(data[pos:pos+2], endian='>') + pos += 2 + print "Unknown: %04x" % unknown + string = data[pos:pos+str_length-1] + pos += str_length + (2 - (str_length % 2)) + print "String: %s\n" % string + + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Offset or Length: %08x" % unknown + + print "\n%08x\n" % pos + + string_cnt = Struct.uint16(data[pos:pos+2], endian='>') + pos += 2 + print "String Count: %04x" % string_cnt + unknown = Struct.uint16(data[pos:pos+2], endian='>') + pos += 2 + print "Unknown: %04x" % unknown + + print "\n%08x\n" % pos + + string_groups = [] + for x in xrange(string_cnt): + str_length = Struct.uint16(data[pos:pos+2], endian='>') + pos += 2 + print "String Length with null added: %04x" % str_length + string = nullterm(data[pos:pos+str_length]) + pos += str_length + print "String: %s" % string + string_section1 = self.BREFF_REFF_StringSection1() + string_section1.unpack(data[pos:pos+len(string_section1)]) + pos += len(string_section1) + print string_section1 + string_groups.append(string_section1) + + print "\n%08x\n" % pos + + while pos % 0x10: + padding = Struct.uint8(data[pos:pos+1]) + pos += 1 + print "Padding: %02x" % padding + + print "\n%08x\n" % pos + + assert pos == string_groups[0].offset + 0x34 + for x in xrange(string_cnt): + pos = 0x34 + string_groups[x].offset + reff_section2 = self.BREFF_REFF_Section2() + reff_section2.unpack(data[pos:pos+len(reff_section2)]) + pos += len(reff_section2) + print reff_section2 + print "\n%08x\n" % pos + + ''' LARGE TEST DATA + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown01: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown02: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown03: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown04: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown05: %08x" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown06: %f" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown07: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown08: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown09: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown10: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown11: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown12: %08x" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') + pos += 4 + print "PI TIMES 2 BITCHES: %.20f" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown14: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown15: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown16: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown17: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown18: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown19: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown20: %08x" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') + pos += 4 + print "PI DIVIDED BY 4 BITCHES: %.20f" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown22: %f" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown23: %f" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') + pos += 4 + print "PI BITCHES: %.20f" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') + pos += 4 + print "PI DIVIDED BY 2 BITCHES: %.20f" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown26: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown27: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown28: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown29: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown30: %08x" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown31: %f" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown32: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown33: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown34: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown35: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown36: %08x" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown37: %f" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown38: %f" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown39: %f" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown40: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown41: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown42: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown43: %08x" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown44: %.20f" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown45: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown46: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown47: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown48: %08x" % unknown + LARGE TEST DATA ''' + + #''' BEGIN TEST DATA + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown: %08x" % unknown + unknown = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Unknown: %08x" % unknown + #END TEST DATA ''' + +def main(): + if len(sys.argv) != 2: + print 'Usage: python breff.py ' + sys.exit(1) + + f = open(sys.argv[1], 'rb') + if f: + reff = f.read() + f.close() + assert reff[0:8] == 'REFF\xfe\xff\x00\x04' + breff = BREFF(reff) + else: + print 'Could not open %s' % sys.argv[1] + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/experimental/thp.py b/experimental/thp.py new file mode 100644 index 0000000..f05abc0 --- /dev/null +++ b/experimental/thp.py @@ -0,0 +1,182 @@ +from Struct import * +from pyglet import clock, window, image +from pyglet.gl import * +import cStringIO +import math + +from time import time + + +class THP(): + class THPHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.magic = Struct.string(4) + self.version = Struct.uint32 + self.bufSize = Struct.uint32 + self.audioMaxSamples = Struct.uint32 + self.frameRate = Struct.float + self.numFrames = Struct.uint32 + self.firstFrameSize = Struct.uint32 + self.movieDataSize = Struct.uint32 + self.compInfoDataOffsets = Struct.uint32 + self.offsetDataOffsets = Struct.uint32 #Offset to a offset table, containing offsets to each frame, this allows for starting playback from any frame. If this is 0 then it does not exist. + self.movieDataOffsets = Struct.uint32 + self.finalFrameDataOffsets = Struct.uint32 + def __str__(self): + ret = "\n" + ret += "Magic: %s\n" % self.magic + ret += "Version: %d.%d.%d\n" % (((self.version & 0xFFFF0000) >> 16), ((self.version & 0xFF00) >> 8), ((self.version & 0xFF))) + ret += "bufSize: %s\n" % self.bufSize + ret += "audioMaxSamples: %d\n" % self.audioMaxSamples + ret += "frameRate: %f\n" % self.frameRate + ret += "numFrames: %d\n" % self.numFrames + ret += "firstFrameSize: %d\n" % self.firstFrameSize + ret += "movieDataSize: %d\n" % self.movieDataSize + ret += "compInfoDataOffsets: 0x%08X\n" % self.compInfoDataOffsets + ret += "offsetDataOffsets: 0x%08X\n" % self.offsetDataOffsets + ret += "movieDataOffsets: 0x%08X\n" % self.movieDataOffsets + ret += "finalFrameDataOffsets: 0x%08X\n" % self.finalFrameDataOffsets + return ret + class THPFrameCompInfo(Struct): + __endian__ = Struct.BE + def __format__(self): + self.numComponents = Struct.uint32 + self.frameComp = Struct.uint8[16] + def __str__(self): + ret = "" + ret += "Number of Components: %d\n" % self.numComponents + return ret + class THPCompVideoInfo(Struct): + __endian__ = Struct.BE + def __format__(self): + self.width = Struct.uint32 + self.height = Struct.uint32 + self.videoType = Struct.uint32 + def __str__(self): + tempType = ("Non-Interlaced", "Interlaced", "Odd Interlace", "3", "Even Interlace") + ret = "" + ret += "Width: %d\n" % self.width + ret += "Height: %d\n" % self.height + ret += "VideoType: %s\n" % tempType[self.videoType] + return ret + class THPCompAudioInfo(Struct): + __endian__ = Struct.BE + def __format__(self): + self.sndChannels = Struct.uint32 + self.sndFrequency = Struct.uint32 + self.sndNumberSamples = Struct.uint32 + self.sndNumberTracks = Struct.uint32 + def __str__(self): + ret = "" + ret += "Channels: %d\n" % self.sndChannels + ret += "Frequency: %d\n" % self.sndFrequency + ret += "Samples: %d\n" % self.sndNumberSamples + ret += "Tracks: %d\n" % self.sndNumberTracks + return ret + class THPFrameHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.frameSizeNext = Struct.uint32 + self.frameSizePrev = Struct.uint32 + self.vidFileSize = Struct.uint32 + self.sndFileSize = Struct.uint32 + def __str__(self): + ret = "" + ret += "next Frame Size: %d\n" % self.frameSizeNext + ret += "previous Frame Size: %d\n" % self.frameSizePrev + ret += "Video frame data size: %d\n" % self.vidFileSize + ret += "Track file size: %d\n" % self.sndFileSize + return ret + def readData(self, fp, i=0): + self.frameImage = fp.read(self.vidFileSize) + #fileName = "frame%06d.jpg" % i + #open("out/" + fileName, 'w+b').write(self.frameImage) + #print "Frame: %d" % i + startTime = time() + start = self.frameImage.find('\xff\xda') + end = self.frameImage.rfind('\xff\xd9') + #print "find(%d): This took "%i, time()-startTime,start,end + startTime = time() + startStr = self.frameImage[:start+2] + endStr = self.frameImage[end:] + #print "extr(%d): This took "%i, time()-startTime + self.frameImage = self.frameImage[start+2:end] + self.frameImage = startStr + self.frameImage.replace('\xff','\xff\x00') + endStr + #print self.frameImage + + + return cStringIO.StringIO(self.frameImage) + def __init__(self, movieFile=None): + if(movieFile==None): + print "Usage: python thp.py filename.thp" + exit(-1) + fp = file(movieFile, 'rb') + HEADER = self.THPHeader() + HEADER.unpack(fp.read(len(HEADER))) + print HEADER + fp.seek(HEADER.compInfoDataOffsets) + CompInfo = self.THPFrameCompInfo() + CompInfo.unpack(fp.read(len(CompInfo))) + print CompInfo + for i in range(0, CompInfo.numComponents): + if(CompInfo.frameComp[i] == 0): + VideoInfo = self.THPCompVideoInfo() + VideoInfo.unpack(fp.read(len(VideoInfo))) + print VideoInfo + if(CompInfo.frameComp[i] == 1): + AudioInfo = self.THPCompAudioInfo() + AudioInfo.unpack(fp.read(len(AudioInfo))) + print AudioInfo + + clock.set_fps_limit(HEADER.frameRate) + currOff = HEADER.movieDataOffsets + currSize = HEADER.firstFrameSize + fp.seek(currOff) + + win = window.Window(VideoInfo.width, VideoInfo.height) + fps_display = clock.ClockDisplay() + i = 1 + j = 1 + image_index = 0 + image_period = 1.0 / HEADER.frameRate # Reciprocal of the frame rate + remained = 0 + + while not win.has_exit: + + win.dispatch_events() + win.clear() + + dt = clock.tick() + + skip = math.floor((dt+remained)/image_period) + j += skip + print skip, ":break:", i, j, skip + remained = dt - skip * image_period + + tempFrame = self.THPFrameHeader() + tempFrame.unpack(fp.read(len(tempFrame))) + + for xx in range(1,skip): + currOff = currOff+currSize + currSize = tempFrame.frameSizeNext + fp.seek(currOff) + tempFrame = self.THPFrameHeader() + tempFrame.unpack(fp.read(len(tempFrame))) + + imagedat = tempFrame.readData(fp, i) + + pic = image.load("image.jpg",imagedat) + pic.blit(0,0) + + currOff = currOff+currSize + currSize = tempFrame.frameSizeNext + fp.seek(currOff) + + + fps_display.draw() + win.flip() + i += 1 + +if __name__=='__main__': + THP(*sys.argv[1:]) \ No newline at end of file From 9b8368270aa8ce88277f33c2f973c273b14a8eb6 Mon Sep 17 00:00:00 2001 From: Xuzz Date: Mon, 29 Jun 2009 18:36:57 -0700 Subject: [PATCH 5/7] experimenatl folder --- breff.py | 564 ------------------------------------------------------- thp.py | 182 ------------------ 2 files changed, 746 deletions(-) delete mode 100755 breff.py delete mode 100644 thp.py diff --git a/breff.py b/breff.py deleted file mode 100755 index ef17c7d..0000000 --- a/breff.py +++ /dev/null @@ -1,564 +0,0 @@ -#!/usr/bin/python - -import sys, struct - -from Struct import Struct - -def nullterm(str_plus): - z = str_plus.find('\0') - if z != -1: - return str_plus[:z] - else: - return str_plus - -class BREFF(object): - class BREFF_REFF_Section2(Struct): - __endian__ = Struct.BE - def __format__(self): - self.unknown01 = Struct.uint32 - self.unknown02 = Struct.uint32 - self.unk03p1 = Struct.uint16 - self.unk03p2 = Struct.uint16 - self.unk04p1 = Struct.int16 - self.unk04p2 = Struct.uint16 - self.unknown05 = Struct.uint32 - self.unknown06 = Struct.float - self.unknown07 = Struct.uint32 - self.unknown08 = Struct.uint32 - self.unknown09 = Struct.uint32 - self.unknown10 = Struct.float - self.unknown11 = Struct.float - self.unknown12 = Struct.uint32 - self.unknown13 = Struct.float - self.unknown14 = Struct.uint32 - self.unknown15 = Struct.uint32 - self.unk16p1 = Struct.uint16 - self.unk16p2 = Struct.uint16 - self.unknown17 = Struct.float - self.unknown18 = Struct.float - self.unknown19 = Struct.uint32 - self.unknown20 = Struct.float - self.unknown21 = Struct.float - self.unknown22 = Struct.float - self.unknown23 = Struct.float - self.unknown24 = Struct.float - self.unknown25 = Struct.float - self.unknown26 = Struct.uint32 - self.unknown27 = Struct.uint32 - self.unknown28 = Struct.uint32 - self.unknown29 = Struct.uint32 - self.unknown30 = Struct.uint32 - self.unknown31 = Struct.float - self.unknown32 = Struct.uint32 - self.unknown33 = Struct.uint32 - self.unknown34 = Struct.uint32 - self.unknown35 = Struct.uint32 - self.unknown36 = Struct.uint32 - self.unknown37 = Struct.float - self.unknown38 = Struct.float - self.unknown39 = Struct.float - self.unknown40 = Struct.float - self.unknown41 = Struct.float - self.unknown42 = Struct.uint32 - self.unknown43 = Struct.uint32 - self.unknown44 = Struct.float - self.unknown45 = Struct.uint32 - self.unknown46 = Struct.uint32 - self.unknown47 = Struct.uint32 - self.unknown48 = Struct.uint32 - self.unknown49 = Struct.uint32 - self.unknown50 = Struct.uint32 - self.unknown51 = Struct.uint32 - self.unknown52 = Struct.uint32 - self.unknown53 = Struct.uint32 - self.unknown54 = Struct.uint32 - self.unknown55 = Struct.uint32 - self.unknown56 = Struct.uint32 - self.unknown57 = Struct.uint32 - self.unknown58 = Struct.uint32 - self.unknown59 = Struct.uint32 - self.unknown60 = Struct.uint32 - self.unknown61 = Struct.uint32 - self.unknown62 = Struct.uint32 - self.unknown63 = Struct.uint32 - self.unknown64 = Struct.uint32 - self.unknown65 = Struct.uint32 - self.unknown66 = Struct.uint32 - self.unknown67 = Struct.uint32 - self.unknown68 = Struct.uint32 - self.unknown69 = Struct.uint32 - self.unknown70 = Struct.uint32 - self.unknown71 = Struct.uint32 - self.unknown72 = Struct.uint32 - self.unknown73 = Struct.uint32 - self.unknown74 = Struct.uint32 - self.unknown75 = Struct.uint32 - self.unknown76 = Struct.uint32 - self.unknown77 = Struct.uint32 - self.unknown78 = Struct.uint32 - self.unknown79 = Struct.uint32 - self.unknown80 = Struct.uint32 - self.unknown81 = Struct.uint32 - self.unknown82 = Struct.uint32 - self.unknown83 = Struct.uint32 - self.unknown84 = Struct.uint32 - self.unknown85 = Struct.uint32 - self.unknown86 = Struct.uint32 - self.unknown87 = Struct.uint32 - self.unknown88 = Struct.uint32 - self.unknown89 = Struct.uint32 - self.unknown90 = Struct.uint32 - self.unknown91 = Struct.uint32 - self.unknown92 = Struct.uint32 - self.unknown93 = Struct.uint32 - self.unknown94 = Struct.uint32 - self.unknown95 = Struct.uint32 - self.unknown96 = Struct.uint32 - self.unknown97 = Struct.uint32 - self.unknown98 = Struct.uint32 - self.unknown99 = Struct.uint32 - self.unknownA0 = Struct.uint32 - self.unknownA1 = Struct.uint32 - self.unknownA2 = Struct.uint32 - self.unknownA3 = Struct.uint32 - self.unknownA4 = Struct.uint32 - self.unknownA5 = Struct.uint32 - self.unknownA6 = Struct.uint32 - self.unknownA7 = Struct.uint32 - self.unknownA8 = Struct.uint32 - self.unknownA9 = Struct.uint32 - self.unknownB0 = Struct.uint32 - self.unknownB1 = Struct.uint32 - self.unknownB2 = Struct.uint32 - def __str__(self): - return_string = "Unknown01: %08x\talways 00000128 ?\n" % self.unknown01 - return_string += "Unknown02: %08x\talways 80000xxx ?\n" % self.unknown02 - return_string += "Unknown03: %04x\t%04x\n" % (self.unk03p1 , self.unk03p2) - return_string += "Unknown04: %.2d\t%04x\n" % (self.unk04p1 , self.unk04p2) - return_string += "Unknown05: %08x\n" % self.unknown05 - return_string += "Unknown06: %.9f\n" % self.unknown06 - return_string += "Unknown07: %08x\n" % self.unknown07 - return_string += "Unknown08: %08x\n" % self.unknown08 - return_string += "Unknown09: %08x\n" % self.unknown09 - return_string += "Unknown10: %.9f\n" % self.unknown10 - return_string += "Unknown11: %.9f\n" % self.unknown11 - return_string += "Unknown12: %08x\n" % self.unknown12 - return_string += "Unknown13: %.9f\n" % self.unknown13 - return_string += "Unknown14: %08x\n" % self.unknown14 - return_string += "Unknown15: %08x\n" % self.unknown15 - return_string += "Unknown16: %04x\t%04x\n" % (self.unk16p1, self.unk16p2) - return_string += "Unknown17: %.9f\n" % self.unknown17 - return_string += "Unknown18: %.9f\n" % self.unknown18 - return_string += "Unknown19: %08x\n" % self.unknown19 - return_string += "Unknown20: %.9f\n" % self.unknown20 - return_string += "Unknown21: %.9f\n" % self.unknown21 - return_string += "Unknown22: %08x\n" % self.unknown22 - return_string += "Unknown23: %08x\n" % self.unknown23 - return_string += "Unknown24: %.20f\n" % self.unknown24 - return_string += "Unknown25: %.9f\n" % self.unknown25 - return_string += "Unknown26: %08x\n" % self.unknown26 - return_string += "Unknown27: %08x\n" % self.unknown27 - return_string += "Unknown28: %08x\n" % self.unknown28 - return_string += "Unknown29: %08x\n" % self.unknown29 - return_string += "Unknown30: %08x\n" % self.unknown30 - return_string += "Unknown31: %.9f\n" % self.unknown31 - return_string += "Unknown32: %08x\n" % self.unknown32 - return_string += "Unknown33: %08x\n" % self.unknown33 - return_string += "Unknown34: %08x\n" % self.unknown34 - return_string += "Unknown35: %08x\n" % self.unknown35 - return_string += "Unknown36: %08x\n" % self.unknown36 - return_string += "Unknown37: %.9f\n" % self.unknown37 - return_string += "Unknown38: %.9f\n" % self.unknown38 - return_string += "Unknown39: %.9f\n" % self.unknown39 - return_string += "Unknown40: %.9f\n" % self.unknown40 - return_string += "Unknown41: %.9f\n" % self.unknown41 - return_string += "Unknown42: %08x\n" % self.unknown42 - return_string += "Unknown43: %08x\n" % self.unknown43 - return_string += "Unknown44: %.9f\n" % self.unknown44 - return_string += "Unknown45: %08x\n" % self.unknown45 - return_string += "Unknown46: %08x\n" % self.unknown46 - return_string += "Unknown47: %08x\n" % self.unknown47 - return_string += "Unknown48: %08x\n" % self.unknown48 - return_string += "Unknown49: %08x\n" % self.unknown49 - return_string += "Unknown50: %08x\n" % self.unknown50 - return_string += "Unknown51: %08x\n" % self.unknown51 - return_string += "Unknown52: %08x\n" % self.unknown52 - return_string += "Unknown53: %08x\n" % self.unknown53 - return_string += "Unknown54: %08x\n" % self.unknown54 - return_string += "Unknown55: %08x\n" % self.unknown55 - return_string += "Unknown56: %08x\n" % self.unknown56 - return_string += "Unknown57: %08x\n" % self.unknown57 - return_string += "Unknown58: %08x\n" % self.unknown58 - return_string += "Unknown59: %08x\n" % self.unknown59 - return_string += "Unknown60: %08x\n" % self.unknown60 - return_string += "Unknown61: %08x\n" % self.unknown61 - return_string += "Unknown62: %08x\n" % self.unknown62 - return_string += "Unknown63: %08x\n" % self.unknown63 - return_string += "Unknown64: %08x\n" % self.unknown64 - return_string += "Unknown65: %08x\n" % self.unknown65 - return_string += "Unknown66: %08x\n" % self.unknown66 - return_string += "Unknown67: %08x\n" % self.unknown67 - return_string += "Unknown68: %08x\n" % self.unknown68 - return_string += "Unknown69: %08x\n" % self.unknown69 - return_string += "Unknown70: %08x\n" % self.unknown70 - return_string += "Unknown71: %08x\n" % self.unknown71 - return_string += "Unknown72: %08x\n" % self.unknown72 - return_string += "Unknown73: %08x\n" % self.unknown73 - return_string += "Unknown74: %08x\n" % self.unknown74 - return_string += "Unknown75: %08x\n" % self.unknown75 - return_string += "Unknown76: %08x\n" % self.unknown76 - return_string += "Unknown77: %08x\n" % self.unknown77 - return_string += "Unknown78: %08x\n" % self.unknown78 - return_string += "Unknown79: %08x\n" % self.unknown79 - return_string += "Unknown80: %08x\n" % self.unknown80 - return_string += "Unknown81: %08x\n" % self.unknown81 - return_string += "Unknown82: %08x\n" % self.unknown82 - return_string += "Unknown83: %08x\n" % self.unknown83 - return_string += "Unknown84: %08x\n" % self.unknown84 - return_string += "Unknown85: %08x\n" % self.unknown85 - return_string += "Unknown86: %08x\n" % self.unknown86 - return_string += "Unknown87: %08x\n" % self.unknown87 - return_string += "Unknown88: %08x\n" % self.unknown88 - return_string += "Unknown89: %08x\n" % self.unknown89 - return_string += "Unknown90: %08x\n" % self.unknown90 - return_string += "Unknown91: %08x\n" % self.unknown91 - return_string += "Unknown92: %08x\n" % self.unknown92 - return_string += "Unknown93: %08x\n" % self.unknown93 - return_string += "Unknown94: %08x\n" % self.unknown94 - return_string += "Unknown95: %08x\n" % self.unknown95 - return_string += "Unknown96: %08x\n" % self.unknown96 - return_string += "Unknown97: %08x\n" % self.unknown97 - return_string += "Unknown98: %08x\n" % self.unknown98 - return_string += "Unknown99: %08x\n" % self.unknown99 - return_string += "UnknownA0: %08x\n" % self.unknownA0 - return_string += "UnknownA1: %08x\n" % self.unknownA1 - return_string += "UnknownA2: %08x\n" % self.unknownA2 - return_string += "UnknownA3: %08x\n" % self.unknownA3 - return_string += "UnknownA4: %08x\n" % self.unknownA4 - return_string += "UnknownA5: %08x\n" % self.unknownA5 - return_string += "UnknownA6: %08x\n" % self.unknownA6 - return_string += "UnknownA7: %08x\n" % self.unknownA7 - return_string += "UnknownA8: %08x\n" % self.unknownA8 - return_string += "UnknownA9: %08x\n" % self.unknownA9 - return_string += "UnknownB0: %08x\n" % self.unknownB0 - return_string += "UnknownB1: %08x\n" % self.unknownB1 - return_string += "UnknownB2: %08x\n" % self.unknownB2 - return return_string - - class BREFF_REFF_StringSection1(Struct): - __endian__ = Struct.BE - def __format__(self): - self.offset = Struct.uint32 - self.length = Struct.uint32 - def __str__(self): - return_string = "Offset: %08x\n" % self.offset - return_string += "Length: %08x\n" % self.length - return return_string - - class BREFF_REFF(Struct): - __endian__ = Struct.BE - def __format__(self): - self.magic = Struct.string(4) - self.length = Struct.uint32 - self.chunk_cnt = Struct.uint32 - def __str__(self): - return_string = "Magic: %s\n" % self.magic - return_string += "Length: %08x\n" % self.length - return_string += "Chunk Count: %08x\n" % self.chunk_cnt - return return_string - - class BREFF_Header(Struct): - __endian__ = Struct.BE - def __format__(self): - self.magic = Struct.string(4) - self.version = Struct.uint32 - self.length = Struct.uint32 - self.header_size = Struct.uint16 - self.chunk_cnt = Struct.uint16 - def __str__(self): - return_string = "Magic: %s\n" % self.magic - return_string += "Version: %08x\n" % self.version - return_string += "Length: %08x\n" % self.length - return_string += "Header Size: %04x\n" % self.header_size - return_string += "Chunk Count: %04x\n" % self.chunk_cnt - return return_string - - def __init__(self, data): - self.data = [] - if data != None: - self.Unpack(data) - - def Unpack(self, data): - pos = 0 - header = self.BREFF_Header() - header.unpack(data[pos:pos+len(header)]) - pos += len(header) - print header - assert header.magic == "REFF" - assert header.version == 0xfeff0004 - reff = self.BREFF_REFF() - reff.unpack(data[pos:pos+len(reff)]) - pos += len(reff) - print reff - assert reff.magic == "REFF" - - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown: %08x" % unknown - str_length = Struct.uint16(data[pos:pos+2], endian='>') - pos += 2 - print "String Length with null added: %04x" % str_length - unknown = Struct.uint16(data[pos:pos+2], endian='>') - pos += 2 - print "Unknown: %04x" % unknown - string = data[pos:pos+str_length-1] - pos += str_length + (2 - (str_length % 2)) - print "String: %s\n" % string - - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Offset or Length: %08x" % unknown - - print "\n%08x\n" % pos - - string_cnt = Struct.uint16(data[pos:pos+2], endian='>') - pos += 2 - print "String Count: %04x" % string_cnt - unknown = Struct.uint16(data[pos:pos+2], endian='>') - pos += 2 - print "Unknown: %04x" % unknown - - print "\n%08x\n" % pos - - string_groups = [] - for x in xrange(string_cnt): - str_length = Struct.uint16(data[pos:pos+2], endian='>') - pos += 2 - print "String Length with null added: %04x" % str_length - string = nullterm(data[pos:pos+str_length]) - pos += str_length - print "String: %s" % string - string_section1 = self.BREFF_REFF_StringSection1() - string_section1.unpack(data[pos:pos+len(string_section1)]) - pos += len(string_section1) - print string_section1 - string_groups.append(string_section1) - - print "\n%08x\n" % pos - - while pos % 0x10: - padding = Struct.uint8(data[pos:pos+1]) - pos += 1 - print "Padding: %02x" % padding - - print "\n%08x\n" % pos - - assert pos == string_groups[0].offset + 0x34 - for x in xrange(string_cnt): - pos = 0x34 + string_groups[x].offset - reff_section2 = self.BREFF_REFF_Section2() - reff_section2.unpack(data[pos:pos+len(reff_section2)]) - pos += len(reff_section2) - print reff_section2 - print "\n%08x\n" % pos - - ''' LARGE TEST DATA - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown01: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown02: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown03: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown04: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown05: %08x" % unknown - unknown = Struct.float(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown06: %f" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown07: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown08: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown09: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown10: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown11: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown12: %08x" % unknown - unknown = Struct.float(data[pos:pos+4], endian='>') - pos += 4 - print "PI TIMES 2 BITCHES: %.20f" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown14: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown15: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown16: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown17: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown18: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown19: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown20: %08x" % unknown - unknown = Struct.float(data[pos:pos+4], endian='>') - pos += 4 - print "PI DIVIDED BY 4 BITCHES: %.20f" % unknown - unknown = Struct.float(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown22: %f" % unknown - unknown = Struct.float(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown23: %f" % unknown - unknown = Struct.float(data[pos:pos+4], endian='>') - pos += 4 - print "PI BITCHES: %.20f" % unknown - unknown = Struct.float(data[pos:pos+4], endian='>') - pos += 4 - print "PI DIVIDED BY 2 BITCHES: %.20f" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown26: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown27: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown28: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown29: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown30: %08x" % unknown - unknown = Struct.float(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown31: %f" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown32: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown33: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown34: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown35: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown36: %08x" % unknown - unknown = Struct.float(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown37: %f" % unknown - unknown = Struct.float(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown38: %f" % unknown - unknown = Struct.float(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown39: %f" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown40: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown41: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown42: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown43: %08x" % unknown - unknown = Struct.float(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown44: %.20f" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown45: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown46: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown47: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown48: %08x" % unknown - LARGE TEST DATA ''' - - #''' BEGIN TEST DATA - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown: %08x" % unknown - #END TEST DATA ''' - -def main(): - if len(sys.argv) != 2: - print 'Usage: python breff.py ' - sys.exit(1) - - f = open(sys.argv[1], 'rb') - if f: - reff = f.read() - f.close() - assert reff[0:8] == 'REFF\xfe\xff\x00\x04' - breff = BREFF(reff) - else: - print 'Could not open %s' % sys.argv[1] - sys.exit(1) - -if __name__ == "__main__": - main() diff --git a/thp.py b/thp.py deleted file mode 100644 index f05abc0..0000000 --- a/thp.py +++ /dev/null @@ -1,182 +0,0 @@ -from Struct import * -from pyglet import clock, window, image -from pyglet.gl import * -import cStringIO -import math - -from time import time - - -class THP(): - class THPHeader(Struct): - __endian__ = Struct.BE - def __format__(self): - self.magic = Struct.string(4) - self.version = Struct.uint32 - self.bufSize = Struct.uint32 - self.audioMaxSamples = Struct.uint32 - self.frameRate = Struct.float - self.numFrames = Struct.uint32 - self.firstFrameSize = Struct.uint32 - self.movieDataSize = Struct.uint32 - self.compInfoDataOffsets = Struct.uint32 - self.offsetDataOffsets = Struct.uint32 #Offset to a offset table, containing offsets to each frame, this allows for starting playback from any frame. If this is 0 then it does not exist. - self.movieDataOffsets = Struct.uint32 - self.finalFrameDataOffsets = Struct.uint32 - def __str__(self): - ret = "\n" - ret += "Magic: %s\n" % self.magic - ret += "Version: %d.%d.%d\n" % (((self.version & 0xFFFF0000) >> 16), ((self.version & 0xFF00) >> 8), ((self.version & 0xFF))) - ret += "bufSize: %s\n" % self.bufSize - ret += "audioMaxSamples: %d\n" % self.audioMaxSamples - ret += "frameRate: %f\n" % self.frameRate - ret += "numFrames: %d\n" % self.numFrames - ret += "firstFrameSize: %d\n" % self.firstFrameSize - ret += "movieDataSize: %d\n" % self.movieDataSize - ret += "compInfoDataOffsets: 0x%08X\n" % self.compInfoDataOffsets - ret += "offsetDataOffsets: 0x%08X\n" % self.offsetDataOffsets - ret += "movieDataOffsets: 0x%08X\n" % self.movieDataOffsets - ret += "finalFrameDataOffsets: 0x%08X\n" % self.finalFrameDataOffsets - return ret - class THPFrameCompInfo(Struct): - __endian__ = Struct.BE - def __format__(self): - self.numComponents = Struct.uint32 - self.frameComp = Struct.uint8[16] - def __str__(self): - ret = "" - ret += "Number of Components: %d\n" % self.numComponents - return ret - class THPCompVideoInfo(Struct): - __endian__ = Struct.BE - def __format__(self): - self.width = Struct.uint32 - self.height = Struct.uint32 - self.videoType = Struct.uint32 - def __str__(self): - tempType = ("Non-Interlaced", "Interlaced", "Odd Interlace", "3", "Even Interlace") - ret = "" - ret += "Width: %d\n" % self.width - ret += "Height: %d\n" % self.height - ret += "VideoType: %s\n" % tempType[self.videoType] - return ret - class THPCompAudioInfo(Struct): - __endian__ = Struct.BE - def __format__(self): - self.sndChannels = Struct.uint32 - self.sndFrequency = Struct.uint32 - self.sndNumberSamples = Struct.uint32 - self.sndNumberTracks = Struct.uint32 - def __str__(self): - ret = "" - ret += "Channels: %d\n" % self.sndChannels - ret += "Frequency: %d\n" % self.sndFrequency - ret += "Samples: %d\n" % self.sndNumberSamples - ret += "Tracks: %d\n" % self.sndNumberTracks - return ret - class THPFrameHeader(Struct): - __endian__ = Struct.BE - def __format__(self): - self.frameSizeNext = Struct.uint32 - self.frameSizePrev = Struct.uint32 - self.vidFileSize = Struct.uint32 - self.sndFileSize = Struct.uint32 - def __str__(self): - ret = "" - ret += "next Frame Size: %d\n" % self.frameSizeNext - ret += "previous Frame Size: %d\n" % self.frameSizePrev - ret += "Video frame data size: %d\n" % self.vidFileSize - ret += "Track file size: %d\n" % self.sndFileSize - return ret - def readData(self, fp, i=0): - self.frameImage = fp.read(self.vidFileSize) - #fileName = "frame%06d.jpg" % i - #open("out/" + fileName, 'w+b').write(self.frameImage) - #print "Frame: %d" % i - startTime = time() - start = self.frameImage.find('\xff\xda') - end = self.frameImage.rfind('\xff\xd9') - #print "find(%d): This took "%i, time()-startTime,start,end - startTime = time() - startStr = self.frameImage[:start+2] - endStr = self.frameImage[end:] - #print "extr(%d): This took "%i, time()-startTime - self.frameImage = self.frameImage[start+2:end] - self.frameImage = startStr + self.frameImage.replace('\xff','\xff\x00') + endStr - #print self.frameImage - - - return cStringIO.StringIO(self.frameImage) - def __init__(self, movieFile=None): - if(movieFile==None): - print "Usage: python thp.py filename.thp" - exit(-1) - fp = file(movieFile, 'rb') - HEADER = self.THPHeader() - HEADER.unpack(fp.read(len(HEADER))) - print HEADER - fp.seek(HEADER.compInfoDataOffsets) - CompInfo = self.THPFrameCompInfo() - CompInfo.unpack(fp.read(len(CompInfo))) - print CompInfo - for i in range(0, CompInfo.numComponents): - if(CompInfo.frameComp[i] == 0): - VideoInfo = self.THPCompVideoInfo() - VideoInfo.unpack(fp.read(len(VideoInfo))) - print VideoInfo - if(CompInfo.frameComp[i] == 1): - AudioInfo = self.THPCompAudioInfo() - AudioInfo.unpack(fp.read(len(AudioInfo))) - print AudioInfo - - clock.set_fps_limit(HEADER.frameRate) - currOff = HEADER.movieDataOffsets - currSize = HEADER.firstFrameSize - fp.seek(currOff) - - win = window.Window(VideoInfo.width, VideoInfo.height) - fps_display = clock.ClockDisplay() - i = 1 - j = 1 - image_index = 0 - image_period = 1.0 / HEADER.frameRate # Reciprocal of the frame rate - remained = 0 - - while not win.has_exit: - - win.dispatch_events() - win.clear() - - dt = clock.tick() - - skip = math.floor((dt+remained)/image_period) - j += skip - print skip, ":break:", i, j, skip - remained = dt - skip * image_period - - tempFrame = self.THPFrameHeader() - tempFrame.unpack(fp.read(len(tempFrame))) - - for xx in range(1,skip): - currOff = currOff+currSize - currSize = tempFrame.frameSizeNext - fp.seek(currOff) - tempFrame = self.THPFrameHeader() - tempFrame.unpack(fp.read(len(tempFrame))) - - imagedat = tempFrame.readData(fp, i) - - pic = image.load("image.jpg",imagedat) - pic.blit(0,0) - - currOff = currOff+currSize - currSize = tempFrame.frameSizeNext - fp.seek(currOff) - - - fps_display.draw() - win.flip() - i += 1 - -if __name__=='__main__': - THP(*sys.argv[1:]) \ No newline at end of file From 1ca063a8fcb33a84f53dc1709d3dfb826be7ad7c Mon Sep 17 00:00:00 2001 From: Xuzz Date: Tue, 30 Jun 2009 00:25:23 -0700 Subject: [PATCH 6/7] restructured layout of all code. archive.py is for all "archive" files, or files that contain other files. export.py is for stuff the wii spits onto SD (savegames, content.bin, etc). image.py is just TPL for now, but it can be expanded. headers.py has IMD5 and IMET. title.py is just NUS, Ticket, and TMD now. formats.py contains general other file formats. compression.py is JUST for compression (LZ77, ASH0, yaz0, yay0, etc). Ticket and TMD now use the "new" handling code for load-and-dumpable files - you do TMD() for a blank tmd, TMD().load(data) to load from data, TMD.loadFile(filename) to load from a filename. I think thats all --- Wii.py | 25 +- archive.py | 501 ++++++++++++++++++++++++++ common.py | 12 +- compression.py | 119 ------- disc.py | 8 +- experimental/breff.py | 203 ++++++----- export.py | 253 ++++++++++++++ formats.py | 53 ++- headers.py | 145 ++++++++ image.py | 796 ++++++++++++++++++++++++++++++++++++++++++ nand.py | 4 - title.py | 229 ++---------- 12 files changed, 1887 insertions(+), 461 deletions(-) create mode 100644 archive.py create mode 100644 export.py create mode 100644 headers.py create mode 100644 image.py diff --git a/Wii.py b/Wii.py index 483db7d..593734a 100644 --- a/Wii.py +++ b/Wii.py @@ -1,14 +1,21 @@ __all__ = [] - -from compression import * -from savedata import * -from banner import * -from disc import * -from nand import * + +from common import * from formats import * +from banner import * from title import * -from TPL import * -from U8 import * +from disc import * +from image import * +from archive import * +from export import * +from compression import * +from nand import * if (__name__ == "__main__"): - print ("\nAll components loaded sucessfully!\n\n") + Crypto() + TMD() + Ticket() + + #insert non-dependant check code here + + print ("\nAll Wii.py components loaded sucessfully!\n") diff --git a/archive.py b/archive.py new file mode 100644 index 0000000..6466311 --- /dev/null +++ b/archive.py @@ -0,0 +1,501 @@ +from common import * +from title import * +import zlib + +class U8(): + """This class can unpack and pack U8 archives, which are used all over the Wii. They are often used in Banners and contents in Downloadable Titles. Please remove all headers and compression first, kthx. + + The f parameter is either the source folder to pack, or the source file to unpack.""" + class U8Header(Struct): + __endian__ = Struct.BE + def __format__(self): + self.tag = Struct.string(4) + self.rootnode_offset = Struct.uint32 + self.header_size = Struct.uint32 + self.data_offset = Struct.uint32 + self.zeroes = Struct.string(16) + class U8Node(Struct): + __endian__ = Struct.BE + def __format__(self): + self.type = Struct.uint16 + self.name_offset = Struct.uint16 + self.data_offset = Struct.uint32 + self.size = Struct.uint32 + def __init__(self, f): + self.f = f + def _pack(self, file, recursion, is_root = 0): #internal + node = self.U8Node() + node.name_offset = len(self.strings) + if(is_root != 1): + self.strings += (file) + self.strings += ("\x00") + + if(os.path.isdir(file)): + node.type = 0x0100 + node.data_offset = recursion - 1 + recursion += 1 + files = sorted(os.listdir(file)) + #if(sorted(files) == ["banner.bin", "icon.bin", "sound.bin"]): + # files = ["icon.bin", "banner.bin", "sound.bin"] + + oldsz = len(self.nodes) + if(is_root != 1): + self.nodes.append(node) + + os.chdir(file) + for entry in files: + if(entry != ".DS_Store" and entry[len(entry) - 4:] != "_out"): + self._pack(entry, recursion) + os.chdir("..") + + self.nodes[oldsz].size = len(self.nodes) + 1 + else: + f = open(file, "rb") + data = f.read() + f.close() + sz = len(data) + data += "\x00" * (align(sz, 32) - sz) #32 seems to work best for fuzzyness? I'm still really not sure + node.data_offset = len(self.data) + self.data += data + node.size = sz + node.type = 0x0000 + if(is_root != 1): + self.nodes.append(node) + + def pack(self, fn = ""): + """This function will pack a folder into a U8 archive. The output file name is specified in the parameter fn. If fn is an empty string, the filename is deduced from the input folder name. Returns the output filename. + + This creates valid U8 archives for all purposes.""" + header = self.U8Header() + rootnode = self.U8Node() + + header.tag = "U\xAA8-" + header.rootnode_offset = 0x20 + header.zeroes = "\x00" * 16 + + self.nodes = [] + self.strings = "\x00" + self.data = "" + origdir = os.getcwd() + os.chdir(self.f) + self._pack(".", 0, 1) + os.chdir(origdir) + + header.header_size = (len(self.nodes) + 1) * len(rootnode) + len(self.strings) + header.data_offset = align(header.header_size + header.rootnode_offset, 64) + rootnode.size = len(self.nodes) + 1 + rootnode.type = 0x0100 + + for i in range(len(self.nodes)): + if(self.nodes[i].type == 0x0000): + self.nodes[i].data_offset += header.data_offset + + if(fn == ""): + if(self.f[len(self.f) - 4:] == "_out"): + fn = os.path.dirname(self.f) + "/" + os.path.basename(self.f)[:-4].replace("_", ".") + else: + fn = self.f + + fd = open(fn, "wb") + fd.write(header.pack()) + fd.write(rootnode.pack()) + for node in self.nodes: + fd.write(node.pack()) + fd.write(self.strings) + fd.write("\x00" * (header.data_offset - header.rootnode_offset - header.header_size)) + fd.write(self.data) + fd.close() + + return fn + + def unpack(self, fn = ""): + """This will unpack the U8 archive specified by the initialization parameter into either the folder specified by the parameter fn, or into a folder created with this formula: + ``filename_extension_out`` + + This will recreate the directory structure, including the initial root folder in the U8 archive (such as "arc" or "meta"). Returns the output directory name.""" + data = open(self.f, "rb").read() + + offset = 0 + + header = self.U8Header() + header.unpack(data[offset:offset + len(header)]) + offset += len(header) + + if(header.tag != "U\xAA8-"): + raise NameError("Bad U8 Tag") + offset = header.rootnode_offset + + rootnode = self.U8Node() + rootnode.unpack(data[offset:offset + len(rootnode)]) + offset += len(rootnode) + + nodes = [] + for i in range(rootnode.size - 1): + node = self.U8Node() + node.unpack(data[offset:offset + len(node)]) + offset += len(node) + nodes.append(node) + + strings = data[offset:offset + header.data_offset - len(header) - (len(rootnode) * rootnode.size)] + offset += len(strings) + + if(fn == ""): + fn = os.path.dirname(self.f) + "/" + os.path.basename(self.f).replace(".", "_") + "_out" + try: + origdir = os.getcwd() + os.mkdir(fn) + except: + pass + os.chdir(fn) + + recursion = [rootnode.size] + counter = 0 + for node in nodes: + counter += 1 + name = strings[node.name_offset:].split('\0', 1)[0] + + if(node.type == 0x0100): #folder + recursion.append(node.size) + try: + os.mkdir(name) + except: + pass + os.chdir(name) + continue + elif(node.type == 0): #file + file = open(name, "wb") + file.write(data[node.data_offset:node.data_offset + node.size]) + offset += node.size + else: #unknown + pass #ignore + + sz = recursion.pop() + if(sz == counter + 1): + os.chdir("..") + else: + recursion.append(sz) + os.chdir("..") + + os.chdir(origdir) + return fn + def __str__(self): + data = open(self.f, "rb").read() + + offset = 0 + + header = self.U8Header() + header.unpack(data[offset:offset + len(header)]) + offset += len(header) + + if(header.tag != "U\xAA8-"): + raise NameError("Bad U8 Tag") + offset = header.rootnode_offset + + rootnode = self.U8Node() + rootnode.unpack(data[offset:offset + len(rootnode)]) + offset += len(rootnode) + + nodes = [] + for i in xrange(rootnode.size - 1): + node = self.U8Node() + node.unpack(data[offset:offset + len(node)]) + offset += len(node) + nodes.append(node) + + strings = data[offset:offset + header.data_offset - len(header) - (len(rootnode) * rootnode.size)] + offset += len(strings) + + out = "[root]\n" + recursion = [rootnode.size] + counter = 0 + for node in nodes: + counter += 1 + name = strings[node.name_offset:].split('\0', 1)[0] + out += " " * len(recursion) + if(node.type == 0x0100): #folder + recursion.append(node.size) + out += "[%s]\n" % name + continue + elif(node.type == 0): #file + out += "%s\n" % name + offset += node.size + else: #unknown, ignore + pass + + sz = recursion.pop() + if(sz == counter + 1): + pass + else: + recursion.append(sz) + return out + +class WAD: + """This class is to pack and unpack WAD files, which store a single title. You pass the input filename or input directory name to the parameter f. + + WAD packing support currently creates WAD files that return -4100 on install.""" + def __init__(self, f, boot2 = False): + self.f = f + self.boot2 = boot2 + def pack(self, fn = "", fakesign = True, decrypted = True): + """Packs a WAD into the filename specified by fn, if it is not empty. If it is empty, it packs into a filename generated from the folder's name. If fakesign is True, it will fakesign the Ticket and TMD, and update them as needed. If decrypted is true, it will assume the contents are already decrypted. For now, fakesign can not be True if decrypted is False, however fakesign can be False if decrypted is True. Title ID is a long integer of the destination title id.""" + os.chdir(self.f) + + tik = Ticket("tik") + tmd = TMD("tmd") + titlekey = tik.getTitleKey() + contents = tmd.getContents() + + apppack = "" + for content in contents: + tmpdata = open("%08x.app" % content.index, "rb").read() + + if(decrypted): + if(fakesign): + content.hash = str(Crypto().createSHAHash(tmpdata)) + content.size = len(tmpdata) + + encdata = Crypto().encryptContent(titlekey, content.index, tmpdata) + else: + encdata = tmpdata + + apppack += encdata + if(len(encdata) % 64 != 0): + apppack += "\x00" * (64 - (len(encdata) % 64)) + + if(fakesign): + tmd.setContents(contents) + tmd.dump() + tik.dump() + + rawtmd = open("tmd", "rb").read() + rawcert = open("cert", "rb").read() + rawtik = open("tik", "rb").read() + + sz = 0 + for i in range(len(contents)): + sz += contents[i].size + if(sz % 64 != 0): + sz += 64 - (contents[i].size % 64) + + if(self.boot2 != True): + pack = struct.pack('>I4s6I', 32, "Is\x00\x00", len(rawcert), 0, len(rawtik), len(rawtmd), sz, 0) + pack += "\x00" * 32 + else: + pack = struct.pack('>IIIII12s', 32, align(len(rawcert) + len(rawtik) + len(rawtmd), 0x40), len(rawcert), len(rawtik), len(rawtmd), "\x00" * 12) + + pack += rawcert + if(len(rawcert) % 64 != 0 and self.boot2 != True): + pack += "\x00" * (64 - (len(rawcert) % 64)) + pack += rawtik + if(len(rawtik) % 64 != 0 and self.boot2 != True): + pack += "\x00" * (64 - (len(rawtik) % 64)) + pack += rawtmd + if(len(rawtmd) % 64 != 0 and self.boot2 != True): + pack += "\x00" * (64 - (len(rawtmd) % 64)) + + if(self.boot2 == True): + pack += "\x00" * (align(len(rawcert) + len(rawtik) + len(rawtmd), 0x40) - (len(rawcert) + len(rawtik) + len(rawtmd))) + + pack += apppack + + os.chdir('..') + if(fn == ""): + if(self.f[len(self.f) - 4:] == "_out"): + fn = os.path.dirname(self.f) + "/" + os.path.basename(self.f)[:len(os.path.basename(self.f)) - 4].replace("_", ".") + else: + fn = self.f + open(fn, "wb").write(pack) + return fn + def unpack(self, fn = ""): + """Unpacks the WAD from the parameter f in the initializer to either the value of fn, if there is one, or a folder created with this formula: `filename_extension_out`. Certs are put in the file "cert", TMD in the file "tmd", ticket in the file "tik", and contents are put in the files based on index and with ".app" added to the end.""" + fd = open(self.f, 'rb') + if(self.boot2 != True): + headersize, wadtype, certsize, reserved, tiksize, tmdsize, datasize, footersize, padding= struct.unpack('>I4s6I32s', fd.read(64)) + else: + headersize, data_offset, certsize, tiksize, tmdsize, padding = struct.unpack('>IIIII12s', fd.read(32)) + + try: + if(fn == ""): + fn = self.f.replace(".", "_") + "_out" + os.mkdir(fn) + except OSError: + pass + os.chdir(fn) + + rawcert = fd.read(certsize) + if(self.boot2 != True): + if(certsize % 64 != 0): + fd.seek(64 - (certsize % 64), 1) + open('cert', 'wb').write(rawcert) + + rawtik = fd.read(tiksize) + if(self.boot2 != True): + if(tiksize % 64 != 0): + fd.seek(64 - (tiksize % 64), 1) + open('tik', 'wb').write(rawtik) + + rawtmd = fd.read(tmdsize) + if(self.boot2 == True): + fd.seek(data_offset) + else: + fd.seek(64 - (tmdsize % 64), 1) + open('tmd', 'wb').write(rawtmd) + + titlekey = Ticket("tik").getTitleKey() + contents = TMD("tmd").getContents() + for i in range(0, len(contents)): + tmpsize = contents[i].size + if(tmpsize % 16 != 0): + tmpsize += 16 - (tmpsize % 16) + tmptmpdata = fd.read(tmpsize) + tmpdata = Crypto().decryptContent(titlekey, contents[i].index, tmptmpdata) + open("%08x.app" % contents[i].index, "wb").write(tmpdata) + if(tmpsize % 64 != 0): + fd.seek(64 - (tmpsize % 64), 1) + fd.close() + os.chdir('..') + + return fn + def __str__(self): + out = "" + out += "Wii WAD:\n" + fd = open(self.f, 'rb') + + if(self.boot2 != True): + headersize, wadtype, certsize, reserved, tiksize, tmdsize, datasize, footersize, padding= struct.unpack('>I4s6I32s', fd.read(64)) + else: + headersize, data_offset, certsize, tiksize, tmdsize, padding = struct.unpack('>IIIII12s', fd.read(32)) + + rawcert = fd.read(certsize) + if(certsize % 64 != 0): + fd.seek(64 - (certsize % 64), 1) + rawtik = fd.read(tiksize) + if(self.boot2 != True): + if(tiksize % 64 != 0): + fd.seek(64 - (tiksize % 64), 1) + rawtmd = fd.read(tmdsize) + + if(self.boot2 != True): + out += " Header %02x Type '%s' Certs %x Tiket %x TMD %x Data %x Footer %x\n" % (headersize, wadtype, certsize, tiksize, tmdsize, datasize, footersize) + else: + out += " Header %02x Type 'boot2' Certs %x Tiket %x TMD %x Data @ %x\n" % (headersize, certsize, tiksize, tmdsize, data_offset) + + out += str(Ticket(rawtik)) + out += str(TMD(rawtmd)) + + return out + + +class CCF(): + class CCFHeader(Struct): + __endian__ = Struct.LE + def __format__(self): + self.magic = Struct.string(4) + self.zeroes12 = Struct.string(12) + self.rootOffset = Struct.uint32 + self.filesCount = Struct.uint32 + self.zeroes8 = Struct.string(8) + + class CCFFile(Struct): + __endian__ = Struct.LE + def __format__(self): + self.fileName = Struct.string(20) + self.fileOffset = Struct.uint32 + self.fileSize = Struct.uint32 + self.fileSizeDecompressed = Struct.uint32 + + def __init__(self, fileName): + self.fileName = fileName + self.fd = open(fileName, 'r+b') + + def compress(self, folder): + fileList = [] + + fileHdr = self.CCFHeader() + + files = os.listdir(folder) + + fileHdr.magic = "\x43\x43\x46\x00" + fileHdr.zeroes12 = '\x00' * 12 + fileHdr.rootOffset = 0x20 + fileHdr.zeroes8 = '\x00' * 8 + + currentOffset = len(fileHdr) + packedFiles = 0 + previousFileEndOffset = 0 + + for file in files: + if os.path.isdir(folder + '/' + file) or file == '.DS_Store': + continue + else: + fileList.append(file) + + fileHdr.filesCount = len(fileList) + self.fd.write(fileHdr.pack()) + self.fd.write('\x00' * (fileHdr.filesCount * len(self.CCFFile()))) + + for fileNumber in range(len(fileList)): + + fileEntry = self.CCFFile() + + compressedBuffer = zlib.compress(open(folder + '/' + fileList[fileNumber]).read()) + + fileEntry.fileName = fileList[fileNumber] + fileEntry.fileSize = len(compressedBuffer) + fileEntry.fileSizeDecompressed = os.stat(folder + '/' + fileList[fileNumber]).st_size + fileEntry.fileOffset = align(self.fd.tell(), 32) / 32 + + print 'File {0} ({1}Kb) placed at offset 0x{2:X}'.format(fileEntry.fileName, fileEntry.fileSize / 1024, fileEntry.fileOffset * 32) + + self.fd.seek(len(fileHdr) + fileNumber * len(self.CCFFile())) + self.fd.write(fileEntry.pack()) + self.fd.seek(fileEntry.fileOffset * 32) + self.fd.write(compressedBuffer) + + self.fd.close() + + def decompress(self): + fileHdr = self.CCFHeader() + hdrData = self.fd.read(len(fileHdr)) + fileHdr.unpack(hdrData) + + print 'Found {0} file/s and root node at 0x{1:X}'.format(fileHdr.filesCount, fileHdr.rootOffset) + + if fileHdr.magic != "\x43\x43\x46\x00": + raise ValueError("Wrong magic, 0x{0}".format(fileHdr.magic)) + + try: + os.mkdir(os.path.dirname(self.fileName) + '/' + self.fd.name.replace(".", "_") + "_out") + except: + pass + + os.chdir(os.path.dirname(self.fileName) + '/' + self.fd.name.replace(".", "_") + "_out") + + currentOffset = len(fileHdr) + + for x in range(fileHdr.filesCount): + self.fd.seek(currentOffset) + + fileEntry = self.CCFFile() + fileData = self.fd.read(len(fileEntry)) + fileEntry.unpack(fileData) + + fileEntry.fileOffset = fileEntry.fileOffset * 32 + + print 'File {0} at offset 0x{1:X}'.format(fileEntry.fileName, fileEntry.fileOffset) + print 'File size {0}Kb ({1}Kb decompressed)'.format(fileEntry.fileSize / 1024, fileEntry.fileSizeDecompressed / 1024) + + output = open(fileEntry.fileName.rstrip('\0'), 'w+b') + + self.fd.seek(fileEntry.fileOffset) + if fileEntry.fileSize == fileEntry.fileSizeDecompressed: + print 'The file is stored uncompressed' + output.write(self.fd.read(fileEntry.fileSize)) + else: + print 'The file is stored compressed..decompressing' + decompressedBuffer = zlib.decompress(self.fd.read(fileEntry.fileSize)) + output.write(decompressedBuffer) + output.close() + + currentOffset += len(fileEntry) + diff --git a/common.py b/common.py index e1bcd61..94fcac8 100644 --- a/common.py +++ b/common.py @@ -1,14 +1,14 @@ -import os, hashlib, struct, subprocess, fnmatch, shutil, urllib, array +import os, hashlib, struct, subprocess, fnmatch, shutil, urllib, array, time, sys, tempfile from Crypto.Cipher import AES +from PIL import Image + from Struct import Struct - def align(x, boundary): - if(x % boundary == 0): - return x - else: - return (x + boundary) - (x % boundary) + if(x % boundary): + x += (x + boundary) - (x % boundary) + return x def hexdump(s, sep=" "): return sep.join(map(lambda x: "%02x" % ord(x), s)) diff --git a/compression.py b/compression.py index 880c434..ca767b2 100644 --- a/compression.py +++ b/compression.py @@ -1,123 +1,4 @@ -import os, struct, subprocess, fnmatch, shutil, urllib, array - -import zlib -from Struct import Struct - from common import * - -class CCF(): - class CCFHeader(Struct): - __endian__ = Struct.LE - def __format__(self): - self.magic = Struct.string(4) - self.zeroes12 = Struct.string(12) - self.rootOffset = Struct.uint32 - self.filesCount = Struct.uint32 - self.zeroes8 = Struct.string(8) - - class CCFFile(Struct): - __endian__ = Struct.LE - def __format__(self): - self.fileName = Struct.string(20) - self.fileOffset = Struct.uint32 - self.fileSize = Struct.uint32 - self.fileSizeDecompressed = Struct.uint32 - - def __init__(self, fileName): - self.fileName = fileName - self.fd = open(fileName, 'r+b') - - def compress(self, folder): - fileList = [] - - fileHdr = self.CCFHeader() - - files = os.listdir(folder) - - fileHdr.magic = "\x43\x43\x46\x00" - fileHdr.zeroes12 = '\x00' * 12 - fileHdr.rootOffset = 0x20 - fileHdr.zeroes8 = '\x00' * 8 - - currentOffset = len(fileHdr) - packedFiles = 0 - previousFileEndOffset = 0 - - for file in files: - if os.path.isdir(folder + '/' + file) or file == '.DS_Store': - continue - else: - fileList.append(file) - - fileHdr.filesCount = len(fileList) - self.fd.write(fileHdr.pack()) - self.fd.write('\x00' * (fileHdr.filesCount * len(self.CCFFile()))) - - for fileNumber in range(len(fileList)): - - fileEntry = self.CCFFile() - - compressedBuffer = zlib.compress(open(folder + '/' + fileList[fileNumber]).read()) - - fileEntry.fileName = fileList[fileNumber] - fileEntry.fileSize = len(compressedBuffer) - fileEntry.fileSizeDecompressed = os.stat(folder + '/' + fileList[fileNumber]).st_size - fileEntry.fileOffset = align(self.fd.tell(), 32) / 32 - - print 'File {0} ({1}Kb) placed at offset 0x{2:X}'.format(fileEntry.fileName, fileEntry.fileSize / 1024, fileEntry.fileOffset * 32) - - self.fd.seek(len(fileHdr) + fileNumber * len(self.CCFFile())) - self.fd.write(fileEntry.pack()) - self.fd.seek(fileEntry.fileOffset * 32) - self.fd.write(compressedBuffer) - - self.fd.close() - - def decompress(self): - fileHdr = self.CCFHeader() - hdrData = self.fd.read(len(fileHdr)) - fileHdr.unpack(hdrData) - - print 'Found {0} file/s and root node at 0x{1:X}'.format(fileHdr.filesCount, fileHdr.rootOffset) - - if fileHdr.magic != "\x43\x43\x46\x00": - raise ValueError("Wrong magic, 0x{0}".format(fileHdr.magic)) - - try: - os.mkdir(os.path.dirname(self.fileName) + '/' + self.fd.name.replace(".", "_") + "_out") - except: - pass - - os.chdir(os.path.dirname(self.fileName) + '/' + self.fd.name.replace(".", "_") + "_out") - - currentOffset = len(fileHdr) - - for x in range(fileHdr.filesCount): - self.fd.seek(currentOffset) - - fileEntry = self.CCFFile() - fileData = self.fd.read(len(fileEntry)) - fileEntry.unpack(fileData) - - fileEntry.fileOffset = fileEntry.fileOffset * 32 - - print 'File {0} at offset 0x{1:X}'.format(fileEntry.fileName, fileEntry.fileOffset) - print 'File size {0}Kb ({1}Kb decompressed)'.format(fileEntry.fileSize / 1024, fileEntry.fileSizeDecompressed / 1024) - - output = open(fileEntry.fileName.rstrip('\0'), 'w+b') - - self.fd.seek(fileEntry.fileOffset) - if fileEntry.fileSize == fileEntry.fileSizeDecompressed: - print 'The file is stored uncompressed' - output.write(self.fd.read(fileEntry.fileSize)) - else: - print 'The file is stored compressed..decompressing' - decompressedBuffer = zlib.decompress(self.fd.read(fileEntry.fileSize)) - output.write(decompressedBuffer) - output.close() - - currentOffset += len(fileEntry) - class LZ77(): class WiiLZ77: #class by marcan diff --git a/disc.py b/disc.py index 5205e47..27f14be 100644 --- a/disc.py +++ b/disc.py @@ -1,11 +1,5 @@ -import os, struct, subprocess, fnmatch, shutil, urllib, array - -import time -from title import * -from Struct import Struct - from common import * - +from title import * class WOD: #WiiOpticalDisc class discHeader(Struct): diff --git a/experimental/breff.py b/experimental/breff.py index ef17c7d..484ebaf 100755 --- a/experimental/breff.py +++ b/experimental/breff.py @@ -15,6 +15,7 @@ class BREFF(object): class BREFF_REFF_Section2(Struct): __endian__ = Struct.BE def __format__(self): + self.unknown00 = Struct.uint32 self.unknown01 = Struct.uint32 self.unknown02 = Struct.uint32 self.unk03p1 = Struct.uint16 @@ -23,7 +24,7 @@ class BREFF(object): self.unk04p2 = Struct.uint16 self.unknown05 = Struct.uint32 self.unknown06 = Struct.float - self.unknown07 = Struct.uint32 + self.unknown07 = Struct.float self.unknown08 = Struct.uint32 self.unknown09 = Struct.uint32 self.unknown10 = Struct.float @@ -98,19 +99,19 @@ class BREFF(object): self.unknown78 = Struct.uint32 self.unknown79 = Struct.uint32 self.unknown80 = Struct.uint32 - self.unknown81 = Struct.uint32 - self.unknown82 = Struct.uint32 - self.unknown83 = Struct.uint32 - self.unknown84 = Struct.uint32 + self.unknown81 = Struct.float + self.unknown82 = Struct.float + self.unknown83 = Struct.float + self.unknown84 = Struct.float self.unknown85 = Struct.uint32 self.unknown86 = Struct.uint32 self.unknown87 = Struct.uint32 - self.unknown88 = Struct.uint32 - self.unknown89 = Struct.uint32 - self.unknown90 = Struct.uint32 - self.unknown91 = Struct.uint32 - self.unknown92 = Struct.uint32 - self.unknown93 = Struct.uint32 + self.unknown88 = Struct.float + self.unknown89 = Struct.float + self.unknown90 = Struct.float + self.unknown91 = Struct.float + self.unknown92 = Struct.float + self.unknown93 = Struct.float self.unknown94 = Struct.uint32 self.unknown95 = Struct.uint32 self.unknown96 = Struct.uint32 @@ -129,49 +130,49 @@ class BREFF(object): self.unknownA9 = Struct.uint32 self.unknownB0 = Struct.uint32 self.unknownB1 = Struct.uint32 - self.unknownB2 = Struct.uint32 def __str__(self): - return_string = "Unknown01: %08x\talways 00000128 ?\n" % self.unknown01 + return_string = "Unknown00: %08x\n" % self.unknown00 + return_string += "Unknown01: %08x\talways 00000128 ?\n" % self.unknown01 return_string += "Unknown02: %08x\talways 80000xxx ?\n" % self.unknown02 return_string += "Unknown03: %04x\t%04x\n" % (self.unk03p1 , self.unk03p2) return_string += "Unknown04: %.2d\t%04x\n" % (self.unk04p1 , self.unk04p2) return_string += "Unknown05: %08x\n" % self.unknown05 return_string += "Unknown06: %.9f\n" % self.unknown06 - return_string += "Unknown07: %08x\n" % self.unknown07 + return_string += "Unknown07: %f\n" % self.unknown07 return_string += "Unknown08: %08x\n" % self.unknown08 return_string += "Unknown09: %08x\n" % self.unknown09 - return_string += "Unknown10: %.9f\n" % self.unknown10 - return_string += "Unknown11: %.9f\n" % self.unknown11 - return_string += "Unknown12: %08x\n" % self.unknown12 - return_string += "Unknown13: %.9f\n" % self.unknown13 + return_string += "Size Outer Radius X: %.9f\n" % self.unknown10 + return_string += "Size Outer Radius Y: %.9f\n" % self.unknown11 + return_string += "Size Outer Radius Z: %.9f\n" % self.unknown12 + return_string += "Inner Radius: %.9f\n" % self.unknown13 return_string += "Unknown14: %08x\n" % self.unknown14 return_string += "Unknown15: %08x\n" % self.unknown15 return_string += "Unknown16: %04x\t%04x\n" % (self.unk16p1, self.unk16p2) - return_string += "Unknown17: %.9f\n" % self.unknown17 - return_string += "Unknown18: %.9f\n" % self.unknown18 - return_string += "Unknown19: %08x\n" % self.unknown19 - return_string += "Unknown20: %.9f\n" % self.unknown20 + return_string += "All Direction Speed: %.9f\n" % self.unknown17 + return_string += "Y Axis Difuse Speed: %.9f\n" % self.unknown18 + return_string += "Random Direction Speed: %.9f\n" % self.unknown19 + return_string += "Normal Direction Speed: %.9f\n" % self.unknown20 return_string += "Unknown21: %.9f\n" % self.unknown21 - return_string += "Unknown22: %08x\n" % self.unknown22 + return_string += "Move to Specific Direction: %.9f\n" % self.unknown22 return_string += "Unknown23: %08x\n" % self.unknown23 return_string += "Unknown24: %.20f\n" % self.unknown24 return_string += "Unknown25: %.9f\n" % self.unknown25 return_string += "Unknown26: %08x\n" % self.unknown26 - return_string += "Unknown27: %08x\n" % self.unknown27 - return_string += "Unknown28: %08x\n" % self.unknown28 - return_string += "Unknown29: %08x\n" % self.unknown29 + return_string += "Unknown27: %.9f\n" % self.unknown27 + return_string += "Unknown28: %.9f\n" % self.unknown28 + return_string += "Unknown29: %.9f\n" % self.unknown29 return_string += "Unknown30: %08x\n" % self.unknown30 return_string += "Unknown31: %.9f\n" % self.unknown31 return_string += "Unknown32: %08x\n" % self.unknown32 - return_string += "Unknown33: %08x\n" % self.unknown33 + return_string += "Four Bytes: %08x\n" % self.unknown33 return_string += "Unknown34: %08x\n" % self.unknown34 return_string += "Unknown35: %08x\n" % self.unknown35 return_string += "Unknown36: %08x\n" % self.unknown36 - return_string += "Unknown37: %.9f\n" % self.unknown37 - return_string += "Unknown38: %.9f\n" % self.unknown38 - return_string += "Unknown39: %.9f\n" % self.unknown39 - return_string += "Unknown40: %.9f\n" % self.unknown40 - return_string += "Unknown41: %.9f\n" % self.unknown41 + return_string += "Transform Scale X: %.9f\n" % self.unknown37 + return_string += "Transform Scale Y: %.9f\n" % self.unknown38 + return_string += "Transform Scale Z: %.9f\n" % self.unknown39 + return_string += "Center of Particle SRT Horiz: %.9f\n" % self.unknown40 + return_string += "Center of Particle SRT Vert: %.9f\n" % self.unknown41 return_string += "Unknown42: %08x\n" % self.unknown42 return_string += "Unknown43: %08x\n" % self.unknown43 return_string += "Unknown44: %.9f\n" % self.unknown44 @@ -211,19 +212,19 @@ class BREFF(object): return_string += "Unknown78: %08x\n" % self.unknown78 return_string += "Unknown79: %08x\n" % self.unknown79 return_string += "Unknown80: %08x\n" % self.unknown80 - return_string += "Unknown81: %08x\n" % self.unknown81 - return_string += "Unknown82: %08x\n" % self.unknown82 - return_string += "Unknown83: %08x\n" % self.unknown83 - return_string += "Unknown84: %08x\n" % self.unknown84 + return_string += "Unknown81: %.9f\n" % self.unknown81 + return_string += "Unknown82: %.9f\n" % self.unknown82 + return_string += "Unknown83: %.9f\n" % self.unknown83 + return_string += "Unknown84: %.9f\n" % self.unknown84 return_string += "Unknown85: %08x\n" % self.unknown85 return_string += "Unknown86: %08x\n" % self.unknown86 return_string += "Unknown87: %08x\n" % self.unknown87 - return_string += "Unknown88: %08x\n" % self.unknown88 - return_string += "Unknown89: %08x\n" % self.unknown89 - return_string += "Unknown90: %08x\n" % self.unknown90 - return_string += "Unknown91: %08x\n" % self.unknown91 - return_string += "Unknown92: %08x\n" % self.unknown92 - return_string += "Unknown93: %08x\n" % self.unknown93 + return_string += "Unknown88: %.9f\n" % self.unknown88 + return_string += "Unknown89: %.9f\n" % self.unknown89 + return_string += "Unknown90: %.9f\n" % self.unknown90 + return_string += "Unknown91: %.9f\n" % self.unknown91 + return_string += "Unknown92: %.9f\n" % self.unknown92 + return_string += "Unknown93: %.9f\n" % self.unknown93 return_string += "Unknown94: %08x\n" % self.unknown94 return_string += "Unknown95: %08x\n" % self.unknown95 return_string += "Unknown96: %08x\n" % self.unknown96 @@ -242,7 +243,6 @@ class BREFF(object): return_string += "UnknownA9: %08x\n" % self.unknownA9 return_string += "UnknownB0: %08x\n" % self.unknownB0 return_string += "UnknownB1: %08x\n" % self.unknownB1 - return_string += "UnknownB2: %08x\n" % self.unknownB2 return return_string class BREFF_REFF_StringSection1(Struct): @@ -260,11 +260,9 @@ class BREFF(object): def __format__(self): self.magic = Struct.string(4) self.length = Struct.uint32 - self.chunk_cnt = Struct.uint32 def __str__(self): return_string = "Magic: %s\n" % self.magic return_string += "Length: %08x\n" % self.length - return_string += "Chunk Count: %08x\n" % self.chunk_cnt return return_string class BREFF_Header(Struct): @@ -302,6 +300,10 @@ class BREFF(object): print reff assert reff.magic == "REFF" + temp = pos + project = Struct.uint32(data[pos:pos+4], endian='>') + pos += 4 + print "Header Size: %08x" % project unknown = Struct.uint32(data[pos:pos+4], endian='>') pos += 4 print "Unknown: %08x" % unknown @@ -315,12 +317,23 @@ class BREFF(object): pos += 2 print "Unknown: %04x" % unknown string = data[pos:pos+str_length-1] - pos += str_length + (2 - (str_length % 2)) + pos += str_length print "String: %s\n" % string - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Offset or Length: %08x" % unknown + while pos % 2: + unknown = Struct.uint8(data[pos:pos+1]) + pos += 1 + print "Padding: %02x" % unknown + + print "\n%08x\n" % pos + temp = pos + + unknown = Struct.uint16(data[pos:pos+2], endian='>') + pos += 2 + print "Offset: %04x" % unknown + unknown = Struct.uint16(data[pos:pos+2], endian='>') + pos += 2 + print "Length: %04x" % unknown print "\n%08x\n" % pos @@ -349,16 +362,16 @@ class BREFF(object): print "\n%08x\n" % pos - while pos % 0x10: + while pos % 0x04: padding = Struct.uint8(data[pos:pos+1]) pos += 1 print "Padding: %02x" % padding print "\n%08x\n" % pos - assert pos == string_groups[0].offset + 0x34 + assert pos == string_groups[0].offset + temp for x in xrange(string_cnt): - pos = 0x34 + string_groups[x].offset + pos = temp + string_groups[x].offset reff_section2 = self.BREFF_REFF_Section2() reff_section2.unpack(data[pos:pos+len(reff_section2)]) pos += len(reff_section2) @@ -372,39 +385,39 @@ class BREFF(object): unknown = Struct.uint32(data[pos:pos+4], endian='>') pos += 4 print "Unknown02: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') + unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 - print "Unknown03: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') + print "Unknown03: %f" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 - print "Unknown04: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') + print "Unknown04: %f" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 - print "Unknown05: %08x" % unknown + print "Unknown05: %f" % unknown unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 print "Unknown06: %f" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') + unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 - print "Unknown07: %08x" % unknown + print "Unknown07: %f" % unknown unknown = Struct.uint32(data[pos:pos+4], endian='>') pos += 4 print "Unknown08: %08x" % unknown unknown = Struct.uint32(data[pos:pos+4], endian='>') pos += 4 print "Unknown09: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown10: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown11: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') - pos += 4 - print "Unknown12: %08x" % unknown unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 - print "PI TIMES 2 BITCHES: %.20f" % unknown + print "Size Outer Radius X: %f" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') + pos += 4 + print "Size Outer Radius Y: %f" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') + pos += 4 + print "Size Outer Radius Z: %f" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') + pos += 4 + print "Inner Radius: %f" % unknown unknown = Struct.uint32(data[pos:pos+4], endian='>') pos += 4 print "Unknown14: %08x" % unknown @@ -414,24 +427,24 @@ class BREFF(object): unknown = Struct.uint32(data[pos:pos+4], endian='>') pos += 4 print "Unknown16: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') + unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 - print "Unknown17: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') + print "All Direction Speed: %f" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 - print "Unknown18: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') + print "Y Axis Difuse Speed: %f" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 - print "Unknown19: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') + print "Random Direction Speed: %f" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 - print "Unknown20: %08x" % unknown + print "Normal Direction Speed: %f" % unknown unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 print "PI DIVIDED BY 4 BITCHES: %.20f" % unknown unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 - print "Unknown22: %f" % unknown + print "Move to specific direction: %f" % unknown unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 print "Unknown23: %f" % unknown @@ -444,15 +457,15 @@ class BREFF(object): unknown = Struct.uint32(data[pos:pos+4], endian='>') pos += 4 print "Unknown26: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') + unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 - print "Unknown27: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') + print "Unknown27: %f" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 - print "Unknown28: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') + print "Unknown28: %f" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 - print "Unknown29: %08x" % unknown + print "Unknown29: %f" % unknown unknown = Struct.uint32(data[pos:pos+4], endian='>') pos += 4 print "Unknown30: %08x" % unknown @@ -464,7 +477,7 @@ class BREFF(object): print "Unknown32: %08x" % unknown unknown = Struct.uint32(data[pos:pos+4], endian='>') pos += 4 - print "Unknown33: %08x" % unknown + print "Bytes: %08x" % unknown unknown = Struct.uint32(data[pos:pos+4], endian='>') pos += 4 print "Unknown34: %08x" % unknown @@ -476,19 +489,19 @@ class BREFF(object): print "Unknown36: %08x" % unknown unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 - print "Unknown37: %f" % unknown + print "Transform Scale X: %f" % unknown unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 - print "Unknown38: %f" % unknown + print "Transform Scale Y: %f" % unknown unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 - print "Unknown39: %f" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') + print "Transform Scale Z: %f" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 - print "Unknown40: %08x" % unknown - unknown = Struct.uint32(data[pos:pos+4], endian='>') + print "Center of Particle SRT Horizontal(x): %f" % unknown + unknown = Struct.float(data[pos:pos+4], endian='>') pos += 4 - print "Unknown41: %08x" % unknown + print "Center of Particle SRT Verticle(y): %f" % unknown unknown = Struct.uint32(data[pos:pos+4], endian='>') pos += 4 print "Unknown42: %08x" % unknown @@ -512,7 +525,7 @@ class BREFF(object): print "Unknown48: %08x" % unknown LARGE TEST DATA ''' - #''' BEGIN TEST DATA + ''' BEGIN TEST DATA unknown = Struct.uint32(data[pos:pos+4], endian='>') pos += 4 print "Unknown: %08x" % unknown @@ -543,7 +556,7 @@ class BREFF(object): unknown = Struct.uint32(data[pos:pos+4], endian='>') pos += 4 print "Unknown: %08x" % unknown - #END TEST DATA ''' + END TEST DATA ''' def main(): if len(sys.argv) != 2: diff --git a/export.py b/export.py new file mode 100644 index 0000000..4e1f93d --- /dev/null +++ b/export.py @@ -0,0 +1,253 @@ +from common import * +from title import * +from image import * + +class Savegame(): + class savegameHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.savegameId = Struct.uint32[2] + self.bannerSize = Struct.uint32 + self.permissions = Struct.uint8 + self.unknown1 = Struct.uint8 + self.md5hash = Struct.string(16) + self.unknown2 = Struct.uint16 + + class savegameBanner(Struct): + __endian__ = Struct.BE + def __format__(self): + self.magic = Struct.string(4) + self.reserved = Struct.uint8[4] + self.flags = Struct.uint32 + self.reserved = Struct.uint32[5] + self.gameTitle = Struct.string(64) + self.gameSubTitle = Struct.string(64) + self.banner = Struct.string(24576) + self.icon0 = Struct.string(4608) + self.icon1 = Struct.string(4608) + self.icon2 = Struct.string(4608) + self.icon3 = Struct.string(4608) + self.icon4 = Struct.string(4608) + self.icon5 = Struct.string(4608) + self.icon6 = Struct.string(4608) + self.icon7 = Struct.string(4608) + + class backupHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.hdrSize = Struct.uint32 + self.magic = Struct.string(2) + self.version = Struct.uint16 + self.NGid = Struct.uint32 + self.filesCount = Struct.uint32 + self.filesSize = Struct.uint32 + self.unknown1 = Struct.uint32 + self.unknown2 = Struct.uint32 + self.totalSize = Struct.uint32 + self.unknown3 = Struct.uint8[64] + self.unknown4 = Struct.uint32 + self.gameId = Struct.string(4) + self.wiiMacAddr = Struct.uint8[6] + self.unknown6 = Struct.uint16 + self.padding = Struct.uint32[4] + + class fileHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.magic = Struct.uint32 + self.size = Struct.uint32 + self.permissions = Struct.uint8 + self.attribute = Struct.uint8 + self.type = Struct.uint8 + self.nameIV = Struct.string(0x45) + + def __init__(self, f): + self.f = f + try: + self.fd = open(f, 'r+b') + except: + raise Exception('Cannot open input') + + self.sdKey = '\xab\x01\xb9\xd8\xe1\x62\x2b\x08\xaf\xba\xd8\x4d\xbf\xc2\xa5\x5d' + self.sdIv = '\x21\x67\x12\xe6\xaa\x1f\x68\x9f\x95\xc5\xa2\x23\x24\xdc\x6a\x98' + + self.iconCount = 1 + + def __str__(self): + ret = '' + ret += '\nSavegame header \n' + + ret += 'Savegame ID : 0x%x%x\n' % (self.hdr.savegameId[0], self.hdr.savegameId[1]) + ret += 'Banner size : 0x%x\n' % self.hdr.bannerSize + ret += 'Permissions : 0x%x\n' % self.hdr.permissions + ret += 'Unknown : 0x%x\n' % self.hdr.unknown1 + ret += 'MD5 hash : %s\n' % hexdump(self.hdr.md5hash) + ret += 'Unknown : 0x%x\n' % self.hdr.unknown2 + + ret += '\nBanner header \n' + + ret += 'Flags : 0x%x\n' % self.bnr.flags + ret += 'Game title : %s\n' % self.bnr.gameTitle + ret += 'Game subtitle : %s\n' % self.bnr.gameSubTitle + ret += 'Icons found : %i\n' % self.iconCount + + ret += '\nBackup header \n' + + ret += 'Header size : 0x%x (+ 0x10 of padding) version 0x%x\n' % (self.bkHdr.hdrSize, self.bkHdr.version) + if self.bkHdr.gameId[3] == 'P': + ret += 'Region : PAL\n' + elif self.bkHdr.gameId[3] == 'E': + ret += 'Region : NTSC\n' + elif self.bkHdr.gameId[3] == 'J': + ret += 'Region : JAP\n' + ret += 'Game ID : %s\n' % self.bkHdr.gameId + ret += 'Wii unique ID : 0x%x\n' % self.bkHdr.NGid + ret += 'Wii MAC address %02x:%02x:%02x:%02x:%02x:%02x\n' % (self.bkHdr.wiiMacAddr[0], self.bkHdr.wiiMacAddr[1], self.bkHdr.wiiMacAddr[2], self.bkHdr.wiiMacAddr[3], self.bkHdr.wiiMacAddr[4], self.bkHdr.wiiMacAddr[5]) + ret += 'Found %i files for %i bytes\n' % (self.bkHdr.filesCount, self.bkHdr.filesSize) + ret += 'Total size : %i bytes\n' % self.bkHdr.totalSize + ret += 'This save is %i blocks wise' % (self.bkHdr.totalSize / 0x20000) + + return ret + + def extractFiles(self): + + try: + os.mkdir(os.path.dirname(self.f) + '/' + self.bkHdr.gameId) + except: + pass + + os.chdir(os.path.dirname(self.f) + '/' + self.bkHdr.gameId) + + self.fd.seek(self.fileStartOffset) + + for i in range(self.bkHdr.filesCount): + + fileHdr = self.fd.read(0x80) + fileHdr = self.fileHeader().unpack(fileHdr) + + if fileHdr.magic != 0x03adf17e: + raise Exception('Wrong file magic') + + fileHdr.size = align(fileHdr.size, 64) + + ivpos = 0 + name = "" + i = 0 + for char in list(fileHdr.nameIV): + if(char == "\x00"): + i -= 1 + ivpos = i + break + else: + name += char + i += 1 + + + fileIV = fileHdr.nameIV[ivpos:ivpos + 16] + + if len(fileIV) != 16: + raise Exception('IV alignment issue') + + if fileHdr.type == 1: + print 'Extracted %s (%ib)' % (name, fileHdr.size) + + fileBuffer = self.fd.read(fileHdr.size) + fileBuffer = Crypto().decryptData(self.sdKey, fileIV, fileBuffer, True) + try: + open(name, 'w+b').write(fileBuffer) + except: + raise Exception('Cannot write the output') + elif fileHdr.type == 2: + print 'Extracted folder %s' % name + try: + os.mkdir(name) + except: + pass + + print 'Attribute %i Permission %i' % (fileHdr.attribute, fileHdr.permissions) + print 'File IV : 0x%s' % hexdump(fileIV, '') + + os.chdir('..') + + def analyzeHeader(self): + headerBuffer = self.fd.read(0xF0C0) + headerBuffer = Crypto().decryptData(self.sdKey, self.sdIv, headerBuffer, True) + + self.hdr = self.savegameHeader().unpack(headerBuffer[:0x20]) + + #headerBuffer.replace(self.hdr.md5hash, '\x0e\x65\x37\x81\x99\xbe\x45\x17\xab\x06\xec\x22\x45\x1a\x57\x93') + #print 'Reashed md5 : %s' % hexdump(Crypto().createMD5Hash(headerBuffer)) + + self.bnr = self.savegameBanner().unpack(headerBuffer[0x20:]) + + if self.bnr.magic != 'WIBN': + raise Exception ('Wrong magic, should be WIBN') + + if self.hdr.bannerSize != 0x72A0: + self.iconCount += 7 + + bkHdrBuffer = self.fd.read(0x80) + self.bkHdr = self.backupHeader().unpack(bkHdrBuffer) + + if self.bkHdr.magic != 'Bk' or self.bkHdr.hdrSize != 0x70: + raise Exception ('Bk header error') + + self.fileStartOffset = self.fd.tell() + + def eraseWiiMac(self): + self.fd.seek(0xF128) + print self.fd.write('\x00' * 6) + + def getBanner(self): + try: + os.mkdir(os.path.dirname(self.f) + '/' + self.bkHdr.gameId) + except: + pass + + os.chdir(os.path.dirname(self.f) + '/' + self.bkHdr.gameId) + + return Image.fromstring("RGBA", (192, 64), TPL('').RGB5A3((192, 64), self.bnr.banner)).save('banner', 'png') + + def getIcon(self, index): + if index < 0 or index > 7 or index > self.iconCount: + return -1 + + try: + os.mkdir(os.path.dirname(self.f) + '/' + self.bkHdr.gameId) + except: + pass + + os.chdir(os.path.dirname(self.f) + '/' + self.bkHdr.gameId) + + if index == 0: + return Image.fromstring("RGBA", (48, 48), TPL('').RGB5A3((48, 48), self.bnr.icon0)).save('icon' + str(index), 'png') + if index == 1: + return Image.fromstring("RGBA", (48, 48), TPL('').RGB5A3((48, 48), self.bnr.icon1)).save('icon' + str(index), 'png') + if index == 2: + return Image.fromstring("RGBA", (48, 48), TPL('').RGB5A3((48, 48), self.bnr.icon2)).save('icon' + str(index), 'png') + if index == 3: + return Image.fromstring("RGBA", (48, 48), TPL('').RGB5A3((48, 48), self.bnr.icon3)).save('icon' + str(index), 'png') + if index == 4: + return Image.fromstring("RGBA", (48, 48), TPL('').RGB5A3((48, 48), self.bnr.icon4)).save('icon' + str(index), 'png') + if index == 5: + return Image.fromstring("RGBA", (48, 48), TPL('').RGB5A3((48, 48), self.bnr.icon5)).save('icon' + str(index), 'png') + if index == 6: + return Image.fromstring("RGBA", (48, 48), TPL('').RGB5A3((48, 48), self.bnr.icon6)).save('icon' + str(index), 'png') + if index == 7: + return Image.fromstring("RGBA", (48, 48), TPL('').RGB5A3((48, 48), self.bnr.icon7)).save('icon' + str(index), 'png') + + def getIconsCount(self): + return self.iconCount + + def getSaveString(self, string): + if string == 'id': + return self.bkHdr.gameId + elif string == 'title': + return self.bnr.gameTitle + elif string == 'subtitle': + return self.bnr.gameSubTitle + elif string == 'mac': + return self.bkHdr.wiiMacAddr[0] + ':' + self.bkHdr.wiiMacAddr[1] + ':' + self.bkHdr.wiiMacAddr[2] + ':' + self.bkHdr.wiiMacAddr[3] + ':' + self.bkHdr.wiiMacAddr[4] + ':' + self.bkHdr.wiiMacAddr[5] + + def getFilesCount(self): + return self.bkHdr.filesCount diff --git a/formats.py b/formats.py index 991ee0a..0446a5c 100644 --- a/formats.py +++ b/formats.py @@ -1,8 +1,5 @@ -import os, struct, subprocess, fnmatch, shutil, urllib, array from binascii import * - -from Struct import Struct -from struct import * +import struct from common import * from title import * @@ -12,7 +9,7 @@ class locDat: def __format__(self): self.magic = Struct.string(4) self.md5 = Struct.string(16) - + def __init__(self, f): self.sdKey = '\xab\x01\xb9\xd8\xe1\x62\x2b\x08\xaf\xba\xd8\x4d\xbf\xc2\xa5\x5d' self.sdIv = '\x21\x67\x12\xe6\xaa\x1f\x68\x9f\x95\xc5\xa2\x23\x24\xdc\x6a\x98' @@ -335,7 +332,7 @@ class netConfig: def getNotBlank(self, config): fp = open(self.f, "rb") fp.seek(8 + (0x91C * config)) - sel = unpack(">B", fp.read(1))[0] + sel = struct.unpack(">B", fp.read(1))[0] fp.close() if(sel & 0x20): return 1 @@ -347,7 +344,7 @@ class netConfig: return None fp = open(self.f, "rb") fp.seek(8 + (0x91C * config)) - sel = unpack(">B", fp.read(1))[0] + sel = struct.unpack(">B", fp.read(1))[0] if(sel & 0x04): return 0 else: @@ -360,7 +357,7 @@ class netConfig: return None fp = open(self.f, "rb") fp.seek(8 + (0x91C * config)) - sel = unpack(">B", fp.read(1))[0] + sel = struct.unpack(">B", fp.read(1))[0] if(sel & 0x02): return 0 else: @@ -372,7 +369,7 @@ class netConfig: return None fp = open(self.f, "rb") fp.seek(8 + (0x91C * config) + 2021) - len = unpack(">B", fp.read(1))[0] + len = struct.unpack(">B", fp.read(1))[0] fp.seek(8 + (0x91C * config) + 1988) ssid = fp.read(len) fp.close() @@ -383,7 +380,7 @@ class netConfig: return None fp = open(self.f, "rb") fp.seek(8 + (0x91C * config) + 2025) - crypt = unpack(">B", fp.read(1))[0] + crypt = struct.unpack(">B", fp.read(1))[0] type = "" if(crypt == 0): type = "OPEN" @@ -407,7 +404,7 @@ class netConfig: return None fp = open(self.f, "rb") fp.seek(8 + (0x91C * config) + 2025) - crypt = unpack(">B", fp.read(1))[0] + crypt = struct.unpack(">B", fp.read(1))[0] type = "" if(crypt == 0): type = "OPEN" @@ -425,7 +422,7 @@ class netConfig: return None if(crypt != "\x00"): fp.seek(8 + (0x91C * config) + 2029) - keylen = unpack(">B", fp.read(1))[0] + keylen = struct.unpack(">B", fp.read(1))[0] fp.seek(8 + (0x91C * config) + 2032) key = fp.read(keylen) fp.close() @@ -436,44 +433,44 @@ class netConfig: def clearConfig(self, config): fp = open(self.f, "rb+") fp.seek(8 + (0x91C * config)) - sel = unpack(">B", fp.read(1))[0] + sel = struct.unpack(">B", fp.read(1))[0] sel &= 0xDF fp.seek(8 + (0x91C * config)) - fp.write(pack(">B", sel)) + fp.write(struct.pack(">B", sel)) fp.close() def setNotBlank(self, config): fp = open(self.f, "rb+") fp.seek(8 + (0x91C * config)) - sel = unpack(">B", fp.read(1))[0] + sel = struct.unpack(">B", fp.read(1))[0] sel |= 0x20 fp.seek(8 + (0x91C * config)) - fp.write(pack(">B", sel)) + fp.write(struct.pack(">B", sel)) fp.close() def setIPType(self, config, static): fp = open(self.f, "rb+") fp.seek(8 + (0x91C * config)) - sel = unpack(">B", fp.read(1))[0] + sel = struct.unpack(">B", fp.read(1))[0] if(not static): sel |= 0x04 else: sel &= 0xFB fp.seek(8 + (0x91C * config)) - fp.write(pack(">B", sel)) + fp.write(struct.pack(">B", sel)) fp.close() self.setNotBlank(config) def setWireType(self, config, wired): fp = open(self.f, "rb+") fp.seek(8 + (0x91C * config)) - sel = unpack(">B", fp.read(1))[0] + sel = struct.unpack(">B", fp.read(1))[0] if(not wired): sel |= 0x02 else: sel &= 0xFD fp.seek(8 + (0x91C * config)) - fp.write(pack(">B", sel)) + fp.write(struct.pack(">B", sel)) fp.close() self.setNotBlank(config) @@ -514,29 +511,29 @@ class netConfig: def selectConfig(self, config): fp = open(self.f, "rb+") fp.seek(8 + (0x91C * 0)) - sel = unpack(">B", fp.read(1))[0] + sel = struct.unpack(">B", fp.read(1))[0] if(config == 0): sel |= 0x80 else: sel &= 0x7F fp.seek(8 + (0x91C * 0)) - fp.write(pack(">B", sel)) + fp.write(struct.pack(">B", sel)) fp.seek(8 + (0x91C * 1)) - sel = unpack(">B", fp.read(1))[0] + sel = struct.unpack(">B", fp.read(1))[0] if(config == 1): sel |= 0x80 else: sel &= 0x7F fp.seek(8 + (0x91C * 1)) - fp.write(pack(">B", sel)) + fp.write(struct.pack(">B", sel)) fp.seek(8 + (0x91C * 2)) - sel = unpack(">B", fp.read(1))[0] + sel = struct.unpack(">B", fp.read(1))[0] if(config == 2): sel |= 0x80 else: sel &= 0x7F fp.seek(8 + (0x91C * 2)) - fp.write(pack(">B", sel)) + fp.write(struct.pack(">B", sel)) self.setNotBlank(config) fp.close() @@ -710,8 +707,8 @@ class uidsys: if(hexdump(uidstr.titleid, "") == ("%016X" % title)): uidfp.close() return uidstr.uid - if(unpack(">H", uidstr.uid) >= unpack(">H", enduid)): - enduid = a2b_hex("%04X" % (unpack(">H", uidstr.uid)[0] + 1)) + if(struct.unpack(">H", uidstr.uid) >= struct.unpack(">H", enduid)): + enduid = a2b_hex("%04X" % (struct.unpack(">H", uidstr.uid)[0] + 1)) uidict[uidstr.titleid] = uidstr.uid uidict[a2b_hex("%016X" % title)] = enduid uidfp.close() diff --git a/headers.py b/headers.py new file mode 100644 index 0000000..120097a --- /dev/null +++ b/headers.py @@ -0,0 +1,145 @@ +from common import * + +class IMD5(): + """This class can add and remove IMD5 headers to files. The parameter f is the file to use for the addition or removal of the header. IMD5 headers are found in banner.bin, icon.bin, and sound.bin.""" + class IMD5Header(Struct): + __endian__ = Struct.BE + def __format__(self): + self.tag = Struct.string(4) + self.size = Struct.uint32 + self.zeroes = Struct.uint8[8] + self.crypto = Struct.string(16) + def __init__(self, f): + self.f = f + def add(self, fn = ""): + """This function adds an IMD5 header to the file specified by f in the initializer. The output file is specified with fn, if it is empty, it will overwrite the input file. If the file already has an IMD5 header, it will now have two. Returns the output filename.""" + data = open(self.f, "rb").read() + + imd5 = self.IMD5Header() + for i in range(8): + imd5.zeroes[i] = 0x00 + imd5.tag = "IMD5" + imd5.size = len(data) + imd5.crypto = str(Crypto().createMD5Hash(data)) + data = imd5.pack() + data + + if(fn != ""): + open(fn, "wb").write(data) + return fn + else: + open(self.f, "wb").write(data) + return self.f + def remove(self, fn = ""): + """This will remove an IMD5 header from the file specified in f, if one exists. If there is no IMD5 header, it will output the file as it is. It will output in the parameter fn if available, otherwise it will overwrite the source. Returns the output filename.""" + data = open(self.f, "rb").read() + imd5 = self.IMD5Header() + if(data[:4] != "IMD5"): + if(fn != ""): + open(fn, "wb").write(data) + return fn + else: + return self.f + data = data[len(imd5):] + + if(fn != ""): + open(fn, "wb").write(data) + return fn + else: + open(self.f, "wb").write(data) + return self.f + +class IMET(): + """IMET headers are found in Opening.bnr and 0000000.app files. They contain the channel titles and more metadata about channels. They are in two different formats with different amounts of padding before the start of the IMET header. This class suports both. + + The parameter f is used to specify the input file name.""" + class IMETHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.zeroes = Struct.uint8[128] + self.tag = Struct.string(4) + self.unk = Struct.uint64 + self.sizes = Struct.uint32[3] #icon, banner, sound + self.unk2 = Struct.uint32 + self.names = Struct.string(84, encoding = "utf-16-be", stripNulls = True)[7] + self.zeroes2 = Struct.uint8[840] + self.hash = Struct.string(16) + def __init__(self, f): + self.f = f + def add(self, iconsz, bannersz, soundsz, name = "", langs = [], fn = ""): + """This function adds an IMET header to the file specified with f in the initializer. The file will be output to fn if it is not empty, otherwise it will overwrite the input file. You must specify the size of banner.bin in bannersz, and respectivly for iconsz and soundsz. langs is an optional arguement that is a list of different langauge channel titles. name is the english name that is copied everywhere in langs that there is an empty string. Returns the output filename.""" + data = open(self.f, "rb").read() + imet = self.IMETHeader() + + for i in imet.zeroes: + imet.zeroes[i] = 0x00 + imet.tag = "IMET" + imet.unk = 0x0000060000000003 + imet.sizes[0] = iconsz + imet.sizes[1] = bannersz + imet.sizes[2] = soundsz + imet.unk2 = 0 + for i in range(len(imet.names)): + if(len(langs) > 0 and langs[i] != ""): + imet.names[i] = langs[i] + else: + imet.names[i] = name + for i in imet.zeroes2: + imet.zeroes2[i] = 0x00 + imet.hash = "\x00" * 16 + + tmp = imet.pack() + imet.hash = Crypto().createMD5Hash(tmp[0x40:0x640]) #0x00 or 0x40? + + data = imet.pack() + data + + if(fn != ""): + open(fn, "wb").write(data) + return fn + else: + open(self.f, "wb").write(data) + return self.f + + def remove(self, fn = ""): + """This method removes an IMET header from a file specified with f in the initializer. fn is the output file name if it isn't an empty string, if it is, it will overwrite the input. If the input has no IMD5 header, it is output as is. Returns the output filename.""" + data = open(self.f, "rb").read() + if(data[0x80:0x84] == "IMET"): + data = data[0x640:] + elif(data[0x40:0x44] == "IMET"): + data = data[0x640:] + else: + if(fn != ""): + open(fn, "wb").write(data) + return fn + else: + return self.f + if(fn != ""): + open(fn, "wb").write(data) + return fn + else: + open(self.f, "wb").write(data) + return self.f + def getTitle(self): + imet = self.IMETHeader() + data = open(self.f, "rb").read() + + if(data[0x40:0x44] == "IMET"): + pass + elif(data[0x80:0x84] == "IMET"): + data = data[0x40:] + else: + return "" + + imet.unpack(data[:len(imet)]) + name = imet.names[1] + topop = [] + for i in range(len(name)): + if(name[i] == "\x00"): + topop.append(i) + name = list(name) + popped = 0 #don't ask me why I did this + for pop in topop: + name.pop(pop - popped) + popped += 1 + + name = ''.join(name) + return name diff --git a/image.py b/image.py new file mode 100644 index 0000000..144df51 --- /dev/null +++ b/image.py @@ -0,0 +1,796 @@ +from common import * + +def flatten(myTuple): + if (len(myTuple) == 4): + return myTuple[0] << 0 | myTuple[1] << 8 | myTuple[2] << 16 | myTuple[3] << 24 + else: + return myTuple[0] << 0 | myTuple[1] << 8 | myTuple[2] << 16 | 0xff << 24 + +def round_up(x, n): + left = x % n + return x + left + +def avg(w0, w1, c0, c1): + a0 = c0 >> 11 + a1 = c1 >> 11 + a = (w0*a0 + w1*a1) / (w0 + w1) + c = (a << 11) & 0xffff + + a0 = (c0 >> 5) & 63 + a1 = (c1 >> 5) & 63 + a = (w0*a0 + w1*a1) / (w0 + w1) + c = c | ((a << 5) & 0xffff) + + a0 = c0 & 31 + a1 = c1 & 31 + a = (w0*a0 + w1*a1) / (w0 + w1) + c = c | a + + return c + + +class TPL(): + """This is the class to generate TPL texutres from PNG images, and to convert TPL textures to PNG images. The parameter file specifies the filename of the source, either a PNG image or a TPL image. + + Currently supported are the following formats to convert from TPL (all formats): RGBA8, RGB565, RGB5A3, I4, IA4, I8, IA8, CI4, CI8, CMP, CI14X2. + + Currently supported to convert to TPL: I4, I8, IA4, IA8, RBG565, RBGA8, RGB5A3. Currently not supported are CI4, CI8, CMP, CI14X2.""" + + + class TPLHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.magic = Struct.uint32 + self.ntextures = Struct.uint32 + self.header_size = Struct.uint32 + class TPLTexture(Struct): + __endian__ = Struct.BE + def __format__(self): + self.header_offset = Struct.uint32 + self.palette_offset = Struct.uint32 + class TPLTextureHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.height = Struct.uint16 + self.width = Struct.uint16 + self.format = Struct.uint32 + self.data_off = Struct.uint32 + self.wrap = Struct.uint32[2] + self.filter = Struct.uint32[2] + self.lod_bias = Struct.float + self.edge_lod = Struct.uint8 + self.min_lod = Struct.uint8 + self.max_lod = Struct.uint8 + self.unpacked = Struct.uint8 + class TPLPaletteHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.nitems = Struct.uint16 + self.unpacked = Struct.uint8 + self.pad = Struct.uint8 + self.format = Struct.uint32 + self.offset = Struct.uint32 + def __init__(self, file): + if(os.path.isfile(file)): + self.file = file + self.data = None + else: + self.file = None + self.data = file + def toTPL(self, outfile, (width, height) = (None, None), format = "RGBA8"): #single texture only + """This converts an image into a TPL. The image is specified as the file parameter to the class initializer, while the output filename is specified here as the parameter outfile. Width and height are optional parameters and specify the size to resize the image to, if needed. Returns the output filename. + + This only can create TPL images with a single texture.""" + head = self.TPLHeader() + head.magic = 0x0020AF30 + head.ntextures = 1 + head.header_size = 0x0C + + tex = self.TPLTexture() + tex.header_offset = 0x14 + tex.pallete_offset = 0 + + img = Image.open(self.file) + theWidth, theHeight = img.size + if(width != None and height != None and (width != theWidth or height != theHeight)): + img = img.resize((width, height), Image.ANTIALIAS) + w, h = img.size + + texhead = self.TPLTextureHeader() + texhead.height = h + texhead.width = w + if format == "I4": + texhead.format = 0 + tpldata = self.toI4((w, h), img) + elif format == "I8": + texhead.format = 1 + tpldata = self.toI8((w, h), img) + elif format == "IA4": + texhead.format = 2 + tpldata = self.toIA4((w, h), img) + elif format == "IA8": + texhead.format = 3 + tpldata = self.toIA8((w, h), img) + elif format == "RGB565": + texhead.format = 4 + tpldata = self.toRGB565((w, h), img) + elif format == "RGB5A3": + texhead.format = 5 + tpldata = self.toRGB5A3((w, h), img) + elif format == "RGBA8": + texhead.format = 6 + tpldata = self.toRGBA8((w, h), img) + elif format == "CI4": + texhead.format = 8 + ''' ADD toCI4 ''' + raise Exception("toCI4 not done") + #tpldata = self.toCI4((w, h), img) + elif format == "CI8": + texhead.format = 9 + ''' ADD toCI8 ''' + raise Exception("toCI8 not done") + #tpldata = self.toCI8((w, h), img) + elif format == "CI14X2": + texhead.format = 10 + ''' ADD toCI14X2 ''' + raise Exception("toCI14X2 not done") + #tpldata = self.toCI14X2((w, h), img) + elif format == "CMP": + texhead.format = 14 + ''' ADD toCMP ''' + raise Exception("toCMP not done") + #tpldata = self.toCMP((w, h), img) + + texhead.data_off = 0x14 + len(texhead) + texhead.wrap = [0, 0] + texhead.filter = [1, 1] + texhead.lod_bias = 0 + texhead.edge_lod = 0 + texhead.min_lod = 0 + texhead.max_lod = 0 + texhead.unpacked = 0 + + f = open(outfile, "wb") + f.write(head.pack()) + f.write(tex.pack()) + f.write(texhead.pack()) + if format == "I4": + f.write(struct.pack(">" + str(align(w,4) * align(h,4) / 2) + "B", *tpldata)) + if format == "I8": + f.write(struct.pack(">" + str(align(w,4) * align(h,4) * 1) + "B", *tpldata)) + if format == "IA4": + f.write(struct.pack(">" + str(align(w,4) * align(h,4) * 1) + "B", *tpldata)) + if format == "IA8": + f.write(struct.pack(">" + str(align(w,4) * align(h,4) * 1) + "H", *tpldata)) + if format == "RGB565": + f.write(struct.pack(">" + str(align(w,4) * align(h,4) * 1) + "H", *tpldata)) + if format == "RGB5A3": + f.write(struct.pack(">" + str(align(w,4) * align(h,4) * 1) + "H", *tpldata)) + if format == "RGBA8": + f.write(struct.pack(">" + str(align(w,4) * align(h,4) * 4) + "B", *tpldata)) + if format == "CI4": + ''' ADD toCI4 ''' + #f.write(struct.pack(">"+ str(align(w,4) * align(h,4) * 4) + "B", *tpldata)) + if format == "CI8": + ''' ADD toCI8 ''' + #f.write(struct.pack(">"+ str(align(w,4) * align(h,4) * 4) + "B", *tpldata)) + if format == "CI14X2": + ''' ADD toCI14X2 ''' + #f.write(struct.pack(">"+ str(align(w,4) * align(h,4) * 4) + "B", *tpldata)) + if format == "CMP": + ''' ADD toCMP ''' + #f.write(struct.pack(">"+ str(align(w,4) * align(h,4) * 4) + "B", *tpldata)) + f.close() + + return outfile + def toI4(self, (w, h), img): + out = [0 for i in range(align(w, 4) * align(h, 4) / 2)] + outp = 0 + inp = list(img.getdata()) + for y1 in range(0, h, 8): + for x1 in range(0, w, 8): + for y in range(y1, y1+8, 1): + for x in range(x1, x1+8, 2): + if x>=w or y>=h: + newpixel = 0 + else: + rgba = flatten(inp[x+y*w]) + r = (rgba >> 0) & 0xff + g = (rgba >> 8) & 0xff + b = (rgba >> 16) & 0xff + i1 = ((r + g + b) / 3) & 0xff + rgba = flatten(inp[x+1+y*w]) + r = (rgba >> 0) & 0xff + g = (rgba >> 8) & 0xff + b = (rgba >> 16) & 0xff + i2 = ((r + g + b) / 3) & 0xff + + newpixel = (((i1 * 15) / 255) << 4) + newpixel |= (((i2 * 15) / 255) & 0xf) + out[outp] = newpixel + outp += 1 + return out + def toI8(self, (w, h), img): + out = [0 for i in range(align(w, 4) * align(h, 4))] + outp = 0 + inp = list(img.getdata()) + for y1 in range(0, h, 4): + for x1 in range(0, w, 8): + for y in range(y1, y1+4, 1): + for x in range(x1, x1+8, 1): + rgba = flatten(inp[x + (y * w)]) + if x>= w or y>=h: + i1 = 0 + else: + r = (rgba >> 0) & 0xff + g = (rgba >> 8) & 0xff + b = (rgba >> 16) & 0xff + i1 = ((r + g + b) / 3) & 0xff + out[outp] = i1 + outp += 1 + return out + def toIA4(self, (w, h), img): + out = [0 for i in range(align(w, 4) * align(h, 4))] + outp = 0 + inp = list(img.getdata()) + for y1 in range(0, h, 4): + for x1 in range(0, w, 8): + for y in range(y1, y1+4, 1): + for x in range(x1, x1+8, 1): + if x>=w or y>=h: + newpixel = 0 + else: + rgba = flatten(inp[x + (y * w)]) + r = (rgba >> 0) & 0xff + g = (rgba >> 8) & 0xff + b = (rgba >> 16) & 0xff + i1 = ((r + g + b) / 3) & 0xff + a1 = (rgba >> 24) & 0xff + + newpixel = (((i1 * 15) / 255) & 0xf) + newpixel = newpixel | (((a1 * 15) / 255) << 4) + out[outp] = newpixel + outp += 1 + return out + def toIA8(self, (w, h), img): + out = [0 for i in range(align(w, 4) * align(h, 4))] + outp = 0 + inp = list(img.getdata()) + for y1 in range(0, h, 4): + for x1 in range(0, w, 4): + for y in range(y1, y1+4, 1): + for x in range(x1, x1+4, 1): + if x>=w or y>=h: + newpixel = 0 + else: + rgba = flatten(inp[x + (y * w)]) + r = (rgba >> 0) & 0xff + g = (rgba >> 8) & 0xff + b = (rgba >> 16) & 0xff + i1 = ((r + g + b) / 3) & 0xff + a1 = (rgba >> 24) & 0xff + + newpixel = i1 << 8 + newpixel = newpixel | a1 + out[outp] = newpixel + outp += 1 + return out + def toRGB565(self, (w, h), img): + out = [0 for i in range(align(w, 4) * align(h, 4))] + outp = 0 + inp = img.getdata() + for y1 in range(0, h, 4): + for x1 in range(0, w, 4): + for y in range(y1, y1+4, 1): + for x in range(x1, x1+4, 1): + newpixel = 0 + if x>=w or y>=h: + newpixel = 0 + else: + rgba = flatten(inp[x+y*w]) + r = (rgba >> 0) & 0xff + g = (rgba >> 8) & 0xff + b = (rgba >> 16) & 0xff + newpixel = ((b >>3) << 11) | ((g >>2) << 5) | ((r >>3) << 0) + out[outp] = newpixel + outp += 1 + return out + def toRGB5A3(self, (w, h), img): + out = [0 for i in range(align(w, 4) * align(h, 4))] + outp = 0 + inp = list(img.getdata()) + for y1 in range(0, h, 4): + for x1 in range(0, w, 4): + for y in range(y1, y1+4, 1): + for x in range(x1, x1+4, 1): + newpixel = 0 + if x>=w or y>=h: + newpixel = 0 + else: + rgba = flatten(inp[x + (y * h)]) + r = (rgba >> 0) & 0xff + g = (rgba >> 8) & 0xff + b = (rgba >> 16) & 0xff + a = (rgba >> 24) & 0xff + if (a <= 0xda): + newpixel &= ~(1 << 15) + r = ((r * 15) / 255) & 0xf + g = ((g * 15) / 255) & 0xf + b = ((b * 15) / 255) & 0xf + a = ((a * 7) / 255) & 0x7 + #newpixel |= r << 12 + #newpixel |= g << 8 + #newpixel |= b << 4 + #newpixel |= a << 0 + newpixel |= a << 12 + newpixel |= b << 8 + newpixel |= g << 4 + newpixel |= r << 0 + else: + newpixel |= (1 << 15) + r = ((r * 31) / 255) & 0x1f + g = ((g * 31) / 255) & 0x1f + b = ((b * 31) / 255) & 0x1f + newpixel |= b << 10 + newpixel |= g << 5 + newpixel |= r << 0 + out[outp] = newpixel + outp += 1 + return out + def toRGBA8(self, (w, h), img): + out = [0 for i in range(align(w, 4) * align(h, 4) * 4)] + inp = list(img.getdata()) + iv = 0 + z = 0 + lr = [0 for i in range(32)] + lg = [0 for i in range(32)] + lb = [0 for i in range(32)] + la = [0 for i in range(32)] + for y1 in range(0, h, 4): + for x1 in range(0, w, 4): + for y in range(y1, y1 + 4, 1): + for x in range(x1, x1 + 4, 1): + if(y >= h or x >= w): + lr[z] = 0 + lg[z] = 0 + lb[z] = 0 + la[z] = 0 + else: + rgba = flatten(inp[x + (y * w)]) + lr[z] = (rgba >> 0) & 0xff + lg[z] = (rgba >> 8) & 0xff + lb[z] = (rgba >> 16) & 0xff + la[z] = (rgba >> 24) & 0xff + z += 1 + if(z == 16): + for i in range(16): + out[iv] = la[i] & 0xff + iv += 1 + out[iv] = lr[i] & 0xff + iv += 1 + for i in range(16): + out[iv] = lg[i] & 0xff + iv += 1 + out[iv] = lb[i] & 0xff + iv += 1 + z = 0 + return out + def toImage(self, outfile): + """This converts a TPL texture to a PNG image. You specify the input TPL filename in the initializer, and you specify the output filename in the outfile parameter to this method. Returns the output filename. + + This only supports single textured TPL images.""" + if(self.file): + data = open(self.file, "rb").read() + else: + data = self.data + + header = self.TPLHeader() + textures = [] + pos = 0 + + header.unpack(data[pos:pos + len(header)]) + pos += len(header) + + palette_offsets = [] + + for i in range(header.ntextures): + tmp = self.TPLTexture() + tmp.unpack(data[pos:pos + len(tmp)]) + textures.append(tmp) + pos += len(tmp) + if(tmp.palette_offset > 0): + palette_offsets.append(tmp.palette_offset) + + if(header.ntextures > 1): + raise ValueError("Only one texture supported. Don't touch me!") + + for i in range(header.ntextures): + head = textures[i] + tex = self.TPLTextureHeader() + tex.unpack(data[head.header_offset:head.header_offset + len(tex)]) + w = tex.width + h = tex.height + + if(tex.format == 0): #I4, 4-bit + tpldata = struct.unpack(">" + str((w * h) / 2) + "B", data[tex.data_off:tex.data_off + ((w * h) / 2)]) + rgbdata = self.I4((w, h), tpldata) + + elif(tex.format == 1): #I8, 8-bit + tpldata = struct.unpack(">" + str(w * h) + "B", data[tex.data_off:tex.data_off + (w * h * 1)]) + rgbdata = self.I8((w, h), tpldata) + elif(tex.format == 2): #IA4, 8-bit + tpldata = struct.unpack(">" + str(w * h) + "B", data[tex.data_off:tex.data_off + (w * h * 1)]) + rgbdata = self.IA4((w, h), tpldata) + + elif(tex.format == 4): #RGB565, 16-bit + tpldata = data[tex.data_off:] + rgbdata = self.RGB565((w, h), tpldata) + elif(tex.format == 5): #RGB5A3, 16-bit + tpldata = data[tex.data_off:] + rgbdata = self.RGB5A3((w, h), tpldata) + elif(tex.format == 3): #IA8, 16-bit + tpldata = data[tex.data_off:] + rgbdata = self.IA8((w, h), tpldata) + + elif(tex.format == 6): #RGBA8, 32-bit, but for easyness's sake lets do it with 16-bit + tpldata = data[tex.data_off:] + rgbdata = self.RGBA8((w, h), tpldata) + + elif(tex.format == 8 or tex.format == 9 or tex.format == 10): + palhead = self.TPLPaletteHeader() + offs = palette_offsets.pop(0) + palhead.unpack(data[offs:offs + len(palhead)]) + + tpldata = struct.unpack(">" + str(palhead.nitems) + "H", data[palhead.offset:palhead.offset + (palhead.nitems * 2)]) + if(palhead.format == 0): + palette_data = self.IA8((palhead.nitems, 1), tpldata)[0] + elif(palhead.format == 1): + palette_data = self.RGB565((palhead.nitems, 1), tpldata)[0] + elif(palhead.format == 2): + palette_data = self.RGB5A3((palhead.nitems, 1), tpldata)[0] + + paldata = [] + for i in range(0, palhead.nitems * 4, 4): + tmp = 0 + tmp |= palette_data[i + 0] << 24 + tmp |= palette_data[i + 1] << 16 + tmp |= palette_data[i + 2] << 8 + tmp |= palette_data[i + 3] << 0 + paldata.append(tmp) + + if(tex.format == 8): + tpldata = struct.unpack(">" + str((w * h) / 2) + "B", data[tex.data_off:tex.data_off + ((w * h) / 2)]) + rgbdata = self.CI4((w, h), tpldata, paldata) + if(tex.format == 9): + tpldata = struct.unpack(">" + str(w * h) + "B", data[tex.data_off:tex.data_off + (w * h * 1)]) + rgbdata = self.CI8((w, h), tpldata, paldata) + if(tex.format == 10): + tpldata = struct.unpack(">" + str(w * h) + "H", data[tex.data_off:tex.data_off + (w * h * 2)]) + rgbdata = self.CI14X2((w, h), tpldata, paldata) + elif(tex.format == 14): + tpldata = ''.join(data[tex.data_off:]) + + rgbdata = self.CMP((w, h), tpldata) + else: + raise TypeError("Unsupported TPL Format: " + str(tex.format)) + + output = Image.fromstring("RGBA", (w, h), rgbdata) + ext = outfile[outfile.rfind(".")+1:] + output.save(outfile, ext) + + return outfile + def getSizes(self): + """This returns a tuple containing the width and height of the TPL image filename in the class initializer. Will only return the size of single textured TPL images.""" + data = open(self.file, "rb").read() + + header = self.TPLHeader() + textures = [] + pos = 0 + + header.unpack(data[pos:pos + len(header)]) + pos += len(header) + + for i in range(header.ntextures): + tmp = self.TPLTexture() + tmp.unpack(data[pos:pos + len(tmp)]) + textures.append(tmp) + pos += len(tmp) + + for i in range(header.ntextures): + head = textures[i] + tex = self.TPLTextureHeader() + tex.unpack(data[head.header_offset:head.header_offset + len(tex)]) + w = tex.width + h = tex.height + return (w, h) + def toScreen(self): #single texture only + """This will draw a simple window with the TPL image displayed on it. It uses WxPython for the window creation and management. The window has a minimum width and height of 300 x 200. Does not return a value. + + Again, only a single texture is supported.""" + import wx + class imp(wx.Dialog): + def __init__(self, title, im): + w = img.GetWidth() + h = img.GetHeight() + + wx.Dialog.__init__(self, None, -1, title, size = (max(w, 300), max(h, 200))) + + wx.StaticBitmap(self, -1, im, ( ((max(w, 300) - w) / 2), ((max(h, 200) - h) / 2) ), (w, h)) + self.toImage("tmp.png") + img = wx.Image("tmp.png", wx.BITMAP_TYPE_ANY).ConvertToBitmap() + w = img.GetWidth() + h = img.GetHeight() + dialog = imp("TPL (" + str(w) + ", " + str(h) + ")", img) + dialog.ShowModal() + dialog.Destroy() + os.unlink("tmp.png") + def RGBA8(self, (x, y), data): + out = [0 for i in range(x * y)] + inp = 0 + for i in xrange(0, y, 4): + for j in xrange(0, x, 4): + for k in xrange(2): + for l in xrange(i, i + 4, 1): + for m in xrange(j, j + 4, 1): + texel = Struct.uint16(data[inp * 2:inp * 2 + 2], endian = '>') + inp += 1 + if (m >= x) or (l >= y): + continue + if k == 0: + a = (texel >> 8) & 0xff + r = (texel >> 0) & 0xff + out[m + (l * x)] = out[m + (l * x)] | ((r<<0) | (a<<24)) + else: + g = (texel >> 8) & 0xff + b = (texel >> 0) & 0xff + out[m + (l * x)] = out[m + (l * x)] | ((g<<8) | (b<<16)) + return ''.join(Struct.uint32(p) for p in out) + def RGB5A3(self, (w, h), jar): + out = [0 for i in range(w * h)] + i = 0 + for y in range(0, h, 4): + for x in range(0, w, 4): + for y1 in range(y, y + 4): + for x1 in range(x, x + 4): + if(y1 >= h or x1 >= w): + continue + pixel = Struct.uint16(jar[i * 2:i * 2 + 2], endian='>') + i += 1 + + if(pixel & (1 << 15)): #RGB555 + b = (((pixel >> 10) & 0x1F) * 255) / 31 + g = (((pixel >> 5) & 0x1F) * 255) / 31 + r = (((pixel >> 0) & 0x1F) * 255) / 31 + a = 255 + else: #RGB4A3 + a = (((pixel >> 12) & 0x07) * 255) / 7 + b = (((pixel >> 8) & 0x0F) * 255) / 15 + g = (((pixel >> 4) & 0x0F) * 255) / 15 + r = (((pixel >> 0) & 0x0F) * 255)/ 15 + + rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) + out[(y1 * w) + x1] = rgba + return ''.join(Struct.uint32(p) for p in out) + def RGB565(self, (w, h), jar): + out = [0 for i in range(w * h)] + i = 0 + for y in range(0, h, 4): + for x in range(0, w, 4): + for y1 in range(y, y + 4): + for x1 in range(x, x + 4): + if(y1 >= h or x1 >= w): + continue + pixel = Struct.uint16(jar[i * 2:i * 2 + 2], endian='>') + i += 1 + + b = (((pixel >> 11) & 0x1F) << 3) & 0xff + g = (((pixel >> 5) & 0x3F) << 2) & 0xff + r = (((pixel >> 0) & 0x1F) << 3) & 0xff + a = 255 + + rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) + out[y1 * w + x1] = rgba + return ''.join(Struct.uint32(p) for p in out) + def I4(self, (w, h), jar): + out = [0 for i in range(w * h)] + i = 0 + for y in range(0, h, 8): + for x in range(0, w, 8): + for y1 in range(y, y + 8): + for x1 in range(x, x + 8, 2): + if(y1 >= h or x1 >= w): + continue + pixel = jar[i] + + r = (pixel >> 4) * 255 / 15 + g = (pixel >> 4) * 255 / 15 + b = (pixel >> 4) * 255 / 15 + a = 255 + + rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) + out[y1 * w + x1] = rgba + + if(y1 >= h or x1 >= w): + continue + pixel = jar[i] + i += 1 + + r = (pixel & 0x0F) * 255 / 15 + g = (pixel & 0x0F) * 255 / 15 + b = (pixel & 0x0F) * 255 / 15 + a = 255 + + rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) + out[y1 * w + x1 + 1] = rgba + return ''.join(Struct.uint32(p) for p in out) + def IA4(self, (w, h), jar): + out = [0 for i in range(w * h)] + i = 0 + for y in range(0, h, 4): + for x in range(0, w, 8): + for y1 in range(y, y + 4): + for x1 in range(x, x + 8): + if(y1 >= h or x1 >= w): + continue + pixel = jar[i] + i += 1 + + r = ((pixel & 0x0F) * 255 / 15) & 0xff + g = ((pixel & 0x0F) * 255 / 15) & 0xff + b = ((pixel & 0x0F) * 255 / 15) & 0xff + a = (((pixel >> 4) * 255) / 15) & 0xff + + rgba = ( r<< 0) | (g << 8) | (b << 16) | (a << 24) + out[y1 * w + x1] = rgba + return ''.join(Struct.uint32(p) for p in out) + def I8(self, (w, h), jar): + out = [0 for i in range(w * h)] + i = 0 + for y in range(0, h, 4): + for x in range(0, w, 8): + for y1 in range(y, y + 4): + for x1 in range(x, x + 8): + if(y1 >= h or x1 >= w): + continue + pixel = jar[i] + i += 1 + + r = pixel + g = pixel + b = pixel + a = 255 + + rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) + out[y1 * w + x1] = rgba + return ''.join(Struct.uint32(p) for p in out) + def IA8(self, (w, h), jar): + out = [0 for i in range(w * h)] + i = 0 + for y in range(0, h, 4): + for x in range(0, w, 4): + for y1 in range(y, y + 4): + for x1 in range(x, x + 4): + if(y1 >= h or x1 >= w): + continue + pixel = Struct.uint16(jar[i * 2:i * 2 + 2], endian='>') + i += 1 + + r = (pixel >> 8) & 0xff + g = (pixel >> 8) & 0xff + b = (pixel >> 8) & 0xff + a = pixel & 0xff + + rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) + out[y1 * w + x1] = rgba + return ''.join(Struct.uint32(p) for p in out) + def CI4(self, (w, h), jar, pal): + out = [0 for i in range(w * h)] + i = 0 + for y in range(0, h, 8): + for x in range(0, w, 8): + for y1 in range(y, y + 8): + for x1 in range(x, x + 8, 2): + if(y1 >= h or x1 >= w): + continue + pixel = jar[i] + + r = (pal[pixel] & 0xFF000000) >> 24 + g = (pal[pixel] & 0x00FF0000) >> 16 + b = (pal[pixel] & 0x0000FF00) >> 8 + a = (pal[pixel] & 0x000000FF) >> 0 + + rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) + out[y1 * w + x1] = rgba + + if(y1 >= h or x1 >= w): + continue + pixel = jar[i] + i += 1 + + r = (pal[pixel] & 0xFF000000) >> 24 + g = (pal[pixel] & 0x00FF0000) >> 16 + b = (pal[pixel] & 0x0000FF00) >> 8 + a = (pal[pixel] & 0x000000FF) >> 0 + + rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) + out[y1 * w + x1 + 1] = rgba + return ''.join(Struct.uint32(p) for p in out) + def CI8(self, (w, h), jar, pal): + out = [0 for i in range(w * h)] + i = 0 + for y in range(0, h, 4): + for x in range(0, w, 8): + for y1 in range(y, y + 4): + for x1 in range(x, x + 8): + if(y1 >= h or x1 >= w): + continue + pixel = jar[i] + i += 1 + + r = (pal[pixel] & 0xFF000000) >> 24 + g = (pal[pixel] & 0x00FF0000) >> 16 + b = (pal[pixel] & 0x0000FF00) >> 8 + a = (pal[pixel] & 0x000000FF) >> 0 + + rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) + out[y1 * w + x1] = rgba + return ''.join(Struct.uint32(p) for p in out) + def CMP(self, (w, h), data): + temp = [0 for i in range(w * h)] + pix = [ 0 , 0 , 0 ] + c = [ 0 , 0 , 0 , 0 ] + outp = 0 + for y in xrange(h): + for x in xrange(w): + ww = round_up(w, 8) + + x0 = x & 0x03 + x1 = (x >> 2) & 0x01 + x2 = x >> 3 + + y0 = y & 0x03 + y1 = (y >> 2) & 0x01 + y2 = y >> 3 + + off = (8 * x1) + (16 * y1) + (32 * x2) + (4 * ww * y2) + + c[0] = Struct.uint16(data[off + 0:off + 2], endian='>') + c[1] = Struct.uint16(data[off + 2:off + 4], endian='>') + if(c[0] > c[1]): + c[2] = avg(2, 1, c[0], c[1]) + c[3] = avg(1, 2, c[0], c[1]) + else: + c[2] = avg(1, 1, c[0], c[1]) + c[3] = 0 + + px = Struct.uint32(data[off+4:off + 8], endian='>') + ix = x0 + ( 4 * y0 ) + raw = c[(px >> (30 - (2 * ix))) & 0x03] + + pix[0] = (raw >> 8) & 0xf8 + pix[1] = (raw >> 3) & 0xf8 + pix[2] = (raw << 3) & 0xf8 + + temp[outp] = (pix[0] <<0) | (pix[1] << 8) | (pix[2] << 16) | (255 << 24) + outp += 1 + return ''.join(Struct.uint32(p) for p in temp) + def CI14X2(self, (w, h), jar): + out = [0 for i in range(w * h)] + i = 0 + for y in range(0, h, 4): + for x in range(0, w, 4): + for y1 in range(y, y + 4): + for x1 in range(x, x + 4): + if(y1 >= h or x1 >= w): + continue + pixel = jar[i] + i += 1 + + r = (pal[pixel & 0x3FFF] & 0xFF000000) >> 24 + g = (pal[pixel & 0x3FFF] & 0x00FF0000) >> 16 + b = (pal[pixel & 0x3FFF] & 0x0000FF00) >> 8 + a = (pal[pixel & 0x3FFF] & 0x000000FF) >> 0 + + rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) + out[y1 * w + x1] = rgba + return ''.join(Struct.uint32(p) for p in out) diff --git a/nand.py b/nand.py index 9f56a00..d67ab49 100644 --- a/nand.py +++ b/nand.py @@ -1,14 +1,10 @@ -import os, struct, subprocess, fnmatch, shutil, urllib, array from binascii import * - -from Struct import Struct from struct import * from common import * from title import * from formats import * - class NAND: """This class performs all NAND related things. It includes functions to copy a title (given the TMD) into the correct structure as the Wii does, and has an entire ES-like system. Parameter f to the initializer is the folder that will be used as the NAND root.""" def __init__(self, f): diff --git a/title.py b/title.py index 21fd6a0..49223c9 100644 --- a/title.py +++ b/title.py @@ -1,7 +1,3 @@ -import os, struct, subprocess, fnmatch, shutil, urllib, array - -from Struct import Struct - from common import * class TicketView: @@ -41,7 +37,6 @@ class TicketView: return out - class Ticket: """Creates a ticket from the filename defined in f. This may take a longer amount of time than expected, as it also decrypts the title key. Now supports Korean tickets (but their title keys stay Korean on dump).""" class TicketStruct(Struct): @@ -65,21 +60,26 @@ class Ticket: self.unk3 = Struct.uint16 self.limits = Struct.string(96) self.unk4 = Struct.uint8 - def __init__(self, f): - isf = False - try: - isf = os.path.isfile(f) - except: - pass - if(isf): - self.f = f - data = open(f, "rb").read() - else: - self.f = "tik" - data = f - - self.size = len(data) + def __init__(self): self.tik = self.TicketStruct() + + self.tik.rsaexp = 0x10001 + self.tik.rsamod = "\x00" * 256 + self.tik.padding1 = "\x00" * 60 + self.tik.rsaid = "\x00" * 64 + self.tik.padding2 = "\x00" * 63 + self.tik.enctitlekey = "\x00" * 16 + self.tik.titleid = 0x0000000100000000 + self.tik.reserved = "\x00" * 80 + self.tik.limits = "\x00" * 96 + + commonkey = "\xEB\xE4\x2A\x22\x5E\x85\x93\xE4\x48\xD9\xC5\x45\x73\x81\xAA\xF7" + koreankey = "\x63\xB8\x2B\xB4\xF4\x61\x4E\x2E\x13\xF2\xFE\xFB\xBA\x4C\x9B\x7E" + + if(self.tik.commonkey_index == 1): #korean, kekekekek! + commonkey = koreankey + self.titlekey = Crypto().decryptTitleKey(commonkey, self.tik.titleid, self.tik.enctitlekey) + def load(self, data): self.tik.unpack(data[:len(self.tik)]) commonkey = "\xEB\xE4\x2A\x22\x5E\x85\x93\xE4\x48\xD9\xC5\x45\x73\x81\xAA\xF7" @@ -89,6 +89,9 @@ class Ticket: commonkey = koreankey self.titlekey = Crypto().decryptTitleKey(commonkey, self.tik.titleid, self.tik.enctitlekey) + return self + def loadFile(self, filename): + return self.load(open(filename, "rb").read()) def getTitleKey(self): """Returns a string containing the title key.""" return self.titlekey @@ -98,6 +101,12 @@ class Ticket: def setTitleID(self, titleid): """Sets the title id of the ticket from the long integer passed in titleid.""" self.tik.titleid = titleid + commonkey = "\xEB\xE4\x2A\x22\x5E\x85\x93\xE4\x48\xD9\xC5\x45\x73\x81\xAA\xF7" + koreankey = "\x63\xB8\x2B\xB4\xF4\x61\x4E\x2E\x13\xF2\xFE\xFB\xBA\x4C\x9B\x7E" + + if(self.tik.commonkey_index == 1): #korean, kekekekek! + commonkey = koreankey + self.titlekey = Crypto().decryptTitleKey(commonkey, self.tik.titleid, self.tik.enctitlekey) #This changes the decrypted title key! def __str__(self): out = "" out += " Ticket:\n" @@ -116,7 +125,6 @@ class Ticket: out += "\n" return out - def dump(self, fn = ""): """Fakesigns (or Trucha signs) and dumps the ticket to either fn, if not empty, or overwriting the source if empty. Returns the output filename.""" self.rsamod = self.rsamod = "\x00" * 256 @@ -173,30 +181,21 @@ class TMD: self.boot_index = Struct.uint16 self.padding2 = Struct.uint16 #contents follow this - - def __init__(self, f): - isf = False - try: - isf = os.path.isfile(f) - except: - pass - if(isf): - self.f = f - data = open(f, "rb").read() - else: - self.f = "tmd" - data = f - - self.tmd = self.TMDStruct() + def load(self, data): self.tmd.unpack(data[:len(self.tmd)]) - - self.contents = [] pos = len(self.tmd) for i in range(self.tmd.numcontents): cont = self.TMDContent() cont.unpack(data[pos:pos + len(cont)]) pos += len(cont) self.contents.append(cont) + return self + def loadFile(self, filename): + return self.load(open(filename, "rb").read()) + def __init__(self): + self.tmd = self.TMDStruct() + self.tmd.titleid = 0x0000000100000000 + self.contents = [] def getContents(self): """Returns a list of contents. Each content is an object with the members "size", the size of the content's decrypted data; "cid", the content id; "type", the type of the content (0x8001 for shared, 0x0001 for standard, more possible), and a 20 byte string called "hash".""" return self.contents @@ -342,159 +341,3 @@ class NUS: open("%08x.app" % output, "wb").write(tmpdata) os.chdir("..") - -class WAD: - """This class is to pack and unpack WAD files, which store a single title. You pass the input filename or input directory name to the parameter f. - - WAD packing support currently creates WAD files that return -4100 on install.""" - def __init__(self, f, boot2 = False): - self.f = f - self.boot2 = boot2 - def pack(self, fn = "", fakesign = True, decrypted = True): - """Packs a WAD into the filename specified by fn, if it is not empty. If it is empty, it packs into a filename generated from the folder's name. If fakesign is True, it will fakesign the Ticket and TMD, and update them as needed. If decrypted is true, it will assume the contents are already decrypted. For now, fakesign can not be True if decrypted is False, however fakesign can be False if decrypted is True. Title ID is a long integer of the destination title id.""" - os.chdir(self.f) - - tik = Ticket("tik") - tmd = TMD("tmd") - titlekey = tik.getTitleKey() - contents = tmd.getContents() - - apppack = "" - for content in contents: - tmpdata = open("%08x.app" % content.index, "rb").read() - - if(decrypted): - if(fakesign): - content.hash = str(Crypto().createSHAHash(tmpdata)) - content.size = len(tmpdata) - - encdata = Crypto().encryptContent(titlekey, content.index, tmpdata) - else: - encdata = tmpdata - - apppack += encdata - if(len(encdata) % 64 != 0): - apppack += "\x00" * (64 - (len(encdata) % 64)) - - if(fakesign): - tmd.setContents(contents) - tmd.dump() - tik.dump() - - rawtmd = open("tmd", "rb").read() - rawcert = open("cert", "rb").read() - rawtik = open("tik", "rb").read() - - sz = 0 - for i in range(len(contents)): - sz += contents[i].size - if(sz % 64 != 0): - sz += 64 - (contents[i].size % 64) - - if(self.boot2 != True): - pack = struct.pack('>I4s6I', 32, "Is\x00\x00", len(rawcert), 0, len(rawtik), len(rawtmd), sz, 0) - pack += "\x00" * 32 - else: - pack = struct.pack('>IIIII12s', 32, align(len(rawcert) + len(rawtik) + len(rawtmd), 0x40), len(rawcert), len(rawtik), len(rawtmd), "\x00" * 12) - - pack += rawcert - if(len(rawcert) % 64 != 0 and self.boot2 != True): - pack += "\x00" * (64 - (len(rawcert) % 64)) - pack += rawtik - if(len(rawtik) % 64 != 0 and self.boot2 != True): - pack += "\x00" * (64 - (len(rawtik) % 64)) - pack += rawtmd - if(len(rawtmd) % 64 != 0 and self.boot2 != True): - pack += "\x00" * (64 - (len(rawtmd) % 64)) - - if(self.boot2 == True): - pack += "\x00" * (align(len(rawcert) + len(rawtik) + len(rawtmd), 0x40) - (len(rawcert) + len(rawtik) + len(rawtmd))) - - pack += apppack - - os.chdir('..') - if(fn == ""): - if(self.f[len(self.f) - 4:] == "_out"): - fn = os.path.dirname(self.f) + "/" + os.path.basename(self.f)[:len(os.path.basename(self.f)) - 4].replace("_", ".") - else: - fn = self.f - open(fn, "wb").write(pack) - return fn - def unpack(self, fn = ""): - """Unpacks the WAD from the parameter f in the initializer to either the value of fn, if there is one, or a folder created with this formula: `filename_extension_out`. Certs are put in the file "cert", TMD in the file "tmd", ticket in the file "tik", and contents are put in the files based on index and with ".app" added to the end.""" - fd = open(self.f, 'rb') - if(self.boot2 != True): - headersize, wadtype, certsize, reserved, tiksize, tmdsize, datasize, footersize, padding= struct.unpack('>I4s6I32s', fd.read(64)) - else: - headersize, data_offset, certsize, tiksize, tmdsize, padding = struct.unpack('>IIIII12s', fd.read(32)) - - try: - if(fn == ""): - fn = self.f.replace(".", "_") + "_out" - os.mkdir(fn) - except OSError: - pass - os.chdir(fn) - - rawcert = fd.read(certsize) - if(self.boot2 != True): - if(certsize % 64 != 0): - fd.seek(64 - (certsize % 64), 1) - open('cert', 'wb').write(rawcert) - - rawtik = fd.read(tiksize) - if(self.boot2 != True): - if(tiksize % 64 != 0): - fd.seek(64 - (tiksize % 64), 1) - open('tik', 'wb').write(rawtik) - - rawtmd = fd.read(tmdsize) - if(self.boot2 == True): - fd.seek(data_offset) - else: - fd.seek(64 - (tmdsize % 64), 1) - open('tmd', 'wb').write(rawtmd) - - titlekey = Ticket("tik").getTitleKey() - contents = TMD("tmd").getContents() - for i in range(0, len(contents)): - tmpsize = contents[i].size - if(tmpsize % 16 != 0): - tmpsize += 16 - (tmpsize % 16) - tmptmpdata = fd.read(tmpsize) - tmpdata = Crypto().decryptContent(titlekey, contents[i].index, tmptmpdata) - open("%08x.app" % contents[i].index, "wb").write(tmpdata) - if(tmpsize % 64 != 0): - fd.seek(64 - (tmpsize % 64), 1) - fd.close() - os.chdir('..') - - return fn - def __str__(self): - out = "" - out += "Wii WAD:\n" - fd = open(self.f, 'rb') - - if(self.boot2 != True): - headersize, wadtype, certsize, reserved, tiksize, tmdsize, datasize, footersize, padding= struct.unpack('>I4s6I32s', fd.read(64)) - else: - headersize, data_offset, certsize, tiksize, tmdsize, padding = struct.unpack('>IIIII12s', fd.read(32)) - - rawcert = fd.read(certsize) - if(certsize % 64 != 0): - fd.seek(64 - (certsize % 64), 1) - rawtik = fd.read(tiksize) - if(self.boot2 != True): - if(tiksize % 64 != 0): - fd.seek(64 - (tiksize % 64), 1) - rawtmd = fd.read(tmdsize) - - if(self.boot2 != True): - out += " Header %02x Type '%s' Certs %x Tiket %x TMD %x Data %x Footer %x\n" % (headersize, wadtype, certsize, tiksize, tmdsize, datasize, footersize) - else: - out += " Header %02x Type 'boot2' Certs %x Tiket %x TMD %x Data @ %x\n" % (headersize, certsize, tiksize, tmdsize, data_offset) - - out += str(Ticket(rawtik)) - out += str(TMD(rawtmd)) - - return out From a072ea5a757854705dac1f7c4007e54b024caaa5 Mon Sep 17 00:00:00 2001 From: Xuzz Date: Tue, 30 Jun 2009 00:27:15 -0700 Subject: [PATCH 7/7] removed useless files #1 --- TPL.py | 801 ----------------------- U8.py | 377 ----------- banner.py | 1803 --------------------------------------------------- savedata.py | 260 -------- 4 files changed, 3241 deletions(-) delete mode 100644 TPL.py delete mode 100644 U8.py delete mode 100755 banner.py delete mode 100644 savedata.py diff --git a/TPL.py b/TPL.py deleted file mode 100644 index 854e1fa..0000000 --- a/TPL.py +++ /dev/null @@ -1,801 +0,0 @@ -import os, struct, subprocess, fnmatch, shutil, urllib, array -from PIL import Image - -from Struct import Struct - -from common import * - -def flatten(myTuple): - if (len(myTuple) == 4): - return myTuple[0] << 0 | myTuple[1] << 8 | myTuple[2] << 16 | myTuple[3] << 24 - else: - return myTuple[0] << 0 | myTuple[1] << 8 | myTuple[2] << 16 | 0xff << 24 - -def round_up(x, n): - left = x % n - return x + left - -def avg(w0, w1, c0, c1): - a0 = c0 >> 11 - a1 = c1 >> 11 - a = (w0*a0 + w1*a1) / (w0 + w1) - c = (a << 11) & 0xffff - - a0 = (c0 >> 5) & 63 - a1 = (c1 >> 5) & 63 - a = (w0*a0 + w1*a1) / (w0 + w1) - c = c | ((a << 5) & 0xffff) - - a0 = c0 & 31 - a1 = c1 & 31 - a = (w0*a0 + w1*a1) / (w0 + w1) - c = c | a - - return c - - -class TPL(): - """This is the class to generate TPL texutres from PNG images, and to convert TPL textures to PNG images. The parameter file specifies the filename of the source, either a PNG image or a TPL image. - - Currently supported are the following formats to convert from TPL: RGBA8, RGB565, I4, IA4, I8, IA8, CI4, CI8, CMP, CI14X2. Currently not working is RBG5A3. RBG5A3 is having alpha issues, i'm working on it. - - Currently support to convert to TPL: I4, I8, IA4, IA8, RBG565, RBGA8. Currently not working/done are CI4, CI8, CMP, CI14X2, and RBG5A3. RBG5A3 is having alpha issues.""" - - - class TPLHeader(Struct): - __endian__ = Struct.BE - def __format__(self): - self.magic = Struct.uint32 - self.ntextures = Struct.uint32 - self.header_size = Struct.uint32 - class TPLTexture(Struct): - __endian__ = Struct.BE - def __format__(self): - self.header_offset = Struct.uint32 - self.palette_offset = Struct.uint32 - class TPLTextureHeader(Struct): - __endian__ = Struct.BE - def __format__(self): - self.height = Struct.uint16 - self.width = Struct.uint16 - self.format = Struct.uint32 - self.data_off = Struct.uint32 - self.wrap = Struct.uint32[2] - self.filter = Struct.uint32[2] - self.lod_bias = Struct.float - self.edge_lod = Struct.uint8 - self.min_lod = Struct.uint8 - self.max_lod = Struct.uint8 - self.unpacked = Struct.uint8 - class TPLPaletteHeader(Struct): - __endian__ = Struct.BE - def __format__(self): - self.nitems = Struct.uint16 - self.unpacked = Struct.uint8 - self.pad = Struct.uint8 - self.format = Struct.uint32 - self.offset = Struct.uint32 - def __init__(self, file): - if(os.path.isfile(file)): - self.file = file - self.data = None - else: - self.file = None - self.data = file - def toTPL(self, outfile, (width, height) = (None, None), format = "RGBA8"): #single texture only - """This converts an image into a TPL. The image is specified as the file parameter to the class initializer, while the output filename is specified here as the parameter outfile. Width and height are optional parameters and specify the size to resize the image to, if needed. Returns the output filename. - - This only can create TPL images with a single texture.""" - head = self.TPLHeader() - head.magic = 0x0020AF30 - head.ntextures = 1 - head.header_size = 0x0C - - tex = self.TPLTexture() - tex.header_offset = 0x14 - tex.pallete_offset = 0 - - img = Image.open(self.file) - theWidth, theHeight = img.size - if(width != None and height != None and (width != theWidth or height != theHeight)): - img = img.resize((width, height), Image.ANTIALIAS) - w, h = img.size - - texhead = self.TPLTextureHeader() - texhead.height = h - texhead.width = w - if format == "I4": - texhead.format = 0 - tpldata = self.toI4((w, h), img) - elif format == "I8": - texhead.format = 1 - tpldata = self.toI8((w, h), img) - elif format == "IA4": - texhead.format = 2 - tpldata = self.toIA4((w, h), img) - elif format == "IA8": - texhead.format = 3 - tpldata = self.toIA8((w, h), img) - elif format == "RGB565": - texhead.format = 4 - tpldata = self.toRGB565((w, h), img) - elif format == "RGB5A3": - texhead.format = 5 - tpldata = self.toRGB5A3((w, h), img) - elif format == "RGBA8": - texhead.format = 6 - tpldata = self.toRGBA8((w, h), img) - elif format == "CI4": - texhead.format = 8 - ''' ADD toCI4 ''' - raise Exception("toCI4 not done") - #tpldata = self.toCI4((w, h), img) - elif format == "CI8": - texhead.format = 9 - ''' ADD toCI8 ''' - raise Exception("toCI8 not done") - #tpldata = self.toCI8((w, h), img) - elif format == "CI14X2": - texhead.format = 10 - ''' ADD toCI14X2 ''' - raise Exception("toCI14X2 not done") - #tpldata = self.toCI14X2((w, h), img) - elif format == "CMP": - texhead.format = 14 - ''' ADD toCMP ''' - raise Exception("toCMP not done") - #tpldata = self.toCMP((w, h), img) - - texhead.data_off = 0x14 + len(texhead) - texhead.wrap = [0, 0] - texhead.filter = [1, 1] - texhead.lod_bias = 0 - texhead.edge_lod = 0 - texhead.min_lod = 0 - texhead.max_lod = 0 - texhead.unpacked = 0 - - f = open(outfile, "wb") - f.write(head.pack()) - f.write(tex.pack()) - f.write(texhead.pack()) - if format == "I4": - f.write(struct.pack(">" + str(align(w,4) * align(h,4) / 2) + "B", *tpldata)) - if format == "I8": - f.write(struct.pack(">" + str(align(w,4) * align(h,4) * 1) + "B", *tpldata)) - if format == "IA4": - f.write(struct.pack(">" + str(align(w,4) * align(h,4) * 1) + "B", *tpldata)) - if format == "IA8": - f.write(struct.pack(">" + str(align(w,4) * align(h,4) * 1) + "H", *tpldata)) - if format == "RGB565": - f.write(struct.pack(">" + str(align(w,4) * align(h,4) * 1) + "H", *tpldata)) - if format == "RGB5A3": - f.write(struct.pack(">" + str(align(w,4) * align(h,4) * 1) + "H", *tpldata)) - if format == "RGBA8": - f.write(struct.pack(">" + str(align(w,4) * align(h,4) * 4) + "B", *tpldata)) - if format == "CI4": - ''' ADD toCI4 ''' - #f.write(struct.pack(">"+ str(align(w,4) * align(h,4) * 4) + "B", *tpldata)) - if format == "CI8": - ''' ADD toCI8 ''' - #f.write(struct.pack(">"+ str(align(w,4) * align(h,4) * 4) + "B", *tpldata)) - if format == "CI14X2": - ''' ADD toCI14X2 ''' - #f.write(struct.pack(">"+ str(align(w,4) * align(h,4) * 4) + "B", *tpldata)) - if format == "CMP": - ''' ADD toCMP ''' - #f.write(struct.pack(">"+ str(align(w,4) * align(h,4) * 4) + "B", *tpldata)) - f.close() - - return outfile - def toI4(self, (w, h), img): - out = [0 for i in range(align(w, 4) * align(h, 4) / 2)] - outp = 0 - inp = list(img.getdata()) - for y1 in range(0, h, 8): - for x1 in range(0, w, 8): - for y in range(y1, y1+8, 1): - for x in range(x1, x1+8, 2): - if x>=w or y>=h: - newpixel = 0 - else: - rgba = flatten(inp[x+y*w]) - r = (rgba >> 0) & 0xff - g = (rgba >> 8) & 0xff - b = (rgba >> 16) & 0xff - i1 = ((r + g + b) / 3) & 0xff - rgba = flatten(inp[x+1+y*w]) - r = (rgba >> 0) & 0xff - g = (rgba >> 8) & 0xff - b = (rgba >> 16) & 0xff - i2 = ((r + g + b) / 3) & 0xff - - newpixel = (((i1 * 15) / 255) << 4) - newpixel |= (((i2 * 15) / 255) & 0xf) - out[outp] = newpixel - outp += 1 - return out - def toI8(self, (w, h), img): - out = [0 for i in range(align(w, 4) * align(h, 4))] - outp = 0 - inp = list(img.getdata()) - for y1 in range(0, h, 4): - for x1 in range(0, w, 8): - for y in range(y1, y1+4, 1): - for x in range(x1, x1+8, 1): - rgba = flatten(inp[x + (y * w)]) - if x>= w or y>=h: - i1 = 0 - else: - r = (rgba >> 0) & 0xff - g = (rgba >> 8) & 0xff - b = (rgba >> 16) & 0xff - i1 = ((r + g + b) / 3) & 0xff - out[outp] = i1 - outp += 1 - return out - def toIA4(self, (w, h), img): - out = [0 for i in range(align(w, 4) * align(h, 4))] - outp = 0 - inp = list(img.getdata()) - for y1 in range(0, h, 4): - for x1 in range(0, w, 8): - for y in range(y1, y1+4, 1): - for x in range(x1, x1+8, 1): - if x>=w or y>=h: - newpixel = 0 - else: - rgba = flatten(inp[x + (y * w)]) - r = (rgba >> 0) & 0xff - g = (rgba >> 8) & 0xff - b = (rgba >> 16) & 0xff - i1 = ((r + g + b) / 3) & 0xff - a1 = (rgba >> 24) & 0xff - - newpixel = (((i1 * 15) / 255) & 0xf) - newpixel = newpixel | (((a1 * 15) / 255) << 4) - out[outp] = newpixel - outp += 1 - return out - def toIA8(self, (w, h), img): - out = [0 for i in range(align(w, 4) * align(h, 4))] - outp = 0 - inp = list(img.getdata()) - for y1 in range(0, h, 4): - for x1 in range(0, w, 4): - for y in range(y1, y1+4, 1): - for x in range(x1, x1+4, 1): - if x>=w or y>=h: - newpixel = 0 - else: - rgba = flatten(inp[x + (y * w)]) - r = (rgba >> 0) & 0xff - g = (rgba >> 8) & 0xff - b = (rgba >> 16) & 0xff - i1 = ((r + g + b) / 3) & 0xff - a1 = (rgba >> 24) & 0xff - - newpixel = i1 << 8 - newpixel = newpixel | a1 - out[outp] = newpixel - outp += 1 - return out - def toRGB565(self, (w, h), img): - out = [0 for i in range(align(w, 4) * align(h, 4))] - outp = 0 - inp = img.getdata() - for y1 in range(0, h, 4): - for x1 in range(0, w, 4): - for y in range(y1, y1+4, 1): - for x in range(x1, x1+4, 1): - newpixel = 0 - if x>=w or y>=h: - newpixel = 0 - else: - rgba = flatten(inp[x+y*w]) - r = (rgba >> 0) & 0xff - g = (rgba >> 8) & 0xff - b = (rgba >> 16) & 0xff - newpixel = ((b >>3) << 11) | ((g >>2) << 5) | ((r >>3) << 0) - out[outp] = newpixel - outp += 1 - return out - def toRGB5A3(self, (w, h), img): - out = [0 for i in range(align(w, 4) * align(h, 4))] - outp = 0 - inp = list(img.getdata()) - for y1 in range(0, h, 4): - for x1 in range(0, w, 4): - for y in range(y1, y1+4, 1): - for x in range(x1, x1+4, 1): - newpixel = 0 - if x>=w or y>=h: - newpixel = 0 - else: - rgba = flatten(inp[x + (y * h)]) - r = (rgba >> 0) & 0xff - g = (rgba >> 8) & 0xff - b = (rgba >> 16) & 0xff - a = (rgba >> 24) & 0xff - if (a <= 0xda): - newpixel &= ~(1 << 15) - r = ((r * 15) / 255) & 0xf - g = ((g * 15) / 255) & 0xf - b = ((b * 15) / 255) & 0xf - a = ((a * 7) / 255) & 0x7 - #newpixel |= r << 12 - #newpixel |= g << 8 - #newpixel |= b << 4 - #newpixel |= a << 0 - newpixel |= a << 12 - newpixel |= b << 8 - newpixel |= g << 4 - newpixel |= r << 0 - else: - newpixel |= (1 << 15) - r = ((r * 31) / 255) & 0x1f - g = ((g * 31) / 255) & 0x1f - b = ((b * 31) / 255) & 0x1f - newpixel |= b << 10 - newpixel |= g << 5 - newpixel |= r << 0 - out[outp] = newpixel - outp += 1 - return out - def toRGBA8(self, (w, h), img): - out = [0 for i in range(align(w, 4) * align(h, 4) * 4)] - inp = list(img.getdata()) - iv = 0 - z = 0 - lr = [0 for i in range(32)] - lg = [0 for i in range(32)] - lb = [0 for i in range(32)] - la = [0 for i in range(32)] - for y1 in range(0, h, 4): - for x1 in range(0, w, 4): - for y in range(y1, y1 + 4, 1): - for x in range(x1, x1 + 4, 1): - if(y >= h or x >= w): - lr[z] = 0 - lg[z] = 0 - lb[z] = 0 - la[z] = 0 - else: - rgba = flatten(inp[x + (y * w)]) - lr[z] = (rgba >> 0) & 0xff - lg[z] = (rgba >> 8) & 0xff - lb[z] = (rgba >> 16) & 0xff - la[z] = (rgba >> 24) & 0xff - z += 1 - if(z == 16): - for i in range(16): - out[iv] = la[i] & 0xff - iv += 1 - out[iv] = lr[i] & 0xff - iv += 1 - for i in range(16): - out[iv] = lg[i] & 0xff - iv += 1 - out[iv] = lb[i] & 0xff - iv += 1 - z = 0 - return out - def toImage(self, outfile): - """This converts a TPL texture to a PNG image. You specify the input TPL filename in the initializer, and you specify the output filename in the outfile parameter to this method. Returns the output filename. - - This only supports single textured TPL images.""" - if(self.file): - data = open(self.file, "rb").read() - else: - data = self.data - - header = self.TPLHeader() - textures = [] - pos = 0 - - header.unpack(data[pos:pos + len(header)]) - pos += len(header) - - palette_offsets = [] - - for i in range(header.ntextures): - tmp = self.TPLTexture() - tmp.unpack(data[pos:pos + len(tmp)]) - textures.append(tmp) - pos += len(tmp) - if(tmp.palette_offset > 0): - palette_offsets.append(tmp.palette_offset) - - if(header.ntextures > 1): - raise ValueError("Only one texture supported. Don't touch me!") - - for i in range(header.ntextures): - head = textures[i] - tex = self.TPLTextureHeader() - tex.unpack(data[head.header_offset:head.header_offset + len(tex)]) - w = tex.width - h = tex.height - - if(tex.format == 0): #I4, 4-bit - tpldata = struct.unpack(">" + str((w * h) / 2) + "B", data[tex.data_off:tex.data_off + ((w * h) / 2)]) - rgbdata = self.I4((w, h), tpldata) - - elif(tex.format == 1): #I8, 8-bit - tpldata = struct.unpack(">" + str(w * h) + "B", data[tex.data_off:tex.data_off + (w * h * 1)]) - rgbdata = self.I8((w, h), tpldata) - elif(tex.format == 2): #IA4, 8-bit - tpldata = struct.unpack(">" + str(w * h) + "B", data[tex.data_off:tex.data_off + (w * h * 1)]) - rgbdata = self.IA4((w, h), tpldata) - - elif(tex.format == 4): #RGB565, 16-bit - tpldata = data[tex.data_off:] - rgbdata = self.RGB565((w, h), tpldata) - elif(tex.format == 5): #RGB5A3, 16-bit - tpldata = data[tex.data_off:] - rgbdata = self.RGB5A3((w, h), tpldata) - elif(tex.format == 3): #IA8, 16-bit - tpldata = data[tex.data_off:] - rgbdata = self.IA8((w, h), tpldata) - - elif(tex.format == 6): #RGBA8, 32-bit, but for easyness's sake lets do it with 16-bit - tpldata = data[tex.data_off:] - rgbdata = self.RGBA8((w, h), tpldata) - - elif(tex.format == 8 or tex.format == 9 or tex.format == 10): - palhead = self.TPLPaletteHeader() - offs = palette_offsets.pop(0) - palhead.unpack(data[offs:offs + len(palhead)]) - - tpldata = struct.unpack(">" + str(palhead.nitems) + "H", data[palhead.offset:palhead.offset + (palhead.nitems * 2)]) - if(palhead.format == 0): - palette_data = self.IA8((palhead.nitems, 1), tpldata)[0] - elif(palhead.format == 1): - palette_data = self.RGB565((palhead.nitems, 1), tpldata)[0] - elif(palhead.format == 2): - palette_data = self.RGB5A3((palhead.nitems, 1), tpldata)[0] - - paldata = [] - for i in range(0, palhead.nitems * 4, 4): - tmp = 0 - tmp |= palette_data[i + 0] << 24 - tmp |= palette_data[i + 1] << 16 - tmp |= palette_data[i + 2] << 8 - tmp |= palette_data[i + 3] << 0 - paldata.append(tmp) - - if(tex.format == 8): - tpldata = struct.unpack(">" + str((w * h) / 2) + "B", data[tex.data_off:tex.data_off + ((w * h) / 2)]) - rgbdata = self.CI4((w, h), tpldata, paldata) - if(tex.format == 9): - tpldata = struct.unpack(">" + str(w * h) + "B", data[tex.data_off:tex.data_off + (w * h * 1)]) - rgbdata = self.CI8((w, h), tpldata, paldata) - if(tex.format == 10): - tpldata = struct.unpack(">" + str(w * h) + "H", data[tex.data_off:tex.data_off + (w * h * 2)]) - rgbdata = self.CI14X2((w, h), tpldata, paldata) - elif(tex.format == 14): - tpldata = ''.join(data[tex.data_off:]) - - rgbdata = self.CMP((w, h), tpldata) - else: - raise TypeError("Unsupported TPL Format: " + str(tex.format)) - - output = Image.fromstring("RGBA", (w, h), rgbdata) - ext = outfile[outfile.rfind(".")+1:] - output.save(outfile, ext) - - return outfile - def getSizes(self): - """This returns a tuple containing the width and height of the TPL image filename in the class initializer. Will only return the size of single textured TPL images.""" - data = open(self.file, "rb").read() - - header = self.TPLHeader() - textures = [] - pos = 0 - - header.unpack(data[pos:pos + len(header)]) - pos += len(header) - - for i in range(header.ntextures): - tmp = self.TPLTexture() - tmp.unpack(data[pos:pos + len(tmp)]) - textures.append(tmp) - pos += len(tmp) - - for i in range(header.ntextures): - head = textures[i] - tex = self.TPLTextureHeader() - tex.unpack(data[head.header_offset:head.header_offset + len(tex)]) - w = tex.width - h = tex.height - return (w, h) - def toScreen(self): #single texture only - """This will draw a simple window with the TPL image displayed on it. It uses WxPython for the window creation and management. The window has a minimum width and height of 300 x 200. Does not return a value. - - Again, only a single texture is supported.""" - import wx - class imp(wx.Dialog): - def __init__(self, title, im): - w = img.GetWidth() - h = img.GetHeight() - - wx.Dialog.__init__(self, None, -1, title, size = (max(w, 300), max(h, 200))) - - wx.StaticBitmap(self, -1, im, ( ((max(w, 300) - w) / 2), ((max(h, 200) - h) / 2) ), (w, h)) - self.toImage("tmp.png") - img = wx.Image("tmp.png", wx.BITMAP_TYPE_ANY).ConvertToBitmap() - w = img.GetWidth() - h = img.GetHeight() - dialog = imp("TPL (" + str(w) + ", " + str(h) + ")", img) - dialog.ShowModal() - dialog.Destroy() - os.unlink("tmp.png") - def RGBA8(self, (x, y), data): - out = [0 for i in range(x * y)] - inp = 0 - for i in xrange(0, y, 4): - for j in xrange(0, x, 4): - for k in xrange(2): - for l in xrange(i, i + 4, 1): - for m in xrange(j, j + 4, 1): - texel = Struct.uint16(data[inp * 2:inp * 2 + 2], endian = '>') - inp += 1 - if (m >= x) or (l >= y): - continue - if k == 0: - a = (texel >> 8) & 0xff - r = (texel >> 0) & 0xff - out[m + (l * x)] = out[m + (l * x)] | ((r<<0) | (a<<24)) - else: - g = (texel >> 8) & 0xff - b = (texel >> 0) & 0xff - out[m + (l * x)] = out[m + (l * x)] | ((g<<8) | (b<<16)) - return ''.join(Struct.uint32(p) for p in out) - def RGB5A3(self, (w, h), jar): - out = [0 for i in range(w * h)] - i = 0 - for y in range(0, h, 4): - for x in range(0, w, 4): - for y1 in range(y, y + 4): - for x1 in range(x, x + 4): - if(y1 >= h or x1 >= w): - continue - pixel = Struct.uint16(jar[i * 2:i * 2 + 2], endian='>') - i += 1 - - if(pixel & (1 << 15)): #RGB555 - b = (((pixel >> 10) & 0x1F) * 255) / 31 - g = (((pixel >> 5) & 0x1F) * 255) / 31 - r = (((pixel >> 0) & 0x1F) * 255) / 31 - a = 255 - else: #RGB4A3 - a = (((pixel >> 12) & 0x07) * 255) / 7 - b = (((pixel >> 8) & 0x0F) * 255) / 15 - g = (((pixel >> 4) & 0x0F) * 255) / 15 - r = (((pixel >> 0) & 0x0F) * 255)/ 15 - - rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) - out[(y1 * w) + x1] = rgba - return ''.join(Struct.uint32(p) for p in out) - def RGB565(self, (w, h), jar): - out = [0 for i in range(w * h)] - i = 0 - for y in range(0, h, 4): - for x in range(0, w, 4): - for y1 in range(y, y + 4): - for x1 in range(x, x + 4): - if(y1 >= h or x1 >= w): - continue - pixel = Struct.uint16(jar[i * 2:i * 2 + 2], endian='>') - i += 1 - - b = (((pixel >> 11) & 0x1F) << 3) & 0xff - g = (((pixel >> 5) & 0x3F) << 2) & 0xff - r = (((pixel >> 0) & 0x1F) << 3) & 0xff - a = 255 - - rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) - out[y1 * w + x1] = rgba - return ''.join(Struct.uint32(p) for p in out) - def I4(self, (w, h), jar): - out = [0 for i in range(w * h)] - i = 0 - for y in range(0, h, 8): - for x in range(0, w, 8): - for y1 in range(y, y + 8): - for x1 in range(x, x + 8, 2): - if(y1 >= h or x1 >= w): - continue - pixel = jar[i] - - r = (pixel >> 4) * 255 / 15 - g = (pixel >> 4) * 255 / 15 - b = (pixel >> 4) * 255 / 15 - a = 255 - - rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) - out[y1 * w + x1] = rgba - - if(y1 >= h or x1 >= w): - continue - pixel = jar[i] - i += 1 - - r = (pixel & 0x0F) * 255 / 15 - g = (pixel & 0x0F) * 255 / 15 - b = (pixel & 0x0F) * 255 / 15 - a = 255 - - rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) - out[y1 * w + x1 + 1] = rgba - return ''.join(Struct.uint32(p) for p in out) - def IA4(self, (w, h), jar): - out = [0 for i in range(w * h)] - i = 0 - for y in range(0, h, 4): - for x in range(0, w, 8): - for y1 in range(y, y + 4): - for x1 in range(x, x + 8): - if(y1 >= h or x1 >= w): - continue - pixel = jar[i] - i += 1 - - r = ((pixel & 0x0F) * 255 / 15) & 0xff - g = ((pixel & 0x0F) * 255 / 15) & 0xff - b = ((pixel & 0x0F) * 255 / 15) & 0xff - a = (((pixel >> 4) * 255) / 15) & 0xff - - rgba = ( r<< 0) | (g << 8) | (b << 16) | (a << 24) - out[y1 * w + x1] = rgba - return ''.join(Struct.uint32(p) for p in out) - def I8(self, (w, h), jar): - out = [0 for i in range(w * h)] - i = 0 - for y in range(0, h, 4): - for x in range(0, w, 8): - for y1 in range(y, y + 4): - for x1 in range(x, x + 8): - if(y1 >= h or x1 >= w): - continue - pixel = jar[i] - i += 1 - - r = pixel - g = pixel - b = pixel - a = 255 - - rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) - out[y1 * w + x1] = rgba - return ''.join(Struct.uint32(p) for p in out) - def IA8(self, (w, h), jar): - out = [0 for i in range(w * h)] - i = 0 - for y in range(0, h, 4): - for x in range(0, w, 4): - for y1 in range(y, y + 4): - for x1 in range(x, x + 4): - if(y1 >= h or x1 >= w): - continue - pixel = Struct.uint16(jar[i * 2:i * 2 + 2], endian='>') - i += 1 - - r = (pixel >> 8) & 0xff - g = (pixel >> 8) & 0xff - b = (pixel >> 8) & 0xff - a = pixel & 0xff - - rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) - out[y1 * w + x1] = rgba - return ''.join(Struct.uint32(p) for p in out) - def CI4(self, (w, h), jar, pal): - out = [0 for i in range(w * h)] - i = 0 - for y in range(0, h, 8): - for x in range(0, w, 8): - for y1 in range(y, y + 8): - for x1 in range(x, x + 8, 2): - if(y1 >= h or x1 >= w): - continue - pixel = jar[i] - - r = (pal[pixel] & 0xFF000000) >> 24 - g = (pal[pixel] & 0x00FF0000) >> 16 - b = (pal[pixel] & 0x0000FF00) >> 8 - a = (pal[pixel] & 0x000000FF) >> 0 - - rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) - out[y1 * w + x1] = rgba - - if(y1 >= h or x1 >= w): - continue - pixel = jar[i] - i += 1 - - r = (pal[pixel] & 0xFF000000) >> 24 - g = (pal[pixel] & 0x00FF0000) >> 16 - b = (pal[pixel] & 0x0000FF00) >> 8 - a = (pal[pixel] & 0x000000FF) >> 0 - - rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) - out[y1 * w + x1 + 1] = rgba - return ''.join(Struct.uint32(p) for p in out) - def CI8(self, (w, h), jar, pal): - out = [0 for i in range(w * h)] - i = 0 - for y in range(0, h, 4): - for x in range(0, w, 8): - for y1 in range(y, y + 4): - for x1 in range(x, x + 8): - if(y1 >= h or x1 >= w): - continue - pixel = jar[i] - i += 1 - - r = (pal[pixel] & 0xFF000000) >> 24 - g = (pal[pixel] & 0x00FF0000) >> 16 - b = (pal[pixel] & 0x0000FF00) >> 8 - a = (pal[pixel] & 0x000000FF) >> 0 - - rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) - out[y1 * w + x1] = rgba - return ''.join(Struct.uint32(p) for p in out) - def CMP(self, (w, h), data): - temp = [0 for i in range(w * h)] - pix = [ 0 , 0 , 0 ] - c = [ 0 , 0 , 0 , 0 ] - outp = 0 - for y in xrange(h): - for x in xrange(w): - ww = round_up(w, 8) - - x0 = x & 0x03 - x1 = (x >> 2) & 0x01 - x2 = x >> 3 - - y0 = y & 0x03 - y1 = (y >> 2) & 0x01 - y2 = y >> 3 - - off = (8 * x1) + (16 * y1) + (32 * x2) + (4 * ww * y2) - - c[0] = Struct.uint16(data[off + 0:off + 2], endian='>') - c[1] = Struct.uint16(data[off + 2:off + 4], endian='>') - if(c[0] > c[1]): - c[2] = avg(2, 1, c[0], c[1]) - c[3] = avg(1, 2, c[0], c[1]) - else: - c[2] = avg(1, 1, c[0], c[1]) - c[3] = 0 - - px = Struct.uint32(data[off+4:off + 8], endian='>') - ix = x0 + ( 4 * y0 ) - raw = c[(px >> (30 - (2 * ix))) & 0x03] - - pix[0] = (raw >> 8) & 0xf8 - pix[1] = (raw >> 3) & 0xf8 - pix[2] = (raw << 3) & 0xf8 - - temp[outp] = (pix[0] <<0) | (pix[1] << 8) | (pix[2] << 16) | (255 << 24) - outp += 1 - return ''.join(Struct.uint32(p) for p in temp) - def CI14X2(self, (w, h), jar): - out = [0 for i in range(w * h)] - i = 0 - for y in range(0, h, 4): - for x in range(0, w, 4): - for y1 in range(y, y + 4): - for x1 in range(x, x + 4): - if(y1 >= h or x1 >= w): - continue - pixel = jar[i] - i += 1 - - r = (pal[pixel & 0x3FFF] & 0xFF000000) >> 24 - g = (pal[pixel & 0x3FFF] & 0x00FF0000) >> 16 - b = (pal[pixel & 0x3FFF] & 0x0000FF00) >> 8 - a = (pal[pixel & 0x3FFF] & 0x000000FF) >> 0 - - rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24) - out[y1 * w + x1] = rgba - return ''.join(Struct.uint32(p) for p in out) diff --git a/U8.py b/U8.py deleted file mode 100644 index 7f30fa2..0000000 --- a/U8.py +++ /dev/null @@ -1,377 +0,0 @@ -import os, struct, subprocess, fnmatch, shutil, urllib, array - -from Struct import Struct - -from common import * - - -class U8(): - """This class can unpack and pack U8 archives, which are used all over the Wii. They are often used in Banners and contents in Downloadable Titles. Please remove all headers and compression first, kthx. - - The f parameter is either the source folder to pack, or the source file to unpack.""" - class U8Header(Struct): - __endian__ = Struct.BE - def __format__(self): - self.tag = Struct.string(4) - self.rootnode_offset = Struct.uint32 - self.header_size = Struct.uint32 - self.data_offset = Struct.uint32 - self.zeroes = Struct.string(16) - class U8Node(Struct): - __endian__ = Struct.BE - def __format__(self): - self.type = Struct.uint16 - self.name_offset = Struct.uint16 - self.data_offset = Struct.uint32 - self.size = Struct.uint32 - def __init__(self, f): - self.f = f - def _pack(self, file, recursion, is_root = 0): #internal - node = self.U8Node() - node.name_offset = len(self.strings) - if(is_root != 1): - self.strings += (file) - self.strings += ("\x00") - - if(os.path.isdir(file)): - node.type = 0x0100 - node.data_offset = recursion - 1 - recursion += 1 - files = sorted(os.listdir(file)) - #if(sorted(files) == ["banner.bin", "icon.bin", "sound.bin"]): - # files = ["icon.bin", "banner.bin", "sound.bin"] - - oldsz = len(self.nodes) - if(is_root != 1): - self.nodes.append(node) - - os.chdir(file) - for entry in files: - if(entry != ".DS_Store" and entry[len(entry) - 4:] != "_out"): - self._pack(entry, recursion) - os.chdir("..") - - self.nodes[oldsz].size = len(self.nodes) + 1 - else: - f = open(file, "rb") - data = f.read() - f.close() - sz = len(data) - data += "\x00" * (align(sz, 32) - sz) #32 seems to work best for fuzzyness? I'm still really not sure - node.data_offset = len(self.data) - self.data += data - node.size = sz - node.type = 0x0000 - if(is_root != 1): - self.nodes.append(node) - - def pack(self, fn = ""): - """This function will pack a folder into a U8 archive. The output file name is specified in the parameter fn. If fn is an empty string, the filename is deduced from the input folder name. Returns the output filename. - - This creates valid U8 archives for all purposes.""" - header = self.U8Header() - rootnode = self.U8Node() - - header.tag = "U\xAA8-" - header.rootnode_offset = 0x20 - header.zeroes = "\x00" * 16 - - self.nodes = [] - self.strings = "\x00" - self.data = "" - origdir = os.getcwd() - os.chdir(self.f) - self._pack(".", 0, 1) - os.chdir(origdir) - - header.header_size = (len(self.nodes) + 1) * len(rootnode) + len(self.strings) - header.data_offset = align(header.header_size + header.rootnode_offset, 64) - rootnode.size = len(self.nodes) + 1 - rootnode.type = 0x0100 - - for i in range(len(self.nodes)): - if(self.nodes[i].type == 0x0000): - self.nodes[i].data_offset += header.data_offset - - if(fn == ""): - if(self.f[len(self.f) - 4:] == "_out"): - fn = os.path.dirname(self.f) + "/" + os.path.basename(self.f)[:-4].replace("_", ".") - else: - fn = self.f - - fd = open(fn, "wb") - fd.write(header.pack()) - fd.write(rootnode.pack()) - for node in self.nodes: - fd.write(node.pack()) - fd.write(self.strings) - fd.write("\x00" * (header.data_offset - header.rootnode_offset - header.header_size)) - fd.write(self.data) - fd.close() - - return fn - - def unpack(self, fn = ""): - """This will unpack the U8 archive specified by the initialization parameter into either the folder specified by the parameter fn, or into a folder created with this formula: - ``filename_extension_out`` - - This will recreate the directory structure, including the initial root folder in the U8 archive (such as "arc" or "meta"). Returns the output directory name.""" - data = open(self.f, "rb").read() - - offset = 0 - - header = self.U8Header() - header.unpack(data[offset:offset + len(header)]) - offset += len(header) - - if(header.tag != "U\xAA8-"): - raise NameError("Bad U8 Tag") - offset = header.rootnode_offset - - rootnode = self.U8Node() - rootnode.unpack(data[offset:offset + len(rootnode)]) - offset += len(rootnode) - - nodes = [] - for i in range(rootnode.size - 1): - node = self.U8Node() - node.unpack(data[offset:offset + len(node)]) - offset += len(node) - nodes.append(node) - - strings = data[offset:offset + header.data_offset - len(header) - (len(rootnode) * rootnode.size)] - offset += len(strings) - - if(fn == ""): - fn = os.path.dirname(self.f) + "/" + os.path.basename(self.f).replace(".", "_") + "_out" - try: - origdir = os.getcwd() - os.mkdir(fn) - except: - pass - os.chdir(fn) - - recursion = [rootnode.size] - counter = 0 - for node in nodes: - counter += 1 - name = strings[node.name_offset:].split('\0', 1)[0] - - if(node.type == 0x0100): #folder - recursion.append(node.size) - try: - os.mkdir(name) - except: - pass - os.chdir(name) - continue - elif(node.type == 0): #file - file = open(name, "wb") - file.write(data[node.data_offset:node.data_offset + node.size]) - offset += node.size - else: #unknown - pass #ignore - - sz = recursion.pop() - if(sz == counter + 1): - os.chdir("..") - else: - recursion.append(sz) - os.chdir("..") - - os.chdir(origdir) - return fn - def __str__(self): - data = open(self.f, "rb").read() - - offset = 0 - - header = self.U8Header() - header.unpack(data[offset:offset + len(header)]) - offset += len(header) - - if(header.tag != "U\xAA8-"): - raise NameError("Bad U8 Tag") - offset = header.rootnode_offset - - rootnode = self.U8Node() - rootnode.unpack(data[offset:offset + len(rootnode)]) - offset += len(rootnode) - - nodes = [] - for i in xrange(rootnode.size - 1): - node = self.U8Node() - node.unpack(data[offset:offset + len(node)]) - offset += len(node) - nodes.append(node) - - strings = data[offset:offset + header.data_offset - len(header) - (len(rootnode) * rootnode.size)] - offset += len(strings) - - out = "[root]\n" - recursion = [rootnode.size] - counter = 0 - for node in nodes: - counter += 1 - name = strings[node.name_offset:].split('\0', 1)[0] - out += " " * len(recursion) - if(node.type == 0x0100): #folder - recursion.append(node.size) - out += "[%s]\n" % name - continue - elif(node.type == 0): #file - out += "%s\n" % name - offset += node.size - else: #unknown, ignore - pass - - sz = recursion.pop() - if(sz == counter + 1): - pass - else: - recursion.append(sz) - return out - -class IMD5(): - """This class can add and remove IMD5 headers to files. The parameter f is the file to use for the addition or removal of the header. IMD5 headers are found in banner.bin, icon.bin, and sound.bin.""" - class IMD5Header(Struct): - __endian__ = Struct.BE - def __format__(self): - self.tag = Struct.string(4) - self.size = Struct.uint32 - self.zeroes = Struct.uint8[8] - self.crypto = Struct.string(16) - def __init__(self, f): - self.f = f - def add(self, fn = ""): - """This function adds an IMD5 header to the file specified by f in the initializer. The output file is specified with fn, if it is empty, it will overwrite the input file. If the file already has an IMD5 header, it will now have two. Returns the output filename.""" - data = open(self.f, "rb").read() - - imd5 = self.IMD5Header() - for i in range(8): - imd5.zeroes[i] = 0x00 - imd5.tag = "IMD5" - imd5.size = len(data) - imd5.crypto = str(Crypto().createMD5Hash(data)) - data = imd5.pack() + data - - if(fn != ""): - open(fn, "wb").write(data) - return fn - else: - open(self.f, "wb").write(data) - return self.f - def remove(self, fn = ""): - """This will remove an IMD5 header from the file specified in f, if one exists. If there is no IMD5 header, it will output the file as it is. It will output in the parameter fn if available, otherwise it will overwrite the source. Returns the output filename.""" - data = open(self.f, "rb").read() - imd5 = self.IMD5Header() - if(data[:4] != "IMD5"): - if(fn != ""): - open(fn, "wb").write(data) - return fn - else: - return self.f - data = data[len(imd5):] - - if(fn != ""): - open(fn, "wb").write(data) - return fn - else: - open(self.f, "wb").write(data) - return self.f - -class IMET(): - """IMET headers are found in Opening.bnr and 0000000.app files. They contain the channel titles and more metadata about channels. They are in two different formats with different amounts of padding before the start of the IMET header. This class suports both. - - The parameter f is used to specify the input file name.""" - class IMETHeader(Struct): - __endian__ = Struct.BE - def __format__(self): - self.zeroes = Struct.uint8[128] - self.tag = Struct.string(4) - self.unk = Struct.uint64 - self.sizes = Struct.uint32[3] #icon, banner, sound - self.unk2 = Struct.uint32 - self.names = Struct.string(84, encoding = "utf-16-be", stripNulls = True)[7] - self.zeroes2 = Struct.uint8[840] - self.hash = Struct.string(16) - def __init__(self, f): - self.f = f - def add(self, iconsz, bannersz, soundsz, name = "", langs = [], fn = ""): - """This function adds an IMET header to the file specified with f in the initializer. The file will be output to fn if it is not empty, otherwise it will overwrite the input file. You must specify the size of banner.bin in bannersz, and respectivly for iconsz and soundsz. langs is an optional arguement that is a list of different langauge channel titles. name is the english name that is copied everywhere in langs that there is an empty string. Returns the output filename.""" - data = open(self.f, "rb").read() - imet = self.IMETHeader() - - for i in imet.zeroes: - imet.zeroes[i] = 0x00 - imet.tag = "IMET" - imet.unk = 0x0000060000000003 - imet.sizes[0] = iconsz - imet.sizes[1] = bannersz - imet.sizes[2] = soundsz - imet.unk2 = 0 - for i in range(len(imet.names)): - if(len(langs) > 0 and langs[i] != ""): - imet.names[i] = langs[i] - else: - imet.names[i] = name - for i in imet.zeroes2: - imet.zeroes2[i] = 0x00 - imet.hash = "\x00" * 16 - - tmp = imet.pack() - imet.hash = Crypto().createMD5Hash(tmp[0x40:0x640]) #0x00 or 0x40? - - data = imet.pack() + data - - if(fn != ""): - open(fn, "wb").write(data) - return fn - else: - open(self.f, "wb").write(data) - return self.f - - def remove(self, fn = ""): - """This method removes an IMET header from a file specified with f in the initializer. fn is the output file name if it isn't an empty string, if it is, it will overwrite the input. If the input has no IMD5 header, it is output as is. Returns the output filename.""" - data = open(self.f, "rb").read() - if(data[0x80:0x84] == "IMET"): - data = data[0x640:] - elif(data[0x40:0x44] == "IMET"): - data = data[0x640:] - else: - if(fn != ""): - open(fn, "wb").write(data) - return fn - else: - return self.f - if(fn != ""): - open(fn, "wb").write(data) - return fn - else: - open(self.f, "wb").write(data) - return self.f - def getTitle(self): - imet = self.IMETHeader() - data = open(self.f, "rb").read() - - if(data[0x40:0x44] == "IMET"): - pass - elif(data[0x80:0x84] == "IMET"): - data = data[0x40:] - else: - return "" - - imet.unpack(data[:len(imet)]) - name = imet.names[1] - topop = [] - for i in range(len(name)): - if(name[i] == "\x00"): - topop.append(i) - name = list(name) - popped = 0 #don't ask me why I did this - for pop in topop: - name.pop(pop - popped) - popped += 1 - - name = ''.join(name) - return name diff --git a/banner.py b/banner.py deleted file mode 100755 index 32f5e4f..0000000 --- a/banner.py +++ /dev/null @@ -1,1803 +0,0 @@ -#!/usr/bin/python - -import sys, struct, re, os - -''' STOLEN FROM COMEX ''' -def nullterm(str_plus): - z = str_plus.find('\0') - if z != -1: - return str_plus[:z] - else: - return str_plus - -def unnullterm(var, size): - if len(var) > size: - raise Exception('unnullterm: "%s" too long' % var) - return var.ljust(size, '\0') - -def bit_extract(num, start, end=None): - if end is None: - end = start - mask = (2**(31 - start + 1) - 1) - (2**(31 - end) - 1) - ret = (num & mask) >> (31 - end) - - return ret - -def bit_place(num, start, end=None): - # Just for sanity - if end is None: - end = start - assert num <= 2**(end - start) - return num << (31 - end) - -def untv(name): - #assert '\0' not in name - lex = len(name) + 16 - lex -= lex % 16 - return name.ljust(lex, '\0') -''' END THEFT FROM COMEX ''' - -class BRLYT_Numoffs: - def __init__(self): - self.number = 0x00 - self.offset = 0x00 - def eat_numoffs(self, file, offset): - self.number, self.offset = struct.unpack('>HH', file[offset:offset+4]) - return - def show_numoffs(self): - print "Number: %04x" % self.number - print "Offset: %04x" % self.offset - return - def add(self): - self.number = self.number + 1 - return - def get_length(self): - templength = 2 + 2 - return templength - def write_to_file(self, file): - file.write(struct.pack('>H', self.number)) - file.write(struct.pack('>H', self.offset)) - -class BRLYT_SignedColor: - def __init__(self): - self.color1 = 255 - self.color2 = 255 - self.color3 = 255 - self.color4 = 255 - def eat_signedcolor(self, file, offset): - self.color1, self.color2, self.color3, self.color4 = struct.unpack('>hhhh', file[offset:offset+8]) - return - def show_signedcolor(self): - print "\tColor: %d" % self.color1 - print "\tColor: %d" % self.color2 - print "\tColor: %d" % self.color3 - print "\tColor: %d" % self.color4 - return - def get_length(self): - templength = 2 + 2 + 2 + 2 - return templength - def write_to_file(self, file): - file.write(struct.pack('>h', self.color1)) - file.write(struct.pack('>h', self.color2)) - file.write(struct.pack('>h', self.color3)) - file.write(struct.pack('>h', self.color4)) - return - -class BRLYT_Color: - def __init__(self): - self.color1 = 0xFFFFFFFF - self.color2 = 0xFFFFFFFF - self.color3 = 0xFFFFFFFF - self.color4 = 0xFFFFFFFF - def eat_color(self, file, offset): - self.color1, self.color2, self.color3, self.color4 = struct.unpack('>IIII', file[offset:offset+16]) - return - def show_color(self): - print "\tColor: %08x" % self.color1 - print "\tColor: %08x" % self.color2 - print "\tColor: %08x" % self.color3 - print "\tColor: %08x" % self.color4 - return - def get_length(self): - templength = 4 + 4 + 4 + 4 - return templength - def write_to_file(self, file): - file.write(struct.pack('>I', self.color1)) - file.write(struct.pack('>I', self.color2)) - file.write(struct.pack('>I', self.color3)) - file.write(struct.pack('>I', self.color4)) - return - -class BRLYT_Coordinates: - def __init__(self): - self.coord1 = 0.0 - self.coord2 = 0.0 - self.coord3 = 1.0 - self.coord4 = 0.0 - self.coord5 = 0.0 - self.coord6 = 1.0 - self.coord7 = 1.0 - self.coord8 = 1.0 - def eat_coordinates(self, file, offset): - self.coord1, self.coord2, self.coord3, self.coord4, self.coord5, self.coord6, self.coord7, self.coord8 = struct.unpack('>8f', file[offset:offset+32]) - return - def show_coordinates(self): - print "Coordinate: %f , %f" % ( self.coord1 , self.coord2 ) - print "Coordinate: %f , %f" % ( self.coord3 , self.coord4 ) - print "Coordinate: %f , %f" % ( self.coord5 , self.coord6 ) - print "Coordinate: %f , %f" % ( self.coord7 , self.coord8 ) - return - def get_length(self): - templength = 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 - return templength - def write_to_file(self, file): - file.write(struct.pack('>f', self.coord1)) - file.write(struct.pack('>f', self.coord2)) - file.write(struct.pack('>f', self.coord3)) - file.write(struct.pack('>f', self.coord4)) - file.write(struct.pack('>f', self.coord5)) - file.write(struct.pack('>f', self.coord6)) - file.write(struct.pack('>f', self.coord7)) - file.write(struct.pack('>f', self.coord8)) - return - -class BRLYT_Uab: - def __init__(self): - self.byte1 = 0x01 - self.byte2 = 0x04 - self.byte3 = 0x05 - self.byte4 = 0x00 - def eat_uab(self, file, offset): - self.byte1, self.byte2, self.byte3, self.byte4 = struct.unpack('BBBB', file[offset:offset+4]) - return - def show_uab(self): - print "UAb: %02x %02x %02x %02x" % ( self.byte1, self.byte2, self.byte3, self.byte4) - return - def get_length(self): - templength = 1 + 1 + 1 + 1 - return templength - def write_to_file(self, file): - file.write(struct.pack('>B', self.byte1)) - file.write(struct.pack('>B', self.byte2)) - file.write(struct.pack('>B', self.byte3)) - file.write(struct.pack('>B', self.byte4)) - return - -class BRLYT_Uaa: - def __init__(self): - self.byte1 = 0x77 - self.byte2 = 0x00 - self.byte3 = 0x00 - self.byte4 = 0x00 - def eat_uaa(self, file, offset): - self.byte1, self.byte2, self.byte3, self.byte4 = struct.unpack('BBBB', file[offset:offset+4]) - return - def show_uaa(self): - print "UAa: %02x %02x %02x %02x" % ( self.byte1, self.byte2, self.byte3, self.byte4) - return - def get_length(self): - templength = 1 + 1 + 1 + 1 - return templength - def write_to_file(self, file): - file.write(struct.pack('>B', self.byte1)) - file.write(struct.pack('>B', self.byte2)) - file.write(struct.pack('>B', self.byte3)) - file.write(struct.pack('>B', self.byte4)) - return - -class BRLYT_Ua9: - def __init__(self): - self.byte01 = 0x00 - self.byte02 = 0x00 - self.byte03 = 0x00 - self.byte04 = 0x00 - self.byte05 = 0x00 - self.byte06 = 0x00 - self.byte07 = 0x00 - self.byte08 = 0x00 - self.byte09 = 0x00 - self.byte10 = 0x00 - def eat_ua9(self, file, offset): - self.byte01, self.byte02, self.byte03, self.byte04, self.byte05, self.byte06, self.byte07, self.byte08, self.byte09, self.byte10 = struct.unpack('>10B', file[offset:offset+10]) - return - def show_ua9(self): - print "UA9: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x" % ( self.byte01, self.byte02, self.byte03, self.byte04, self.byte05, self.byte06, self.byte07, self.byte08, self.byte09, self.byte10 ) - return - def get_length(self): - templength = 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 - return templength - def write_to_file(self, file): - file.write(struct.pack('>B', self.byte01)) - file.write(struct.pack('>B', self.byte02)) - file.write(struct.pack('>B', self.byte03)) - file.write(struct.pack('>B', self.byte04)) - file.write(struct.pack('>B', self.byte05)) - file.write(struct.pack('>B', self.byte06)) - file.write(struct.pack('>B', self.byte07)) - file.write(struct.pack('>B', self.byte08)) - file.write(struct.pack('>B', self.byte09)) - file.write(struct.pack('>B', self.byte10)) - return - -class BRLYT_Ua8: - def __init__(self): - self.byte1 = 0x01 - self.byte2 = 0x04 - self.byte3 = 0x05 - self.byte4 = 0x00 - def eat_ua8(self, file, offset): - self.byte1, self.byte2, self.byte3, self.byte4 = struct.unpack('BBBB', file[offset:offset+4]) - return - def show_ua8(self): - print "UA8: %02x %02x %02x %02x" % ( self.byte1, self.byte2, self.byte3, self.byte4) - return - def get_length(self): - templength = 1 + 1 + 1 + 1 - return templength - def write_to_file(self, file): - file.write(struct.pack('>B', self.byte1)) - file.write(struct.pack('>B', self.byte2)) - file.write(struct.pack('>B', self.byte3)) - file.write(struct.pack('>B', self.byte4)) - return - -class BRLYT_Ua7: - def __init__(self): - self.a = 0x00000000 - self.b = 0x00000000 - self.c = 0.0 - self.d = 0.0 - self.e = 0.0 - def eat_ua7(self, file, offset): - self.a, self.b, self.c, self.d, self.e = struct.unpack('>IIfff', file[offset:offset+20]) - return - def show_ua7(self): - print "UA7: %08x %08x %f %f %f" % ( self.a , self.b , self.c , self.d , self.e ) - return - def get_length(self): - templength = 4 + 4 + 4 + 4 + 4 - return templength - def write_to_file(self, file): - file.write(struct.pack('>I', self.a)) - file.write(struct.pack('>I', self.b)) - file.write(struct.pack('>f', self.c)) - file.write(struct.pack('>f', self.d)) - file.write(struct.pack('>f', self.e)) - return - -class BRLYT_Ua6: - def __init__(self): - self.byte1 = 0x01 - self.byte2 = 0x04 - self.byte3 = 0x05 - self.byte4 = 0x00 - def eat_ua6(self, file, offset): - self.byte1, self.byte2, self.byte3, self.byte4 = struct.unpack('BBBB', file[offset:offset+4]) - return - def show_ua6(self): - print "UA6: %02x %02x %02x %02x" % ( self.byte1, self.byte2, self.byte3, self.byte4) - return - def get_length(self): - templength = 1 + 1 + 1 + 1 - return templength - def write_to_file(self, file): - file.write(struct.pack('>B', self.byte1)) - file.write(struct.pack('>B', self.byte2)) - file.write(struct.pack('>B', self.byte3)) - file.write(struct.pack('>B', self.byte4)) - return - -class BRLYT_Ua5: - def __init__(self): - self.byte1 = 0x01 - self.byte2 = 0x04 - self.byte3 = 0x05 - self.byte4 = 0x00 - def eat_ua5(self, file, offset): - self.byte1, self.byte2, self.byte3, self.byte4 = struct.unpack('BBBB', file[offset:offset+4]) - return - def show_ua5(self): - print "UA5: %02x %02x %02x %02x" % ( self.byte1, self.byte2, self.byte3, self.byte4) - return - def get_length(self): - templength = 1 + 1 + 1 + 1 - return templength - def write_to_file(self, file): - file.write(struct.pack('>B', self.byte1)) - file.write(struct.pack('>B', self.byte2)) - file.write(struct.pack('>B', self.byte3)) - file.write(struct.pack('>B', self.byte4)) - return - -class BRLYT_Ua4: - def __init__(self): - self.byte1 = 0x01 - self.byte2 = 0x04 - self.byte3 = 0x05 - self.byte4 = 0x00 - def eat_ua4(self, file, offset): - self.byte1, self.byte2, self.byte3, self.byte4 = struct.unpack('BBBB', file[offset:offset+4]) - return - def show_ua4(self): - print "UA4: %02x %02x %02x %02x" % ( self.byte1, self.byte2, self.byte3, self.byte4) - return - def get_length(self): - templength = 1 + 1 + 1 + 1 - return templength - def write_to_file(self, file): - file.write(struct.pack('>B', self.byte1)) - file.write(struct.pack('>B', self.byte2)) - file.write(struct.pack('>B', self.byte3)) - file.write(struct.pack('>B', self.byte4)) - return - -class BRLYT_Ua3: - def __init__(self): - self.byte1 = 0x01 - self.byte2 = 0x04 - self.byte3 = 0x1e - self.byte4 = 0x00 - def eat_ua3(self, file, offset): - self.byte1, self.byte2, self.byte3, self.byte4 = struct.unpack('BBBB', file[offset:offset+4]) - return - def show_ua3(self): - print "UA3: %02x %02x %02x %02x" % ( self.byte1, self.byte2, self.byte3, self.byte4) - return - def get_length(self): - templength = 1 + 1 + 1 + 1 - return templength - def write_to_file(self, file): - file.write(struct.pack('>B', self.byte1)) - file.write(struct.pack('>B', self.byte2)) - file.write(struct.pack('>B', self.byte3)) - file.write(struct.pack('>B', self.byte4)) - -class BRLYT_TextureMap: - def __init__(self): - self.x1 = 0.0 - self.y1 = 0.0 - self.angle = 0.0 - self.x2 = 1.0 - self.y2 = 1.0 - def eat_texturemap(self, file, offset): - self.x1, self.y1, self.angle, self.x2, self.y2 = struct.unpack('>fffff', file[offset:offset+20]) - return - def show_texturemap(self): - print "Coordinate 1: %f %f" % ( self.x1 , self.y1 ) - print "Angle: %f" % self.angle - print "Coordinate 2: %f %f" % ( self.x2 , self.y2 ) - return - def get_length(self): - templength = 4 + 4 + 4 + 4 + 4 - return templength - def write_to_file(self, file): - file.write(struct.pack('>f', self.x1)) - file.write(struct.pack('>f', self.y1)) - file.write(struct.pack('>f', self.angle)) - file.write(struct.pack('>f', self.x2)) - file.write(struct.pack('>f', self.y2)) - return - -class BRLYT_TexRef: - def __init__(self): - self.texture_offset = 0x0000 - self.wrap_s = 0x00 - self.wrap_t = 0x00 - def eat_texref(self, file, offset): - self.texture_offset, self.wrap_s, self.wrap_t = struct.unpack('>HBB', file[offset:offset+4]) - return - def show_texref(self): - print "Texture Offset: %04x" % self.texture_offset - print "Wrap_S: %02x" % self.wrap_s - print "Wrap_T: %02x" % self.wrap_t - return - def set_texture(self, texture, wrap_s=0, wrap_t=0): - self.texture_offset = texture - self.wrap_s = wrap_s - self.wrap_s = wrap_t - def get_length(self): - templength = 2 + 1 + 1 - return templength - def write_to_file(self, file): - file.write(struct.pack('>H', self.texture_offset)) - file.write(struct.pack('>B', self.wrap_s)) - file.write(struct.pack('>B', self.wrap_t)) - return - -class BRLYT_Material: - def __init__(self): - self.name = "material00" - self.forecolor = BRLYT_SignedColor() - self.backcolor = BRLYT_SignedColor() - self.unknowncolor = BRLYT_SignedColor() - self.tevcolor = BRLYT_Color() - self.flags = 0x00000000 - self.texrefs = { } - self.texturemaps = { } - self.ua3s = { } - self.ua4s = { } - self.ua5s = { } - self.ua6s = { } - self.ua7s = { } - self.ua8s = { } - self.ua9s = { } - self.uaas = { } - self.uabs = { } - def eat_material(self, file, offset): - dummy, self.name = struct.unpack('>I20s', file[offset-4:offset+20]) - self.forecolor.eat_signedcolor(file, offset+20) - self.backcolor.eat_signedcolor(file, offset+28) - self.unknowncolor.eat_signedcolor(file, offset+36) - self.tevcolor.eat_color(file, offset+44) - dummy, self.flags = struct.unpack('>II', file[offset+60-4:offset+60+4]) - file_offset = offset + 64 - for x in range(bit_extract(self.flags, 28, 31)): - self.texrefs[x] = BRLYT_TexRef() - self.texrefs[x].eat_texref(file, file_offset) - file_offset = file_offset + 4 - for x in range(bit_extract(self.flags, 24, 27)): - self.texturemaps[x] = BRLYT_TextureMap() - self.texturemaps[x].eat_texturemap(file, file_offset) - file_offset = file_offset + 20 - for x in range(bit_extract(self.flags, 20, 23)): - self.ua3s[x] = BRLYT_Ua3() - self.ua3s[x].eat_ua3(file, file_offset) - file_offset = file_offset + 4 - for x in range(bit_extract(self.flags, 6)): - self.ua4s[x] = BRLYT_Ua4() - self.ua4s[x].eat_ua4(file, file_offset) - file_offset = file_offset + 4 - for x in range(bit_extract(self.flags, 4)): - self.ua5s[x] = BRLYT_Ua5() - self.ua5s[x].eat_ua5(file, file_offset) - file_offset = file_offset + 4 - for x in range(bit_extract(self.flags, 19)): - self.ua6s[x] = BRLYT_Ua6() - self.ua6s[x].eat_ua6(file, file_offset) - file_offset = file_offset + 4 - for x in range(bit_extract(self.flags, 17, 18)): - self.ua7s[x] = BRLYT_Ua7() - self.ua7s[x].eat_ua7(file, file_offset) - file_offset = file_offset + 4 - for x in range(bit_extract(self.flags, 14, 16)): - self.ua8s[x] = BRLYT_Ua8() - self.ua8s[x].eat_ua8(file, file_offset) - file_offset = file_offset + 4 - for x in range(bit_extract(self.flags, 9, 13)): - self.ua9s[x] = BRLYT_Ua9() - self.ua9s[x].eat_ua9(file, file_offset) - file_offset = file_offset + 4 - for x in range(bit_extract(self.flags, 8)): - self.uaas[x] = BRLYT_Uaa() - self.uaas[x].eat_uaa(file, file_offset) - file_offset = file_offset + 4 - for x in range(bit_extract(self.flags, 7)): - self.uabs[x] = BRLYT_Uab() - self.uabs[x].eat_uab(file, file_offset) - file_offset = file_offset + 4 - return - def show_material(self): - print "Name: %s" % self.name.rstrip('\x00') - print "Forecolor: " - self.forecolor.show_signedcolor() - print "Backcolor: " - self.backcolor.show_signedcolor() - print "Unknown Color: " - self.unknowncolor.show_signedcolor() - print "Tev Color: " - self.tevcolor.show_color() - print "Flags: %08x" % self.flags - for x in range(bit_extract(self.flags, 28, 31)): - self.texrefs[x].show_texref() - for x in range(bit_extract(self.flags, 24, 27)): - self.texturemaps[x].show_texturemap() - for x in range(bit_extract(self.flags, 20, 23)): - self.ua3s[x].show_ua3() - for x in range(bit_extract(self.flags, 6)): - self.ua4s[x].show_ua4() - for x in range(bit_extract(self.flags, 4)): - self.ua5s[x].show_ua5() - for x in range(bit_extract(self.flags, 19)): - self.ua6s[x].show_ua6() - for x in range(bit_extract(self.flags, 17, 18)): - self.ua7s[x].show_ua7() - for x in range(bit_extract(self.flags, 14, 16)): - self.ua8s[x].show_ua8() - for x in range(bit_extract(self.flags, 9, 13)): - self.ua9s[x].show_ua9() - for x in range(bit_extract(self.flags, 8)): - self.uaas[x].show_uaa() - for x in range(bit_extract(self.flags, 7)): - self.uabs[x].show_uab() - return - def set_texture(self, texture, wrap_s=0, wrap_t=0): - self.texrefs[0] = BRLYT_TexRef() - self.texrefs[0].set_texture(texture, wrap_s, wrap_t) - def get_length(self): - templength = 20 + self.forecolor.get_length() + self.backcolor.get_length() - templength = templength + self.unknowncolor.get_length() + self.tevcolor.get_length() + 4 - for x in range(len(self.texrefs)): - templength = templength + self.texrefs[x].get_length() - for x in range(len(self.texturemaps)): - templength = templength + self.texturemaps[x].get_length() - for x in range(len(self.ua3s)): - templength = templength + self.ua3s[x].get_length() - for x in range(len(self.ua4s)): - templength = templength + self.ua4s[x].get_length() - for x in range(len(self.ua5s)): - templength = templength + self.ua5s[x].get_length() - for x in range(len(self.ua6s)): - templength = templength + self.ua6s[x].get_length() - for x in range(len(self.ua7s)): - templength = templength + self.ua7s[x].get_length() - for x in range(len(self.ua8s)): - templength = templength + self.ua8s[x].get_length() - for x in range(len(self.ua9s)): - templength = templength + self.ua9s[x].get_length() - for x in range(len(self.uaas)): - templength = templength + self.uaas[x].get_length() - for x in range(len(self.uabs)): - templength = templength + self.uabs[x].get_length() - return templength - def write_to_file(self, file): - file.write(struct.pack('>20s', self.name)) - self.forecolor.write_to_file(file) - self.backcolor.write_to_file(file) - self.unknowncolor.write_to_file(file) - self.tevcolor.write_to_file(file) - file.write(struct.pack('>I', self.flags)) - for x in range(bit_extract(self.flags, 28, 31)): - self.texrefs[x].write_to_file(file) - for x in range(bit_extract(self.flags, 24, 27)): - self.texturemaps[x].write_to_file(file) - for x in range(bit_extract(self.flags, 20, 23)): - self.ua3s[x].write_to_file(file) - for x in range(bit_extract(self.flags, 6)): - self.ua4s[x].write_to_file(file) - for x in range(bit_extract(self.flags, 4)): - self.ua5s[x].write_to_file(file) - for x in range(bit_extract(self.flags, 19)): - self.ua6s[x].write_to_file(file) - for x in range(bit_extract(self.flags, 17, 18)): - self.ua7s[x].write_to_file(file) - for x in range(bit_extract(self.flags, 14, 16)): - self.ua8s[x].write_to_file(file) - for x in range(bit_extract(self.flags, 9, 13)): - self.ua9s[x].write_to_file(file) - for x in range(bit_extract(self.flags, 8)): - self.uaas[x].write_to_file(file) - for x in range(bit_extract(self.flags, 7)): - self.uabs[x].write_to_file(file) - return - -class BRLYT_Pane: - def __init__(self, name = "RootPane", x = 0, y = 0, z = 0, w = 608, h = 456): - self.orientation1 = 0x01 - self.orientation2 = 0x04 - self.alpha1 = 0xff - self.alpha2 = 0x00 - self.name = name - self.x = x - self.y = y - self.z = z - self.flipx = 0.0 - self.flipy = 0.0 - self.angle = 0.0 - self.xmag = 1.0 - self.ymag = 1.0 - self.width = w - self.height = h - def eat_pane(self, file, offset): - self.orientation1, self.orientation2, self.alpha1, self.alpha2 = struct.unpack('BBBB', file[offset:offset+4]) - self.name, self.x, self.y, self.z = struct.unpack('>24sfff', file[offset+0x04:offset+0x04+36]) - self.flipx, self.flipy, self.angle = struct.unpack('>fff', file[offset+0x28:offset+0x28+12]) - self.xmag, self.ymag = struct.unpack('>ff', file[offset+0x34:offset+0x34+8]) - self.width, self.height = struct.unpack('>ff', file[offset+0x3C:offset+0x3C+8]) - return - def show_pane(self): - print "Orientation: %02x %02x" % (self.orientation1 , self.orientation2) - print "Alpha: %02x %02x" % (self.alpha1 , self.alpha2) - print "Name: %s" % self.name.rstrip('\x00') - print "X: %f" % self.x - print "y: %f" % self.y - print "z: %f" % self.z - print "flip x: %f" % self.flipx - print "flip y: %f" % self.flipy - print "angle: %f" % self.angle - print "x zoom: %f" % self.xmag - print "y zoom: %f" % self.ymag - print "width: %f" % self.width - print "height: %f" % self.height - return - def get_length(self): - templength = 1 + 1 + 1 + 1 + 24 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 - return templength - def write_to_file(self, file): - file.write(struct.pack('>B', self.orientation1)) - file.write(struct.pack('>B', self.orientation2)) - file.write(struct.pack('>B', self.alpha1)) - file.write(struct.pack('>B', self.alpha2)) - file.write(struct.pack('>24s', self.name)) - file.write(struct.pack('>f', self.x)) - file.write(struct.pack('>f', self.y)) - file.write(struct.pack('>f', self.z)) - file.write(struct.pack('>f', self.flipx)) - file.write(struct.pack('>f', self.flipy)) - file.write(struct.pack('>f', self.angle)) - file.write(struct.pack('>f', self.xmag)) - file.write(struct.pack('>f', self.ymag)) - file.write(struct.pack('>f', self.width)) - file.write(struct.pack('>f', self.height)) - return - -class BRLYT_gre1: - def __init__(self): - self.magic = "gre1" - self.length = 0x08 - def eat_tag(self, file, offset): - self.magic, self.length = struct.unpack('>4sI', file[offset:offset+8]) - return - def show_tag(self): - print "Magic: %s" % self.magic - print "Length: %08x" % self.length - return - def get_length(self): - self.length = 4 + 4 - return self.length - def write_to_file(self, file): - file.write(self.magic) - file.write(struct.pack('>I', self.length)) - return - -class BRLYT_grs1: - def __init__(self): - self.magic = "grs1" - self.length = 0x08 - def eat_tag(self, file, offset): - self.magic, self.length = struct.unpack('>4sI', file[offset:offset+8]) - return - def show_tag(self): - print "Magic: %s" % self.magic - print "Length: %08x" % self.length - return - def get_length(self): - self.length = 4 + 4 - return self.length - def write_to_file(self, file): - file.write(self.magic) - file.write(struct.pack('>I', self.length)) - return - -class BRLYT_grp1: - def __init__(self): - self.magic = "grp1" - self.length = 0x00000000 - self.name = "RootGroup" - self.numsubs = 0x0000 - self.unknown = 0x0000 - self.subs = [] - def eat_tag(self, file, offset): - self.magic, self.length = struct.unpack('>4sI', file[offset:offset+8]) - self.name, self.numsubs, self.unknown = struct.unpack('>16sHH', file[offset+0x08:offset+0x08+20]) - for x in range(self.numsubs): - dummy, subname = struct.unpack('>I16s', file[offset+0x1C+16*x-4:offset+0x1C+16*x+16]) - self.subs.append(subname) - return - def show_tag(self): - print "Magic: %s" % self.magic - print "Length: %08x" % self.length - print "Name: %s" % self.name.rstrip('\x00') - print "Number of Subs: %04x" % self.numsubs - print "Unknown: %04x" % self.unknown - for x in self.subs: - print "Sub: %s" % x.rstrip('\x00') - return - def get_length(self): - self.length = 4 + 4 + 16 + 2 + 2 + self.numsubs * 16 - return self.length - def write_to_file(self, file): - file.write(self.magic) - file.write(struct.pack('>I', self.length)) - file.write(struct.pack('>16s', self.name)) - file.write(struct.pack('>H', self.numsubs)) - file.write(struct.pack('>H', self.unknown)) - for x in self.subs: - file.write(struct.pack('>16s', x)) - return - -class BRLYT_txt1: - def __init__(self): - self.magic = "txt1" - self.pane = BRLYT_Pane() - len1 = 0x0000 - len2 = 0x0000 - mat_off = 0x0000 - font = 0x0000 - unknown = 0x00 - padding1 = 0 - padding2 = 0 - padding3 = 0 - name_offs = 0x00000000 - color1 = 0xFFFFFFFF - color2 = 0x00000000 - font_size_x = 32.0 - font_size_y = 32.0 - char_space = 32.0 - line_space = 32.0 - def eat_tag(self, file, offset): - self.magic, self.length = struct.unpack('>4sI', file[offset:offset+8]) - self.pane.eat_pane(file, offset+8) - self.len1, self.len2, self.mat_off, self.font = struct.unpack('>HHHH', file[offset+0x4C:offset+0x4C+8]) - self.unknown, self.padding1, self.padding2, self.padding3 = struct.unpack('>BBBB', file[offset+0x54:offset+0x54+4]) - self.name_offs, self.color1, self.color2 = struct.unpack('>III', file[offset+0x58:offset+0x58+12]) - self.font_size_x, self.font_size_y = struct.unpack('>ff', file[offset+0x64:offset+0x64+8]) - self.char_space, self.line_space = struct.unpack('>ff', file[offset+0x6C:offset+0x6C+8]) - text = file[offset+0x74:offset+0x74+self.len2] - self.text = unicode(text, 'utf_16_be').rstrip('\x00') - return - def show_tag(self): - print "Magic: %s" % self.magic - print "Length: %08x" % self.length - self.pane.show_pane() - print "Length: %04x %04x" % ( self.len1 , self.len2 ) - print "Material: %04x" % self.mat_off - print "Font: %04x" % self.font - print "Unknown: %02x" % self.unknown - print "Padding: %02x %02x %02x" % ( self.padding1 , self.padding2 , self.padding3 ) - print "Name offset: %08x" % self.name_offs - print "Color1: %08x" % self.color1 - print "Color2: %08x" % self.color2 - print "Font Size X: %f" % self.font_size_x - print "Font Size Y: %f" % self.font_size_y - print "Character Spacing: %f" % self.char_space - print "Line Spacing: %f" % self.line_space - print "Text: ", self.text # N E E D S S O M E W O R K - return - def get_text_length(self): - return len(self.text) - def get_length(self): - templength = 4 + 4 + self.pane.get_length() - templength = templength + 2 + 2 + 2 + 2 + 1 + 1 + 1 + 1 - templength = templength + 4 + 4 + 4 + 4 + 4 + 4 + 4 - templength = templength + self.get_text_length() - self.length = templength - return self.length - def write_to_file(self, file): - file.write(self.magic) - file.write(struct.pack('>I', self.length)) - self.pane.write_to_file(file) - file.write(struct.pack('>H', self.len1)) - file.write(struct.pack('>H', self.len2)) - file.write(struct.pack('>H', self.mat_off)) - file.write(struct.pack('>H', self.font)) - file.write(struct.pack('>B', self.unknown)) - file.write(struct.pack('>B', self.padding1)) - file.write(struct.pack('>B', self.padding2)) - file.write(struct.pack('>B', self.padding3)) - file.write(struct.pack('>I', self.name_offs)) - file.write(struct.pack('>I', self.color1)) - file.write(struct.pack('>I', self.color2)) - file.write(struct.pack('>f', self.font_size_x)) - file.write(struct.pack('>f', self.font_size_y)) - file.write(struct.pack('>f', self.char_space)) - file.write(struct.pack('>f', self.line_space)) - text = untv(unicode(self.text).encode('utf_16_be')) - file.write(text) - return - -class BRLYT_pic1: - def __init__(self, name = "Picture", x = 0, y = 0, z = 0, w = 608, h = 456, material_offs = 0): - self.magic = "pic1" - self.length = 0x0000000 - self.pane = BRLYT_Pane(name, x, y, z, w, h) - self.vtx_color1 = 0xFFFFFFFF - self.vtx_color2 = 0xFFFFFFFF - self.vtx_color3 = 0xFFFFFFFF - self.vtx_color4 = 0xFFFFFFFF - self.mat_off = material_offs - self.num_coordinates = 0x01 - self.padding = 0x00 - self.coordinates = { } - self.coordinates[0] = BRLYT_Coordinates() - def eat_tag(self, file, offset): - self.magic, self.length = struct.unpack('>4sI', file[offset:offset+8]) - self.pane.eat_pane(file, offset+8) - self.vtx_color1, self.vtx_color2, self.vtx_color3, self.vtx_color4 = struct.unpack('>IIII', file[offset+0x4C:offset+0x4C+16]) - self.mat_off, self.num_coordinates, self.padding = struct.unpack('>HBB', file[offset+0x5C:offset+0x5C+4]) - for x in range(self.num_coordinates): - self.coordinates[x] = BRLYT_Coordinates() - self.coordinates[x].eat_coordinates(file, offset+0x60+x*32) - return - def show_tag(self): - print "Magic: %s" % self.magic - print "Length: %08x" % self.length - self.pane.show_pane() - print "Vertex Colors: %08x %08x %08x %08x" % (self.vtx_color1, self.vtx_color2, self.vtx_color3, self.vtx_color4) - print "Material Offset: %04x" % self.mat_off - print "Number of Coordinates: %02x" % self.num_coordinates - print "Padding: %02x" % self.padding - for x in range(len(self.coordinates)): - self.coordinates[x].show_coordinates() - return - def get_length(self): - templength = 4 + 4 + self.pane.get_length() - templength = templength + 4 + 4 + 4 + 2 + 1 + 1 - for x in range(len(self.coordinates)): - templength = templength + self.coordinates[x].get_length() - self.length = templength - return self.length - def write_to_file(self, file): - file.write(self.magic) - file.write(struct.pack('>I', self.length)) - self.pane.write_to_file(file) - file.write(struct.pack('>I', self.vtx_color1)) - file.write(struct.pack('>I', self.vtx_color2)) - file.write(struct.pack('>I', self.vtx_color3)) - file.write(struct.pack('>I', self.vtx_color4)) - file.write(struct.pack('>H', self.mat_off)) - file.write(struct.pack('>B', self.num_coordinates)) - file.write(struct.pack('>B', self.padding)) - for x in range(len(self.coordinates)): - self.coordinates[x].write_to_file(file) - return - -class BRLYT_WindowAddon3: - def __init__(self): - self.unknown1 = 0x0000 - self.unknown2 = 0x0000 - def eat_windowaddon3(self, file, offset): - self.unknown1, self.unknown2 = struct.unpack('>HH', file[offset:offset+4]) - return - def show_windowaddon3(self): - print "Unknown: %04x %04x" % ( self.unknown1 , self.unknown2 ) - return - def get_length(self): - templength = 2 + 2 - return templength - def write_to_file(self, file): - file.write(struct.pack('>H', self.unknown1)) - file.write(struct.pack('>H', self.unknown2)) - return - -class BRLYT_WindowAddon2: - def __init__(self): - self.unknown1 = 0x00000000 - self.unknown2 = 0x00000000 - self.unknown3 = 0x00000000 - self.unknown4 = 0x00000000 - def eat_windowaddon2(self, file, offset): - self.unknown1, self.unknown2, self.unknown3, self.unknown4 = struct.unpack('>IIII', file[offset:offset+16]) - return - def show_windowaddon2(self): - print "Unknown: %08x %08x %08x %08x" % ( self.unknown1, self.unknown2, self.unknown3, self.unknown4 ) - return - def get_length(self): - templength = 4 + 4 + 4 + 4 - return templength - def write_to_file(self, file): - file.write(struct.pack('>I', self.unknown1)) - file.write(struct.pack('>I', self.unknown2)) - file.write(struct.pack('>I', self.unknown3)) - file.write(struct.pack('>I', self.unknown4)) - return - -class BRLYT_WindowAddon1: - def __init__(self): - self.unknown1 = 0.0 - self.unknown2 = 0.0 - self.unknown3 = 0.0 - self.unknown4 = 0.0 - self.count = 0x01 - self.padding1 = 0x00 - self.padding2 = 0x00 - self.padding3 = 0x00 - self.offset1 = 0x00000068 - self.offset2 = 0x0000007C - def eat_windowaddon1(self, file, offset): - self.unknown1, self.unknown2, self.unknown3, self.unknown4 = struct.unpack('>ffff', file[offset:offset+16]) - self.count, self.padding1, self.padding2, self.padding3 = struct.unpack('>BBBB', file[offset+0x10:offset+0x10+4]) - self.offset1, self.offset2 = struct.unpack('>II', file[offset+0x14:offset+0x14+8]) - return - def show_windowaddon1(self): - print "Unknown: %f %f %f %f" % ( self.unknown1, self.unknown2, self.unknown3, self.unknown4 ) - print "Count: %02x" % self.count - print "Padding %02x %02x %02x" % ( self.padding1, self.padding2, self.padding3 ) - print "Offset 1: %08x" % self.offset1 - print "Offset 2: %08x" % self.offset2 - return - def get_length(self): - templength = 4 + 4 + 4 + 4 + 1 + 1 + 1 + 1 + 4 + 4 - return templength - def write_to_file(self, file): - file.write(struct.pack('>B', self.count)) - file.write(struct.pack('>B', self.padding1)) - file.write(struct.pack('>B', self.padding2)) - file.write(struct.pack('>B', self.padding3)) - file.write(struct.pack('>I', self.offset1)) - file.write(struct.pack('>I', self.offset2)) - return - -class BRLYT_wnd1: - def __init__(self): - self.magic = "wnd1" - self.pane = BRLYT_Pane() - self.addon1 = BRLYT_WindowAddon1() - self.addon2 = BRLYT_WindowAddon2() - self.addon3 = BRLYT_WindowAddon3() - self.offsets = [] - self.materials = [] - def eat_tag(self, file, offset): - self.magic, self.length = struct.unpack('>4sI', file[offset:offset+8]) - self.pane.eat_pane(file, offset+8) - self.addon1.eat_windowaddon1(file, offset+0x4c) - self.addon2.eat_windowaddon2(file, offset+0x4c+28) - self.addon3.eat_windowaddon3(file, offset+0x4c+44) - if self.addon1.offset1 == 0x9c: - self.addon4 = BRLYT_Coordinates() - self.addon4.eat_coordinates(file, offset+0x4c+48) - for x in range(self.addon1.count): - dummy, offs = struct.unpack('>II', file[offset+0x4c+48+32-4:offset+0x4c+48+32+4]) - self.offsets.append(offs) - for x in range(self.addon1.count): - dummy, mat = struct.unpack('>II', file[offset+0x4c+48+32+self.addon1.count*4-4:offset+0x4c+48+32+self.addon1.count*4+4]) - self.materials.append(mat) - return - def show_tag(self): - print "Magic: %s" % self.magic - print "Length: %08x" % self.length - self.pane.show_pane() - self.addon1.show_windowaddon1() - self.addon2.show_windowaddon2() - self.addon3.show_windowaddon3() - if self.addon1.offset1 == 0x9c: - self.addon4.show_coordinates() - for x in range(self.addon1.count): - print "Offset: %08x" % self.offsets[x] - print "Material: %08x" % self.materials[x] - return - def get_length(self): - templength = 4 + 4 + self.addon1.get_length() + self.addon2.get_length() + self.addon3.get_length() - if self.addon1.offset1 == 0x9c: - templength = templength + self.addon4.get_length() - templength = templength + self.addon1.count * 8 - self.length = templength - return self.length - def write_to_file(self, file): - file.write(self.magic) - file.write(struct.pack('>I', self.length)) - self.pane.write_to_file(file) - self.addon1.write_to_file(file) - self.addon2.write_to_file(file) - self.addon3.write_to_file(file) - if self.addon1.offset1 == 0x9c: - self.addon4.write_to_file(file) - tempOffset = self.addon1.count * 4 - for x in range(self.addon1.count): - file.write(struct.pack('>I', tempOffset)) - self.offsets[x] = tempOffset - for x in self.materials: - file.write(struct.pack('>I', x)) - return - -class BRLYT_bnd1: - def __init__(self): - self.magic = "bnd1" - self.pane = BRLYT_Pane() - def eat_tag(self, file, offset): - self.magic, self.length = struct.unpack('>4sI', file[offset:offset+8]) - self.pane.eat_pane(file, offset+8) - return - def show_tag(self): - print "Magic: %s" % self.magic - print "Length: %08x" % self.length - self.pane.show_pane() - return - def get_length(self): - self.length = 4 + 4 + self.pane.get_length() - return self.length - def write_to_file(self, file): - file.write(self.magic) - file.write(struct.pack('>I', self.length)) - self.pane.write_to_file(file) - return - -class BRLYT_pae1: - def __init__(self): - self.magic = "pae1" - self.length = 0x08 - def eat_tag(self, file, offset): - self.magic, self.length = struct.unpack('>4sI', file[offset:offset+8]) - return - def show_tag(self): - print "Magic: %s" % self.magic - print "Length: %08x" % self.length - return - def get_length(self): - self.length = 4 + 4 - return self.length - def write_to_file(self, file): - file.write(self.magic) - file.write(struct.pack('>I', self.length)) - return - -class BRLYT_pas1: - def __init__(self): - self.magic = "pas1" - self.length = 0x08 - def eat_tag(self, file, offset): - self.magic, self.length = struct.unpack('>4sI', file[offset:offset+8]) - return - def show_tag(self): - print "Magic: %s" % self.magic - print "Length: %08x" % self.length - return - def get_length(self): - self.length = 4 + 4 - return self.length - def write_to_file(self, file): - file.write(self.magic) - file.write(struct.pack('>I', self.length)) - return - -class BRLYT_pan1: - def __init__(self, name = "RootPane", x = 0, y = 0, z = 0, w = 608, h = 456): - self.magic = "pan1" - self.pane = BRLYT_Pane(name, x, y, z, w, h) - def eat_tag(self, file, offset): - self.magic, self.length = struct.unpack('>4sI', file[offset:offset+8]) - self.pane.eat_pane(file, offset+8) - return - def show_tag(self): - print "Magic: %s" % self.magic - print "Length: %08x" % self.length - self.pane.show_pane() - return - def get_length(self): - self.length = 4 + 4 + self.pane.get_length() - return self.length - def write_to_file(self, file): - file.write(self.magic) - file.write(struct.pack('>I', self.length)) - self.pane.write_to_file(file) - return - -class BRLYT_mat1: - def __init__(self): - self.magic = "mat1" - self.numoffs = BRLYT_Numoffs() - self.offsets = [] - self.materials = { } - def eat_tag(self, file, offset): - self.magic, self.length = struct.unpack('>4sI', file[offset:offset+8]) - self.numoffs.eat_numoffs(file, offset+8) - for x in range(self.numoffs.number): - dummy, offs = struct.unpack('>II', file[offset+0x0C+4*x-4:offset+0x0C+4*x+4]) - self.offsets.append(offs) - self.materials[x] = BRLYT_Material() - self.materials[x].eat_material(file, offset+self.offsets[x]) - return - def show_tag(self): - print "Magic: %s" % self.magic - print "Length: %08x" % self.length - self.numoffs.show_numoffs() - for x in range(self.numoffs.number): - print "Offsets[%d]: %08x" % ( x , self.offsets[x] ) - self.materials[x].show_material() - return - def add_material(self, material, texture): - self.materials[self.numoffs.number] = BRLYT_Material() - self.offsets.append(self.numoffs.number) - self.numoffs.add() - self.materials[self.numoffs.number - 1].name = material - self.materials[self.numoffs.number - 1].set_texture(texture) - def get_length(self): - templength = 4 + 4 + 4 + self.numoffs.number * 4 - for x in range(self.numoffs.number): - templength = templength + self.materials[x].get_length() - self.length = templength - return self.length - def write_to_file(self, file): - file.write(self.magic) - file.write(struct.pack('>I', self.length)) - self.numoffs.write_to_file(file) - tempOffset = self.numoffs.number * 4 + 0xC - for x in range(self.numoffs.number): - file.write(struct.pack('>I', tempOffset)) - #self.offsets[x] = tempOffset - tempOffset = tempOffset + self.materials[x].get_length() - for x in range(len(self.materials)): - self.materials[x].write_to_file(file) - return - -class BRLYT_fnl1: - def __init__(self): - self.magic = "fnl1" - self.numoffs = BRLYT_Numoffs() - self.offsets = [] - self.fonts = [] - self.padding_to_add = 0 - def eat_tag(self, file, offset): - self.magic, self.length = struct.unpack('>4sI', file[offset:offset+8]) - self.numoffs.eat_numoffs(file, offset+8) - for x in range(self.numoffs.number): - ''' Grab font name ''' - offs, unknown = struct.unpack('>II', file[offset+8+4+x*8:offset+8+4+x*8+8]) - self.offsets.append(offs) - font = nullterm(file[offset+12+self.offsets[x]:]) - self.fonts.append(font) - return - def show_tag(self): - print "Magic: %s" % self.magic - print "Length: %08x" % self.length - self.numoffs.show_numoffs() - for x in range(len(self.fonts)): - print "Font: %s offset: %08x" % ( self.fonts[x] , self.offsets[x] ) - return - def add_font(self, font): - self.fonts.append(font) - self.numoffs.add() - if len(self.fonts) > 1: - self.offsets.append(self.offsets[-1] + len(self.textures[-2]) + 1) - else: - self.offsets.appen(4) - return - def get_length(self): - templength = 4 + 4 + 4 + self.numoffs.number * 8 - for x in self.fonts: - templength = templength + len(x) + 1 - self.length = templength - self.padding_to_add = 4 - (self.length % 4) - self.padding_to_add = self.padding_to_add % 4 - self.length = self.length + self.padding_to_add - return self.length - def write_to_file(self, file): - file.write(self.magic) - file.write(struct.pack('>I', self.length)) - self.numoffs.write_to_file(file) - tempOffset = self.numoffs.number * 4 - unknown = 0x00000000 - for x in range(len(self.offsets)): - file.write(struct.pack('>I', tempOffset)) - file.write(struct.pack('>I', unknown)) - self.offsets[x] = tempOffset - tempOffset = tempOffset + len(self.fonts[x]) + 1 - for x in self.fonts: - file.write(x) - file.write(struct.pack('s', '\x00')) - for x in range(self.padding_to_add): - file.write(struct.pack('s', "\0")) - return - -class BRLYT_txl1: - def __init__(self): - self.magic = "txl1" - self.numoffs = BRLYT_Numoffs() - self.offsets = [] - self.textures = [] - self.padding_to_add = 0 - def eat_tag(self, file, offset): - self.magic, self.length = struct.unpack('>4sI', file[offset:offset+8]) - self.numoffs.eat_numoffs(file, offset+8) - for x in range(self.numoffs.number): - ''' Grab texture name ''' - offs, unknown = struct.unpack('>II', file[offset+8+4+x*8:offset+8+4+x*8+8]) - self.offsets.append(offs) - texture = nullterm(file[offset+12+self.offsets[x]:]) - self.textures.append(texture) - return - def show_tag(self): - print "Magic: %s" % self.magic - print "Length: %08x" % self.length - self.numoffs.show_numoffs() - for x in range(len(self.textures)): - print "Texture: %s offset: %08x" % ( self.textures[x] , self.offsets[x] ) - return - def add_texture(self, texture): - self.textures.append(texture) - self.numoffs.add() - if len(self.textures) > 1: - self.offsets.append(self.offsets[-1] + len(self.textures[-2]) + 1) - else: - self.offsets.append(4) - return - def get_texoffset(self, texture): - texoffset = -1 - for x in range(len(self.textures)): - if self.textures[x] == texture: - texoffset = x - return texoffset - def get_length(self): - templength = 4 + 4 + 4 + self.numoffs.number * 8 - for x in self.textures: - templength = templength + len(x) + 1 - self.length = templength - self.padding_to_add = 4 - (self.length % 4) - self.padding_to_add = self.padding_to_add % 4 - self.length = self.length + self.padding_to_add - return self.length - def write_to_file(self, file): - file.write(self.magic) - file.write(struct.pack('>I', self.length)) - self.numoffs.write_to_file(file) - tempOffset = self.numoffs.number * 8 - unknown = 0x00000000 - for x in range(len(self.offsets)): - file.write(struct.pack('>I', tempOffset)) - file.write(struct.pack('>I', unknown)) - self.offsets[x] = tempOffset - tempOffset = tempOffset + len(self.textures[x]) + 1 - for x in self.textures: - file.write(x) - file.write(struct.pack('s', "\0")) - for x in range(self.padding_to_add): - file.write(struct.pack('s', "\0")) - return - -class BRLYT_lyt1: - def __init__(self): - self.magic = "lyt1" - self.length = 0x14 - self.a = 1 - self.pad1 = 0 - self.pad2 = 0 - self.pad3 = 0 - self.width = 608.0 - self.height = 456.0 - def eat_tag(self, file, offset): - self.magic, self.length = struct.unpack('>4sI', file[offset:offset+8]) - self.a, self.pad1, self.pad2, self.pad3 = struct.unpack('>4B', file[offset+0x08:offset+0x08+4]) - self.width, self.height = struct.unpack('>ff', file[offset+0x0C:offset+0x0C+8]) - return - def show_tag(self): - print "Magic: %s" % self.magic - print "Length: %08x" % self.length - print "a: %02x" % self.a - print "width: %f" % self.width - print "height: %f" % self.height - return - def get_length(self): - self.length = 4 + 4 + 1 + 1 + 1 + 1 + 4 + 4 - return self.length - def write_to_file(self, file): - file.write(self.magic) - file.write(struct.pack('>I', self.length)) - file.write(struct.pack('>B', self.a)) - file.write(struct.pack('>B', self.pad1)) - file.write(struct.pack('>B', self.pad2)) - file.write(struct.pack('>B', self.pad3)) - file.write(struct.pack('>f', self.width)) - file.write(struct.pack('>f', self.width)) - return - -class BRLYT_Header: - def __init__(self): - self.data = [] - def eat_header(self, buffer, offset): - self.magic, self.length = struct.unpack('>4sI', buffer[offset:offset+8]) - return - def show_header(self, offset): - print "Offset: %08x" % offset - print "Magic: %s" % self.magic - print "Length: %08x" % self.length - return - -class BRLYT: - def __init__(self): - self.tags_filled = 0 - self.data = [] - self.magic = "RLYT" - self.version = 0xfeff0101 - self.offset = 0x10 - self.chunks = 0x0000 - self.tags = { } - def grab_brlyt(self, file): - for x in file: - self.data.append(x) - return - def eat_brlyt(self, file): - file_offset = 0 - self.magic, self.version = struct.unpack('>4sI', file[0x00:0x08]) - self.length, self.offset, self.count = struct.unpack('>IHH', file[0x08:0x10]) - file_offset = 0x10 - tempHeader = BRLYT_Header() - for x in range(self.count): - tempHeader.eat_header(file, file_offset) - ''' DO BIG CASE IF FOR TYPE ''' - if tempHeader.magic == "lyt1": - self.tags[x] = BRLYT_lyt1() - elif tempHeader.magic == "txl1": - self.tags[x] = BRLYT_txl1() - elif tempHeader.magic == "fnl1": - self.tags[x] = BRLYT_fnl1() - elif tempHeader.magic == "mat1": - self.tags[x] = BRLYT_mat1() - elif tempHeader.magic == "pan1": - self.tags[x] = BRLYT_pan1() - elif tempHeader.magic == "pas1": - self.tags[x] = BRLYT_pas1() - elif tempHeader.magic == "pae1": - self.tags[x] = BRLYT_pae1() - elif tempHeader.magic == "wnd1": - self.tags[x] = BRLYT_wnd1() - elif tempHeader.magic == "bnd1": - self.tags[x] = BRLYT_bnd1() - elif tempHeader.magic == "pic1": - self.tags[x] = BRLYT_pic1() - elif tempHeader.magic == "txt1": - self.tags[x] = BRLYT_txt1() - elif tempHeader.magic == "grp1": - self.tags[x] = BRLYT_grp1() - elif tempHeader.magic == "grs1": - self.tags[x] = BRLYT_grs1() - elif tempHeader.magic == "gre1": - self.tags[x] = BRLYT_gre1() - else: - print "BAD TAG" - break - self.tags[x].eat_tag(file, file_offset) - file_offset = file_offset + self.tags[x].length - self.tags_filled = self.chunks - return - def get_texoffset(self, texture): - texoffset = self.tags[1].get_texoffset(texture) - return texoffset - def add_material(self, material, texture): - texoffset = self.get_texoffset(texture) - if texoffset == -1: - print "texture not found in txl1" - return - for x in range(self.tags_filled): - if isinstance(self.tags[x], BRLYT_mat1): - self.tags[x].add_material(material, texoffset) - return - def add_picture(self, name, (x, y), (w, h), material): - self.add_pas1() - - mat_offs = None - for i in range(len(self.tags[2].materials)): - if(self.tags[2].materials[i].name == material): - mat_offs = self.tags[2].offsets[i] - if(mat_offs == None): - raise IndexError("Material not found!") - self.tags[self.tags_filled] = BRLYT_pic1(name, x, y, 0, w, h, mat_offs) - self.tags_filled = self.tags_filled + 1 - self.add_pae1() - def add_rootpane(self, (w, h)): - self.tags[self.tags_filled] = BRLYT_pan1("RootPane", 0, 0, 0, w, h) - self.tags_filled = self.tags_filled + 1 - def add_grp1(self): - self.tags[self.tags_filled] = BRLYT_grp1() - self.tags_filled = self.tags_filled + 1 - def add_txt1(self): - self.tags[self.tags_filled] = BRLYT_txt1() - self.tags_filled = self.tags_filled + 1 - def add_pic1(self): - self.tags[self.tags_filled] = BRLYT_pic1() - self.tags_filled = self.tags_filled + 1 - def add_pae1(self): - self.tags[self.tags_filled] = BRLYT_pae1() - self.tags_filled = self.tags_filled + 1 - def add_pas1(self): - self.tags[self.tags_filled] = BRLYT_pas1() - self.tags_filled = self.tags_filled + 1 - def add_pan1(self): - self.tags[self.tags_filled] = BRLYT_pan1() - self.tags_filled = self.tags_filled + 1 - def add_mat1(self): - self.tags[self.tags_filled] = BRLYT_mat1() - self.tags_filled = self.tags_filled + 1 - def add_txl1(self): - self.tags[self.tags_filled] = BRLYT_txl1() - self.tags_filled = self.tags_filled + 1 - return - def add_lyt1(self): - self.tags[self.tags_filled] = BRLYT_lyt1() - self.tags_filled = self.tags_filled + 1 - return - def add_texture(self, texture): - self.tags[1].add_texture(texture) - return - def add_font(self, font): - self.tags[2].add_font(font) - return - def get_length(self): - templength = 4 + 4 + 4 + 2 + 2 - for x in range(len(self.tags)): - templength = templength + self.tags[x].get_length() - self.length = templength - def write_brlyt(self, filename): - self.get_length() - file = open(filename, 'wb') - if file: - file.write(self.magic) - file.write(struct.pack('>I', self.version)) - file.write(struct.pack('>I', self.length)) - file.write(struct.pack('>H', self.offset)) - file.write(struct.pack('>H', self.chunks)) - for x in range(len(self.tags)): - self.tags[x].write_to_file(file) - file.close() - else: - print "could not open file for write" - return - def show_brlyt(self): - print "Magic: %s" % self.magic - print "Version: %08x" % self.version - print "File size: %08x" % self.length - print "Header size: %04x" % self.offset - print "Chunk count: %04x" % self.count - for x in range(len(self.tags)): - self.tags[x].show_tag() - print - return - -class BRLAN_TagData: - def __init__(self): - self.part1 = 0x0 - self.part2 = 0x0 - self.part3 = 0x0 - def eat_tagdata(self, file, offset): - pass - def get_length(self): - pass - def write_to_file(self, file): - pass - -class BRLAN_TagDataTriplet(BRLAN_TagData): - def eat_tagdata(self, file, offset): - self.part1, self.part2, self.part3 = struct.unpack('>fff', file[offset:offset+12]) - return - def show_tagdata(self): - print "Frame: %f" % self.part1 - print "Value: %f" % self.part2 - print "Blend: %f" % self.part3 - return - def get_length(self): - templength = 4 + 4 + 4 - return templength - def write_to_file(self, file): - file.write(struct.pack('>f', self.part1)) - file.write(struct.pack('>f', self.part2)) - file.write(struct.pack('>f', self.part3)) - return - -class BRLAN_TagDataPair(BRLAN_TagData): - def eat_tagdata(self, file, offset): - self.part1, self.part2, self.part3 = struct.unpack('>IHH', file[offset:offset+8]) - return - def show_tagdata(self): - print "Pair 1: %08x" % self.part1 - print "Pair 2: %04x" % self.part2 - print "Padding: %04x" % self.part3 - return - def get_length(self): - templength = 4 + 2 + 2 - return templength - def write_to_file(self, file): - file.write(struct.pack('>I', self.part1)) - file.write(struct.pack('>H', self.part2)) - file.write(struct.pack('>H', self.part3)) - return - -class BRLAN_TagEntryInfo: - def __init__(self): - self.type = 0x0000 - self.data_type = 0x0020 # 0x20 is triplet 0x10 is pair - self.coord_count = 0x0000 - self.pad1 = 0x0000 - self.unknown = 0x0000000C - self.tag_data = { } - def eat_tagentryinfo(self, file, offset): - file_offset = offset - self.type, self.data_type, self.coord_count, self.pad1, self.unknown = struct.unpack('>HHHHI', file[offset:offset+12]) - file_offset = file_offset + 12 - for x in range(self.coord_count): - if self.data_type == 0x0200: - self.tag_data[x] = BRLAN_TagDataTriplet() - self.tag_data[x].eat_tagdata(file, file_offset) - file_offset = file_offset + 12 - elif self.data_type == 0x0100: - self.tag_data[x] = BRLAN_TagDataPair() - self.tag_data[x].eat_tagdata(file, file_offset) - file_offset = file_offset + 8 - return - def show_tagentryinfo(self): - print "Type: %04x" % self.type - print "Data Type: %04x" % self.data_type - print "Coordinate Count: %04x" % self.coord_count - print "Padding: %04x" % self.pad1 - print "Unknown: %08x" % self.unknown - for x in range(len(self.tag_data)): - self.tag_data[x].show_tagdata() - return - def get_length(self): - templength = 2 + 2 + 2 + 2 + 4 - for x in range(len(self.tag_data)): - templength = templength + self.tag_data[x].get_length() - return templength - def write_to_file(self, file): - file.write(struct.pack('>H', self.type)) - file.write(struct.pack('>H', self.data_type)) - file.write(struct.pack('>H', self.coord_count)) - file.write(struct.pack('>H', self.pad1)) - file.write(struct.pack('>I', self.unknown)) - for x in range(len(self.tag_data)): - self.tag_data[x].write_to_file(file) - return - -class BRLAN_TagHeader: - def __init__(self): - self.magic = "RLPA" - self.entry_count = 0x00 - self.pad1 = 0x00 - self.pad2 = 0x00 - self.pad3 = 0x00 - self.tag_entry_offsets = [] - self.tag_entries = { } - def eat_tagheader(self, file, offset): - self.magic, self.entry_count, self.pad1, self.pad2, self.pad3 = struct.unpack('>4sBBBB', file[offset:offset+8]) - for x in range(self.entry_count): - dummy, offs = struct.unpack('>II', file[offset+8+x*4-4:offset+8+x*4+4]) - self.tag_entry_offsets.append(offs) - self.tag_entries[x] = BRLAN_TagEntryInfo() - self.tag_entries[x].eat_tagentryinfo(file, offset+self.tag_entry_offsets[x]) - return - def show_tagheader(self): - print "Magic: %s" % self.magic - print "Entry Count: %02x" % self.entry_count - print "Padding: %02x %02x %02x" % ( self.pad1 , self.pad2 , self.pad3 ) - for x in range(self.entry_count): - print "Offset: %08x" % self.tag_entry_offsets[x] - self.tag_entries[x].show_tagentryinfo() - return - def get_length(self): - templength = 4 + 1 + 1 + 1 + 1 - templength = templength + self.entry_count * 4 - for x in range(self.entry_count): - templength = templength + self.tag_entries[x].get_length() - return templength - def write_to_file(self, file): - file.write(struct.pack('>4s', self.magic)) - file.write(struct.pack('>B', self.entry_count)) - file.write(struct.pack('>B', self.pad1)) - file.write(struct.pack('>B', self.pad2)) - file.write(struct.pack('>B', self.pad3)) - for x in range(self.entry_count): - file.write(struct.pack('>I', self.tag_entry_offsets[x])) - for x in range(self.entry_count): - self.tag_entries[x].write_to_file(file) - return - -class BRLAN_entry(): - def __init__(self): - self.name = "name" - self.num_tags = 0x00 - self.is_material = 0x00 - self.pad1 = 0x00 - self.pad2 = 0x00 - self.tag_offsets = [] - self.tags = { } - def eat_entry(self, file, offset): - file_offset = offset - self.name, self.num_tags, self.is_material, self.pad1, self.pad2 = struct.unpack('>20sBBBB', file[offset:offset+24]) - file_offset = file_offset + 24 - for x in range(self.num_tags): - dummy, offs = struct.unpack('>II', file[offset+24+x*4-4:offset+24+x*4+4]) - self.tag_offsets.append(offs) - self.tags[x] = BRLAN_TagHeader() - self.tags[x].eat_tagheader(file, offset+self.tag_offsets[x]) - return - def show_entry(self): - print "Name: %s" % nullterm(self.name) - print "Number of Tags: %02x" % self.num_tags - print "Is a Material: %02x" % self.is_material - print "Padding: %02x %02x" % ( self.pad1, self.pad2 ) - for x in range(self.num_tags): - self.tags[x].show_tagheader() - return - def get_length(self): - templength = 20 + 1 + 1 + 1 + 1 - for x in range(self.num_tags): - templength = templength + 4 + self.tags[x].get_length() - return templength - def write_to_file(self, file): - file.write(struct.pack('>20s', self.name)) - file.write(struct.pack('>B', self.num_tags)) - file.write(struct.pack('>B', self.is_material)) - file.write(struct.pack('>B', self.pad1)) - file.write(struct.pack('>B', self.pad2)) - for x in range(self.num_tags): - file.write(struct.pack('>I', self.tag_offsets[x])) - for x in range(self.num_tags): - self.tags[x].write_to_file(file) - return - -class BRLAN_pai1(): - def __init__(self): - self.magic = "pai1" - self.length = 0x00000000 - self.framesize = 0x0000 - self.flags = 0x00 - self.unknown = 0x00 - self.num_timgs = 0x0000 - self.num_entries = 0x0000 - self.entry_offset = 0x00000000 - self.timg_offsets = [] - self.timgs = [] - self.entry_offsets = [] - self.entries = { } - def eat_pai1(self, file, offset): - file_offset = offset - self.magic, self.length = struct.unpack('>4sI', file[offset:offset+8]) - self.framesize, self.flags, self.unknown = struct.unpack('>HBB', file[offset+0x08:offset+0x08+4]) - self.num_timgs, self.num_entries = struct.unpack('>HH', file[offset+0x0C:offset+0x0C+4]) - file_offset = file_offset + 0x10 - if bit_extract(self.flags, 25): - self.unknown2, self.entry_offset = struct.unpack('>II', file[offset+0x10:offset+0x10+8]) - file_offset = file_offset + 8 - else: - dummy, self.entry_offset = struct.unpack('>II', file[offset+0x10-4:offset+0x10+4]) - file_offset = file_offset + 4 - for x in range(self.num_timgs): - dummy, offs = struct.unpack('>II', file[file_offset+x*4-4:file_offset+x*4+4]) - self.timg_offsets.append(offs) - name = nullterm(file[file_offset+self.timg_offsets[x]:]) - self.timgs.append(name) - for x in range(self.num_entries): - dummy, offs = struct.unpack('>II', file[offset+self.entry_offset+x*4-4:offset+self.entry_offset+x*4+4]) - self.entry_offsets.append(offs) - self.entries[x] = BRLAN_entry() - self.entries[x].eat_entry(file, offset+self.entry_offsets[x]) - return - def show_pai1(self): - print "Magic: %s" % self.magic - print "Length: %08x" % self.length - print "Framesize: %04x" % self.framesize - print "Flags: %02x" % self.flags - print "Unknown: %02x" % self.unknown - print "Number of Images: %04x" % self.num_timgs - print "Number of Entries: %04x" % self.num_entries - if bit_extract(self.flags, 25): - print "Unknown2: %08x" % self.unknown2 - print "Entry Offset: %08x" % self.entry_offset - for x in range(len(self.timgs)): - print "Image: %s offset: %08x" % ( self.timgs[x] , self.offsets[x] ) - for x in range(len(self.entry_offsets)): - print "Offset: %08x" % self.entry_offsets[x] - self.entries[x].show_entry() - return - def get_length(self): - templength = 4 + 4 + 2 + 1 + 1 + 2 + 2 - if bit_extract(self.flags, 25): - templength = templength + 4 - templength = templength + 4 - templegnth = templength + self.num_timgs * 4 - for x in range(self.num_timgs): - templength = templength + len(self.timgs[x]) + 1 - templength = templength + self.num_entries * 4 - for x in range(self.num_entries): - templength = templength + self.entries[x].get_length() - self.length = templength - return templength - def write_to_file(self, file): - file.write(self.magic) - file.write(struct.pack('>I', self.length)) - file.write(struct.pack('>H', self.framesize)) - file.write(struct.pack('>B', self.flags)) - file.write(struct.pack('>B', self.unknown)) - file.write(struct.pack('>H', self.num_timgs)) - file.write(struct.pack('>H', self.num_entries)) - if bit_extract(self.flags, 25): - file.write(struct.pack('>I', self.unknown2)) - file.write(struct.pack('>I', self.entry_offset)) - tempOffset = self.num_timgs * 4 + self.entry_offset - for x in range(len(self.timgs)): - file.write(struct.pack('>I', tempOffset)) - self.timg_offsets[x] = tempOffset - tempOffset = tempOffset + len(self.timgs[x]) + 1 - for x in self.timgs: - file.write(x) - file.write(struct.pack('s', '\x00')) - tempOffset = self.num_entries * 4 + self.entry_offset - for x in range(len(self.entry_offsets)): - file.write(struct.pack('>I', tempOffset)) - self.entry_offsets[x] = tempOffset - tempOffset = tempOffset + self.entries[x].get_length() - for x in range(self.num_entries): - self.entries[x].write_to_file(file) - return - -class BRLAN: - def __init__(self): - self.magic = "RLAN" - self.version = 0xfeff0008 - self.length = 0x00000000 - self.offset = 0x0010 - self.chunks = 0x0001 - self.pai1 = BRLAN_pai1() - def eat_brlan(self, file): - self.magic, self.version, self.length = struct.unpack('>4sII', file[0x00:0x00+12]) - self.offset, self.chunks = struct.unpack('>HH', file[0x0c:0x0c+4]) - self.pai1.eat_pai1(file, self.offset) - return - def show_brlan(self): - print "Magic: %s" % self.magic - print "Version: %08x" % self.version - print "File Size: %08x" % self.length - print "Header Size: %04x" % self.offset - print "Chunk Count: %04x" % self.chunks - self.pai1.show_pai1() - return - def get_length(self): - templength = 4 + 4 + 4 + 2 + 2 - templength = templength + self.pai1.get_length() - self.length = templength - return self.templength - def write_brlan(self, filename): - self.get_length() - file = open(filename, 'wb') - if file: - file.write(self.magic) - file.write(struct.pack('>I', self.version)) - file.write(struct.pack('>I', self.length)) - file.write(struct.pack('>H', self.offset)) - file.write(struct.pack('>H', self.chunks)) - self.pai1.write_to_file(file) - file.close() - else: - print "could now open file for writing" - return - -if(__name__ == "__main__"): - - if len(sys.argv) != 2: - print 'Usage: python banner.py ' - sys.exit(1) - - ''' START BRLAN READING TEST ''' ''' - f = open(sys.argv[1], 'rb') - if f: - rlan = f.read() - f.close() - else: - print "could not open file for reading" - - brlan = BRLAN() - brlan.eat_brlan(rlan) - brlan.show_brlan() - brlan.write_brlan("testout.brlan") - ''' ''' END BRLAN READING TEST ''' - - ''' START BRLYT READING TEST ''' #''' - f = open(sys.argv[1], 'rb') - if f: - rlyt = f.read() - f.close() - else: - print "could not open file" - - brlyt = BRLYT() - brlyt.eat_brlyt(rlyt) - brlyt.show_brlyt() - brlyt.write_brlyt("testout.brlyt") - #''' ''' END BRLYT READING TEST ''' - - ''' TEST FOR WRITING A BRLYT FROM SCRATCH ''' ''' - brlyt2 = BRLYT() - brlyt2.add_lyt1() - brlyt2.add_txl1() - brlyt2.add_texture("texture1.tpl") - brlyt2.add_mat1() - brlyt2.add_material("material1", "texture1.tpl") - brlyt2.add_pan1() - brlyt2.add_pas1() - brlyt2.add_pic1() - brlyt2.add_pae1() - brlyt2.add_grp1() - brlyt2.write_brlyt("testout.brlyt") - ''' '''END TEST FOR BRLYT WRITING ''' - - ''' T O D O ''' ''' - fix txt1 text output - add brlan making methods - ''' diff --git a/savedata.py b/savedata.py deleted file mode 100644 index b6ec61a..0000000 --- a/savedata.py +++ /dev/null @@ -1,260 +0,0 @@ -import os, struct, subprocess, fnmatch, shutil, urllib, array - -from Struct import Struct - -from common import * -from title import * -from TPL import * -from PIL import Image - -class Savegame(): - class savegameHeader(Struct): - __endian__ = Struct.BE - def __format__(self): - self.savegameId = Struct.uint32[2] - self.bannerSize = Struct.uint32 - self.permissions = Struct.uint8 - self.unknown1 = Struct.uint8 - self.md5hash = Struct.string(16) - self.unknown2 = Struct.uint16 - - class savegameBanner(Struct): - __endian__ = Struct.BE - def __format__(self): - self.magic = Struct.string(4) - self.reserved = Struct.uint8[4] - self.flags = Struct.uint32 - self.reserved = Struct.uint32[5] - self.gameTitle = Struct.string(64) - self.gameSubTitle = Struct.string(64) - self.banner = Struct.string(24576) - self.icon0 = Struct.string(4608) - self.icon1 = Struct.string(4608) - self.icon2 = Struct.string(4608) - self.icon3 = Struct.string(4608) - self.icon4 = Struct.string(4608) - self.icon5 = Struct.string(4608) - self.icon6 = Struct.string(4608) - self.icon7 = Struct.string(4608) - - class backupHeader(Struct): - __endian__ = Struct.BE - def __format__(self): - self.hdrSize = Struct.uint32 - self.magic = Struct.string(2) - self.version = Struct.uint16 - self.NGid = Struct.uint32 - self.filesCount = Struct.uint32 - self.filesSize = Struct.uint32 - self.unknown1 = Struct.uint32 - self.unknown2 = Struct.uint32 - self.totalSize = Struct.uint32 - self.unknown3 = Struct.uint8[64] - self.unknown4 = Struct.uint32 - self.gameId = Struct.string(4) - self.wiiMacAddr = Struct.uint8[6] - self.unknown6 = Struct.uint16 - self.padding = Struct.uint32[4] - - class fileHeader(Struct): - __endian__ = Struct.BE - def __format__(self): - self.magic = Struct.uint32 - self.size = Struct.uint32 - self.permissions = Struct.uint8 - self.attribute = Struct.uint8 - self.type = Struct.uint8 - self.nameIV = Struct.string(0x45) - - def __init__(self, f): - self.f = f - try: - self.fd = open(f, 'r+b') - except: - raise Exception('Cannot open input') - - self.sdKey = '\xab\x01\xb9\xd8\xe1\x62\x2b\x08\xaf\xba\xd8\x4d\xbf\xc2\xa5\x5d' - self.sdIv = '\x21\x67\x12\xe6\xaa\x1f\x68\x9f\x95\xc5\xa2\x23\x24\xdc\x6a\x98' - - self.iconCount = 1 - - def __str__(self): - ret = '' - ret += '\nSavegame header \n' - - ret += 'Savegame ID : 0x%x%x\n' % (self.hdr.savegameId[0], self.hdr.savegameId[1]) - ret += 'Banner size : 0x%x\n' % self.hdr.bannerSize - ret += 'Permissions : 0x%x\n' % self.hdr.permissions - ret += 'Unknown : 0x%x\n' % self.hdr.unknown1 - ret += 'MD5 hash : %s\n' % hexdump(self.hdr.md5hash) - ret += 'Unknown : 0x%x\n' % self.hdr.unknown2 - - ret += '\nBanner header \n' - - ret += 'Flags : 0x%x\n' % self.bnr.flags - ret += 'Game title : %s\n' % self.bnr.gameTitle - ret += 'Game subtitle : %s\n' % self.bnr.gameSubTitle - ret += 'Icons found : %i\n' % self.iconCount - - ret += '\nBackup header \n' - - ret += 'Header size : 0x%x (+ 0x10 of padding) version 0x%x\n' % (self.bkHdr.hdrSize, self.bkHdr.version) - if self.bkHdr.gameId[3] == 'P': - ret += 'Region : PAL\n' - elif self.bkHdr.gameId[3] == 'E': - ret += 'Region : NTSC\n' - elif self.bkHdr.gameId[3] == 'J': - ret += 'Region : JAP\n' - ret += 'Game ID : %s\n' % self.bkHdr.gameId - ret += 'Wii unique ID : 0x%x\n' % self.bkHdr.NGid - ret += 'Wii MAC address %02x:%02x:%02x:%02x:%02x:%02x\n' % (self.bkHdr.wiiMacAddr[0], self.bkHdr.wiiMacAddr[1], self.bkHdr.wiiMacAddr[2], self.bkHdr.wiiMacAddr[3], self.bkHdr.wiiMacAddr[4], self.bkHdr.wiiMacAddr[5]) - ret += 'Found %i files for %i bytes\n' % (self.bkHdr.filesCount, self.bkHdr.filesSize) - ret += 'Total size : %i bytes\n' % self.bkHdr.totalSize - ret += 'This save is %i blocks wise' % (self.bkHdr.totalSize / 0x20000) - - return ret - - def extractFiles(self): - - try: - os.mkdir(os.path.dirname(self.f) + '/' + self.bkHdr.gameId) - except: - pass - - os.chdir(os.path.dirname(self.f) + '/' + self.bkHdr.gameId) - - self.fd.seek(self.fileStartOffset) - - for i in range(self.bkHdr.filesCount): - - fileHdr = self.fd.read(0x80) - fileHdr = self.fileHeader().unpack(fileHdr) - - if fileHdr.magic != 0x03adf17e: - raise Exception('Wrong file magic') - - fileHdr.size = align(fileHdr.size, 64) - - ivpos = 0 - name = "" - i = 0 - for char in list(fileHdr.nameIV): - if(char == "\x00"): - i -= 1 - ivpos = i - break - else: - name += char - i += 1 - - - fileIV = fileHdr.nameIV[ivpos:ivpos + 16] - - if len(fileIV) != 16: - raise Exception('IV alignment issue') - - if fileHdr.type == 1: - print 'Extracted %s (%ib)' % (name, fileHdr.size) - - fileBuffer = self.fd.read(fileHdr.size) - fileBuffer = Crypto().decryptData(self.sdKey, fileIV, fileBuffer, True) - try: - open(name, 'w+b').write(fileBuffer) - except: - raise Exception('Cannot write the output') - elif fileHdr.type == 2: - print 'Extracted folder %s' % name - try: - os.mkdir(name) - except: - pass - - print 'Attribute %i Permission %i' % (fileHdr.attribute, fileHdr.permissions) - print 'File IV : 0x%s' % hexdump(fileIV, '') - - os.chdir('..') - - def analyzeHeader(self): - headerBuffer = self.fd.read(0xF0C0) - headerBuffer = Crypto().decryptData(self.sdKey, self.sdIv, headerBuffer, True) - - self.hdr = self.savegameHeader().unpack(headerBuffer[:0x20]) - - #headerBuffer.replace(self.hdr.md5hash, '\x0e\x65\x37\x81\x99\xbe\x45\x17\xab\x06\xec\x22\x45\x1a\x57\x93') - #print 'Reashed md5 : %s' % hexdump(Crypto().createMD5Hash(headerBuffer)) - - self.bnr = self.savegameBanner().unpack(headerBuffer[0x20:]) - - if self.bnr.magic != 'WIBN': - raise Exception ('Wrong magic, should be WIBN') - - if self.hdr.bannerSize != 0x72A0: - self.iconCount += 7 - - bkHdrBuffer = self.fd.read(0x80) - self.bkHdr = self.backupHeader().unpack(bkHdrBuffer) - - if self.bkHdr.magic != 'Bk' or self.bkHdr.hdrSize != 0x70: - raise Exception ('Bk header error') - - self.fileStartOffset = self.fd.tell() - - def eraseWiiMac(self): - self.fd.seek(0xF128) - print self.fd.write('\x00' * 6) - - def getBanner(self): - try: - os.mkdir(os.path.dirname(self.f) + '/' + self.bkHdr.gameId) - except: - pass - - os.chdir(os.path.dirname(self.f) + '/' + self.bkHdr.gameId) - - return Image.fromstring("RGBA", (192, 64), TPL('').RGB5A3((192, 64), self.bnr.banner)).save('banner', 'png') - - def getIcon(self, index): - if index < 0 or index > 7 or index > self.iconCount: - return -1 - - try: - os.mkdir(os.path.dirname(self.f) + '/' + self.bkHdr.gameId) - except: - pass - - os.chdir(os.path.dirname(self.f) + '/' + self.bkHdr.gameId) - - if index == 0: - return Image.fromstring("RGBA", (48, 48), TPL('').RGB5A3((48, 48), self.bnr.icon0)).save('icon' + str(index), 'png') - if index == 1: - return Image.fromstring("RGBA", (48, 48), TPL('').RGB5A3((48, 48), self.bnr.icon1)).save('icon' + str(index), 'png') - if index == 2: - return Image.fromstring("RGBA", (48, 48), TPL('').RGB5A3((48, 48), self.bnr.icon2)).save('icon' + str(index), 'png') - if index == 3: - return Image.fromstring("RGBA", (48, 48), TPL('').RGB5A3((48, 48), self.bnr.icon3)).save('icon' + str(index), 'png') - if index == 4: - return Image.fromstring("RGBA", (48, 48), TPL('').RGB5A3((48, 48), self.bnr.icon4)).save('icon' + str(index), 'png') - if index == 5: - return Image.fromstring("RGBA", (48, 48), TPL('').RGB5A3((48, 48), self.bnr.icon5)).save('icon' + str(index), 'png') - if index == 6: - return Image.fromstring("RGBA", (48, 48), TPL('').RGB5A3((48, 48), self.bnr.icon6)).save('icon' + str(index), 'png') - if index == 7: - return Image.fromstring("RGBA", (48, 48), TPL('').RGB5A3((48, 48), self.bnr.icon7)).save('icon' + str(index), 'png') - - def getIconsCount(self): - return self.iconCount - - def getSaveString(self, string): - if string == 'id': - return self.bkHdr.gameId - elif string == 'title': - return self.bnr.gameTitle - elif string == 'subtitle': - return self.bnr.gameSubTitle - elif string == 'mac': - return self.bkHdr.wiiMacAddr[0] + ':' + self.bkHdr.wiiMacAddr[1] + ':' + self.bkHdr.wiiMacAddr[2] + ':' + self.bkHdr.wiiMacAddr[3] + ':' + self.bkHdr.wiiMacAddr[4] + ':' + self.bkHdr.wiiMacAddr[5] - - def getFilesCount(self): - return self.bkHdr.filesCount - -