diff --git a/channel/banner/Makefile b/channel/banner/Makefile index d6b8dab..105658c 100644 --- a/channel/banner/Makefile +++ b/channel/banner/Makefile @@ -14,14 +14,14 @@ export ALAMEDA := $(CURDIR)/../../pywii/Alameda export PNG2TPL := $(CURDIR)/tools/png2tpl$(EXE) export MKBNS := $(CURDIR)/tools/mkbns$(EXE) export LZ77 := $(CURDIR)/tools/lz77$(EXE) -export ADDIMD5 := python2 $(CURDIR)/tools/addimd5.py -export ARCPACK := python2 $(PYWII)/arcpack.py +export ADDIMD5 := python3 $(CURDIR)/tools/addimd5.py +export ARCPACK := python3 $(PYWII)/arcpack.py export SOX := sox all: channel.imet channel.imet: build/data.arc names.txt tools/join-imet.py - python2 tools/join-imet.py $@ build/data.arc build/icon.arc build/banner.arc build/sound.bns names.txt + python3 tools/join-imet.py $@ build/data.arc build/icon.arc build/banner.arc build/sound.bns names.txt build/data.arc : build/data/meta/icon.bin build/data/meta/banner.bin build/data/meta/sound.bin $(ARCPACK) $@ build/data @@ -45,9 +45,9 @@ build/%.raw : sound/%.wav $(SOX) $< -r 32000 -c 2 -e signed-integer -b 16 -t raw $@ testi : channel.imet - python2 $(ALAMEDA)/Alameda.py channel.imet icon + python3 $(ALAMEDA)/Alameda.py channel.imet icon testb : channel.imet - python2 $(ALAMEDA)/Alameda.py channel.imet banner + python3 $(ALAMEDA)/Alameda.py channel.imet banner $(PNG2TPL): tools/*.c $(MAKE) -C tools png2tpl$(EXE) diff --git a/channel/banner/Makefile.section b/channel/banner/Makefile.section index 6c97d73..2fd5c1a 100644 --- a/channel/banner/Makefile.section +++ b/channel/banner/Makefile.section @@ -19,7 +19,7 @@ endif ../build/$(TYPE)/arc/blyt/$(TYPE).brlyt $(ANIMS) : mk$(TYPE).py @[ ! -d ../build/$(TYPE)/arc/anim ] && mkdir -p ../build/$(TYPE)/arc/anim || true @[ ! -d ../build/$(TYPE)/arc/blyt ] && mkdir -p ../build/$(TYPE)/arc/blyt || true - python2 mk$(TYPE).py ../build/$(TYPE)/arc/blyt/$(TYPE).brlyt $(ANIMS) + python3 mk$(TYPE).py ../build/$(TYPE)/arc/blyt/$(TYPE).brlyt $(ANIMS) ../build/$(TYPE).arc : $(TPLS) ../build/$(TYPE)/arc/blyt/$(TYPE).brlyt $(ANIMS) $(ARCPACK) ../build/$(TYPE).arc ../build/$(TYPE) diff --git a/channel/banner/banner/mkbanner.py b/channel/banner/banner/mkbanner.py index bea4316..be91fdf 100644 --- a/channel/banner/banner/mkbanner.py +++ b/channel/banner/banner/mkbanner.py @@ -244,7 +244,7 @@ class BubbleInstance: for i in tps: if len(i.Triplets) > 0: if i.Triplets[-1][0] >= self.Start: - print "WTF at %s: %f >= %f"%(self.Picture.Name,i.Triplets[-1][0],self.Start) + print("WTF at %s: %f >= %f"%(self.Picture.Name,i.Triplets[-1][0],self.Start)) raise RuntimeError("We Have A Problem") brlan.Anim[self.Picture.Name][Brlan.A_COORD][Brlan.C_X].Triplets.append((self.Start, self.X, 0)) @@ -293,15 +293,15 @@ class BubbleCollection: #print "Freeing instance: [%f-%f]"%(user.Start,user.End) tis[i] = pic, None def printinstances(self): - print "Type Instances:" + print("Type Instances:") for tid, tis in enumerate(self.TypeInstances): - print " Type Instances for type %d (%s):"%(tid, self.BubbleTypes[tid][0].Name) + print(" Type Instances for type %d (%s):"%(tid, self.BubbleTypes[tid][0].Name)) for i, ti in enumerate(tis): pic, user = ti if user is None: - print " %d: Picture %s, free"%(i,pic.Name) + print(" %d: Picture %s, free"%(i,pic.Name)) else: - print " %d: Picture %s, user: %s [%f-%f]"%(i,pic.Name,repr(user),user.Start,user.End) + print(" %d: Picture %s, user: %s [%f-%f]"%(i,pic.Name,repr(user),user.Start,user.End)) def render(self): for t,c in self.BubbleTypes: t.makemat(self.Brlyt) @@ -330,9 +330,9 @@ class BubbleCollection: i.render(self.Brlan) #self.printinstances() -print "Fake Start",fakeStart -print "Loop Start",loopStart -print "Loop End",loopEnd +print("Fake Start",fakeStart) +print("Loop Start",loopStart) +print("Loop End",loopEnd) col = BubbleCollection(brlyt, brlan, bubblepane) col.addtype(BubbleType("abubble1", 48, 48),1) @@ -374,10 +374,10 @@ for i in col.Instances: col.render() brldata = brlyt.Pack() -open(sys.argv[1],"w").write(brldata) +open(sys.argv[1],"wb").write(brldata) bradata = brlan.Pack(loopStart) -open(sys.argv[2],"w").write(bradata) +open(sys.argv[2],"wb").write(bradata) bradata = brlan.Pack(loopStart, loopEnd) -open(sys.argv[3],"w").write(bradata) +open(sys.argv[3],"wb").write(bradata) diff --git a/channel/banner/icon/mkicon.py b/channel/banner/icon/mkicon.py index 07ca2c0..e7a41c4 100644 --- a/channel/banner/icon/mkicon.py +++ b/channel/banner/icon/mkicon.py @@ -111,7 +111,7 @@ brlyt.RootPane.Add(tit) brldata = brlyt.Pack() -open(sys.argv[1],"w").write(brldata) +open(sys.argv[1],"wb").write(brldata) brlan = Brlan() @@ -177,6 +177,6 @@ brlan.Anim['shadow'][Brlan.A_COORD][Brlan.C_X].repsimple(0, 960, 2, -45, -0.1, 4 bradata = brlan.Pack(60*16) for a,b,c in brlan.Anim['waveb'][Brlan.A_COORD][Brlan.C_X].Triplets: - print a,b,c + print(a,b,c) -open(sys.argv[2],"w").write(bradata) +open(sys.argv[2],"wb").write(bradata) diff --git a/channel/banner/tools/addimd5.py b/channel/banner/tools/addimd5.py index a33a271..d2a3bea 100644 --- a/channel/banner/tools/addimd5.py +++ b/channel/banner/tools/addimd5.py @@ -1,12 +1,12 @@ -import md5, sys, struct +import hashlib, sys, struct -data= open(sys.argv[1]).read() +data= open(sys.argv[1], "rb").read() -digest = md5.new(data).digest() +digest = hashlib.md5(data).digest() -hdr = struct.pack(">4sI8x","IMD5",len(data)) +hdr = struct.pack(">4sI8x",b"IMD5",len(data)) -f2 = open(sys.argv[2],"w") +f2 = open(sys.argv[2],"wb") f2.write(hdr) f2.write(digest) f2.write(data) diff --git a/channel/banner/tools/join-imet.py b/channel/banner/tools/join-imet.py index 31f19a5..45a5f2a 100644 --- a/channel/banner/tools/join-imet.py +++ b/channel/banner/tools/join-imet.py @@ -1,8 +1,8 @@ -import os, sys, struct, md5 +import os, sys, struct, hashlib output, datafile, iconarc, bannerarc, soundbns, namesfile = sys.argv[1:] -data = open(datafile,"r").read() +data = open(datafile,"rb").read() names={} @@ -11,7 +11,7 @@ for i in open(namesfile,"r"): while b[-1] == "\n": b = b[:-1] b = b.replace("\\n","\n") - names[a] = b.decode("utf-8") + names[a] = b def getsize(x): return os.stat(x).st_size @@ -20,29 +20,29 @@ def pad(x,l): if len(x) > l: raise ValueError("%d > %d",len(x),l) n = l-len(x) - return x + "\x00"*n + return x + b"\x00"*n -imet = "\x00"*0x40 -imet += struct.pack(">4sIIIIII","IMET",0x600,3,getsize(iconarc),getsize(bannerarc),getsize(soundbns),1) +imet = b"\x00"*0x40 +imet += struct.pack(">4sIIIIII",b"IMET",0x600,3,getsize(iconarc),getsize(bannerarc),getsize(soundbns),1) for i in ["jp", "en", "de", "fr", "sp", "it", "nl", "cn", None, "ko"]: try: imet += pad(names[i].encode("UTF-16BE"),0x54) except KeyError: - imet += "\x00"*0x54 -imet += "\x00"*(0x600 - len(imet)) + imet += b"\x00"*0x54 +imet += b"\x00"*(0x600 - len(imet)) -imet = imet[:-16] + md5.new(imet).digest() +imet = imet[:-16] + hashlib.md5(imet).digest() -open(output,"w").write(imet) +open(output,"wb").write(imet) -f = open(sys.argv[1],"w") +f = open(sys.argv[1],"wb") f.write(imet) f.write(data) fsize = f.tell() if (fsize % 20) != 0: - f.write("\x00"*(20-(fsize%20))) + f.write(b"\x00"*(20-(fsize%20))) f.close() diff --git a/channel/channelapp/Makefile b/channel/channelapp/Makefile index eaa0144..31c6a67 100644 --- a/channel/channelapp/Makefile +++ b/channel/channelapp/Makefile @@ -33,7 +33,7 @@ DIR_LIBS = \ $(DEVKITPRO)/libogc/lib/wii \ $(DEVKITPRO)/portlibs/ppc/lib -LIBS = mxml freetype png bz2 z db fat wiiuse bte ogc m +LIBS = mxml freetype png z db fat wiiuse bte ogc m MACHDEP = -g -DGEKKO -mrvl -mcpu=750 -meabi -mhard-float CFLAGS = $(MACHDEP) -Os -Wall -DBASE_ADDR=$(BASE_ADDR) $(DIR_INCLUDES:%=-I%) diff --git a/pywii/Alameda/Alameda.py b/pywii/Alameda/Alameda.py index 0aec325..6807b31 100644 --- a/pywii/Alameda/Alameda.py +++ b/pywii/Alameda/Alameda.py @@ -1,1736 +1,1746 @@ -have_pyglet = False - -try: - from pyglet import clock, window - from pyglet.gl import * - from pyglet.image import * - have_pyglet = True -except: - pass - -import sys, os -sys.path.append(os.path.realpath(os.path.dirname(sys.argv[0]))+"/../Common") -from Struct import Struct -import struct -import pywii as wii - -def LZ77Decompress(data): - inp = 0 - dlen = len(data) - data += '\0' * 16 - - ret = [] - - while inp < dlen: - bitmask = ord(data[inp]) - inp += 1 - - for i in xrange(8): - if bitmask & 0x80: - rep = ord(data[inp]) - repLength = (rep >> 4) + 3 - inp += 1 - repOff = ord(data[inp]) | ((rep & 0x0F) << 8) - inp += 1 - - assert repOff <= len(ret) - - while repLength > 0: - ret.append(ret[-repOff - 1]) - repLength -= 1 - else: - ret.append(data[inp]) - inp += 1 - - bitmask <<= 1 - - return ''.join(ret) - -class U8(object): - class U8Header(Struct): - __endian__ = Struct.BE - def __format__(self): - self.Tag = Struct.string(4) - self.RootNode = Struct.uint32 - self.HeaderSize = Struct.uint32 - self.DataOffset = Struct.uint32 - self.Zeroes = Struct.uint8[0x10] - - class U8Node(Struct): - __endian__ = Struct.BE - def __format__(self): - self.Type = Struct.uint16 - self.NameOffset = Struct.uint16 - self.DataOffset = Struct.uint32 - self.Size = Struct.uint32 - - def __init__(self, data=None): - self.Files = {} - - if data != None: - self.Unpack(data) - - def Unpack(self, data): - pos = 0 - u8 = self.U8Header() - u8.unpack(data[pos:pos+len(u8)]) - pos += len(u8) - - assert u8.Tag == 'U\xAA8-' - pos += u8.RootNode - 0x20 - - root = self.U8Node() - root.unpack(data[pos:pos+len(root)]) - pos += len(root) - - children = [] - for i in xrange(root.Size - 1): - child = self.U8Node() - child.unpack(data[pos:pos+len(child)]) - pos += len(child) - children.append(child) - - stringTable = data[pos:pos + u8.DataOffset - len(u8) - root.Size * len(root)] - pos += len(stringTable) - - currentOffset = u8.DataOffset - - path = ['.'] - pathDepth = [root.Size - 1] - for offset,child in enumerate(children): - name = stringTable[child.NameOffset:].split('\0', 1)[0] - if child.Type == 0x0100: - path.append(name) - pathDepth.append(child.Size-offset-1) - elif child.Type == 0: - name = '/'.join(path + [name]) - - if currentOffset < child.DataOffset: - diff = child.DataOffset - currentOffset - assert diff <= 32 - - pos += diff - currentOffset += diff - - currentOffset += child.Size - - self.Files[name.lower()] = data[pos:pos+child.Size] - pos += child.Size - - pathDepth[-1] -= 1 - if pathDepth[-1] == 0: - path = path[:-1] - pathDepth = pathDepth[:-1] - -class IMD5Header(Struct): - __endian__ = Struct.BE - def __format__(self): - self.Tag = Struct.string(4) - self.Size = Struct.uint32 - self.Zeroes = Struct.uint8[8] - self.MD5 = Struct.uint8[0x10] - -def IMD5(data): - imd5 = IMD5Header() - imd5.unpack(data[:len(imd5)]) - assert imd5.Tag == 'IMD5' - pos = len(imd5) - - if data[pos:pos+4] == 'LZ77': - return LZ77Decompress(data[pos+8:]) - else: - return data[pos:] - -class TPL(object): - class TPLHeader(Struct): - __endian__ = Struct.BE - def __format__(self): - self.Magic = Struct.string(4) - self.Count = Struct.uint32 - self.Size = Struct.uint32 - - class TexOffsets(Struct): - __endian__ = Struct.BE - def __format__(self): - self.HeaderOff = Struct.uint32 - self.PaletteOff = Struct.uint32 - - class TexHeader(Struct): - __endian__ = Struct.BE - def __format__(self): - self.Size = Struct.uint16[2] - self.Format = Struct.uint32 - self.DataOff = Struct.uint32 - self.Wrap = Struct.uint32[2] - self.Filter = Struct.uint32[2] - self.LODBias = Struct.float - self.EdgeLOD = Struct.uint8 - self.LOD = Struct.uint8[2] - self.Unpacked = Struct.uint8 - - class PalHeader(Struct): - __endian__ = Struct.BE - def __format__(self): - self.Count = Struct.uint16 - self.Unpacked = Struct.uint8 - self.Pad = Struct.uint8 - self.Format = Struct.uint32 - self.DataOff = Struct.uint32 - - def __init__(self, data=None): - self.Textures = [] - - if data != None: - self.Unpack(data) - - def Unpack(self, data): - header = self.TPLHeader() - header.unpack(data[:len(header)]) - pos = len(header) - - assert header.Magic == '\x00\x20\xAF\x30' - assert header.Size == 0xc - - for i in xrange(header.Count): - offs = self.TexOffsets() - offs.unpack(data[pos:pos+len(offs)]) - pos += len(offs) - - self.Textures.append(self.ParseTexture(data, offs)) - - def ParseTexture(self, data, offs): - texHeader = self.TexHeader() - texHeader.unpack(data[offs.HeaderOff:offs.HeaderOff+len(texHeader)]) - format = texHeader.Format - self.format = format - rgba = None - if format == 0: - rgba = self.I4(data[texHeader.DataOff:], texHeader.Size) - elif format == 1: - rgba = self.I8(data[texHeader.DataOff:], texHeader.Size) - elif format == 2: - rgba = self.IA4(data[texHeader.DataOff:], texHeader.Size) - elif format == 3: - rgba = self.IA8(data[texHeader.DataOff:], texHeader.Size) - elif format == 4: - rgba = self.RGB565(data[texHeader.DataOff:], texHeader.Size) - elif format == 5: - rgba = self.RGB5A3(data[texHeader.DataOff:], texHeader.Size) - elif format == 6: - rgba = self.RGBA8(data[texHeader.DataOff:], texHeader.Size) - elif format == 14: - rgba = self.S3TC(data[texHeader.DataOff:], texHeader.Size) - else: - print 'Unknown texture format', format - - if rgba == None: - rgba = '\0\0\0\0' * texHeader.Size[0] * texHeader.Size[1] - - image = ImageData(texHeader.Size[1], texHeader.Size[0], 'RGBA', rgba) - print format - return image - - def I4(self, data, (y, x)): - out = [0 for i in xrange(x * y)] - outp = 0 - inp = 0 - for i in xrange(0, y, 8): - for j in xrange(0, x, 8): - ofs = 0 - for k in xrange(8): - off = min(x - j, 8) - for sub in xrange(0, off, 2): - texel = ord(data[inp]) - high, low = texel >> 4, texel & 0xF - if (outp + ofs + sub) < (x*y): - out[outp + ofs + sub] = (high << 4) | (high << 20) | (high << 12) | 0xFF<<24 - - if sub + 1 < off: - if (outp + ofs + sub + 1) < (x*y): - out[outp + ofs + sub + 1] = (low << 4) | (low << 20) | (low << 12) | 0xFF<<24 - - inp += 1 - - ofs += x - inp += (8 - off) / 2 - outp += off - outp += x * 7 - - return ''.join(Struct.uint32(p) for p in out) - - def I8(self, data, (y, x)): - out = [0 for i in xrange(x * y*2)] - outp = 0 - inp = 0 - for i in xrange(0, y, 4): - for j in xrange(0, x, 4): - ofs = 0 - for k in xrange(4): - off = min(x - j, 4) - for sub in xrange(off): - texel = ord(data[inp]) - out[outp + ofs + sub] = (texel << 24) | (texel << 16) | (texel << 8) | 0xFF - inp += 1 - - ofs += x - inp += 4 - off * 2 - outp += off - outp += x * 3 - - return ''.join(Struct.uint32(p) for p in out) - - def IA4(self, data, (y, x)): - out = [0 for i in xrange(x * y)] - outp = 0 - inp = 0 - for i in xrange(0, y, 4): - for j in xrange(0, x, 8): - ofs = 0 - for k in xrange(4): - off = min(x - j, 8) - for sub in xrange(off): - texel = ord(data[inp]) - alpha, inte = texel >> 4, texel & 0xF - if (outp + ofs + sub) < (x*y): - out[outp + ofs + sub] = (inte << 4) | (inte << 12) | (inte << 20) | (alpha << 28) - inp += 1 - - ofs += x - inp += 8 - off - outp += off - outp += x * 3 - - return ''.join(Struct.uint32(p) for p in out) - - def IA8(self, data, (y, x)): - out = [0 for i in xrange(x * y)] - outp = 0 - inp = 0 - for i in xrange(0, y, 4): - for j in xrange(0, x, 4): - ofs = 0 - for k in xrange(4): - off = min(x - j, 4) - for sub in xrange(off): - if (outp + ofs + sub) < (x*y): - texel = Struct.uint16(data[inp:inp + 2], endian='>') - p = (texel & 0xFF) - p |= (texel & 0xFF) << 8 - p |= (texel & 0xFF) << 16 - p |= (texel >> 8) << 24 - out[outp + ofs + sub] = p - inp += 2 - - ofs += x - inp += (4 - off) * 2 - outp += off - outp += x * 3 - - return ''.join(Struct.uint32(p) for p in out) - - def RGB565(self, data, (y, x)): - out = [0 for i in xrange(x * y)] - outp = 0 - inp = 0 - for i in xrange(0, y, 4): - for j in xrange(0, x, 4): - ofs = 0 - for k in xrange(4): - off = min(x - j, 4) - for sub in xrange(off): - if (outp + ofs + sub) < (x*y): - texel = Struct.uint16(data[inp:inp + 2], endian='>') - p = ((texel >> 11) & 0x1F) << 3 - p |= ((texel >> 5) & 0x3F) << 10 - p |= ( texel & 0x1F) << 19 - p |= 0xFF<<24 - out[outp + ofs + sub] = p - inp += 2 - - ofs += x - inp += (4 - off) * 2 - outp += off - outp += x * 3 - - return ''.join(Struct.uint32(p) for p in out) - - def RGB5A3(self, data, (y, x)): - out = [0 for i in xrange(x * y)] - outp = 0 - inp = 0 - for i in xrange(0, y, 4): - for j in xrange(0, x, 4): - ofs = 0 - for k in xrange(4): - off = min(x - j, 4) - for sub in xrange(off): - texel = Struct.uint16(data[inp:inp + 2], endian='>') - if texel & 0x8000: - p = ((texel >> 10) & 0x1F) << 3 - p |= ((texel >> 5) & 0x1F) << 11 - p |= ( texel & 0x1F) << 19 - p |= 0xFF<<24 - else: - p = ((texel >> 12) & 0x07) << 29 - p |= ((texel >> 8) & 0x0F) << 4 - p |= ((texel >> 4) & 0x0F) << 12 - p |= (texel & 0x0F) << 20 - if (outp + ofs + sub) < (x*y): - out[outp + ofs + sub] = p - inp += 2 - - ofs += x - inp += (4 - off) * 2 - outp += off - outp += x * 3 - - return ''.join(Struct.uint32(p) for p in out) - - def RGBA8(self, data, (y, x)): - out = [0 for i in xrange(x * y)] - outp = 0 - inp = 0 - for i in xrange(0, y, 4): - for j in xrange(0, x, 4): - ofs = 0 - for k in xrange(4): - off = min(x - j, 4) - for sub in xrange(off): - texel = Struct.uint16(data[inp:inp + 2], endian='>')<<16 - texel |= Struct.uint16(data[inp+32:inp + 34], endian='>') - if (outp + ofs + sub) < (x*y): - out[outp + ofs + sub] = texel&0xff000000 | ((texel>>16)&0xff) | (texel&0xff00) | ((texel<<16)&0xff0000) - inp += 2 - - ofs += x - inp += (4 - off) * 2 - outp += off - inp += 32 - outp += x * 3 - - return ''.join(Struct.uint32(p) for p in out) - - def unpack_rgb565(self,texel): - b = (texel&0x1f)<<3 - g = ((texel>>5)&0x3f)<<2 - r = ((texel>>11)&0x1f)<<3 - b |= b>>5 - g |= g>>6 - r |= r>>5 - return (0xff<<24) | (b<<16) | (g<<8) | r - def icolor(self,a,b,fa,fb,fc): - c = 0 - for i in xrange(0,32,8): - xa = (a>>i)&0xff - xb = (b>>i)&0xff - xc = min(255,max(0,int((xa*fa + xb*fb)/fc))) - c |= xc< texel2: - rgb[2] = self.icolor (rgb[0], rgb[1], 2, 1, 3) | 0xff000000 - rgb[3] = self.icolor (rgb[1], rgb[0], 2, 1, 3) | 0xff000000 - else: - rgb[2] = self.icolor (rgb[0], rgb[1], 0.5, 0.5, 1) | 0xff000000 - rgb[3] = 0 - - # color selection (00, 01, 10, 11) - cm = map(ord,data[inp+4:inp+8]) - ofs = l*4 - for n in range(4): - if (ofs + outp)<(x*y): - # one row (4 texels) - if maxw > (0 + l*4): - out[ofs + 0 + outp] = rgb[(cm[n] & 0xc0) >> 6]; - if maxw > (1 + l*4): - out[ofs + 1 + outp] = rgb[(cm[n] & 0x30) >> 4]; - if maxw > (2 + l*4): - out[ofs + 2 + outp] = rgb[(cm[n] & 0x0c) >> 2]; - if maxw > (3 + l*4): - out[ofs + 3 + outp] = rgb[(cm[n] & 0x03) >> 0]; - ofs += x - inp += 8 - outp += x * 4 - outp += maxw - x * 8 - outp += x * (TILE_HEIGHT - 1) - - return ''.join(Struct.uint32(p) for p in out) - -class Object(object): - def __init__(self, name): - self.Frame = 0 - self.Name = name - self.Alpha = 255 - self.Animations = 0 - def __str__(self): - return self.Name - -class Pane(Object): - def __init__(self, name, flags=0x104, alpha=255, coords=[0,0,0,0,0,0,1,1,0,0]): - Object.__init__(self, name) - self.Flags = flags - self.Alpha = alpha - self.Coords = list(coords) - self.Children = [] - self.Enabled = True - - def getX(self): return self.Coords[0] - def setX(self,v): self.Coords[0] = v - def getY(self): return self.Coords[1] - def setY(self,v): self.Coords[1] = v - def getMagX(self): return self.Coords[6] - def setMagX(self,v): self.Coords[6] = v - def getMagY(self): return self.Coords[7] - def setMagY(self,v): self.Coords[7] = v - def getW(self): return self.Coords[8] - def setW(self,v): self.Coords[8] = v - def getH(self): return self.Coords[9] - def setH(self,v): self.Coords[9] = v - def getRot(self): return self.Coords[5] - def setRot(self,v): self.Coords[5] = v - - X = property(getX,setX) - Y = property(getY,setY) - MagX = property(getMagX,setMagX) - MagY = property(getMagY,setMagY) - Width = property(getW,setW) - Height = property(getH,setH) - Rot = property(getRot,setRot) - - def Add(self, child): - self.Children.append(child) - - def AnimDone(self): - if not Object.AnimDone(self): - return False - - for child in self.Children: - if not child.AnimDone(): - return False - - return True - -class Picture(Pane): - def __init__(self, name, flags=0x504, alpha=255, coords=[0,0,0,0,0,0,1,1,0,0], unk=[0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff], mat=0, flags2=0x100, matcoord=[(0,0),(1,0),(0,1),(1,1)]): - Pane.__init__(self, name, flags, alpha, coords) - self.Unk = unk - self.Material = mat - self.Flags2 = flags2 - self.MaterialCoords = list(matcoord) - -class ItemList(object): - HDRLEN=4 - LSIZE=4 - OFFSET=0 - IS_ATOM=True - def __init__(self, data=None): - self.Items = [] - if data is not None: - self.unpack(data) - - def add(self,n): - self.Items.append(n) - - def unpack(self, data): - pos = 0 - if self.IS_ATOM: - pos = 8 - count = self.__unpkcnt__(data[pos:]) - pos = self.__getlistoff__(data[pos:]) - for i in xrange(count): - off = Struct.uint32(data[pos:pos+4], endian='>') + self.OFFSET - if i == (count-1): - next = len(data) - else: - next = Struct.uint32(data[pos+self.LSIZE:pos+self.LSIZE+4], endian='>') + self.OFFSET - pos += self.LSIZE - self.unpack_item(i, data[off:next]) - # sanity check - #dp = self.pack() - #assert dp == data - - def pack(self,extra=None): - - extradata = "" - if extra is not None: - extradata = extra.pack() - - data = "" - - offsets = [] - - for n,i in enumerate(self.Items): - offsets.append(len(data)) - data += self.pack_item(n,i) - - listlen = len(self.Items) * self.LSIZE - - head = self.__mkheader__() - outdata = "" - if self.IS_ATOM: - outdata += self.FOURCC + Struct.uint32((len(extradata) + listlen + len(data) + 8 + len(head) + 3) &(~3), endian='>') - outdata += head - - dataoff = len(outdata) + listlen - self.OFFSET - assert dataoff >= 0 - - for n in offsets: - outdata += Struct.uint32(n + dataoff, endian='>') - if self.LSIZE > 4: - outdata += (self.LSIZE-4)*"\x00" - - outdata += data - outdata += extradata - - if len(outdata)%4 != 0: - outdata += (4-len(outdata)%4)*"\x00" - - return outdata - - def __mkheader__(self): - return Struct.uint16(len(self.Items), endian='>') + "\x00\x00" - - def __unpkcnt__(self, data): - return Struct.uint16(data[0:2], endian='>') - - def __getlistoff__(self, data): - off=self.HDRLEN - if self.IS_ATOM: - off += 8 - return off - - def __getitem__(self, n): - return self.Items[n] - - def __len__(self): - return len(self.Items) - -class StdAtom(Struct): - __endian__ = Struct.BE - def __format__(self): - self.FourCC = Struct.string(4) - self.Size = Struct.uint32 - def pack(self): - self.FourCC = self.FOURCC - self.Size = len(self) - return Struct.pack(self) - -class Brlyt(object): - class BrlytHeader(Struct): - __endian__ = Struct.BE - def __format__(self): - self.Magic = Struct.string(4) - self.Unk = Struct.uint32 - self.Size = Struct.uint32 - self.UnkCount = Struct.uint16 - self.AtomCount = Struct.uint16 - - class BrlytLYT1(StdAtom): - FOURCC = "lyt1" - def __format__(self): - StdAtom.__format__(self) - self.Flag = Struct.uint8 - self.pad = Struct.uint8[3] - self.Width = Struct.float - self.Height = Struct.float - - class BrlytTexture(object): - def __init__(self, name, texture=None): - self.Name = name - self.Texture = texture - self.GLTexture = None - def create_texture(self): - self.GLTexture = self.Texture.create_texture(Texture) - - class BrlytTXL1(ItemList): - LSIZE = 8 - OFFSET = 12 - FOURCC = "txl1" - def __init__(self, archive=None, data=None): - self.Archive = archive - ItemList.__init__(self, data) - - def unpack_item(self, i, data): - fn = data.split('\0', 1)[0] - print fn - tex = TPL(self.Archive.Files['./arc/timg/' + fn.lower()]).Textures[0] - self.Items.append(Brlyt.BrlytTexture(fn, tex)) - def pack_item(self, i, item): - return item.Name + "\0" - - class BrlytMAT1(ItemList): - LSIZE = 4 - OFFSET = 0 - FOURCC = "mat1" - def __init__(self, data=None): - ItemList.__init__(self, data) - - def unpack_item(self, num, data): - mtl = Brlyt.BrlytMaterial() - mtl.unpack(data) - self.Items.append(mtl) - - def pack_item(self, i, item): - return item.pack() - - class BrlytMaterialFlags(object): - def __init__(self,value=None): - if value is not None: - self.unpack(value) - def unpack(self,value): - self.value = value - self.NumTextures = value & 15 - self.NumCoords = (value>>4) & 15 - self.m_2 = (value>>8) & 15 - self.m_4 = bool((value>>12) & 1) - self.m_6 = (value>>13) & 3 - self.m_5 = (value>>15) & 7 - self.m_3 = (value>>18) & 31 - self.m_9 = bool((value>>23) & 1) - self.m_10 = bool((value>>24) & 1) - self.m_7 = bool((value>>25) & 1) - self.m_8 = bool((value>>27) & 1) - - def show(self): - print "Flags: %08x"%self.value - print "ReserveGXMem(" - print " r4 =",self.NumTextures - print " r5 =",self.NumCoords - print " r6 =",self.m_2 - print " r7 =",self.m_3 - print " r8 =",self.m_4 - print " r9 =",self.m_5 - print " r10 =",self.m_6 - print " 0x8(%sp) =",self.m_7 - print " 0xC(%sp) =",self.m_8 - print " 0x10(%sp) =",self.m_9 - print " 0x14(%sp) =",self.m_10 - print ")" - - def pack(self): - val = 0 - val |= self.NumTextures - val |= self.NumCoords << 4 - val |= self.m_2 << 8 - val |= self.m_4 << 12 - val |= self.m_6 << 13 - val |= self.m_5 << 15 - val |= self.m_3 << 18 - val |= self.m_9 << 23 - val |= self.m_10 << 24 - val |= self.m_7 << 25 - val |= self.m_8 << 27 - return val - - class BrlytMatHeader(Struct): - __endian__ = Struct.BE - - def __format__(self): - self.Name = Struct.string(0x14) - self.Color1 = Struct.uint16[4] - self.Color2 = Struct.uint16[4] - self.Color3 = Struct.uint16[4] - self.Blah = Struct.uint32[4] - self.Flags = Struct.uint32 - - # 0-3 num 0-8 - # 4-7 num 0-10 - # 8-11 num 0-8 - # 12 bool - # 13-14 num 0-3 - # 15-17 num 0-4 - # 18-22 num 0-16 - # 23 bool - # 24 bool - # 25 bool a - # 27 bool - - - # if 25, xtra word - # if 27, xtra word - # if 12, xtra word - # 13-14 * 0x14 - # 15-17 * 4 - # 18-22 * 16 - # if 23, xtra word - # if 24, xtra word - - class BrlytMaterial(object): - - def __init__(self, name=None): - if name is not None: - self.Name = name - self.Color1 = [0,0,0,0] - self.Color2 = [255,255,255,255] - self.Color3 = [255,255,255,255] - self.Blah = [0xffffffff,0xffffffff,0xffffffff,0xffffffff] - self.Textures = [] - self.TextureCoords = [] - self.SthB = [] - self.SthI = None - self.SthJ = None - self.SthC = None - self.SthD = [] - self.SthE = [] - self.SthF = [] - self.SthG = 0x77000000 - self.SthH = None - - def unpack(self, data): - wii.chexdump(data) - hdr = Brlyt.BrlytMatHeader() - hdr.unpack(data) - self.FlagData = Brlyt.BrlytMaterialFlags(hdr.Flags) - self.FlagData.show() - - self.Name = hdr.Name.split("\0",1)[0] - self.Color1 = hdr.Color1 - self.Color2 = hdr.Color2 - self.Color3 = hdr.Color3 - self.Blah = hdr.Blah - - ptr = 0x40 - - self.Textures = [] - self.TextureCoords = [] - self.SthB = [] - self.SthI = None - self.SthJ = None - self.SthC = None - self.SthD = [] - self.SthE = [] - self.SthF = [] - self.SthG = None - self.SthH = None - - for i in range(self.FlagData.NumTextures): - texid = Struct.uint16(data[ptr:ptr+2], endian='>') - texcs = Struct.uint8(data[ptr+2], endian='>') - texct = Struct.uint8(data[ptr+3], endian='>') - print " * Texture: %04x %d %d"%(texid,texcs,texct) - self.Textures.append((texid,texcs,texct)) - ptr += 4 - for i in range(self.FlagData.NumCoords): - dat = [] - for j in range(5): - dat.append(Struct.float(data[ptr+j*4:ptr+j*4+4], endian='>')) - print " * Coords: [",', '.join(["%f"%x for x in dat]),"]" - ptr += 0x14 - self.TextureCoords.append(dat) - for i in range(self.FlagData.m_2): - dat = Struct.uint32(data[ptr:ptr+4], endian='>') - self.SthB.append(dat) - print " * SthB: %08x"%dat - ptr += 0x04 - if self.FlagData.m_7: - self.SthI = Struct.uint32(data[ptr:ptr+4], endian='>') - print " SthI: %08x"%self.SthI - ptr += 0x04 - if self.FlagData.m_8: - self.SthJ = Struct.uint32(data[ptr:ptr+4], endian='>') - print " SthJ: %08x"%self.SthJ - ptr += 0x04 - if self.FlagData.m_4: - self.SthC = Struct.uint32(data[ptr:ptr+4], endian='>') - print " SthC: %08x"%self.SthC - ptr += 0x04 - for i in range(self.FlagData.m_6): - dat = [] - for j in range(5): - dat.append(Struct.float(data[ptr+j*4:ptr+j*4+4], endian='>')) - self.SthD.append(dat) - print " * SthD: [",', '.join(["%f"%x for x in dat]),"]" - ptr += 0x14 - for i in range(self.FlagData.m_5): - dat = Struct.uint32(data[ptr:ptr+4], endian='>') - self.SthE.append(dat) - print " * SthE: %08x"%dat - ptr += 0x04 - for i in range(self.FlagData.m_3): - dat = [] - for j in range(4): - dat.append(Struct.uint32(data[ptr+j*4:ptr+j*4+4], endian='>')) - self.SthF.append(dat) - print " * SthF: [",', '.join(["%08x"%x for x in dat]),"]" - ptr += 0x10 - if self.FlagData.m_9: - dat = Struct.uint32(data[ptr:ptr+4], endian='>') - self.SthG = dat - print " SthG: %08x"%dat - ptr += 0x04 - if self.FlagData.m_10: - dat = Struct.uint32(data[ptr:ptr+4], endian='>') - self.SthH = dat - print " SthH: %08x"%dat - ptr += 0x04 - - #assert ptr == len(data) - - def pack(self): - - self.FlagData = Brlyt.BrlytMaterialFlags() - - self.FlagData.NumTextures = len(self.Textures) - self.FlagData.NumCoords = len(self.TextureCoords) - self.FlagData.m_2 = len(self.SthB) - self.FlagData.m_7 = self.SthI is not None - self.FlagData.m_8 = self.SthJ is not None - self.FlagData.m_4 = self.SthC is not None - self.FlagData.m_6 = len(self.SthD) - self.FlagData.m_5 = len(self.SthE) - self.FlagData.m_3 = len(self.SthF) - self.FlagData.m_9 = self.SthG is not None - self.FlagData.m_10 = self.SthH is not None - - self.Flags = self.FlagData.pack() - - hdr = Brlyt.BrlytMatHeader() - - hdr.Name = self.Name + "\x00"*(0x14-len(self.Name)) - hdr.Color1 = self.Color1 - hdr.Color2 = self.Color2 - hdr.Color3 = self.Color3 - hdr.Blah = self.Blah - hdr.Flags = self.Flags - - data = hdr.pack() - - for i in self.Textures: - data += Struct.uint16(i[0], endian='>') - data += Struct.uint8(i[1], endian='>') - data += Struct.uint8(i[2], endian='>') - for i in self.TextureCoords: - for j in i: - data += Struct.float(j, endian='>') - for i in self.SthB: - data += Struct.uint32(i, endian='>') - if self.SthI is not None: - data += Struct.uint32(self.SthI, endian='>') - if self.SthJ is not None: - data += Struct.uint32(self.SthJ, endian='>') - if self.SthC is not None: - data += Struct.uint32(self.SthC, endian='>') - for i in self.SthD: - for j in i: - data += Struct.float(j, endian='>') - for i in self.SthE: - data += Struct.uint32(i, endian='>') - for i in self.SthF: - for j in i: - data += Struct.uint32(j, endian='>') - if self.SthG is not None: - data += Struct.uint32(self.SthG, endian='>') - if self.SthH is not None: - data += Struct.uint32(self.SthH, endian='>') - return data - - class BrlytPAN1(StdAtom): - FOURCC = "pan1" - def __format__(self): - StdAtom.__format__(self) - self.Flags = Struct.uint16 - self.Alpha = Struct.uint16 - self.Name = Struct.string(0x18) - self.Coords = Struct.float[10] - - class BrlytPIC1(BrlytPAN1): - FOURCC = "pic1" - def __format__(self): - Brlyt.BrlytPAN1.__format__(self) - self.unk = Struct.uint8[16] - self.Material = Struct.uint16 - self.Flags2 = Struct.uint16 - self.MaterialCoords = Struct.float[8] - - def __init__(self, archive, data, renderer): - self.Archive = archive - self.Textures = Brlyt.BrlytTXL1() - self.Materials = Brlyt.BrlytMAT1() - self.LastPic = None - self.RootPane = None - self.RootPaneName = None - self.Objects = {} - self.PanePath = [] - self.PaneId = 0 - self.Language = "ENG" - self.Renderer = renderer - - if data != None: - self.Unpack(data) - - def Unpack(self, data): - pos = 0 - header = self.BrlytHeader() - header.unpack(data[:len(header)]) - print "BRLYT header:" - wii.chexdump(data[:len(header)]) - print " unk1: %08x"%header.Unk - print " unkc: %08x"%header.UnkCount - pos += len(header) - - print " %d atoms"%header.AtomCount - - assert header.Magic == 'RLYT' - - for i in xrange(header.AtomCount): - atom = StdAtom() - atom.unpack(data[pos:pos+len(atom)]) - - atomdata = data[pos:pos+atom.Size] - if atom.FourCC == 'txl1': - self.TXL1(atomdata) - elif atom.FourCC == 'lyt1': - self.LYT1(atomdata) - elif atom.FourCC == 'mat1': - self.MAT1(atomdata) - elif atom.FourCC == 'pan1': - self.PAN1(atomdata) - elif atom.FourCC == 'pas1': - self.PAS1(atomdata) - elif atom.FourCC == 'pae1': - self.PAE1(atomdata) - elif atom.FourCC == 'pic1': - self.PIC1(atomdata) - elif atom.FourCC == "grp1": - self.GRP1(atomdata) - else: - print "Unknown FOURCC:",atom.FourCC - wii.chexdump(atomdata) - - pos += atom.Size - - def _PackObject(self, object): - atoms = 0 - if isinstance(object,Pane): - atoms += 1 - if isinstance(object,Picture): - atom = Brlyt.BrlytPIC1() - else: - atom = Brlyt.BrlytPAN1() - atom.Name = object.Name + "\x00"*(0x18-len(object.Name)) - atom.Alpha = int(object.Alpha * 256) - atom.Flags = object.Flags - atom.Coords = object.Coords - if isinstance(object,Picture): - atom.Flags2 = object.Flags2 - atom.Material = object.Material - atom.unk = object.Unk - atom.MaterialCoords = sum(map(list,object.MaterialCoords),[]) - data = atom.pack() - - if len(object.Children) > 0: - atoms += 2 - data += "pas1\x00\x00\x00\x08" - for child in object.Children: - ac, dc = self._PackObject(child) - data += dc - atoms += ac - data += "pae1\x00\x00\x00\x08" - return atoms, data - else: - raise ValueError("Unknown object: "+repr(object)) - - def Pack(self, extra=None): - - header = self.BrlytHeader() - header.Unk = 0xfeff0008 - header.UnkCount = 0x10 - header.Magic = "RLYT" - header.AtomCount = 0 - - data = "" - data += self.mkLYT1() - header.AtomCount+=1 - - data += self.mkTXL1() - header.AtomCount+=1 - - data += self.mkMAT1(extra) - header.AtomCount+=1 - - atoms, ndata = self._PackObject(self.RootPane) - data += ndata - header.AtomCount += atoms - - #uuugly. TODO: fix this crap. - data += "grp1\x00\x00\x00\x1cRootGroup\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - header.AtomCount += 1 - - header.Size = len(data) + len(header) - data = header.pack() + data - - return data - - def mkLYT1(self): - lyt1 = self.BrlytLYT1() - lyt1.Width = self.Width - lyt1.Height = self.Height - lyt1.Flag = 1 - for n in range(3): - lyt1.pad[n] = 0 - return lyt1.pack() - - def mkTXL1(self): - return self.Textures.pack() - - def mkMAT1(self, extra=None): - return self.Materials.pack(extra) - - def LYT1(self, data): - lyt1 = self.BrlytLYT1() - lyt1.unpack(data) - self.Width = lyt1.Width - self.Height = lyt1.Height - print "LYT1: %f x %f, flag %d"%(self.Width, self.Height, lyt1.Flag) - self.Renderer.Create(int(self.Width), int(self.Height)) - - def TXL1(self, data): - self.Textures = self.BrlytTXL1(self.Archive, data) - for i in self.Textures: - i.create_texture() - - def ApplyMask(self, image, mask): - print "Making mask:",image,mask - print image.width,image.height,mask.width,mask.height - if image.height != mask.height or image.width != mask.width: - raise ValueError("Mask dimensions must be equal to mask dimensions") - newdata = [0 for x in xrange(image.height * image.width * 4)] - - for pix in xrange(image.height * image.width): - newdata[pix*4 + 0] = image.data[pix*4 + 0] - newdata[pix*4 + 1] = image.data[pix*4 + 1] - newdata[pix*4 + 2] = image.data[pix*4 + 2] - newdata[pix*4 + 3] = mask.data[pix*4 + 0] - - return ImageData(image.width, image.height, 'RGBA', ''.join(newdata)) - - def MAT1(self, data): - self.Materials = self.BrlytMAT1(data) - - def _addpane(self, p): - self.CurPane = p - self.Objects[p.Name] = p - if self.RootPane is None: - self.RootPane = p - else: - self.PanePath[-1].Add(p) - - def PAN1(self, data): - wii.chexdump(data) - pane = Brlyt.BrlytPAN1() - pane.unpack(data) - p = Pane(pane.Name.split('\0',1)[0], pane.Flags, pane.Alpha/256.0, pane.Coords) - print 'Pane %s (flags %04x, alpha %f): ' % (p.Name, pane.Flags, pane.Alpha),pane.Coords - self._addpane(p) - - def PAS1(self, data): - wii.chexdump(data) - if self.CurPane is None: - raise ValueError("No current pane!") - self.PanePath.append(self.CurPane) - print "Pane start:",'.'.join(map(str,self.PanePath)) - self.CurPane = None - - def PAE1(self, data): - print "Pane end:",'.'.join(map(str,self.PanePath)) - self.PanePath = self.PanePath[:-1] - - def PIC1(self, data): - wii.chexdump(data) - pic = Brlyt.BrlytPIC1() - pic.unpack(data) - mc = [] - for i in range(4): - mc.append(pic.MaterialCoords[i*2:i*2+2]) - print mc - p = Picture(pic.Name.split("\0",1)[0], pic.Flags, pic.Alpha/256.0, pic.Coords, pic.unk, pic.Material, pic.Flags2, mc) - print repr(p.Name) - mat = self.Materials[pic.Material] - if mat is not None: - self._addpane(p) - else: - print 'Picture %s with null material!' - - def GRP1(self, data): - wii.chexdump(data) - if len(data) < 0x1c: - pass - lang = data[0x8:0x18].split('\0', 1)[0] - nitems = Struct.uint16(data[0x18:0x1a], endian='>') - p = 0x1c - items = [] - for i in xrange(nitems): - items.append(data[p:].split('\0', 1)[0]) - p += 0x10 - for i in items: - try: - if lang != self.Language: - self.Objects[i].Enabled = False - else: - self.Objects[i].Enabled = True - except: - pass - -class Brlan(object): - A_COORD = "RLPA" - A_PARM = "RLVC" - C_X = 0 - C_Y = 1 - C_ANGLE = 5 - C_MAGX = 6 - C_MAGY = 7 - C_WIDTH = 8 - C_HEIGHT = 9 - P_ALPHA = 0x10 - class BrlanHeader(Struct): - __endian__ = Struct.BE - def __format__(self): - self.Magic = Struct.string(4) - self.Unk = Struct.uint32 - self.Size = Struct.uint32 - self.UnkCount = Struct.uint16 - self.AtomCount = Struct.uint16 - - def __init__(self, data=None): - self.Anim = None - if data != None: - self.Unpack(data) - else: - self.Anim = Brlan.BrlanPAI1() - - def Unpack(self, data): - header = self.BrlanHeader() - header.unpack(data[:len(header)]) - pos = len(header) - - assert header.Magic == 'RLAN' - - for i in xrange(header.AtomCount): - atom = StdAtom() - atom.unpack(data[pos:pos+len(atom)]) - atomdata = data[pos:pos+atom.Size] - pos += atom.Size - - if atom.FourCC == 'pai1': - self.PAI1(atomdata) - else: - print "Unknown animation atom: %s"%atom.FourCC - - class BrlanPAI1(ItemList): - LSIZE=4 - OFFSET=0 - FOURCC="pai1" - HDRLEN=12 - def unpack(self, data): - self.FrameCount = Struct.uint16(data[8:10], endian='>') - print self.FrameCount - ItemList.unpack(self, data) - def __mkheader__(self): - hdr = Struct.uint16(self.FrameCount, endian='>') - hdr += Struct.uint16(0x100, endian='>') - hdr += Struct.uint32(len(self.Items), endian='>') - hdr += Struct.uint32(0x14, endian='>') - return hdr - def __unpkcnt__(self, data): - return Struct.uint32(data[4:8], endian='>') - def __getlistoff__(self, data): - return Struct.uint32(data[8:12], endian='>') - def unpack_item (self, num, data): - self.Items.append(Brlan.BrlanAnimSet(data)) - def pack(self, offset, count): - self.FrameCount = count - self.Offset = offset - return ItemList.pack(self) - def pack_item (self, num, item): - return item.pack(self.Offset) - def __getitem__(self, n): - if isinstance(n,str): - for i in self.Items: - if i.Name == n: - return i - raise KeyError("Key %s not found"%n) - else: - return ItemList.__getitem__(self, n) - - def __contains__(self, n): - if isinstance(n,str): - for i in self.Items: - if i.Name == n: - return True - return False - else: - return n in self.Items - - - - class BrlanAnimSet(ItemList): - LSIZE=4 - OFFSET=0 - HDRLEN=0x18 - IS_ATOM=False - def __init__(self, data=None): - if data is not None and len(data)<0x14: - self.Name = data - ItemList.__init__(self, None) - else: - ItemList.__init__(self, data) - def unpack(self, data): - self.Name = data[:0x14].split("\0",1)[0] - print self.Name - ItemList.unpack(self, data) - def __mkheader__(self): - hdr = self.Name + "\x00" * (0x14-len(self.Name)) - hdr += Struct.uint8(len(self.Items), endian='>') - hdr += "\x00\x00\x00" - return hdr - def __unpkcnt__(self, data): - return Struct.uint8(data[0x14:0x15], endian='>') - def unpack_item (self, num, data): - self.Items.append(Brlan.BrlanAnimClass(data)) - def pack_item (self, num, item): - return item.pack(self.Offset) - def pack(self, offset): - self.Offset = offset - return ItemList.pack(self) - def __getitem__(self, n): - if isinstance(n,str): - for i in self.Items: - if i.Type == n: - return i - raise KeyError("Key %s not found"%n) - else: - return ItemList.__getitem__(self, n) - - class BrlanAnimClass(ItemList): - LSIZE=4 - OFFSET=0 - HDRLEN=8 - IS_ATOM=False - - class BrlanAnimClassIterator(object): - def __init__(self, cl): - self.cl = cl - self.item = 0 - def __iter__(self): - return self - def next(self): - if self.item == len(self.cl.Items): - raise StopIteration() - else: - self.item += 1 - return self.cl.Items[self.item-1] - - def __init__(self, data=None): - if data is not None and len(data) == 4: - self.Type = data - ItemList.__init__(self, None) - else: - ItemList.__init__(self, data) - def unpack(self, data): - self.Type = data[0:4] - print " ",self.Type - ItemList.unpack(self, data) - def __mkheader__(self): - hdr = self.Type - hdr += Struct.uint8(len(self.Items), endian='>') - hdr += "\x00\x00\x00" - return hdr - def __unpkcnt__(self, data): - return Struct.uint8(data[4:5], endian='>') - def unpack_item (self, num, data): - self.Items.append(Brlan.BrlanAnim(data)) - def pack(self, offset): - self.Offset = offset - return ItemList.pack(self) - def pack_item (self, num, item): - return item.pack(self.Offset) - def __getitem__(self, n): - for i in self.Items: - if i.Type == n: - return i - raise KeyError("Key %d not found"%n) - def __iter__(self): - return self.BrlanAnimClassIterator(self) - - class BrlanAnim(object): - def __init__(self, data=None): - self.Triplets = [] - self.Unk = 0x200 - self.Type = 0 - if data is not None and isinstance(data,int): - self.Type = data - else: - self.unpack(data) - def unpack(self, data): - self.Type = Struct.uint16(data[0:2], endian='>') - self.Unk = Struct.uint16(data[2:4], endian='>') - count = Struct.uint16(data[4:6], endian='>') - pos = Struct.uint32(data[8:12], endian='>') - print " ",self.Type - if self.Unk == 0x200: - print " Triplets:" - for i in range(count): - F = Struct.float(data[pos+0:pos+4], endian='>') - P = Struct.float(data[pos+4:pos+8], endian='>') - D = Struct.float(data[pos+8:pos+12], endian='>') - print " %11f %11f %11f"%(F,P,D) - self.Triplets.append((F,P,D)) - pos += 12 - else: - print " Unknown format: %04x"%self.Unk - def pack(self, offset): - self.Triplets.sort(key=lambda x: x[0]) - t = self.Triplets - self.Triplets = [] - lt = (None, None, None) - for i in t: - if i == lt: - pass - elif i[0] == lt[0]: - raise ValueError("Duplicate triplet frame numbers with different data") - else: - self.Triplets.append(i) - - out = Struct.uint16(self.Type, endian='>') - out += Struct.uint16(self.Unk, endian='>') - out += Struct.uint16(len(self.Triplets), endian='>') - out += "\x00\x00" - out += Struct.uint32(0xc, endian='>') - for F,P,D in self.Triplets: - out += Struct.float(F-offset, endian='>') - out += Struct.float(P, endian='>') - out += Struct.float(D, endian='>') - return out - def add(self, F, P=None, D=None): - if isinstance(F,tuple): - self.Triplets.append(F) - else: - self.Triplets.append((F,P,D)) - def rep(self, start, end, times): - replist = [] - for i in self.Triplets: - if i[0] >= start and i[0] <= end: - replist.append(i) - if len(replist) == 0: - return - off = end-start - for i in range(times-1): - for a,b,c in replist: - self.Triplets.append((a+off,b,c)) - off += end-start - a,b,c = replist[0] - if a == start: - self.Triplets.append((a+off,b,c)) - def repsimple(self, start, end, times, sp, sd, ep, ed): - step = float(end-start) / times - self.Triplets.append((start, sp, sd)) - self.Triplets.append((start+step/2.0, ep, ed)) - self.rep(start, start+step, times) - def calc(self, frame): - for tn in range(len(self.Triplets)): - if self.Triplets[tn][0] > frame: - if tn == 0: - return self.Triplets[0][1] - else: - start, value1, coef1 = self.Triplets[tn-1] - end, value2, coef2 = self.Triplets[tn] - t = (frame - start) / (end - start) - nf = end - start - return \ - coef1 * 1 * nf * (t + t**3 - 2*t**2) + \ - coef2 * 1 * nf * (t**3 - t**2) + \ - value1 * (1 + (2*t**3 - 3*t**2)) + \ - value2 * (-2*t**3 + 3*t**2) - else: - return self.Triplets[-1][1] - def __getitem__(self, n): - return self.Triplets[n] - def PAI1(self, data): - assert self.Anim is None - self.Anim = self.BrlanPAI1(data) - return - def Pack(self, a=None, b=None): - - if a is None and b is None: - frames = self.FrameCount - offset = 0 - elif a is not None and b is None: - frames = a - offset = 0 - elif a is not None and b is not None: - frames = b-a - offset = a - else: - raise ValueError("WTF are you doing") - - header = self.BrlanHeader() - header.Unk = 0xfeff0008 - header.UnkCount = 0x10 - header.Magic = "RLAN" - header.AtomCount = 1 - - data = self.Anim.pack(offset, frames) - - header.Size = len(data) + len(header) - data = header.pack() + data - - return data - -if have_pyglet: - class BannerWindow(window.Window): - def on_resize(self, width, height): - glViewport(0, 0, width, height) - glMatrixMode(GL_PROJECTION) - glLoadIdentity() - glOrtho(-width/2, width/2, -height/2, height/2, -1, 1) - glMatrixMode(GL_MODELVIEW) - - -class Renderer(object): - def __init__(self): - self.Brlyt = None - self.Brlan = None - - def Create(self, width, height): - self.Width = width - self.Height = height - print "Render: %f x %f"%(self.Width,self.Height) - self.Window = BannerWindow(self.Width, self.Height) - self.Window.set_exclusive_mouse(False) - - glClearColor(0.0, 0.0, 0.0, 0.0) - glClearDepth(1.0) - glDepthFunc(GL_LEQUAL) - glEnable(GL_DEPTH_TEST) - - glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA) - glEnable(GL_BLEND) - glEnable(GL_TEXTURE_2D) - clock.set_fps_limit(60) - - - def Render(self, item, wireframe=False): - if not item.Enabled: - return - if isinstance(item, Picture): - - mat = self.Brlyt.Materials[item.Material] - texture = self.Brlyt.Textures[mat.Textures[0][0]].GLTexture - mtc = mat.TextureCoords[0] - x, y, a, b, c, rot, xsc, ysc, xs, ys = item.Coords[:10] - - xs *= xsc - ys *= ysc - #print item.Name,x,y,xs,ys - xc, yc = x-(xs/2),y-(ys/2) - - glPushMatrix() - glMatrixMode( GL_MODELVIEW ) - glTranslatef( x, y, 0) - glRotatef(rot,0,0,1) - glScalef(xs,ys,0) - - if not wireframe: - col = [x/255.0 for x in list(mat.Color2)] - col[3] = col[3] * item.Alpha / 255.0 - - tw = texture.tex_coords[6] - th = texture.tex_coords[7] - - mc = item.MaterialCoords - - glMatrixMode( GL_TEXTURE ) - glPushMatrix() - glTranslatef(0.5,0.5,0) - glTranslatef(mtc[0],mtc[1],0) - glScalef(mtc[3],mtc[4],0) - glTranslatef(-0.5,-0.5,0) - array = (GLfloat * 32)( - mc[0][0] * tw, mc[0][1] * th, 0, 1., - -0.5, 0.5, 0, 1., - mc[1][0] * tw, mc[1][1] * th, 0, 1., - 0.5, 0.5, 0, 1., - mc[3][0] * tw, mc[3][1] * th, 0, 1., - 0.5, -0.5, 0, 1., - mc[2][0] * tw, mc[2][1] * th, 0, 1., - -0.5, -0.5, 0, 1.) - - glColor4f(*col) - glPushAttrib(GL_ENABLE_BIT) - glEnable(texture.target) - glBindTexture(texture.target, texture.id) - if mat.Textures[0][1] == 0x0: - glTexParameteri(texture.target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) - elif mat.Textures[0][1] == 0x1: - glTexParameteri(texture.target, GL_TEXTURE_WRAP_S, GL_REPEAT) - elif mat.Textures[0][1] == 0x2: - glTexParameteri(texture.target, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT) - else: - glTexParameteri(texture.target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) - if mat.Textures[0][2] == 0x0: - glTexParameteri(texture.target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) - elif mat.Textures[0][2] == 0x1: - glTexParameteri(texture.target, GL_TEXTURE_WRAP_T, GL_REPEAT) - elif mat.Textures[0][2] == 0x2: - glTexParameteri(texture.target, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT) - else: - glTexParameteri(texture.target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) - - glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT) - glInterleavedArrays(GL_T4F_V4F, 0, array) - glDrawArrays(GL_QUADS, 0, 4) - glPopClientAttrib() - glPopAttrib() - - glBindTexture(texture.target, 0) - glPopMatrix() - glMatrixMode( GL_MODELVIEW ) - - else: - - glColor3f(1,0,0) - glBegin(GL_LINE_STRIP) - glVertex2f(-0.5,-0.5) - glVertex2f(0.5,-0.5) - glVertex2f(0.5,0.5) - glVertex2f(-0.5,0.5) - glVertex2f(-0.5,-0.5) - glColor3f(1,1,1) - glEnd() - pass - - glPopMatrix() - if isinstance(item, Pane): - if item.Coords is not None: - x, y, a, b, c, rot, xsc, ysc, xs, ys = item.Coords[:10] - else: - x = y = 0 - xs = ys = 0 - xsc = 1 - ysc = 1 - glPushMatrix() - glTranslatef(x, y, 0) - glRotatef(rot,0,0,1) - glScalef(xsc,ysc,0) - #glScalef(xs,ys,1) - for child in item.Children: - self.Render(child,wireframe) - glPopMatrix() - - def Animate(self, frame): - for set in self.Brlan.Anim: - for clss in set: - for anim in clss: - #print set.Name, clss.Type, anim.Type, anim.calc(frame), frame - if clss.Type == Brlan.A_COORD: - self.Brlyt.Objects[set.Name].Coords[anim.Type] = anim.calc(frame) - elif clss.Type == Brlan.A_PARM: - if anim.Type == Brlan.P_ALPHA: - self.Brlyt.Objects[set.Name].Alpha = anim.calc(frame) - - def MainLoop(self, loop): - frame = 0 - print "Starting mainloop: loop =",loop - print "Length in frames:",self.Brlan.Anim.FrameCount - while not self.Window.has_exit: - self.Window.dispatch_events() - self.Window.clear() - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) - glLoadIdentity() - glColor4f(1.0, 1.0, 1.0, 1.0) - - self.Render(self.Brlyt.RootPane,False) - #self.Render(self.Brlyt.RootPane,True) - - #clock.tick() - - self.Window.flip() - if self.Brlan is not None: - self.Animate(frame) - if frame >= self.Brlan.Anim.FrameCount: - if not loop: - print "Animation done!" - return True - else: - print "Looping..." - frame = -1 - frame += 1 - -class Alameda(object): - class IMETHeader(Struct): - __endian__ = Struct.BE - def __format__(self): - self.Zeroes = Struct.uint8[0x40] - self.IMET = Struct.string(4) - self.Fixed = Struct.uint8[8] - self.Sizes = Struct.uint32[3] - self.Flag1 = Struct.uint32 - self.Names = Struct.string(0x2A<<1, encoding='utf-16-be', stripNulls=True)[7] - self.Zeroes = Struct.uint8[0x348] - self.MD5 = Struct.uint8[0x10] - - def __init__(self, fn, type='icon'): - renderer = Renderer() - - fp = file(fn, 'rb') - - imet = self.IMETHeader() - try: - imet.unpack(fp.read(len(imet))) - except: - imet = None - if imet is None or imet.IMET != 'IMET': - imet = self.IMETHeader() - fp.seek(0x40) - imet.unpack(fp.read(len(imet))) - assert imet.IMET == 'IMET' - - print 'English title: %s' % imet.Names[1] - - - root = U8(fp.read()) - if type == 'icon': - banner = U8(IMD5(root.Files['./meta/icon.bin'])) - renderer.Brlyt = Brlyt(banner, banner.Files['./arc/blyt/icon.brlyt'], renderer) - fd = None - try: - fd = banner.Files['./arc/anim/icon.brlan'] - except: - pass - if fd is not None: - renderer.Brlan = Brlan(fd) - - loop = True - else: - banner = U8(IMD5(root.Files['./meta/banner.bin'])) - renderer.Brlyt = Brlyt(banner, banner.Files['./arc/blyt/banner.brlyt'], renderer) - loop = not banner.Files.has_key('./arc/anim/banner_start.brlan') - if not loop: - renderer.Brlan = Brlan(banner.Files['./arc/anim/banner_start.brlan']) - else: - renderer.Brlan = Brlan(banner.Files['./arc/anim/banner.brlan']) - - if renderer.MainLoop(loop) and type == 'banner' and not loop: - renderer.Brlan = Brlan(banner.Files['./arc/anim/banner_loop.brlan']) - renderer.MainLoop(True) - -if __name__=='__main__': - Alameda(*sys.argv[1:]) +have_pyglet = False + +try: + from pyglet import clock, window + from pyglet.gl import * + from pyglet.image import * + have_pyglet = True +except: + pass + +import sys, os +sys.path.append(os.path.realpath(os.path.dirname(sys.argv[0]))+"/../Common") +from Struct import Struct +import struct +import pywii as wii + +def LZ77Decompress(data): + inp = 0 + dlen = len(data) + data += b'\0' * 16 + + ret = [] + + while inp < dlen: + bitmask = data[inp] + inp += 1 + + for i in range(8): + if bitmask & 0x80: + rep = data[inp] + repLength = (rep >> 4) + 3 + inp += 1 + repOff = data[inp] | ((rep & 0x0F) << 8) + inp += 1 + + assert repOff <= len(ret) + + while repLength > 0: + ret.append(ret[-repOff - 1]) + repLength -= 1 + else: + ret.append(data[inp]) + inp += 1 + + bitmask <<= 1 + + return bytes(ret) + +class U8(object): + class U8Header(Struct): + __endian__ = Struct.BE + def __format__(self): + self.Tag = Struct.uint32 + self.RootNode = Struct.uint32 + self.HeaderSize = Struct.uint32 + self.DataOffset = Struct.uint32 + self.Zeroes = Struct.uint8[0x10] + + class U8Node(Struct): + __endian__ = Struct.BE + def __format__(self): + self.Type = Struct.uint16 + self.NameOffset = Struct.uint16 + self.DataOffset = Struct.uint32 + self.Size = Struct.uint32 + + def __init__(self, data=None): + self.Files = {} + + if data != None: + self.Unpack(data) + + def Unpack(self, data): + pos = 0 + u8 = self.U8Header() + u8.unpack(data[pos:pos+len(u8)]) + pos += len(u8) + + print(hex(u8.Tag)) + assert u8.Tag == 0x55aa382d + pos += u8.RootNode - 0x20 + + root = self.U8Node() + root.unpack(data[pos:pos+len(root)]) + pos += len(root) + + children = [] + for i in range(root.Size - 1): + child = self.U8Node() + child.unpack(data[pos:pos+len(child)]) + pos += len(child) + children.append(child) + + stringTable = data[pos:pos + u8.DataOffset - len(u8) - root.Size * len(root)] + pos += len(stringTable) + + currentOffset = u8.DataOffset + + path = ['.'] + pathDepth = [root.Size - 1] + for offset,child in enumerate(children): + name = stringTable[child.NameOffset:].split(b'\0', 1)[0].decode("ascii") + if child.Type == 0x0100: + path.append(name) + pathDepth.append(child.Size-offset-1) + elif child.Type == 0: + name = '/'.join(path + [name]) + + if currentOffset < child.DataOffset: + diff = child.DataOffset - currentOffset + assert diff <= 32 + + pos += diff + currentOffset += diff + + currentOffset += child.Size + + self.Files[name.lower()] = data[pos:pos+child.Size] + pos += child.Size + + pathDepth[-1] -= 1 + if pathDepth[-1] == 0: + path = path[:-1] + pathDepth = pathDepth[:-1] + +class IMD5Header(Struct): + __endian__ = Struct.BE + def __format__(self): + self.Tag = Struct.string(4) + self.Size = Struct.uint32 + self.Zeroes = Struct.uint8[8] + self.MD5 = Struct.uint8[0x10] + +def IMD5(data): + imd5 = IMD5Header() + imd5.unpack(data[:len(imd5)]) + assert imd5.Tag == 'IMD5' + pos = len(imd5) + + if data[pos:pos+4] == b'LZ77': + return LZ77Decompress(data[pos+8:]) + else: + return data[pos:] + +class TPL(object): + class TPLHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.Magic = Struct.uint32 + self.Count = Struct.uint32 + self.Size = Struct.uint32 + + class TexOffsets(Struct): + __endian__ = Struct.BE + def __format__(self): + self.HeaderOff = Struct.uint32 + self.PaletteOff = Struct.uint32 + + class TexHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.Size = Struct.uint16[2] + self.Format = Struct.uint32 + self.DataOff = Struct.uint32 + self.Wrap = Struct.uint32[2] + self.Filter = Struct.uint32[2] + self.LODBias = Struct.float + self.EdgeLOD = Struct.uint8 + self.LOD = Struct.uint8[2] + self.Unpacked = Struct.uint8 + + class PalHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.Count = Struct.uint16 + self.Unpacked = Struct.uint8 + self.Pad = Struct.uint8 + self.Format = Struct.uint32 + self.DataOff = Struct.uint32 + + def __init__(self, data=None): + self.Textures = [] + + if data != None: + self.Unpack(data) + + def Unpack(self, data): + header = self.TPLHeader() + header.unpack(data[:len(header)]) + pos = len(header) + + assert header.Magic == 0x0020AF30 + assert header.Size == 0xc + + for i in range(header.Count): + offs = self.TexOffsets() + offs.unpack(data[pos:pos+len(offs)]) + pos += len(offs) + + self.Textures.append(self.ParseTexture(data, offs)) + + def ParseTexture(self, data, offs): + texHeader = self.TexHeader() + texHeader.unpack(data[offs.HeaderOff:offs.HeaderOff+len(texHeader)]) + format = texHeader.Format + self.format = format + rgba = None + if format == 0: + rgba = self.I4(data[texHeader.DataOff:], texHeader.Size) + elif format == 1: + rgba = self.I8(data[texHeader.DataOff:], texHeader.Size) + elif format == 2: + rgba = self.IA4(data[texHeader.DataOff:], texHeader.Size) + elif format == 3: + rgba = self.IA8(data[texHeader.DataOff:], texHeader.Size) + elif format == 4: + rgba = self.RGB565(data[texHeader.DataOff:], texHeader.Size) + elif format == 5: + rgba = self.RGB5A3(data[texHeader.DataOff:], texHeader.Size) + elif format == 6: + rgba = self.RGBA8(data[texHeader.DataOff:], texHeader.Size) + elif format == 14: + rgba = self.S3TC(data[texHeader.DataOff:], texHeader.Size) + else: + print('Unknown texture format', format) + + if rgba == None: + rgba = b'\0\0\0\0' * texHeader.Size[0] * texHeader.Size[1] + + image = ImageData(texHeader.Size[1], texHeader.Size[0], 'RGBA', rgba) + print(format) + return image + + def I4(self, data, xxx_todo_changeme): + (y, x) = xxx_todo_changeme + out = [0 for i in range(x * y)] + outp = 0 + inp = 0 + for i in range(0, y, 8): + for j in range(0, x, 8): + ofs = 0 + for k in range(8): + off = min(x - j, 8) + for sub in range(0, off, 2): + texel = data[inp] + high, low = texel >> 4, texel & 0xF + if (outp + ofs + sub) < (x*y): + out[outp + ofs + sub] = (high << 4) | (high << 20) | (high << 12) | 0xFF<<24 + + if sub + 1 < off: + if (outp + ofs + sub + 1) < (x*y): + out[outp + ofs + sub + 1] = (low << 4) | (low << 20) | (low << 12) | 0xFF<<24 + + inp += 1 + + ofs += x + inp += (8 - off) / 2 + outp += off + outp += x * 7 + + return b''.join(Struct.uint32(p) for p in out) + + def I8(self, data, xxx_todo_changeme1): + (y, x) = xxx_todo_changeme1 + out = [0 for i in range(x * y*2)] + outp = 0 + inp = 0 + for i in range(0, y, 4): + for j in range(0, x, 4): + ofs = 0 + for k in range(4): + off = min(x - j, 4) + for sub in range(off): + texel = data[inp] + out[outp + ofs + sub] = (texel << 24) | (texel << 16) | (texel << 8) | 0xFF + inp += 1 + + ofs += x + inp += 4 - off * 2 + outp += off + outp += x * 3 + + return b''.join(Struct.uint32(p) for p in out) + + def IA4(self, data, xxx_todo_changeme2): + (y, x) = xxx_todo_changeme2 + out = [0 for i in range(x * y)] + outp = 0 + inp = 0 + for i in range(0, y, 4): + for j in range(0, x, 8): + ofs = 0 + for k in range(4): + off = min(x - j, 8) + for sub in range(off): + texel = data[inp] + alpha, inte = texel >> 4, texel & 0xF + if (outp + ofs + sub) < (x*y): + out[outp + ofs + sub] = (inte << 4) | (inte << 12) | (inte << 20) | (alpha << 28) + inp += 1 + + ofs += x + inp += 8 - off + outp += off + outp += x * 3 + + return b''.join(Struct.uint32(p) for p in out) + + def IA8(self, data, xxx_todo_changeme3): + (y, x) = xxx_todo_changeme3 + out = [0 for i in range(x * y)] + outp = 0 + inp = 0 + for i in range(0, y, 4): + for j in range(0, x, 4): + ofs = 0 + for k in range(4): + off = min(x - j, 4) + for sub in range(off): + if (outp + ofs + sub) < (x*y): + texel = Struct.uint16(data[inp:inp + 2], endian='>') + p = (texel & 0xFF) + p |= (texel & 0xFF) << 8 + p |= (texel & 0xFF) << 16 + p |= (texel >> 8) << 24 + out[outp + ofs + sub] = p + inp += 2 + + ofs += x + inp += (4 - off) * 2 + outp += off + outp += x * 3 + + return b''.join(Struct.uint32(p) for p in out) + + def RGB565(self, data, xxx_todo_changeme4): + (y, x) = xxx_todo_changeme4 + out = [0 for i in range(x * y)] + outp = 0 + inp = 0 + for i in range(0, y, 4): + for j in range(0, x, 4): + ofs = 0 + for k in range(4): + off = min(x - j, 4) + for sub in range(off): + if (outp + ofs + sub) < (x*y): + texel = Struct.uint16(data[inp:inp + 2], endian='>') + p = ((texel >> 11) & 0x1F) << 3 + p |= ((texel >> 5) & 0x3F) << 10 + p |= ( texel & 0x1F) << 19 + p |= 0xFF<<24 + out[outp + ofs + sub] = p + inp += 2 + + ofs += x + inp += (4 - off) * 2 + outp += off + outp += x * 3 + + return b''.join(Struct.uint32(p) for p in out) + + def RGB5A3(self, data, xxx_todo_changeme5): + (y, x) = xxx_todo_changeme5 + out = [0 for i in range(x * y)] + outp = 0 + inp = 0 + for i in range(0, y, 4): + for j in range(0, x, 4): + ofs = 0 + for k in range(4): + off = min(x - j, 4) + for sub in range(off): + texel = Struct.uint16(data[inp:inp + 2], endian='>') + if texel & 0x8000: + p = ((texel >> 10) & 0x1F) << 3 + p |= ((texel >> 5) & 0x1F) << 11 + p |= ( texel & 0x1F) << 19 + p |= 0xFF<<24 + else: + p = ((texel >> 12) & 0x07) << 29 + p |= ((texel >> 8) & 0x0F) << 4 + p |= ((texel >> 4) & 0x0F) << 12 + p |= (texel & 0x0F) << 20 + if (outp + ofs + sub) < (x*y): + out[outp + ofs + sub] = p + inp += 2 + + ofs += x + inp += (4 - off) * 2 + outp += off + outp += x * 3 + + return b''.join(Struct.uint32(p) for p in out) + + def RGBA8(self, data, xxx_todo_changeme6): + (y, x) = xxx_todo_changeme6 + out = [0 for i in range(x * y)] + outp = 0 + inp = 0 + for i in range(0, y, 4): + for j in range(0, x, 4): + ofs = 0 + for k in range(4): + off = min(x - j, 4) + for sub in range(off): + texel = Struct.uint16(data[inp:inp + 2], endian='>')<<16 + texel |= Struct.uint16(data[inp+32:inp + 34], endian='>') + if (outp + ofs + sub) < (x*y): + out[outp + ofs + sub] = texel&0xff000000 | ((texel>>16)&0xff) | (texel&0xff00) | ((texel<<16)&0xff0000) + inp += 2 + + ofs += x + inp += (4 - off) * 2 + outp += off + inp += 32 + outp += x * 3 + + return b''.join(Struct.uint32(p) for p in out) + + def unpack_rgb565(self,texel): + b = (texel&0x1f)<<3 + g = ((texel>>5)&0x3f)<<2 + r = ((texel>>11)&0x1f)<<3 + b |= b>>5 + g |= g>>6 + r |= r>>5 + return (0xff<<24) | (b<<16) | (g<<8) | r + def icolor(self,a,b,fa,fb,fc): + c = 0 + for i in range(0,32,8): + xa = (a>>i)&0xff + xb = (b>>i)&0xff + xc = min(255,max(0,int((xa*fa + xb*fb)/fc))) + c |= xc< texel2: + rgb[2] = self.icolor (rgb[0], rgb[1], 2, 1, 3) | 0xff000000 + rgb[3] = self.icolor (rgb[1], rgb[0], 2, 1, 3) | 0xff000000 + else: + rgb[2] = self.icolor (rgb[0], rgb[1], 0.5, 0.5, 1) | 0xff000000 + rgb[3] = 0 + + # color selection (00, 01, 10, 11) + cm = list(data[inp+4:inp+8]) + ofs = l*4 + for n in range(4): + if (ofs + outp)<(x*y): + # one row (4 texels) + if maxw > (0 + l*4): + out[ofs + 0 + outp] = rgb[(cm[n] & 0xc0) >> 6]; + if maxw > (1 + l*4): + out[ofs + 1 + outp] = rgb[(cm[n] & 0x30) >> 4]; + if maxw > (2 + l*4): + out[ofs + 2 + outp] = rgb[(cm[n] & 0x0c) >> 2]; + if maxw > (3 + l*4): + out[ofs + 3 + outp] = rgb[(cm[n] & 0x03) >> 0]; + ofs += x + inp += 8 + outp += x * 4 + outp += maxw - x * 8 + outp += x * (TILE_HEIGHT - 1) + + return b''.join(Struct.uint32(p) for p in out) + +class Object(object): + def __init__(self, name): + self.Frame = 0 + self.Name = name + self.Alpha = 255 + self.Animations = 0 + def __str__(self): + return self.Name + +class Pane(Object): + def __init__(self, name, flags=0x104, alpha=255, coords=[0,0,0,0,0,0,1,1,0,0]): + Object.__init__(self, name) + self.Flags = flags + self.Alpha = alpha + self.Coords = list(coords) + self.Children = [] + self.Enabled = True + + def getX(self): return self.Coords[0] + def setX(self,v): self.Coords[0] = v + def getY(self): return self.Coords[1] + def setY(self,v): self.Coords[1] = v + def getMagX(self): return self.Coords[6] + def setMagX(self,v): self.Coords[6] = v + def getMagY(self): return self.Coords[7] + def setMagY(self,v): self.Coords[7] = v + def getW(self): return self.Coords[8] + def setW(self,v): self.Coords[8] = v + def getH(self): return self.Coords[9] + def setH(self,v): self.Coords[9] = v + def getRot(self): return self.Coords[5] + def setRot(self,v): self.Coords[5] = v + + X = property(getX,setX) + Y = property(getY,setY) + MagX = property(getMagX,setMagX) + MagY = property(getMagY,setMagY) + Width = property(getW,setW) + Height = property(getH,setH) + Rot = property(getRot,setRot) + + def Add(self, child): + self.Children.append(child) + + def AnimDone(self): + if not Object.AnimDone(self): + return False + + for child in self.Children: + if not child.AnimDone(): + return False + + return True + +class Picture(Pane): + def __init__(self, name, flags=0x504, alpha=255, coords=[0,0,0,0,0,0,1,1,0,0], unk=[0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff], mat=0, flags2=0x100, matcoord=[(0,0),(1,0),(0,1),(1,1)]): + Pane.__init__(self, name, flags, alpha, coords) + self.Unk = unk + self.Material = mat + self.Flags2 = flags2 + self.MaterialCoords = list(matcoord) + +class ItemList(object): + HDRLEN=4 + LSIZE=4 + OFFSET=0 + IS_ATOM=True + def __init__(self, data=None): + self.Items = [] + if data is not None: + self.unpack(data) + + def add(self,n): + self.Items.append(n) + + def unpack(self, data): + pos = 0 + if self.IS_ATOM: + pos = 8 + count = self.__unpkcnt__(data[pos:]) + pos = self.__getlistoff__(data[pos:]) + for i in range(count): + off = Struct.uint32(data[pos:pos+4], endian='>') + self.OFFSET + if i == (count-1): + next = len(data) + else: + next = Struct.uint32(data[pos+self.LSIZE:pos+self.LSIZE+4], endian='>') + self.OFFSET + pos += self.LSIZE + self.unpack_item(i, data[off:next]) + # sanity check + #dp = self.pack() + #assert dp == data + + def pack(self,extra=None): + + extradata = b"" + if extra is not None: + extradata = extra.pack() + + data = b"" + + offsets = [] + + for n,i in enumerate(self.Items): + offsets.append(len(data)) + data += self.pack_item(n,i) + + listlen = len(self.Items) * self.LSIZE + + head = self.__mkheader__() + outdata = b"" + if self.IS_ATOM: + outdata += self.FOURCC.encode("ascii") + Struct.uint32((len(extradata) + listlen + len(data) + 8 + len(head) + 3) &(~3), endian='>') + outdata += head + + dataoff = len(outdata) + listlen - self.OFFSET + assert dataoff >= 0 + + for n in offsets: + outdata += Struct.uint32(n + dataoff, endian='>') + if self.LSIZE > 4: + outdata += (self.LSIZE-4)*b"\x00" + + outdata += data + outdata += extradata + + if len(outdata)%4 != 0: + outdata += (4-len(outdata)%4)*b"\x00" + + return outdata + + def __mkheader__(self): + return Struct.uint16(len(self.Items), endian='>') + b"\x00\x00" + + def __unpkcnt__(self, data): + return Struct.uint16(data[0:2], endian='>') + + def __getlistoff__(self, data): + off=self.HDRLEN + if self.IS_ATOM: + off += 8 + return off + + def __getitem__(self, n): + return self.Items[n] + + def __len__(self): + return len(self.Items) + +class StdAtom(Struct): + __endian__ = Struct.BE + def __format__(self): + self.FourCC = Struct.string(4) + self.Size = Struct.uint32 + def pack(self): + self.FourCC = self.FOURCC + self.Size = len(self) + return Struct.pack(self) + +class Brlyt(object): + class BrlytHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.Magic = Struct.string(4) + self.Unk = Struct.uint32 + self.Size = Struct.uint32 + self.UnkCount = Struct.uint16 + self.AtomCount = Struct.uint16 + + class BrlytLYT1(StdAtom): + FOURCC = "lyt1" + def __format__(self): + StdAtom.__format__(self) + self.Flag = Struct.uint8 + self.pad = Struct.uint8[3] + self.Width = Struct.float + self.Height = Struct.float + + class BrlytTexture(object): + def __init__(self, name, texture=None): + self.Name = name + self.Texture = texture + self.GLTexture = None + def create_texture(self): + self.GLTexture = self.Texture.create_texture(Texture) + + class BrlytTXL1(ItemList): + LSIZE = 8 + OFFSET = 12 + FOURCC = "txl1" + def __init__(self, archive=None, data=None): + self.Archive = archive + ItemList.__init__(self, data) + + def unpack_item(self, i, data): + fn = data.split(b'\0', 1)[0].decode("ascii") + print(fn) + tex = TPL(self.Archive.Files['./arc/timg/' + fn.lower()]).Textures[0] + self.Items.append(Brlyt.BrlytTexture(fn, tex)) + def pack_item(self, i, item): + return item.Name.encode("ascii") + b"\0" + + class BrlytMAT1(ItemList): + LSIZE = 4 + OFFSET = 0 + FOURCC = "mat1" + def __init__(self, data=None): + ItemList.__init__(self, data) + + def unpack_item(self, num, data): + mtl = Brlyt.BrlytMaterial() + mtl.unpack(data) + self.Items.append(mtl) + + def pack_item(self, i, item): + return item.pack() + + class BrlytMaterialFlags(object): + def __init__(self,value=None): + if value is not None: + self.unpack(value) + def unpack(self,value): + self.value = value + self.NumTextures = value & 15 + self.NumCoords = (value>>4) & 15 + self.m_2 = (value>>8) & 15 + self.m_4 = bool((value>>12) & 1) + self.m_6 = (value>>13) & 3 + self.m_5 = (value>>15) & 7 + self.m_3 = (value>>18) & 31 + self.m_9 = bool((value>>23) & 1) + self.m_10 = bool((value>>24) & 1) + self.m_7 = bool((value>>25) & 1) + self.m_8 = bool((value>>27) & 1) + + def show(self): + print("Flags: %08x"%self.value) + print("ReserveGXMem(") + print(" r4 =",self.NumTextures) + print(" r5 =",self.NumCoords) + print(" r6 =",self.m_2) + print(" r7 =",self.m_3) + print(" r8 =",self.m_4) + print(" r9 =",self.m_5) + print(" r10 =",self.m_6) + print(" 0x8(%sp) =",self.m_7) + print(" 0xC(%sp) =",self.m_8) + print(" 0x10(%sp) =",self.m_9) + print(" 0x14(%sp) =",self.m_10) + print(")") + + def pack(self): + val = 0 + val |= self.NumTextures + val |= self.NumCoords << 4 + val |= self.m_2 << 8 + val |= self.m_4 << 12 + val |= self.m_6 << 13 + val |= self.m_5 << 15 + val |= self.m_3 << 18 + val |= self.m_9 << 23 + val |= self.m_10 << 24 + val |= self.m_7 << 25 + val |= self.m_8 << 27 + return val + + class BrlytMatHeader(Struct): + __endian__ = Struct.BE + + def __format__(self): + self.Name = Struct.string(0x14, stripNulls=True) + self.Color1 = Struct.uint16[4] + self.Color2 = Struct.uint16[4] + self.Color3 = Struct.uint16[4] + self.Blah = Struct.uint32[4] + self.Flags = Struct.uint32 + + # 0-3 num 0-8 + # 4-7 num 0-10 + # 8-11 num 0-8 + # 12 bool + # 13-14 num 0-3 + # 15-17 num 0-4 + # 18-22 num 0-16 + # 23 bool + # 24 bool + # 25 bool a + # 27 bool + + + # if 25, xtra word + # if 27, xtra word + # if 12, xtra word + # 13-14 * 0x14 + # 15-17 * 4 + # 18-22 * 16 + # if 23, xtra word + # if 24, xtra word + + class BrlytMaterial(object): + + def __init__(self, name=None): + if name is not None: + self.Name = name + self.Color1 = [0,0,0,0] + self.Color2 = [255,255,255,255] + self.Color3 = [255,255,255,255] + self.Blah = [0xffffffff,0xffffffff,0xffffffff,0xffffffff] + self.Textures = [] + self.TextureCoords = [] + self.SthB = [] + self.SthI = None + self.SthJ = None + self.SthC = None + self.SthD = [] + self.SthE = [] + self.SthF = [] + self.SthG = 0x77000000 + self.SthH = None + + def unpack(self, data): + wii.chexdump(data) + hdr = Brlyt.BrlytMatHeader() + hdr.unpack(data) + self.FlagData = Brlyt.BrlytMaterialFlags(hdr.Flags) + self.FlagData.show() + + self.Name = hdr.Name.split("\0",1)[0] + self.Color1 = hdr.Color1 + self.Color2 = hdr.Color2 + self.Color3 = hdr.Color3 + self.Blah = hdr.Blah + + ptr = 0x40 + + self.Textures = [] + self.TextureCoords = [] + self.SthB = [] + self.SthI = None + self.SthJ = None + self.SthC = None + self.SthD = [] + self.SthE = [] + self.SthF = [] + self.SthG = None + self.SthH = None + + for i in range(self.FlagData.NumTextures): + texid = Struct.uint16(data[ptr:ptr+2], endian='>') + texcs = data[ptr+2] + texct = data[ptr+3] + print(" * Texture: %04x %d %d"%(texid,texcs,texct)) + self.Textures.append((texid,texcs,texct)) + ptr += 4 + for i in range(self.FlagData.NumCoords): + dat = [] + for j in range(5): + dat.append(Struct.float(data[ptr+j*4:ptr+j*4+4], endian='>')) + print(" * Coords: [",', '.join(["%f"%x for x in dat]),"]") + ptr += 0x14 + self.TextureCoords.append(dat) + for i in range(self.FlagData.m_2): + dat = Struct.uint32(data[ptr:ptr+4], endian='>') + self.SthB.append(dat) + print(" * SthB: %08x"%dat) + ptr += 0x04 + if self.FlagData.m_7: + self.SthI = Struct.uint32(data[ptr:ptr+4], endian='>') + print(" SthI: %08x"%self.SthI) + ptr += 0x04 + if self.FlagData.m_8: + self.SthJ = Struct.uint32(data[ptr:ptr+4], endian='>') + print(" SthJ: %08x"%self.SthJ) + ptr += 0x04 + if self.FlagData.m_4: + self.SthC = Struct.uint32(data[ptr:ptr+4], endian='>') + print(" SthC: %08x"%self.SthC) + ptr += 0x04 + for i in range(self.FlagData.m_6): + dat = [] + for j in range(5): + dat.append(Struct.float(data[ptr+j*4:ptr+j*4+4], endian='>')) + self.SthD.append(dat) + print(" * SthD: [",', '.join(["%f"%x for x in dat]),"]") + ptr += 0x14 + for i in range(self.FlagData.m_5): + dat = Struct.uint32(data[ptr:ptr+4], endian='>') + self.SthE.append(dat) + print(" * SthE: %08x"%dat) + ptr += 0x04 + for i in range(self.FlagData.m_3): + dat = [] + for j in range(4): + dat.append(Struct.uint32(data[ptr+j*4:ptr+j*4+4], endian='>')) + self.SthF.append(dat) + print(" * SthF: [",', '.join(["%08x"%x for x in dat]),"]") + ptr += 0x10 + if self.FlagData.m_9: + dat = Struct.uint32(data[ptr:ptr+4], endian='>') + self.SthG = dat + print(" SthG: %08x"%dat) + ptr += 0x04 + if self.FlagData.m_10: + dat = Struct.uint32(data[ptr:ptr+4], endian='>') + self.SthH = dat + print(" SthH: %08x"%dat) + ptr += 0x04 + + #assert ptr == len(data) + + def pack(self): + + self.FlagData = Brlyt.BrlytMaterialFlags() + + self.FlagData.NumTextures = len(self.Textures) + self.FlagData.NumCoords = len(self.TextureCoords) + self.FlagData.m_2 = len(self.SthB) + self.FlagData.m_7 = self.SthI is not None + self.FlagData.m_8 = self.SthJ is not None + self.FlagData.m_4 = self.SthC is not None + self.FlagData.m_6 = len(self.SthD) + self.FlagData.m_5 = len(self.SthE) + self.FlagData.m_3 = len(self.SthF) + self.FlagData.m_9 = self.SthG is not None + self.FlagData.m_10 = self.SthH is not None + + self.Flags = self.FlagData.pack() + + hdr = Brlyt.BrlytMatHeader() + + hdr.Name = self.Name.encode("ascii") + b"\x00"*(0x14-len(self.Name)) + hdr.Color1 = self.Color1 + hdr.Color2 = self.Color2 + hdr.Color3 = self.Color3 + hdr.Blah = self.Blah + hdr.Flags = self.Flags + + data = hdr.pack() + + for i in self.Textures: + data += Struct.uint16(i[0], endian='>') + data += Struct.uint8(i[1], endian='>') + data += Struct.uint8(i[2], endian='>') + for i in self.TextureCoords: + for j in i: + data += Struct.float(j, endian='>') + for i in self.SthB: + data += Struct.uint32(i, endian='>') + if self.SthI is not None: + data += Struct.uint32(self.SthI, endian='>') + if self.SthJ is not None: + data += Struct.uint32(self.SthJ, endian='>') + if self.SthC is not None: + data += Struct.uint32(self.SthC, endian='>') + for i in self.SthD: + for j in i: + data += Struct.float(j, endian='>') + for i in self.SthE: + data += Struct.uint32(i, endian='>') + for i in self.SthF: + for j in i: + data += Struct.uint32(j, endian='>') + if self.SthG is not None: + data += Struct.uint32(self.SthG, endian='>') + if self.SthH is not None: + data += Struct.uint32(self.SthH, endian='>') + return data + + class BrlytPAN1(StdAtom): + FOURCC = "pan1" + def __format__(self): + StdAtom.__format__(self) + self.Flags = Struct.uint16 + self.Alpha = Struct.uint16 + self.Name = Struct.string(0x18, stripNulls=True) + self.Coords = Struct.float[10] + + class BrlytPIC1(BrlytPAN1): + FOURCC = "pic1" + def __format__(self): + Brlyt.BrlytPAN1.__format__(self) + self.unk = Struct.uint8[16] + self.Material = Struct.uint16 + self.Flags2 = Struct.uint16 + self.MaterialCoords = Struct.float[8] + + def __init__(self, archive, data, renderer): + self.Archive = archive + self.Textures = Brlyt.BrlytTXL1() + self.Materials = Brlyt.BrlytMAT1() + self.LastPic = None + self.RootPane = None + self.RootPaneName = None + self.Objects = {} + self.PanePath = [] + self.PaneId = 0 + self.Language = "ENG" + self.Renderer = renderer + + if data != None: + self.Unpack(data) + + def Unpack(self, data): + pos = 0 + header = self.BrlytHeader() + header.unpack(data[:len(header)]) + print("BRLYT header:") + wii.chexdump(data[:len(header)]) + print(" unk1: %08x"%header.Unk) + print(" unkc: %08x"%header.UnkCount) + pos += len(header) + + print(" %d atoms"%header.AtomCount) + + assert header.Magic == 'RLYT' + + for i in range(header.AtomCount): + atom = StdAtom() + atom.unpack(data[pos:pos+len(atom)]) + + atomdata = data[pos:pos+atom.Size] + if atom.FourCC == 'txl1': + self.TXL1(atomdata) + elif atom.FourCC == 'lyt1': + self.LYT1(atomdata) + elif atom.FourCC == 'mat1': + self.MAT1(atomdata) + elif atom.FourCC == 'pan1': + self.PAN1(atomdata) + elif atom.FourCC == 'pas1': + self.PAS1(atomdata) + elif atom.FourCC == 'pae1': + self.PAE1(atomdata) + elif atom.FourCC == 'pic1': + self.PIC1(atomdata) + elif atom.FourCC == "grp1": + self.GRP1(atomdata) + else: + print("Unknown FOURCC:",atom.FourCC) + wii.chexdump(atomdata) + + pos += atom.Size + + def _PackObject(self, object): + atoms = 0 + if isinstance(object,Pane): + atoms += 1 + if isinstance(object,Picture): + atom = Brlyt.BrlytPIC1() + else: + atom = Brlyt.BrlytPAN1() + atom.Name = object.Name.encode("ascii") + b"\x00"*(0x18-len(object.Name)) + atom.Alpha = int(object.Alpha * 256) + atom.Flags = object.Flags + atom.Coords = object.Coords + if isinstance(object,Picture): + atom.Flags2 = object.Flags2 + atom.Material = object.Material + atom.unk = object.Unk + atom.MaterialCoords = sum(list(map(list,object.MaterialCoords)),[]) + data = atom.pack() + + if len(object.Children) > 0: + atoms += 2 + data += b"pas1\x00\x00\x00\x08" + for child in object.Children: + ac, dc = self._PackObject(child) + data += dc + atoms += ac + data += b"pae1\x00\x00\x00\x08" + return atoms, data + else: + raise ValueError("Unknown object: "+repr(object)) + + def Pack(self, extra=None): + + header = self.BrlytHeader() + header.Unk = 0xfeff0008 + header.UnkCount = 0x10 + header.Magic = "RLYT" + header.AtomCount = 0 + + data = b"" + data += self.mkLYT1() + header.AtomCount+=1 + + data += self.mkTXL1() + header.AtomCount+=1 + + data += self.mkMAT1(extra) + header.AtomCount+=1 + + atoms, ndata = self._PackObject(self.RootPane) + data += ndata + header.AtomCount += atoms + + #uuugly. TODO: fix this crap. + data += b"grp1\x00\x00\x00\x1cRootGroup\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + header.AtomCount += 1 + + header.Size = len(data) + len(header) + data = header.pack() + data + + return data + + def mkLYT1(self): + lyt1 = self.BrlytLYT1() + lyt1.Width = self.Width + lyt1.Height = self.Height + lyt1.Flag = 1 + for n in range(3): + lyt1.pad[n] = 0 + return lyt1.pack() + + def mkTXL1(self): + return self.Textures.pack() + + def mkMAT1(self, extra=None): + return self.Materials.pack(extra) + + def LYT1(self, data): + lyt1 = self.BrlytLYT1() + lyt1.unpack(data) + self.Width = lyt1.Width + self.Height = lyt1.Height + print("LYT1: %f x %f, flag %d"%(self.Width, self.Height, lyt1.Flag)) + self.Renderer.Create(int(self.Width), int(self.Height)) + + def TXL1(self, data): + self.Textures = self.BrlytTXL1(self.Archive, data) + for i in self.Textures: + i.create_texture() + + def ApplyMask(self, image, mask): + print("Making mask:",image,mask) + print(image.width,image.height,mask.width,mask.height) + if image.height != mask.height or image.width != mask.width: + raise ValueError("Mask dimensions must be equal to mask dimensions") + newdata = [0 for x in range(image.height * image.width * 4)] + + for pix in range(image.height * image.width): + newdata[pix*4 + 0] = image.data[pix*4 + 0] + newdata[pix*4 + 1] = image.data[pix*4 + 1] + newdata[pix*4 + 2] = image.data[pix*4 + 2] + newdata[pix*4 + 3] = mask.data[pix*4 + 0] + + return ImageData(image.width, image.height, 'RGBA', ''.join(newdata)) + + def MAT1(self, data): + self.Materials = self.BrlytMAT1(data) + + def _addpane(self, p): + self.CurPane = p + self.Objects[p.Name] = p + if self.RootPane is None: + self.RootPane = p + else: + self.PanePath[-1].Add(p) + + def PAN1(self, data): + wii.chexdump(data) + pane = Brlyt.BrlytPAN1() + pane.unpack(data) + p = Pane(pane.Name, pane.Flags, pane.Alpha/256.0, pane.Coords) + print('Pane %s (flags %04x, alpha %f): ' % (p.Name, pane.Flags, pane.Alpha),pane.Coords) + self._addpane(p) + + def PAS1(self, data): + wii.chexdump(data) + if self.CurPane is None: + raise ValueError("No current pane!") + self.PanePath.append(self.CurPane) + print("Pane start:",'.'.join(map(str,self.PanePath))) + self.CurPane = None + + def PAE1(self, data): + print("Pane end:",'.'.join(map(str,self.PanePath))) + self.PanePath = self.PanePath[:-1] + + def PIC1(self, data): + wii.chexdump(data) + pic = Brlyt.BrlytPIC1() + pic.unpack(data) + mc = [] + for i in range(4): + mc.append(pic.MaterialCoords[i*2:i*2+2]) + print(mc) + p = Picture(pic.Name, pic.Flags, pic.Alpha/256.0, pic.Coords, pic.unk, pic.Material, pic.Flags2, mc) + print(repr(p.Name)) + mat = self.Materials[pic.Material] + if mat is not None: + self._addpane(p) + else: + print('Picture %s with null material!') + + def GRP1(self, data): + wii.chexdump(data) + if len(data) < 0x1c: + pass + lang = data[0x8:0x18].split(b'\0', 1)[0] + nitems = Struct.uint16(data[0x18:0x1a], endian='>') + p = 0x1c + items = [] + for i in range(nitems): + items.append(data[p:].split(b'\0', 1)[0]) + p += 0x10 + for i in items: + try: + if lang != self.Language: + self.Objects[i].Enabled = False + else: + self.Objects[i].Enabled = True + except: + pass + +class Brlan(object): + A_COORD = "RLPA" + A_PARM = "RLVC" + C_X = 0 + C_Y = 1 + C_ANGLE = 5 + C_MAGX = 6 + C_MAGY = 7 + C_WIDTH = 8 + C_HEIGHT = 9 + P_ALPHA = 0x10 + class BrlanHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.Magic = Struct.string(4) + self.Unk = Struct.uint32 + self.Size = Struct.uint32 + self.UnkCount = Struct.uint16 + self.AtomCount = Struct.uint16 + + def __init__(self, data=None): + self.Anim = None + if data != None: + self.Unpack(data) + else: + self.Anim = Brlan.BrlanPAI1() + + def Unpack(self, data): + header = self.BrlanHeader() + header.unpack(data[:len(header)]) + pos = len(header) + + assert header.Magic == 'RLAN' + + for i in range(header.AtomCount): + atom = StdAtom() + atom.unpack(data[pos:pos+len(atom)]) + atomdata = data[pos:pos+atom.Size] + pos += atom.Size + + if atom.FourCC == 'pai1': + self.PAI1(atomdata) + else: + print("Unknown animation atom: %s"%atom.FourCC) + + class BrlanPAI1(ItemList): + LSIZE=4 + OFFSET=0 + FOURCC="pai1" + HDRLEN=12 + def unpack(self, data): + self.FrameCount = Struct.uint16(data[8:10], endian='>') + print(self.FrameCount) + ItemList.unpack(self, data) + def __mkheader__(self): + hdr = Struct.uint16(self.FrameCount, endian='>') + hdr += Struct.uint16(0x100, endian='>') + hdr += Struct.uint32(len(self.Items), endian='>') + hdr += Struct.uint32(0x14, endian='>') + return hdr + def __unpkcnt__(self, data): + return Struct.uint32(data[4:8], endian='>') + def __getlistoff__(self, data): + return Struct.uint32(data[8:12], endian='>') + def unpack_item (self, num, data): + self.Items.append(Brlan.BrlanAnimSet(data)) + def pack(self, offset, count): + self.FrameCount = count + self.Offset = offset + return ItemList.pack(self) + def pack_item (self, num, item): + return item.pack(self.Offset) + def __getitem__(self, n): + if isinstance(n,str): + for i in self.Items: + if i.Name == n: + return i + raise KeyError("Key %s not found"%n) + else: + return ItemList.__getitem__(self, n) + + def __contains__(self, n): + if isinstance(n,str): + for i in self.Items: + if i.Name == n: + return True + return False + else: + return n in self.Items + + + + class BrlanAnimSet(ItemList): + LSIZE=4 + OFFSET=0 + HDRLEN=0x18 + IS_ATOM=False + def __init__(self, data=None): + if data is not None and len(data)<0x14: + self.Name = data + ItemList.__init__(self, None) + else: + ItemList.__init__(self, data) + def unpack(self, data): + self.Name = data[:0x14].split(b"\0",1)[0].decode("ascii") + print(self.Name) + ItemList.unpack(self, data) + def __mkheader__(self): + hdr = self.Name.encode("ascii") + b"\x00" * (0x14-len(self.Name)) + hdr += Struct.uint8(len(self.Items), endian='>') + hdr += b"\x00\x00\x00" + return hdr + def __unpkcnt__(self, data): + return Struct.uint8(data[0x14:0x15], endian='>') + def unpack_item (self, num, data): + self.Items.append(Brlan.BrlanAnimClass(data)) + def pack_item (self, num, item): + return item.pack(self.Offset) + def pack(self, offset): + self.Offset = offset + return ItemList.pack(self) + def __getitem__(self, n): + if isinstance(n,str): + for i in self.Items: + if i.Type == n: + return i + raise KeyError("Key %s not found"%n) + else: + return ItemList.__getitem__(self, n) + + class BrlanAnimClass(ItemList): + LSIZE=4 + OFFSET=0 + HDRLEN=8 + IS_ATOM=False + + class BrlanAnimClassIterator(object): + def __init__(self, cl): + self.cl = cl + self.item = 0 + def __iter__(self): + return self + def __next__(self): + if self.item == len(self.cl.Items): + raise StopIteration() + else: + self.item += 1 + return self.cl.Items[self.item-1] + + def __init__(self, data=None): + if data is not None and len(data) == 4: + self.Type = data + ItemList.__init__(self, None) + else: + ItemList.__init__(self, data) + def unpack(self, data): + self.Type = data[0:4].decode("ascii") + print(" ",self.Type) + ItemList.unpack(self, data) + def __mkheader__(self): + hdr = self.Type.encode("ascii") + hdr += Struct.uint8(len(self.Items), endian='>') + hdr += b"\x00\x00\x00" + return hdr + def __unpkcnt__(self, data): + return Struct.uint8(data[4:5], endian='>') + def unpack_item (self, num, data): + self.Items.append(Brlan.BrlanAnim(data)) + def pack(self, offset): + self.Offset = offset + return ItemList.pack(self) + def pack_item (self, num, item): + return item.pack(self.Offset) + def __getitem__(self, n): + for i in self.Items: + if i.Type == n: + return i + raise KeyError("Key %d not found"%n) + def __iter__(self): + return self.BrlanAnimClassIterator(self) + + class BrlanAnim(object): + def __init__(self, data=None): + self.Triplets = [] + self.Unk = 0x200 + self.Type = 0 + if data is not None and isinstance(data,int): + self.Type = data + else: + self.unpack(data) + def unpack(self, data): + self.Type = Struct.uint16(data[0:2], endian='>') + self.Unk = Struct.uint16(data[2:4], endian='>') + count = Struct.uint16(data[4:6], endian='>') + pos = Struct.uint32(data[8:12], endian='>') + print(" ",self.Type) + if self.Unk == 0x200: + print(" Triplets:") + for i in range(count): + F = Struct.float(data[pos+0:pos+4], endian='>') + P = Struct.float(data[pos+4:pos+8], endian='>') + D = Struct.float(data[pos+8:pos+12], endian='>') + print(" %11f %11f %11f"%(F,P,D)) + self.Triplets.append((F,P,D)) + pos += 12 + else: + print(" Unknown format: %04x"%self.Unk) + def pack(self, offset): + self.Triplets.sort(key=lambda x: x[0]) + t = self.Triplets + self.Triplets = [] + lt = (None, None, None) + for i in t: + if i == lt: + pass + elif i[0] == lt[0]: + raise ValueError("Duplicate triplet frame numbers with different data") + else: + self.Triplets.append(i) + + out = Struct.uint16(self.Type, endian='>') + out += Struct.uint16(self.Unk, endian='>') + out += Struct.uint16(len(self.Triplets), endian='>') + out += b"\x00\x00" + out += Struct.uint32(0xc, endian='>') + for F,P,D in self.Triplets: + out += Struct.float(F-offset, endian='>') + out += Struct.float(P, endian='>') + out += Struct.float(D, endian='>') + return out + def add(self, F, P=None, D=None): + if isinstance(F,tuple): + self.Triplets.append(F) + else: + self.Triplets.append((F,P,D)) + def rep(self, start, end, times): + replist = [] + for i in self.Triplets: + if i[0] >= start and i[0] <= end: + replist.append(i) + if len(replist) == 0: + return + off = end-start + for i in range(times-1): + for a,b,c in replist: + self.Triplets.append((a+off,b,c)) + off += end-start + a,b,c = replist[0] + if a == start: + self.Triplets.append((a+off,b,c)) + def repsimple(self, start, end, times, sp, sd, ep, ed): + step = float(end-start) / times + self.Triplets.append((start, sp, sd)) + self.Triplets.append((start+step/2.0, ep, ed)) + self.rep(start, start+step, times) + def calc(self, frame): + for tn in range(len(self.Triplets)): + if self.Triplets[tn][0] > frame: + if tn == 0: + return self.Triplets[0][1] + else: + start, value1, coef1 = self.Triplets[tn-1] + end, value2, coef2 = self.Triplets[tn] + t = (frame - start) / (end - start) + nf = end - start + return \ + coef1 * 1 * nf * (t + t**3 - 2*t**2) + \ + coef2 * 1 * nf * (t**3 - t**2) + \ + value1 * (1 + (2*t**3 - 3*t**2)) + \ + value2 * (-2*t**3 + 3*t**2) + else: + return self.Triplets[-1][1] + def __getitem__(self, n): + return self.Triplets[n] + def PAI1(self, data): + assert self.Anim is None + self.Anim = self.BrlanPAI1(data) + return + def Pack(self, a=None, b=None): + + if a is None and b is None: + frames = self.FrameCount + offset = 0 + elif a is not None and b is None: + frames = a + offset = 0 + elif a is not None and b is not None: + frames = b-a + offset = a + else: + raise ValueError("WTF are you doing") + + header = self.BrlanHeader() + header.Unk = 0xfeff0008 + header.UnkCount = 0x10 + header.Magic = "RLAN" + header.AtomCount = 1 + + data = self.Anim.pack(offset, frames) + + header.Size = len(data) + len(header) + data = header.pack() + data + + return data + +if have_pyglet: + class BannerWindow(window.Window): + def on_resize(self, width, height): + glViewport(0, 0, width, height) + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + glOrtho(-width/2, width/2, -height/2, height/2, -1, 1) + glMatrixMode(GL_MODELVIEW) + + +class Renderer(object): + def __init__(self): + self.Brlyt = None + self.Brlan = None + + def Create(self, width, height): + self.Width = width + self.Height = height + print("Render: %f x %f"%(self.Width,self.Height)) + self.Window = BannerWindow(self.Width, self.Height) + self.Window.set_exclusive_mouse(False) + + glClearColor(0.0, 0.0, 0.0, 0.0) + glClearDepth(1.0) + glDepthFunc(GL_LEQUAL) + glEnable(GL_DEPTH_TEST) + + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA) + glEnable(GL_BLEND) + glEnable(GL_TEXTURE_2D) + #clock.set_fps_limit(60) + + + def Render(self, item, wireframe=False): + if not item.Enabled: + return + if isinstance(item, Picture): + + mat = self.Brlyt.Materials[item.Material] + texture = self.Brlyt.Textures[mat.Textures[0][0]].GLTexture + mtc = mat.TextureCoords[0] + x, y, a, b, c, rot, xsc, ysc, xs, ys = item.Coords[:10] + + xs *= xsc + ys *= ysc + #print item.Name,x,y,xs,ys + xc, yc = x-(xs/2),y-(ys/2) + + glPushMatrix() + glMatrixMode( GL_MODELVIEW ) + glTranslatef( x, y, 0) + glRotatef(rot,0,0,1) + glScalef(xs,ys,0) + + if not wireframe: + col = [x/255.0 for x in list(mat.Color2)] + col[3] = col[3] * item.Alpha / 255.0 + + tw = texture.tex_coords[6] + th = texture.tex_coords[7] + + mc = item.MaterialCoords + + glMatrixMode( GL_TEXTURE ) + glPushMatrix() + glTranslatef(0.5,0.5,0) + glTranslatef(mtc[0],mtc[1],0) + glScalef(mtc[3],mtc[4],0) + glTranslatef(-0.5,-0.5,0) + array = (GLfloat * 32)( + mc[0][0] * tw, mc[0][1] * th, 0, 1., + -0.5, 0.5, 0, 1., + mc[1][0] * tw, mc[1][1] * th, 0, 1., + 0.5, 0.5, 0, 1., + mc[3][0] * tw, mc[3][1] * th, 0, 1., + 0.5, -0.5, 0, 1., + mc[2][0] * tw, mc[2][1] * th, 0, 1., + -0.5, -0.5, 0, 1.) + + glColor4f(*col) + glPushAttrib(GL_ENABLE_BIT) + glEnable(texture.target) + glBindTexture(texture.target, texture.id) + if mat.Textures[0][1] == 0x0: + glTexParameteri(texture.target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) + elif mat.Textures[0][1] == 0x1: + glTexParameteri(texture.target, GL_TEXTURE_WRAP_S, GL_REPEAT) + elif mat.Textures[0][1] == 0x2: + glTexParameteri(texture.target, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT) + else: + glTexParameteri(texture.target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) + if mat.Textures[0][2] == 0x0: + glTexParameteri(texture.target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) + elif mat.Textures[0][2] == 0x1: + glTexParameteri(texture.target, GL_TEXTURE_WRAP_T, GL_REPEAT) + elif mat.Textures[0][2] == 0x2: + glTexParameteri(texture.target, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT) + else: + glTexParameteri(texture.target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) + + glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT) + glInterleavedArrays(GL_T4F_V4F, 0, array) + glDrawArrays(GL_QUADS, 0, 4) + glPopClientAttrib() + glPopAttrib() + + glBindTexture(texture.target, 0) + glPopMatrix() + glMatrixMode( GL_MODELVIEW ) + + else: + + glColor3f(1,0,0) + glBegin(GL_LINE_STRIP) + glVertex2f(-0.5,-0.5) + glVertex2f(0.5,-0.5) + glVertex2f(0.5,0.5) + glVertex2f(-0.5,0.5) + glVertex2f(-0.5,-0.5) + glColor3f(1,1,1) + glEnd() + pass + + glPopMatrix() + if isinstance(item, Pane): + if item.Coords is not None: + x, y, a, b, c, rot, xsc, ysc, xs, ys = item.Coords[:10] + else: + x = y = 0 + xs = ys = 0 + xsc = 1 + ysc = 1 + glPushMatrix() + glTranslatef(x, y, 0) + glRotatef(rot,0,0,1) + glScalef(xsc,ysc,0) + #glScalef(xs,ys,1) + for child in item.Children: + self.Render(child,wireframe) + glPopMatrix() + + def Animate(self, frame): + for set in self.Brlan.Anim: + for clss in set: + for anim in clss: + #print(set.Name, clss.Type, anim.Type, anim.calc(frame), frame) + if clss.Type == Brlan.A_COORD: + self.Brlyt.Objects[set.Name].Coords[anim.Type] = anim.calc(frame) + elif clss.Type == Brlan.A_PARM: + if anim.Type == Brlan.P_ALPHA: + self.Brlyt.Objects[set.Name].Alpha = anim.calc(frame) + + def MainLoop(self, loop): + frame = 0 + print("Starting mainloop: loop =",loop) + print("Length in frames:",self.Brlan.Anim.FrameCount) + while not self.Window.has_exit: + self.Window.dispatch_events() + self.Window.clear() + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + glLoadIdentity() + glColor4f(1.0, 1.0, 1.0, 1.0) + + self.Render(self.Brlyt.RootPane,False) + #self.Render(self.Brlyt.RootPane,True) + + clock.tick() + + self.Window.flip() + if self.Brlan is not None: + self.Animate(frame) + if frame >= self.Brlan.Anim.FrameCount: + if not loop: + print("Animation done!") + return True + else: + print("Looping...") + frame = -1 + frame += 1 + +class Alameda(object): + class IMETHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.Zeroes = Struct.uint8[0x40] + self.IMET = Struct.string(4) + self.Fixed = Struct.uint8[8] + self.Sizes = Struct.uint32[3] + self.Flag1 = Struct.uint32 + self.Names = Struct.string(0x2A<<1, encoding='utf-16-be', stripNulls=True)[7] + self.Zeroes = Struct.uint8[0x348] + self.MD5 = Struct.uint8[0x10] + + def __init__(self, fn, type='icon'): + renderer = Renderer() + + fp = open(fn, 'rb') + + imet = self.IMETHeader() + try: + imet.unpack(fp.read(len(imet))) + except: + imet = None + if imet is None or imet.IMET != 'IMET': + imet = self.IMETHeader() + fp.seek(0x40) + imet.unpack(fp.read(len(imet))) + assert imet.IMET == 'IMET' + + print('English title: %s' % imet.Names[1]) + + + root = U8(fp.read()) + if type == 'icon': + banner = U8(IMD5(root.Files['./meta/icon.bin'])) + renderer.Brlyt = Brlyt(banner, banner.Files['./arc/blyt/icon.brlyt'], renderer) + fd = None + try: + fd = banner.Files['./arc/anim/icon.brlan'] + except: + pass + if fd is not None: + renderer.Brlan = Brlan(fd) + + loop = True + else: + banner = U8(IMD5(root.Files['./meta/banner.bin'])) + renderer.Brlyt = Brlyt(banner, banner.Files['./arc/blyt/banner.brlyt'], renderer) + loop = './arc/anim/banner_start.brlan' not in banner.Files + if not loop: + renderer.Brlan = Brlan(banner.Files['./arc/anim/banner_start.brlan']) + loop_anim = Brlan(banner.Files['./arc/anim/banner_loop.brlan']) + else: + renderer.Brlan = Brlan(banner.Files['./arc/anim/banner.brlan']) + + if renderer.MainLoop(loop) and type == 'banner' and not loop: + renderer.Brlan = loop_anim + renderer.MainLoop(True) + +if __name__=='__main__': + Alameda(*sys.argv[1:]) diff --git a/pywii/Common/Struct.py b/pywii/Common/Struct.py index 4acb44f..71c1015 100644 --- a/pywii/Common/Struct.py +++ b/pywii/Common/Struct.py @@ -1,335 +1,339 @@ -import struct, sys - -class StructType(tuple): - def __getitem__(self, value): - return [self] * value - def __call__(self, value, endian='<'): - if isinstance(value, str): - return struct.unpack(endian + tuple.__getitem__(self, 0), value[:tuple.__getitem__(self, 1)])[0] - else: - return struct.pack(endian + tuple.__getitem__(self, 0), value) - -class StructException(Exception): - pass - -class Struct(object): - __slots__ = ('__attrs__', '__baked__', '__defs__', '__endian__', '__next__', '__sizes__', '__values__') - int8 = StructType(('b', 1)) - uint8 = StructType(('B', 1)) - - int16 = StructType(('h', 2)) - uint16 = StructType(('H', 2)) - - int32 = StructType(('l', 4)) - uint32 = StructType(('L', 4)) - - int64 = StructType(('q', 8)) - uint64 = StructType(('Q', 8)) - - float = StructType(('f', 4)) - - @classmethod - def string(cls, len, offset=0, encoding=None, stripNulls=False, value=''): - return StructType(('string', (len, offset, encoding, stripNulls, value))) - - LE = '<' - BE = '>' - __endian__ = '<' - - def __init__(self, func=None, unpack=None, **kwargs): - self.__defs__ = [] - self.__sizes__ = [] - self.__attrs__ = [] - self.__values__ = {} - self.__next__ = True - self.__baked__ = False - - if func == None: - self.__format__() - else: - sys.settrace(self.__trace__) - func() - for name in func.func_code.co_varnames: - value = self.__frame__.f_locals[name] - self.__setattr__(name, value) - - self.__baked__ = True - - if unpack != None: - if isinstance(unpack, tuple): - self.unpack(*unpack) - else: - self.unpack(unpack) - - if len(kwargs): - for name in kwargs: - self.__values__[name] = kwargs[name] - - def __trace__(self, frame, event, arg): - self.__frame__ = frame - sys.settrace(None) - - def __setattr__(self, name, value): - if name in self.__slots__: - return object.__setattr__(self, name, value) - - if self.__baked__ == False: - if not isinstance(value, list): - value = [value] - attrname = name - else: - attrname = '*' + name - - self.__values__[name] = None - - for sub in value: - if isinstance(sub, Struct): - sub = sub.__class__ - try: - if issubclass(sub, Struct): - sub = ('struct', sub) - except TypeError: - pass - type_, size = tuple(sub) - if type_ == 'string': - self.__defs__.append(Struct.string) - self.__sizes__.append(size) - self.__attrs__.append(attrname) - self.__next__ = True - - if attrname[0] != '*': - self.__values__[name] = size[3] - elif self.__values__[name] == None: - self.__values__[name] = [size[3] for val in value] - elif type_ == 'struct': - self.__defs__.append(Struct) - self.__sizes__.append(size) - self.__attrs__.append(attrname) - self.__next__ = True - - if attrname[0] != '*': - self.__values__[name] = size() - elif self.__values__[name] == None: - self.__values__[name] = [size() for val in value] - else: - if self.__next__: - self.__defs__.append('') - self.__sizes__.append(0) - self.__attrs__.append([]) - self.__next__ = False - - self.__defs__[-1] += type_ - self.__sizes__[-1] += size - self.__attrs__[-1].append(attrname) - - if attrname[0] != '*': - self.__values__[name] = 0 - elif self.__values__[name] == None: - self.__values__[name] = [0 for val in value] - else: - try: - self.__values__[name] = value - except KeyError: - raise AttributeError(name) - - def __getattr__(self, name): - if self.__baked__ == False: - return name - else: - try: - return self.__values__[name] - except KeyError: - raise AttributeError(name) - - def __len__(self): - ret = 0 - arraypos, arrayname = None, None - - for i in range(len(self.__defs__)): - sdef, size, attrs = self.__defs__[i], self.__sizes__[i], self.__attrs__[i] - - if sdef == Struct.string: - size, offset, encoding, stripNulls, value = size - if isinstance(size, str): - size = self.__values__[size] + offset - elif sdef == Struct: - if attrs[0] == '*': - if arrayname != attrs: - arrayname = attrs - arraypos = 0 - size = len(self.__values__[attrs[1:]][arraypos]) - size = len(self.__values__[attrs]) - - ret += size - - return ret - - def unpack(self, data, pos=0): - for name in self.__values__: - if not isinstance(self.__values__[name], Struct): - self.__values__[name] = None - elif self.__values__[name].__class__ == list and len(self.__values__[name]) != 0: - if not isinstance(self.__values__[name][0], Struct): - self.__values__[name] = None - - arraypos, arrayname = None, None - - for i in range(len(self.__defs__)): - sdef, size, attrs = self.__defs__[i], self.__sizes__[i], self.__attrs__[i] - - if sdef == Struct.string: - size, offset, encoding, stripNulls, value = size - if isinstance(size, str): - size = self.__values__[size] + offset - - temp = data[pos:pos+size] - if len(temp) != size: - raise StructException('Expected %i byte string, got %i' % (size, len(temp))) - - if encoding != None: - temp = temp.decode(encoding) - - if stripNulls: - temp = temp.rstrip('\0') - - if attrs[0] == '*': - name = attrs[1:] - if self.__values__[name] == None: - self.__values__[name] = [] - self.__values__[name].append(temp) - else: - self.__values__[attrs] = temp - pos += size - elif sdef == Struct: - if attrs[0] == '*': - if arrayname != attrs: - arrayname = attrs - arraypos = 0 - name = attrs[1:] - self.__values__[attrs][arraypos].unpack(data, pos) - pos += len(self.__values__[attrs][arraypos]) - arraypos += 1 - else: - self.__values__[attrs].unpack(data, pos) - pos += len(self.__values__[attrs]) - else: - values = struct.unpack(self.__endian__+sdef, data[pos:pos+size]) - pos += size - j = 0 - for name in attrs: - if name[0] == '*': - name = name[1:] - if self.__values__[name] == None: - self.__values__[name] = [] - self.__values__[name].append(values[j]) - else: - self.__values__[name] = values[j] - j += 1 - - return self - - def pack(self): - arraypos, arrayname = None, None - - ret = '' - for i in range(len(self.__defs__)): - sdef, size, attrs = self.__defs__[i], self.__sizes__[i], self.__attrs__[i] - - if sdef == Struct.string: - size, offset, encoding, stripNulls, value = size - if isinstance(size, str): - size = self.__values__[size]+offset - - if attrs[0] == '*': - if arrayname != attrs: - arraypos = 0 - arrayname = attrs - temp = self.__values__[attrs[1:]][arraypos] - arraypos += 1 - else: - temp = self.__values__[attrs] - - if encoding != None: - temp = temp.encode(encoding) - - temp = temp[:size] - ret += temp + ('\0' * (size - len(temp))) - elif sdef == Struct: - if attrs[0] == '*': - if arrayname != attrs: - arraypos = 0 - arrayname = attrs - ret += self.__values__[attrs[1:]][arraypos].pack() - arraypos += 1 - else: - ret += self.__values__[attrs].pack() - else: - values = [] - for name in attrs: - if name[0] == '*': - if arrayname != name: - arraypos = 0 - arrayname = name - values.append(self.__values__[name[1:]][arraypos]) - arraypos += 1 - else: - values.append(self.__values__[name]) - - ret += struct.pack(self.__endian__+sdef, *values) - return ret - - def __getitem__(self, value): - return [('struct', self.__class__)] * value - -if __name__=='__main__': - class TestStruct(Struct): - __endian__ = Struct.LE - def __format__(self): - self.foo, self.bar = Struct.uint32, Struct.float - self.baz = Struct.string(8) - - self.omg = Struct.uint32 - self.wtf = Struct.string(self.omg) - - class HaxStruct(Struct): - __endian__ = Struct.LE - def __format__(self): - self.thing1 = Struct.uint32 - self.thing2 = Struct.uint32 - self.hax = HaxStruct - - test = TestStruct() - test.unpack('\xEF\xBE\xAD\xDE\x00\x00\x80\x3Fdeadbeef\x04\x00\x00\x00test\xCA\xFE\xBA\xBE\xBE\xBA\xFE\xCA') - assert test.foo == 0xDEADBEEF - assert test.bar == 1.0 - assert test.baz == 'deadbeef' - assert test.omg == 4 - assert test.wtf == 'test' - assert test.hax.thing1 == 0xBEBAFECA - assert test.hax.thing2 == 0xCAFEBABE - - print 'Tests successful' - - """ - @Struct.LE - def TestStruct(): - foo, bar = Struct.uint32, Struct.float - baz = Struct.string(8) - - omg = Struct.uint32 - wtf = Struct.string(omg) - - @Struct.LE - def HaxStruct(): - thing1 = Struct.uint32 - thing2 = Struct.uint32 - hax = HaxStruct() - - test = TestStruct() - test.foo = 0xCAFEBABE - test.bar = 0.0 - thing = test.hax.thing1 - test.hax.thing1 = test.hax.thing2 - test.hax.thing2 = thing - assert test.pack() == '\xBE\xBA\xFE\xCA\0\0\0\0deadbeef\x04\x00\x00\x00test\xBE\xBA\xFE\xCA\xCA\xFE\xBA\xBE' - """ +import struct, sys + +class StructType(tuple): + def __getitem__(self, value): + return [self] * value + def __call__(self, value, endian='<'): + if isinstance(value, bytes): + return struct.unpack(endian + tuple.__getitem__(self, 0), value[:tuple.__getitem__(self, 1)])[0] + else: + return struct.pack(endian + tuple.__getitem__(self, 0), value) + +class StructException(Exception): + pass + +class Struct: + __slots__ = ('__attrs__', '__baked__', '__defs__', '__next__', '__sizes__', '__values__') + int8 = StructType(('b', 1)) + uint8 = StructType(('B', 1)) + + int16 = StructType(('h', 2)) + uint16 = StructType(('H', 2)) + + int32 = StructType(('l', 4)) + uint32 = StructType(('L', 4)) + + int64 = StructType(('q', 8)) + uint64 = StructType(('Q', 8)) + + float = StructType(('f', 4)) + + @classmethod + def string(cls, len, offset=0, encoding=None, stripNulls=False, value=''): + return StructType(('string', (len, offset, encoding, stripNulls, value))) + + LE = '<' + BE = '>' + __endian__ = '<' + + def __init__(self, func=None, unpack=None, **kwargs): + self.__defs__ = [] + self.__sizes__ = [] + self.__attrs__ = [] + self.__values__ = {} + self.__next__ = True + self.__baked__ = False + + if func == None: + self.__format__() + else: + sys.settrace(self.__trace__) + func() + for name in func.__code__.co_varnames: + value = self.__frame__.f_locals[name] + self.__setattr__(name, value) + + self.__baked__ = True + + if unpack != None: + if isinstance(unpack, tuple): + self.unpack(*unpack) + else: + self.unpack(unpack) + + if len(kwargs): + for name in kwargs: + self.__values__[name] = kwargs[name] + + def __trace__(self, frame, event, arg): + self.__frame__ = frame + sys.settrace(None) + + def __setattr__(self, name, value): + if name in self.__slots__: + return object.__setattr__(self, name, value) + + if self.__baked__ == False: + if not isinstance(value, list): + value = [value] + attrname = name + else: + attrname = '*' + name + + self.__values__[name] = None + + for sub in value: + if isinstance(sub, Struct): + sub = sub.__class__ + try: + if issubclass(sub, Struct): + sub = ('struct', sub) + except TypeError: + pass + type_, size = tuple(sub) + if type_ == 'string': + self.__defs__.append(Struct.string) + self.__sizes__.append(size) + self.__attrs__.append(attrname) + self.__next__ = True + + if attrname[0] != '*': + self.__values__[name] = size[3] + elif self.__values__[name] == None: + self.__values__[name] = [size[3] for val in value] + elif type_ == 'struct': + self.__defs__.append(Struct) + self.__sizes__.append(size) + self.__attrs__.append(attrname) + self.__next__ = True + + if attrname[0] != '*': + self.__values__[name] = size() + elif self.__values__[name] == None: + self.__values__[name] = [size() for val in value] + else: + if self.__next__: + self.__defs__.append('') + self.__sizes__.append(0) + self.__attrs__.append([]) + self.__next__ = False + + self.__defs__[-1] += type_ + self.__sizes__[-1] += size + self.__attrs__[-1].append(attrname) + + if attrname[0] != '*': + self.__values__[name] = 0 + elif self.__values__[name] == None: + self.__values__[name] = [0 for val in value] + else: + try: + self.__values__[name] = value + except KeyError: + raise AttributeError(name) + + def __getattr__(self, name): + if self.__baked__ == False: + return name + else: + try: + return self.__values__[name] + except KeyError: + raise AttributeError(name) + + def __len__(self): + ret = 0 + arraypos, arrayname = None, None + + for i in range(len(self.__defs__)): + sdef, size, attrs = self.__defs__[i], self.__sizes__[i], self.__attrs__[i] + + if sdef == Struct.string: + size, offset, encoding, stripNulls, value = size + if isinstance(size, str): + size = self.__values__[size] + offset + elif sdef == Struct: + if attrs[0] == '*': + if arrayname != attrs: + arrayname = attrs + arraypos = 0 + size = len(self.__values__[attrs[1:]][arraypos]) + size = len(self.__values__[attrs]) + + ret += size + + return ret + + def unpack(self, data, pos=0): + for name in self.__values__: + if not isinstance(self.__values__[name], Struct): + self.__values__[name] = None + elif self.__values__[name].__class__ == list and len(self.__values__[name]) != 0: + if not isinstance(self.__values__[name][0], Struct): + self.__values__[name] = None + + arraypos, arrayname = None, None + + for i in range(len(self.__defs__)): + sdef, size, attrs = self.__defs__[i], self.__sizes__[i], self.__attrs__[i] + + if sdef == Struct.string: + size, offset, encoding, stripNulls, value = size + if isinstance(size, str): + size = self.__values__[size] + offset + + temp = data[pos:pos+size] + if len(temp) != size: + raise StructException('Expected %i byte string, got %i' % (size, len(temp))) + + if stripNulls: + temp = temp.rstrip(b'\0') + + if encoding != None: + temp = temp.decode(encoding) + else: + temp = temp.decode("ascii") + + if attrs[0] == '*': + name = attrs[1:] + if self.__values__[name] == None: + self.__values__[name] = [] + self.__values__[name].append(temp) + else: + self.__values__[attrs] = temp + pos += size + elif sdef == Struct: + if attrs[0] == '*': + if arrayname != attrs: + arrayname = attrs + arraypos = 0 + name = attrs[1:] + self.__values__[attrs][arraypos].unpack(data, pos) + pos += len(self.__values__[attrs][arraypos]) + arraypos += 1 + else: + self.__values__[attrs].unpack(data, pos) + pos += len(self.__values__[attrs]) + else: + values = struct.unpack(self.__endian__+sdef, data[pos:pos+size]) + pos += size + j = 0 + for name in attrs: + if name[0] == '*': + name = name[1:] + if self.__values__[name] == None: + self.__values__[name] = [] + self.__values__[name].append(values[j]) + else: + self.__values__[name] = values[j] + j += 1 + + return self + + def pack(self): + arraypos, arrayname = None, None + + ret = b'' + for i in range(len(self.__defs__)): + sdef, size, attrs = self.__defs__[i], self.__sizes__[i], self.__attrs__[i] + + if sdef == Struct.string: + size, offset, encoding, stripNulls, value = size + if isinstance(size, str): + size = self.__values__[size]+offset + + if attrs[0] == '*': + if arrayname != attrs: + arraypos = 0 + arrayname = attrs + temp = self.__values__[attrs[1:]][arraypos] + arraypos += 1 + else: + temp = self.__values__[attrs] + + if encoding != None: + temp = temp.encode(encoding) + elif isinstance(temp, str): + temp = temp.encode("ascii") + + temp = temp[:size] + ret += temp + (b'\0' * (size - len(temp))) + elif sdef == Struct: + if attrs[0] == '*': + if arrayname != attrs: + arraypos = 0 + arrayname = attrs + ret += self.__values__[attrs[1:]][arraypos].pack() + arraypos += 1 + else: + ret += self.__values__[attrs].pack() + else: + values = [] + for name in attrs: + if name[0] == '*': + if arrayname != name: + arraypos = 0 + arrayname = name + values.append(self.__values__[name[1:]][arraypos]) + arraypos += 1 + else: + values.append(self.__values__[name]) + + ret += struct.pack(self.__endian__+sdef, *values) + return ret + + def __getitem__(self, value): + return [('struct', self.__class__)] * value + +if __name__=='__main__': + class TestStruct(Struct): + __endian__ = Struct.LE + def __format__(self): + self.foo, self.bar = Struct.uint32, Struct.float + self.baz = Struct.string(8) + + self.omg = Struct.uint32 + self.wtf = Struct.string(self.omg) + + class HaxStruct(Struct): + __endian__ = Struct.LE + def __format__(self): + self.thing1 = Struct.uint32 + self.thing2 = Struct.uint32 + self.hax = HaxStruct + + test = TestStruct() + test.unpack(b'\xEF\xBE\xAD\xDE\x00\x00\x80\x3Fdeadbeef\x04\x00\x00\x00test\xCA\xFE\xBA\xBE\xBE\xBA\xFE\xCA') + assert test.foo == 0xDEADBEEF + assert test.bar == 1.0 + assert test.baz == b'deadbeef' + assert test.omg == 4 + assert test.wtf == b'test' + assert test.hax.thing1 == 0xBEBAFECA + assert test.hax.thing2 == 0xCAFEBABE + + print('Tests successful') + + """ + @Struct.LE + def TestStruct(): + foo, bar = Struct.uint32, Struct.float + baz = Struct.string(8) + + omg = Struct.uint32 + wtf = Struct.string(omg) + + @Struct.LE + def HaxStruct(): + thing1 = Struct.uint32 + thing2 = Struct.uint32 + hax = HaxStruct() + + test = TestStruct() + test.foo = 0xCAFEBABE + test.bar = 0.0 + thing = test.hax.thing1 + test.hax.thing1 = test.hax.thing2 + test.hax.thing2 = thing + assert test.pack() == '\xBE\xBA\xFE\xCA\0\0\0\0deadbeef\x04\x00\x00\x00test\xBE\xBA\xFE\xCA\xCA\xFE\xBA\xBE' + """ diff --git a/pywii/Common/pywii/__init__.py b/pywii/Common/pywii/__init__.py index 86e42cb..8f4d14c 100644 --- a/pywii/Common/pywii/__init__.py +++ b/pywii/Common/pywii/__init__.py @@ -1,3 +1,3 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 -from wii import * +from .wii import * diff --git a/pywii/Common/pywii/ec.py b/pywii/Common/pywii/ec.py index 6cef40a..5ca8685 100644 --- a/pywii/Common/pywii/ec.py +++ b/pywii/Common/pywii/ec.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # Copyright 2007,2008 Segher Boessenkool # Copyright 2008 Hector Martin # Licensed under the terms of the GNU GPL, version 2 @@ -12,11 +12,11 @@ except ImportError: from Crypto.Util.number import bytes_to_long, long_to_bytes # y**2 + x*y = x**3 + x + b -ec_b = "\x00\x66\x64\x7e\xde\x6c\x33\x2c\x7f\x8c\x09\x23\xbb\x58\x21"+\ - "\x3b\x33\x3b\x20\xe9\xce\x42\x81\xfe\x11\x5f\x7d\x8f\x90\xad" +ec_b = (b"\x00\x66\x64\x7e\xde\x6c\x33\x2c\x7f\x8c\x09\x23\xbb\x58\x21"+ + b"\x3b\x33\x3b\x20\xe9\xce\x42\x81\xfe\x11\x5f\x7d\x8f\x90\xad") def hexdump(s,sep=""): - return sep.join(map(lambda x: "%02x"%ord(x),s)) + return sep.join(["%02x"%ord(x) for x in s]) def bhex(s,sep=""): return hexdump(long_to_bytes(s,30),sep) @@ -41,20 +41,20 @@ class ByteArray(array): else: array.__setitem__(self, item, value & 0xFF) def __long__(self): - return bytes_to_long(self.tostring()) + return bytes_to_long(self.tobytes()) def __str__(self): - return ''.join(["%02x"%ord(x) for x in self.tostring()]) + return ''.join(["%02x"%x for x in self.tobytes()]) def __repr__(self): - return "ByteArray('%s')"%''.join(["\\x%02x"%ord(x) for x in self.tostring()]) + return "ByteArray('%s')"%''.join(["\\x%02x"%x for x in self.tobytes()]) class ELT_PY: SIZEBITS=233 SIZE=(SIZEBITS+7)/8 - square = ByteArray("\x00\x01\x04\x05\x10\x11\x14\x15\x40\x41\x44\x45\x50\x51\x54\x55") + square = ByteArray(b"\x00\x01\x04\x05\x10\x11\x14\x15\x40\x41\x44\x45\x50\x51\x54\x55") def __init__(self, initializer=None): - if isinstance(initializer, long) or isinstance(initializer, int): + if isinstance(initializer, int) or isinstance(initializer, int): self.d = ByteArray(long_to_bytes(initializer,self.SIZE)) - elif isinstance(initializer, str): + elif isinstance(initializer, bytes): self.d = ByteArray(initializer) elif isinstance(initializer, ByteArray): self.d = ByteArray(initializer) @@ -80,12 +80,12 @@ class ELT_PY: return cmp(self.d,other.d) def __long__(self): - return long(self.d) + return int(self.d) def __repr__(self): return repr(self.d).replace("ByteArray","ELT") - def __str__(self): - return str(self.d) - def __nonzero__(self): + def __bytes__(self): + return bytes(self.d) + def __bool__(self): for x in self.d: if x != 0: return True @@ -184,21 +184,21 @@ class ELT_PY: def __setitem__(self,item,value): self.d[item] = value def tobignum(self): - return bytes_to_long(self.d.tostring()) + return bytes_to_long(self.d.tobytes()) def tobytes(self): - return self.d.tostring() + return self.d.tobytes() class ELT_C(ELT_PY): def __mul__(self,other): if not isinstance(other,ELT): return NotImplemented - return ELT(_ec.elt_mul(self.d.tostring(),other.d.tostring())) + return ELT(_ec.elt_mul(self.d.tobytes(),other.d.tobytes())) def __rdiv__(self,other): if other != 1: return ELT_PY.__rdiv__(self,other) - return ELT(_ec.elt_inv(self.d.tostring())) + return ELT(_ec.elt_inv(self.d.tobytes())) def _square(self): - return ELT(_ec.elt_square(self.d.tostring())) + return ELT(_ec.elt_square(self.d.tobytes())) if fastelt: ELT = ELT_C @@ -207,7 +207,7 @@ else: class Point: def __init__(self,x,y=None): - if isinstance(x,str) and (y is None) and (len(x) == 60): + if isinstance(x,bytes) and (y is None) and (len(x) == 60): self.x = ELT(x[:30]) self.y = ELT(x[30:]) elif isinstance(x,Point): @@ -292,7 +292,7 @@ class Point: return "(%s,%s)"%(str(self.x),str(self.y)) def __repr__(self): return "Point"+str(self) - def __nonzero__(self): + def __bool__(self): return self.x or self.y def tobytes(self): return self.x.tobytes() + self.y.tobytes() @@ -305,15 +305,15 @@ def bn_inv(a,N): # order of the addition group of points ec_N = bytes_to_long( - "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+\ - "\x13\xe9\x74\xe7\x2f\x8a\x69\x22\x03\x1d\x26\x03\xcf\xe0\xd7") + b"\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+ + b"\x13\xe9\x74\xe7\x2f\x8a\x69\x22\x03\x1d\x26\x03\xcf\xe0\xd7") # base point ec_G = Point( - "\x00\xfa\xc9\xdf\xcb\xac\x83\x13\xbb\x21\x39\xf1\xbb\x75\x5f"+ - "\xef\x65\xbc\x39\x1f\x8b\x36\xf8\xf8\xeb\x73\x71\xfd\x55\x8b"+ - "\x01\x00\x6a\x08\xa4\x19\x03\x35\x06\x78\xe5\x85\x28\xbe\xbf"+ - "\x8a\x0b\xef\xf8\x67\xa7\xca\x36\x71\x6f\x7e\x01\xf8\x10\x52") + b"\x00\xfa\xc9\xdf\xcb\xac\x83\x13\xbb\x21\x39\xf1\xbb\x75\x5f"+ + b"\xef\x65\xbc\x39\x1f\x8b\x36\xf8\xf8\xeb\x73\x71\xfd\x55\x8b"+ + b"\x01\x00\x6a\x08\xa4\x19\x03\x35\x06\x78\xe5\x85\x28\xbe\xbf"+ + b"\x8a\x0b\xef\xf8\x67\xa7\xca\x36\x71\x6f\x7e\x01\xf8\x10\x52") def generate_ecdsa(k, sha): k = bytes_to_long(k) diff --git a/pywii/Common/pywii/wii.py b/pywii/Common/pywii/wii.py index 4ef701a..3fc50fd 100644 --- a/pywii/Common/pywii/wii.py +++ b/pywii/Common/pywii/wii.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # Copyright 2008 Hector Martin # Licensed under the terms of the GNU GPL, version 2 # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt @@ -21,7 +21,7 @@ except ImportError: from Crypto.Util.number import bytes_to_long, long_to_bytes from Crypto.Signature import pkcs1_15 -import ec +from . import ec WII_RSA4096 = 0 WII_RSA2048 = 1 @@ -30,13 +30,13 @@ WII_ECDSA = 2 sigtypes = [ "RSA-4096", "RSA-2048", "EC-DSA" ] def load_rsa_key(issuer): - print "Loading private key for %s" % issuer + print("Loading private key for %s" % issuer) path = os.path.join(os.environ["HOME"], ".wii", "dpki", issuer + ".pem") return RSA.importKey(open(path, "r").read()) signkeyfuncs = [ load_rsa_key, load_rsa_key, None ] -NULL_IV = "\x00"*16 +NULL_IV = b"\x00"*16 keylist = [ "common-key", @@ -86,13 +86,13 @@ known_titles_noregion = { } def hexdump(s,sep=" "): - return sep.join(map(lambda x: "%02x"%ord(x),s)) + return sep.join(["%02x"%x for x in s]) def strcmp(s1,s2): clen = min(len(s1),len(s2)) for i in range(clen): - if s1[i] == "\0" and s2[i] == "\0": + if s1[i] == 0 and s2[i] == 0: return True if s1[i] != s2[i]: return False @@ -101,10 +101,10 @@ def strcmp(s1,s2): def ascii(s): s2 = "" for c in s: - if ord(c)<0x20 or ord(c)>0x7e: + if c<0x20 or c>0x7e: s2 += "." else: - s2 += c + s2 += chr(c) return s2 def pad(s,c,l): @@ -114,15 +114,10 @@ def pad(s,c,l): def chexdump(s): for i in range(0,len(s),16): - print "%08x %s %s |%s|"%(i,pad(hexdump(s[i:i+8],' ')," ",23),pad(hexdump(s[i+8:i+16],' ')," ",23),pad(ascii(s[i:i+16])," ",16)) + print("%08x %s %s |%s|"%(i,pad(hexdump(s[i:i+8],' ')," ",23),pad(hexdump(s[i+8:i+16],' ')," ",23),pad(ascii(s[i:i+16])," ",16))) def getcstring(s): - s2 = "" - for c in s: - if c == "\x00": - break - s2 += c - return s2 + return s.split(b"\x00")[0].decode("ascii") def align(n,a): if a == 0: @@ -132,10 +127,10 @@ def align(n,a): return n def rangel(n,s): - return range(n,n+s) + return list(range(n,n+s)) def xrangel(n,s): - return xrange(n,n+s) + return range(n,n+s) def falign(f,a): f.seek(align(f.tell(),a)) @@ -200,7 +195,7 @@ def loadkeys(path = None): try: keys[key] = open(path + os.sep + key, "rb").read() except: - print "Warning: failed to load key %s"%key + print("Warning: failed to load key %s"%key) def loadkeys_dpki(path = None): if path is None: @@ -210,7 +205,7 @@ def loadkeys_dpki(path = None): def parse_certs(blob): certs = {} certlist = [] - while blob != "": + while blob != b"": cert = WiiCert(blob) certs[cert.name] = cert certlist.append(cert) @@ -250,7 +245,7 @@ class WiiPKAlgo: code = ">"+codes[bytes] matchlen = len(match) - for pad in xrange(0, 256**bytes): + for pad in range(0, 256**bytes): pad += 0x4612512415125316 pad %= 256**bytes padsig = signature + pack(code, pad) @@ -270,11 +265,11 @@ class WiiRSA(WiiPKAlgo): def get_digest(self, signature): lsig = bytes_to_long(signature) if lsig >= self.n: - print "Warning: signature larger than modulus, using sig%modulus as signature" + print("Warning: signature larger than modulus, using sig%modulus as signature") ldec = pow(lsig, self.e, self.n) dec = long_to_bytes(ldec) pad = len(signature) - len(dec) - dec = "\x00"*pad+dec + dec = b"\x00"*pad+dec return dec[-20:] def sign(self, data, key): @@ -340,11 +335,11 @@ class WiiDisc: return self.partitions def showinfo(self): - print "Game %s, maker %s, magic %08x: %s"%(self.gamecode, self.makercode, self.magic, self.gamename) + print("Game %s, maker %s, magic %08x: %s"%(self.gamecode, self.makercode, self.magic, self.gamename)) self.read_partitions() - print "%d partitions in ISO:"%len(self.partitions) + print("%d partitions in ISO:"%len(self.partitions)) for p_num,p_dat in enumerate(self.partitions): - print " [%2d] 0x%010x (%08x)"%(p_num,p_dat[0],p_dat[1]) + print(" [%2d] 0x%010x (%08x)"%(p_num,p_dat[0],p_dat[1])) class WiiSigned: sigsizes = [512, 256, 60] @@ -370,7 +365,7 @@ class WiiSigned: def update(self): self.data = pack(">I",self.sigtype+0x10000) + self.signature - self.data += "\x00" * (self.body_offset - len(self.data)) + self.data += b"\x00" * (self.body_offset - len(self.data)) self.data += self.body def parse(self): @@ -388,7 +383,7 @@ class WiiSigned: raise ValueError("Signature type %s does not match certificate type %s!"%(sigtypes[self.sigtype],sigtypes[cert.key_type])) return cert.pkalgo.get_digest(self.sigtype, self.signature) - def brute_sha(self, match = "\x00", fillshort = None): + def brute_sha(self, match = b"\x00", fillshort = None): l = len(match) if fillshort is None: @@ -408,7 +403,7 @@ class WiiSigned: if len(issuer) > 39: raise ValueError("issuer name too long!") self.issuer = issuer.split("-") - self.body = issuer + "\x00" * (0x40 - len(issuer)) + self.body[0x40:] + self.body = issuer + b"\x00" * (0x40 - len(issuer)) + self.body[0x40:] self.update() def update_signature(self, sig): @@ -416,7 +411,7 @@ class WiiSigned: self.data = pack(">I",self.sigtype+0x10000) + self.signature + self.data[len(sig) + 4:] def null_signature(self): - self.signature = "\x00"*len(self.signature) + self.signature = b"\x00"*len(self.signature) self.data = pack(">I",self.sigtype+0x10000) + self.signature + self.data[len(self.signature) + 4:] def sign(self,certs): @@ -453,22 +448,22 @@ class WiiSigned: if cert.pkalgo.can_get_digest: signhash = cert.pkalgo.get_digest(self.signature) if myhash == signhash: - print it+"%s signed by %s using %s: %s [OK]"%(self.type, "-".join(self.issuer), sigtypes[self.sigtype], hexdump(myhash)) + print(it+"%s signed by %s using %s: %s [OK]"%(self.type, "-".join(self.issuer), sigtypes[self.sigtype], hexdump(myhash))) elif strcmp(myhash, signhash): - print it+"%s signed by %s using %s: %s [BUG]"%(self.type, "-".join(self.issuer), sigtypes[self.sigtype], hexdump(myhash)) - print it+" Signature hash: %s"%hexdump(signhash) + print(it+"%s signed by %s using %s: %s [BUG]"%(self.type, "-".join(self.issuer), sigtypes[self.sigtype], hexdump(myhash))) + print(it+" Signature hash: %s"%hexdump(signhash)) else: - print it+"%s signed by %s using %s: %s [FAIL]"%(self.type, "-".join(self.issuer), sigtypes[self.sigtype], hexdump(myhash)) - print it+" Signature hash: %s"%hexdump(signhash) + print(it+"%s signed by %s using %s: %s [FAIL]"%(self.type, "-".join(self.issuer), sigtypes[self.sigtype], hexdump(myhash))) + print(it+" Signature hash: %s"%hexdump(signhash)) else: sigok = cert.pkalgo.check_digest(self.signature,myhash) if sigok: - print it+"%s signed by %s using %s: %s [OK]"%(self.type, "-".join(self.issuer), sigtypes[self.sigtype], hexdump(myhash)) + print(it+"%s signed by %s using %s: %s [OK]"%(self.type, "-".join(self.issuer), sigtypes[self.sigtype], hexdump(myhash))) else: - print it+"%s signed by %s using %s: %s [FAIL]"%(self.type, "-".join(self.issuer), sigtypes[self.sigtype], hexdump(myhash)) + print(it+"%s signed by %s using %s: %s [FAIL]"%(self.type, "-".join(self.issuer), sigtypes[self.sigtype], hexdump(myhash))) except KeyError: - print it+"%s signed by %s using %s: %s [ISSUER NOT FOUND]"%(self.type, "-".join(self.issuer), sigtypes[self.sigtype], hexdump(myhash)) + print(it+"%s signed by %s using %s: %s [ISSUER NOT FOUND]"%(self.type, "-".join(self.issuer), sigtypes[self.sigtype], hexdump(myhash))) class WiiTik(WiiSigned): def __init__(self, data): @@ -480,7 +475,7 @@ class WiiTik(WiiSigned): def parse(self): self.title_key_enc = self.body[0x7f:0x8f] self.title_id = self.body[0x9c:0xa4] - self.title_key_iv = self.title_id + "\x00"*8 + self.title_key_iv = self.title_id + b"\x00"*8 self.common_key_index = ord(self.body[0xb1:0xb2]) try: @@ -489,7 +484,7 @@ class WiiTik(WiiSigned): elif self.common_key_index == 1: key = keys["korean-key"] else: - print "WARNING: OLD FAKESIGNED TICKET WITH BAD KEY OFFSET, ASSUMING NORMAL COMMON KEY" + print("WARNING: OLD FAKESIGNED TICKET WITH BAD KEY OFFSET, ASSUMING NORMAL COMMON KEY") key = keys["common-key"] aes = AES.new(key, AES.MODE_CBC, self.title_key_iv) self.title_key = aes.decrypt(self.title_key_enc) @@ -505,13 +500,13 @@ class WiiTik(WiiSigned): return 0x164 def showinfo(self, it=""): - print it+"ETicket: " - print it+" Title ID: "+repr(self.title_id) - print it+" Title key IV: "+hexdump(self.title_key_iv) - print it+" Title key (encrypted): "+hexdump(self.title_key_enc) - print it+" Common key index: %d" % self.common_key_index + print(it+"ETicket: ") + print(it+" Title ID: "+repr(self.title_id)) + print(it+" Title key IV: "+hexdump(self.title_key_iv)) + print(it+" Title key (encrypted): "+hexdump(self.title_key_enc)) + print(it+" Common key index: %d" % self.common_key_index) if self.title_key is not None: - print it+" Title key (decrypted): "+hexdump(self.title_key) + print(it+" Title key (decrypted): "+hexdump(self.title_key)) class WiiPartitionOffsets: def __init__(self, data): @@ -528,9 +523,9 @@ class WiiPartitionOffsets: self.data_size = unpack(">I",self.data[0x18:0x1c])[0]<<2 def showinfo(self, it=""): - print it+"TMD @ 0x%x [0x%x], Certs @ 0x%x [0x%x], H3 @ 0x%x, Data @ 0x%x [0x%x]"%( + print(it+"TMD @ 0x%x [0x%x], Certs @ 0x%x [0x%x], H3 @ 0x%x, Data @ 0x%x [0x%x]"%( self.tmd_offset, self.tmd_size, self.cert_offset, self.cert_size, - self.h3_offset, self.data_offset, self.data_size) + self.h3_offset, self.data_offset, self.data_size)) def update(self): self.data = pack(">II",self.tmd_size, self.tmd_offset>>2) @@ -600,20 +595,20 @@ class WiiTmd(WiiSigned): self.update() def showinfo(self,it=""): - print it+"TMD: " - print it+" Versions: %d, CA CRL %d, Signer CRL %d, System %d-%d"%( - self.version,self.ca_crl_version,self.signer_crl_version,self.sys_version>>32,self.sys_version&0xffffffff) - print it+" Title ID: %s-%s (%s-%s)"%(hexdump(self.title_id[:4],''),hexdump(self.title_id[4:],''),repr(self.title_id[:4]),repr(self.title_id[4:])) - print it+" Title Type: %d"%self.title_type - print it+" Group ID: %s"%repr(self.group_id) - print it+" Access Rights: 0x%08x"%self.access_rights - print it+" Title Version: 0x%x"%self.title_version - print it+" Boot Index: %d"%self.boot_index - print it+" Contents:" - print it+" ID Index Type Size Hash" + print(it+"TMD: ") + print(it+" Versions: %d, CA CRL %d, Signer CRL %d, System %d-%d"%( + self.version,self.ca_crl_version,self.signer_crl_version,self.sys_version>>32,self.sys_version&0xffffffff)) + print(it+" Title ID: %s-%s (%s-%s)"%(hexdump(self.title_id[:4],''),hexdump(self.title_id[4:],''),repr(self.title_id[:4]),repr(self.title_id[4:]))) + print(it+" Title Type: %d"%self.title_type) + print(it+" Group ID: %s"%repr(self.group_id)) + print(it+" Access Rights: 0x%08x"%self.access_rights) + print(it+" Title Version: 0x%x"%self.title_version) + print(it+" Boot Index: %d"%self.boot_index) + print(it+" Contents:") + print(it+" ID Index Type Size Hash") for ct in self.get_content_records(): - print it+" %08X %-5d 0x%-5x %-12s %s"%(ct.cid, ct.index, ct.ftype, "0x%x"%ct.size,hexdump(ct.sha)) + print(it+" %08X %-5d 0x%-5x %-12s %s"%(ct.cid, ct.index, ct.ftype, "0x%x"%ct.size,hexdump(ct.sha))) class WiiCert(WiiSigned): key_sizes = [516, 260, 60] @@ -638,7 +633,7 @@ class WiiCert(WiiSigned): self.pkalgo = self.pk_types[self.key_type](self.key) def showinfo(self,it=""): - print it+"%s (%s)"%(self.name,sigtypes[self.key_type]) + print(it+"%s (%s)"%(self.name,sigtypes[self.key_type])) class WiiRootCert: def __init__(self, data): @@ -650,7 +645,7 @@ class WiiRootCert: self.key_type = 0 def showinfo(self,it=""): - print it+"%s (%s)"%(self.name,sigtypes[self.key_type]) + print(it+"%s (%s)"%(self.name,sigtypes[self.key_type])) class WiiPartition: BLOCKS_PER_SUBGROUP = 8 @@ -732,37 +727,37 @@ class WiiPartition: self.f.write(self.offsets.data) def showinfo(self,it=""): - print it+"Wii Partition at 0x%010x:"%(self.offset) + print(it+"Wii Partition at 0x%010x:"%(self.offset)) self.offsets.showinfo(" ") self.tik.showinfo(it+" ") self.tik.showsig(self.certs,it+" ") self.tmd.showinfo(it+" ") self.tmd.showsig(self.certs,it+" ") if self.checkh4hash(): - print it+" H4 hash check passed" + print(it+" H4 hash check passed") else: - print it+" H4 check failed: SHA1(H3) = "+hexdump(self.geth4hash()) - print it+" Data:" - print it+" Blocks: %d"%self.data_blocks - print it+" Subgroups: %d (plus %d blocks)"%(self.data_subgroups,self.extra_subgroup_blocks) - print it+" Groups: %d (plus %d blocks)"%(self.data_groups,self.extra_group_blocks) + print(it+" H4 check failed: SHA1(H3) = "+hexdump(self.geth4hash())) + print(it+" Data:") + print(it+" Blocks: %d"%self.data_blocks) + print(it+" Subgroups: %d (plus %d blocks)"%(self.data_subgroups,self.extra_subgroup_blocks)) + print(it+" Groups: %d (plus %d blocks)"%(self.data_groups,self.extra_group_blocks)) self.showcerts(it+" ") def showcerts(self,it=""): - print it+"Certificates: " + print(it+"Certificates: ") for cert in self.certlist: cert.showinfo(it+" - ") cert.showsig(self.certs,it+" ") def geth4hash(self): - return SHA.new(''.join(self.h3) + "\x00"*self.TAIL_H3).digest() + return SHA.new(b''.join(self.h3) + b"\x00"*self.TAIL_H3).digest() def checkh4hash(self): return self.geth4hash() == self.tmd.get_content_records()[0].sha def updateh3(self): self._seek(self.offsets.h3_offset) - self.f.write(''.join(self.h3)) + self.f.write(b''.join(self.h3)) def updateh4(self): cr = self.tmd.get_content_records()[0] @@ -903,7 +898,7 @@ class WiiPartition: else: raise ValueError("Attempted to read group past the end of the partition data") - data = "" + data = b"" for i in range(nblocks): data += self.readblock(blockoff+i) return data @@ -919,7 +914,7 @@ class WiiPartition: if groupnum == self.data_groups and self.extra_group_blocks > 0 and len(data) == (self.extra_group_blocks * self.PLAIN_BLOCK_SIZE): blocks = self.extra_group_blocks writesize = blocks * self.CIPHER_BLOCK_SIZE - data += "\x00" * (self.PLAIN_BLOCK_SIZE * self.BLOCKS_PER_GROUP - blocks) + data += b"\x00" * (self.PLAIN_BLOCK_SIZE * self.BLOCKS_PER_GROUP - blocks) else: raise ValueError("Attempted to write group past the end of the partition data") else: @@ -930,12 +925,12 @@ class WiiPartition: h0 = [] h1 = [] - h2 = "" + h2 = b"" for subgroup in range(self.SUBGROUPS_PER_GROUP): - bh1 = "" + bh1 = b"" sh0 = [] for block in range(self.BLOCKS_PER_SUBGROUP): - bh0 = "" + bh0 = b"" for chunk in range(self.DATA_CHUNKS_PER_BLOCK): offset = subgroup * self.PLAIN_SUBGROUP_SIZE + block * self.PLAIN_BLOCK_SIZE + chunk * self.DATA_CHUNK_SIZE bh0 += SHA.new(data[offset:offset+self.DATA_CHUNK_SIZE]).digest() @@ -946,16 +941,16 @@ class WiiPartition: h2 += SHA.new(bh1).digest() h3 = SHA.new(h2).digest() - data_out = "" + data_out = b"" for subgroup in range(self.SUBGROUPS_PER_GROUP): for block in range(self.BLOCKS_PER_SUBGROUP): shablock = "" shablock += h0[subgroup][block] - shablock += "\x00"*20 + shablock += b"\x00"*20 shablock += h1[subgroup] - shablock += "\x00"*32 + shablock += b"\x00"*32 shablock += h2 - shablock += "\x00"*32 + shablock += b"\x00"*32 assert len(shablock) == self.SHA_SIZE, "sha block size messed up" aes = AES.new(self.tik.title_key, AES.MODE_CBC, NULL_IV) shablock = aes.encrypt(shablock) @@ -1019,7 +1014,7 @@ class WiiCachedPartition(WiiPartition): def _dprint(self, s, *args): if self.debug: - print s%tuple(args) + print(s%tuple(args)) def _readblock(self, blocknum): self._dprint("_readblock(0x%x)",blocknum) @@ -1174,7 +1169,7 @@ class WiiCachedPartition(WiiPartition): hb = self.readblock(bstart - 1) hb = hb[:hdroff] + data[:header] + hb[hdroff+header:] self.writeblock(bstart - 1, hb) - for block in xrange(bnum): + for block in range(bnum): self.writeblock(block+bstart, data[header+block*self.PLAIN_BLOCK_SIZE:header+(block+1)*self.PLAIN_BLOCK_SIZE]) if footer: fb = self.readblock(bstart+bnum) @@ -1246,11 +1241,11 @@ class WiiApploader: self.extrafooter = data[0x20+self.textsize+self.trailersize:] def showinfo(self, it=""): - print it+"Apploader:" - print it+" Date: %s"%self.date - print it+" Entrypoint: 0x%08x"%self.entry - print it+" Text size: 0x%x"%self.textsize - print it+" Trailer size: 0x%x"%self.trailersize + print(it+"Apploader:") + print(it+" Date: %s"%self.date) + print(it+" Entrypoint: 0x%08x"%self.entry) + print(it+" Text size: 0x%x"%self.textsize) + print(it+" Trailer size: 0x%x"%self.trailersize) class WiiPartitionData: def __init__(self, partition): @@ -1291,11 +1286,11 @@ class WiiPartitionData: self.dol = dol self.part.write(self.doloff, dol) def showinfo(self,it=""): - print it+"Partition data:" - print it+" Game Name: %s"%self.gamename - print it+" Offsets: DOL @ 0x%x [0x%x], Apploader @ 0x%x [0x%x], FST @ 0x%x [0x%x]"%(self.doloff, self.dolsize, 0x2440, self.apploadersize, self.fstoff, self.fstsize) + print(it+"Partition data:") + print(it+" Game Name: %s"%self.gamename) + print(it+" Offsets: DOL @ 0x%x [0x%x], Apploader @ 0x%x [0x%x], FST @ 0x%x [0x%x]"%(self.doloff, self.dolsize, 0x2440, self.apploadersize, self.fstoff, self.fstsize)) self.apploader.showinfo(it+" ") - print it+"FST:" + print(it+"FST:") self.fst.show(it+" ") class FakeFile: @@ -1381,7 +1376,7 @@ class WiiWad: self.f.seek(4) wt = self.f.read(2) - if wt == "\x00\x00": + if wt == b"\x00\x00": self.read_boot2hdr() else: self.read_hdr() @@ -1389,7 +1384,7 @@ class WiiWad: certdata = self.f.read(self.cert_len) self.certlist = [] self.certs = {} - while certdata != "": + while certdata != b"": cert = WiiCert(certdata) self.certs[cert.name] = cert self.certlist.append(cert) @@ -1415,8 +1410,8 @@ class WiiWad: self.f.write(self.tik.data) def showinfo(self,it=""): - print it+"Wii Wad:" - print it+" Header 0x%x Type %s Certs 0x%x Tik 0x%x TMD 0x%x Data 0x%x @ 0x%x Footer 0x%x"%(self.hdr_len, repr(self.wadtype), self.cert_len, self.tik_len, self.tmd_len, self.data_len, self.data_off, self.footer_len) + print(it+"Wii Wad:") + print(it+" Header 0x%x Type %s Certs 0x%x Tik 0x%x TMD 0x%x Data 0x%x @ 0x%x Footer 0x%x"%(self.hdr_len, repr(self.wadtype), self.cert_len, self.tik_len, self.tmd_len, self.data_len, self.data_off, self.footer_len)) self.tik.showinfo(it+" ") self.tik.showsig(self.certs,it+" ") self.tmd.showinfo(it+" ") @@ -1426,15 +1421,15 @@ class WiiWad: d = self.getcontent(ct.index) sha = SHA.new(d).digest() if sha != ct.sha: - print it+" SHA-1 for content %08x is invalid:"%ct.cid, hexdump(sha) - print it+" Expected:",hexdump(ct.sha) + print(it+" SHA-1 for content %08x is invalid:"%ct.cid, hexdump(sha)) + print(it+" Expected:",hexdump(ct.sha)) allok=False if allok: - print it+" All content SHA-1 hashes are valid" + print(it+" All content SHA-1 hashes are valid") self.showcerts(it+" ") def showcerts(self,it=""): - print it+"Certificates: " + print(it+"Certificates: ") for cert in self.certlist: cert.showinfo(it+" - ") cert.showsig(self.certs,it+" ") @@ -1447,7 +1442,7 @@ class WiiWad: if encrypted: return data - iv = pack(">H",index)+"\x00"*14 + iv = pack(">H",index)+b"\x00"*14 aes = AES.new(self.tik.title_key, AES.MODE_CBC, iv) return aes.decrypt(data)[:ct.size] @@ -1470,14 +1465,14 @@ class WiiWadMaker(WiiWad): self.tik_len = len(self.tik.data) # if boot2, set type to "ib" - if self.tmd.title_id == "\x00\x00\x00\x01\x00\x00\x00\x01": + if self.tmd.title_id == b"\x00\x00\x00\x01\x00\x00\x00\x01": if nandwad: self.wadtype = 0 self.ALIGNMENT = 0 else: - self.wadtype = "ib" + self.wadtype = b"ib" else: - self.wadtype = "Is" + self.wadtype = b"Is" self.data_len = 0 self.footer = footer @@ -1509,16 +1504,16 @@ class WiiWadMaker(WiiWad): cr.size = len(data) self.tmd.update_content_record(i,cr) if len(data)%16 != 0: - data += "\x00"*(16-len(data)%16) + data += b"\x00"*(16-len(data)%16) falign(self.f,0x40) - iv = pack(">H",cr.index)+"\x00"*14 + iv = pack(">H",cr.index)+b"\x00"*14 aes = AES.new(self.tik.title_key, AES.MODE_CBC, iv) self.f.write(aes.encrypt(data)) falign(self.f,0x40) def adddata_encrypted(self, data): if len(data)%16 != 0: - data += "\x00"*(16-len(data)%16) + data += b"\x00"*(16-len(data)%16) falign(self.f,0x40) self.f.write(data) falign(self.f,0x40) @@ -1531,7 +1526,7 @@ class WiiWadMaker(WiiWad): falign(self.f,self.ALIGNMENT) self.f.truncate() if pad: - self.f.write("\x00"*0x40) + self.f.write(b"\x00"*0x40) self.updatetmd() self.f.seek(0) if self.wadtype == 0: @@ -1641,9 +1636,9 @@ class WiiFSTFile: self.off = off self.size = size def show(self, it=""): - print "%s%s @ 0x%x [0x%x]"%(it,self.name,self.off,self.size) + print("%s%s @ 0x%x [0x%x]"%(it,self.name,self.off,self.size)) def generate(self, offset, stringoff, parent, dataoff, wiigcm=False): - stringdata = self.name + "\x00" + stringdata = self.name.encode("ascii") + b"\x00" off = self.off+dataoff if wiigcm: off >>= 2 @@ -1688,9 +1683,9 @@ class WiiFSTDir: raise ValueError("WTF") def show(self, it=""): if self.name == "": - print it+"/" + print(it+"/") else: - print it+self.name+"/" + print(it+self.name+"/") for i in self.entries: i.show(it+self.name+"/") def dump(self): @@ -1698,15 +1693,15 @@ class WiiFSTDir: def add(self,x): self.entries.append(x) def generate(self, offset, stringoff, parent, dataoff, wiigcm=False): - stringdata = self.name + "\x00" + stringdata = self.name.encode("ascii") + b"\x00" myoff = offset mysoff = stringoff stringoff+=len(stringdata) offset += 1 - subdata="" + subdata=b"" for e in self.entries: d, s = e.generate(offset, stringoff, myoff, dataoff, wiigcm) - offset += len(d)/12 + offset += len(d)//12 stringoff += len(s) stringdata += s subdata += d diff --git a/pywii/pywii-tools/addhash.py b/pywii/pywii-tools/addhash.py index 52de600..6176f51 100755 --- a/pywii/pywii-tools/addhash.py +++ b/pywii/pywii-tools/addhash.py @@ -1,11 +1,11 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys import re import pywii as wii hash = wii.SHA.new(open(sys.argv[2]).read()).digest().encode("hex") -f = open(sys.argv[1], "r") +f = open(sys.argv[1], "rb") data = f.read() f.close() data = re.sub('@SHA1SUM@', hash, data) -open(sys.argv[3], "w").write(data) +open(sys.argv[3], "wb").write(data) diff --git a/pywii/pywii-tools/arclist.py b/pywii/pywii-tools/arclist.py index 61cd29c..aad2cde 100755 --- a/pywii/pywii-tools/arclist.py +++ b/pywii/pywii-tools/arclist.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path, struct import pywii as wii diff --git a/pywii/pywii-tools/arcpack.py b/pywii/pywii-tools/arcpack.py index d2c49e8..d5eb130 100755 --- a/pywii/pywii-tools/arcpack.py +++ b/pywii/pywii-tools/arcpack.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path, struct import pywii as wii @@ -7,20 +7,24 @@ fstb = wii.WiiFSTBuilder(0x20) fstb.addfrom(sys.argv[2]) -arc = open(sys.argv[1],"wb") -# dummy generate to get length -fstlen = len(fstb.fst.generate()) -dataoff = wii.align(0x20+fstlen,0x20) -fst = fstb.fst.generate(dataoff) +try: + arc = open(sys.argv[1],"wb") + # dummy generate to get length + fstlen = len(fstb.fst.generate()) + dataoff = wii.align(0x20+fstlen,0x20) + fst = fstb.fst.generate(dataoff) -hdr = struct.pack(">IIII16x",0x55AA382d,0x20,fstlen,dataoff) -arc.write(hdr) + hdr = struct.pack(">IIII16x",0x55AA382d,0x20,fstlen,dataoff) + arc.write(hdr) -arc.write(fst) -wii.falign(arc,0x20) -for f in fstb.files: - data = open(f, "rb").read() - arc.write(data) + arc.write(fst) wii.falign(arc,0x20) + for f in fstb.files: + data = open(f, "rb").read() + arc.write(data) + wii.falign(arc,0x20) -arc.close() + arc.close() +except: + os.remove(sys.argv[1]) + raise diff --git a/pywii/pywii-tools/certinfo.py b/pywii/pywii-tools/certinfo.py index 526c0f7..d0ec2ee 100755 --- a/pywii/pywii-tools/certinfo.py +++ b/pywii/pywii-tools/certinfo.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii @@ -15,12 +15,12 @@ certfile = args.pop(0) certs, certlist = wii.parse_certs(open(args.pop(0), "rb").read()) -print "Certification file %s: " % certfile +print("Certification file %s: " % certfile) cert = wii.WiiCert(open(certfile, "rb").read()) cert.showinfo(" ") cert.showsig(certs," ") -print "Certificates:" +print("Certificates:") for cert in certlist: cert.showinfo(" - ") cert.showsig(certs," ") diff --git a/pywii/pywii-tools/discinfo.py b/pywii/pywii-tools/discinfo.py index c54921d..0a51399 100755 --- a/pywii/pywii-tools/discinfo.py +++ b/pywii/pywii-tools/discinfo.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii @@ -11,7 +11,7 @@ disc.showinfo() partitions = disc.read_partitions() -parts = range(len(partitions)) +parts = list(range(len(partitions))) try: pnum = int(sys.argv[2]) diff --git a/pywii/pywii-tools/dpkisign.py b/pywii/pywii-tools/dpkisign.py index d8de458..d7dc66b 100755 --- a/pywii/pywii-tools/dpkisign.py +++ b/pywii/pywii-tools/dpkisign.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii @@ -17,7 +17,7 @@ if sys.argv[1] == "-cetk": elif sys.argv[1] == "-tmd": signed = pywii.WiiTmd(open(infile, "rb").read()) else: - print "EYOUFAILIT" + print("EYOUFAILIT") sys.exit(1) certs, certlist = pywii.parse_certs(open(certfile).read()) @@ -25,11 +25,11 @@ certs, certlist = pywii.parse_certs(open(certfile).read()) signed.update_issuer(issuer) if not signed.sign(certs): - print "dpki signing failed" + print("dpki signing failed") sys.exit(1) open(outfile, "wb").write(signed.data) -print "successfully signed %s" % outfile +print("successfully signed %s" % outfile) sys.exit(0) diff --git a/pywii/pywii-tools/ecchecksig.py b/pywii/pywii-tools/ecchecksig.py index 21ba519..7abcd0e 100755 --- a/pywii/pywii-tools/ecchecksig.py +++ b/pywii/pywii-tools/ecchecksig.py @@ -1,10 +1,10 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys import pywii as wii if len(sys.argv) != 3: - print "Usage: %s keyfile.[priv|pub] infile"%sys.argv[0] + print("Usage: %s keyfile.[priv|pub] infile"%sys.argv[0]) sys.exit(1) if sys.argv[1] == "-": @@ -12,46 +12,46 @@ if sys.argv[1] == "-": else: k = open(sys.argv[1],"rb").read() if len(k) not in (30,60): - print "Failed to read key" + print("Failed to read key") sys.exit(2) if len(k) == 30: - print "Key is a private key, generating public key..." + print("Key is a private key, generating public key...") q = wii.ec.priv_to_pub(k) else: q = k -print "Public key:" +print("Public key:") pq = q.encode('hex') -print "X =",pq[:30] -print " ",pq[30:60] -print "Y =",pq[60:90] -print " ",pq[90:] -print +print("X =",pq[:30]) +print(" ",pq[30:60]) +print("Y =",pq[60:90]) +print(" ",pq[90:]) +print() indata = open(sys.argv[2],"rb").read() if len(indata) < 64 or indata[:4] != "SIG0": - print "Invalid header" + print("Invalid header") sys.exit(3) r = indata[4:34] s = indata[34:64] sha = wii.SHA.new(indata[64:]).digest() -print "SHA1: %s"%sha.encode('hex') +print("SHA1: %s"%sha.encode('hex')) -print -print "Signature:" -print "R =",r[:15].encode('hex') -print " ",r[15:].encode('hex') -print "S =",s[:15].encode('hex') -print " ",s[15:].encode('hex') -print +print() +print("Signature:") +print("R =",r[:15].encode('hex')) +print(" ",r[15:].encode('hex')) +print("S =",s[:15].encode('hex')) +print(" ",s[15:].encode('hex')) +print() if wii.ec.check_ecdsa(q,r,s,sha): - print "Signature is VALID" + print("Signature is VALID") else: - print "Signature is INVALID" + print("Signature is INVALID") sys.exit(4) diff --git a/pywii/pywii-tools/ecgenpriv.py b/pywii/pywii-tools/ecgenpriv.py index 97a9799..70154b1 100755 --- a/pywii/pywii-tools/ecgenpriv.py +++ b/pywii/pywii-tools/ecgenpriv.py @@ -1,33 +1,33 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os import pywii as wii if len(sys.argv) != 2: - print "Usage: %s keyfile.priv"%sys.argv[0] + print("Usage: %s keyfile.priv"%sys.argv[0]) sys.exit(1) -print "Generating private key..." +print("Generating private key...") k = wii.ec.gen_priv_key() -print "Private key:" +print("Private key:") pk = k.encode('hex') -print "K =",pk[:30] -print " ",pk[30:] +print("K =",pk[:30]) +print(" ",pk[30:]) -print -print "Corresponding public key:" +print() +print("Corresponding public key:") q = wii.ec.priv_to_pub(k) pq = q.encode('hex') -print "X =",pq[:30] -print " ",pq[30:60] -print "Y =",pq[60:90] -print " ",pq[90:] +print("X =",pq[:30]) +print(" ",pq[30:60]) +print("Y =",pq[60:90]) +print(" ",pq[90:]) fd = open(sys.argv[1],"wb") os.fchmod(fd.fileno(), 0o600) fd.write(k) fd.close() -print "Saved private key to %s"%sys.argv[1] +print("Saved private key to %s"%sys.argv[1]) diff --git a/pywii/pywii-tools/ecpriv2pub.py b/pywii/pywii-tools/ecpriv2pub.py index bb85c60..432ad4b 100755 --- a/pywii/pywii-tools/ecpriv2pub.py +++ b/pywii/pywii-tools/ecpriv2pub.py @@ -1,10 +1,10 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys import pywii as wii if len(sys.argv) not in (2,3): - print "Usage: %s keyfile.priv [keyfile.pub]"%sys.argv[0] + print("Usage: %s keyfile.priv [keyfile.pub]"%sys.argv[0]) sys.exit(1) if sys.argv[1] == "-": @@ -12,19 +12,19 @@ if sys.argv[1] == "-": else: k = open(sys.argv[1],"rb").read() if len(k) != 30: - print "Failed to read private key" + print("Failed to read private key") sys.exit(2) -print "Public key:" +print("Public key:") q = wii.ec.priv_to_pub(k) pq = q.encode('hex') -print "X =",pq[:30] -print " ",pq[30:60] -print "Y =",pq[60:90] -print " ",pq[90:] +print("X =",pq[:30]) +print(" ",pq[30:60]) +print("Y =",pq[60:90]) +print(" ",pq[90:]) if len(sys.argv) == 3: fd = open(sys.argv[2],"wb") fd.write(q) fd.close() - print "Saved public key to %s"%sys.argv[2] + print("Saved public key to %s"%sys.argv[2]) diff --git a/pywii/pywii-tools/ecsign.py b/pywii/pywii-tools/ecsign.py index b7467f3..e923c6b 100755 --- a/pywii/pywii-tools/ecsign.py +++ b/pywii/pywii-tools/ecsign.py @@ -1,10 +1,9 @@ -#!/usr/bin/env python2 - +#!/usr/bin/env python3 import sys import pywii as wii if len(sys.argv) != 4: - print "Usage: %s keyfile.priv infile outfile"%sys.argv[0] + print("Usage: %s keyfile.priv infile outfile"%sys.argv[0]) sys.exit(1) if sys.argv[1] == "-": @@ -13,20 +12,20 @@ else: k = open(sys.argv[1],"rb").read() if len(k) != 30: - print "Failed to read private key" + print("Failed to read private key") sys.exit(2) indata = open(sys.argv[2],"rb").read() sha = wii.SHA.new(indata).digest() -print "SHA1: %s"%sha.encode('hex') -print -print "Signature:" +print("SHA1: %s"%sha.encode('hex')) +print() +print("Signature:") r,s = wii.ec.generate_ecdsa(k,sha) -print "R =",r[:15].encode('hex') -print " ",r[15:].encode('hex') -print "S =",s[:15].encode('hex') -print " ",s[15:].encode('hex') +print("R =",r[:15].encode('hex')) +print(" ",r[15:].encode('hex')) +print("S =",s[:15].encode('hex')) +print(" ",s[15:].encode('hex')) outdata = "SIG0" + r + s + indata diff --git a/pywii/pywii-tools/extract.py b/pywii/pywii-tools/extract.py index da1f07c..e92ebe4 100755 --- a/pywii/pywii-tools/extract.py +++ b/pywii/pywii-tools/extract.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii @@ -11,8 +11,8 @@ def parseint(d): return int(d) if len(sys.argv) < 4 or len(sys.argv) > 7: - print "Usage:" - print " python %s [Partition offset] [length]"%sys.argv[0] + print("Usage:") + print(" python %s [Partition offset] [length]"%sys.argv[0]) sys.exit(1) iso_name, partno, data_name = sys.argv[1:4] @@ -27,19 +27,19 @@ if len(sys.argv) == 6: copy_length = parseint(sys.argv[5]) if copy_length is not None and copy_length < 0: - print "Error: negative copy length" + print("Error: negative copy length") sys.exit(1) disc = wii.WiiDisc(iso_name) disc.showinfo() part = wii.WiiCachedPartition(disc, partno, cachesize=32, debug=False, checkhash=False) if part_offset >= part.data_bytes: - print "Error: Offset past end of partition" + print("Error: Offset past end of partition") sys.exit(1) if copy_length is None: copy_length = part.data_bytes - part_offset if copy_length > (part.data_bytes - part_offset): - print "Error: Length too large" + print("Error: Length too large") sys.exit(1) dataf = open(data_name, "wb") @@ -49,7 +49,7 @@ while left > 0: blocklen = min(left, 4*1024*1024) d = part.read(offset, blocklen) if len(d) != blocklen: - print "Part EOF reached!" + print("Part EOF reached!") sys.exit(1) dataf.write(d) offset += blocklen diff --git a/pywii/pywii-tools/extractdol.py b/pywii/pywii-tools/extractdol.py index 8e24de8..c6d1cf6 100755 --- a/pywii/pywii-tools/extractdol.py +++ b/pywii/pywii-tools/extractdol.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 import sys, os, os.path sys.path.append(os.path.realpath(os.path.dirname(sys.argv[0]))+"/../Common") @@ -7,8 +7,8 @@ import pywii as wii wii.loadkeys(os.environ["HOME"]+os.sep+".wii") if len(sys.argv) != 4: - print "Usage:" - print " python %s "%sys.argv[0] + print("Usage:") + print(" python %s "%sys.argv[0]) sys.exit(1) iso_name, partno, dol_name = sys.argv[1:4] diff --git a/pywii/pywii-tools/extractfiles.py b/pywii/pywii-tools/extractfiles.py index b8d9934..177c3ba 100644 --- a/pywii/pywii-tools/extractfiles.py +++ b/pywii/pywii-tools/extractfiles.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii @@ -11,8 +11,8 @@ def parseint(d): return int(d) if len(sys.argv) < 4 or len(sys.argv) > 7: - print "Usage:" - print " python %s "%sys.argv[0] + print("Usage:") + print(" python %s "%sys.argv[0]) sys.exit(1) iso_name, partno, data_name = sys.argv[1:4] @@ -27,19 +27,19 @@ if len(sys.argv) == 6: copy_length = parseint(sys.argv[5]) if copy_length is not None and copy_length < 0: - print "Error: negative copy length" + print("Error: negative copy length") sys.exit(1) disc = wii.WiiDisc(iso_name) disc.showinfo() part = wii.WiiCachedPartition(disc, partno, cachesize=32, debug=False, checkhash=False) if part_offset >= part.data_bytes: - print "Error: Offset past end of partition" + print("Error: Offset past end of partition") sys.exit(1) if copy_length is None: copy_length = part.data_bytes - part_offset if copy_length > (part.data_bytes - part_offset): - print "Error: Length too large" + print("Error: Length too large") sys.exit(1) dataf = open(data_name, "wb") @@ -49,7 +49,7 @@ while left > 0: blocklen = min(left, 4*1024*1024) d = part.read(offset, blocklen) if len(d) != blocklen: - print "Part EOF reached!" + print("Part EOF reached!") sys.exit(1) dataf.write(d) offset += blocklen diff --git a/pywii/pywii-tools/getappldr.py b/pywii/pywii-tools/getappldr.py index 9989b12..5dba4e8 100755 --- a/pywii/pywii-tools/getappldr.py +++ b/pywii/pywii-tools/getappldr.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii @@ -6,8 +6,8 @@ import pywii as wii wii.loadkeys() if len(sys.argv) != 5: - print "Usage:" - print " python %s "%sys.argv[0] + print("Usage:") + print(" python %s "%sys.argv[0]) sys.exit(1) iso_name, partno, app_name, trail_name = sys.argv[1:5] diff --git a/pywii/pywii-tools/inject.py b/pywii/pywii-tools/inject.py index 6a104db..e36a90a 100755 --- a/pywii/pywii-tools/inject.py +++ b/pywii/pywii-tools/inject.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii @@ -11,8 +11,8 @@ def parseint(d): return int(d) if len(sys.argv) < 4 or len(sys.argv) > 7: - print "Usage:" - print " python %s [Partition offset] [data offset] [length]"%sys.argv[0] + print("Usage:") + print(" python %s [Partition offset] [data offset] [length]"%sys.argv[0]) sys.exit(1) iso_name, partno, data_name = sys.argv[1:4] @@ -34,10 +34,10 @@ if copy_length == None: copy_length = data_len - data_offset copy_end = data_offset + copy_length if copy_length < 0: - print "Error: negative copy length" + print("Error: negative copy length") sys.exit(1) if copy_end > data_len: - print "Error: data file is too small" + print("Error: data file is too small") sys.exit(1) disc = wii.WiiDisc(iso_name) @@ -52,7 +52,7 @@ while left > 0: blocklen = min(left, 4*1024*1024) d = dataf.read(blocklen) if len(d) != blocklen: - print "File EOF reached!" + print("File EOF reached!") sys.exit(1) part.write(offset, d) offset += blocklen diff --git a/pywii/pywii-tools/injectdol.py b/pywii/pywii-tools/injectdol.py index 6f5e24b..abbff45 100755 --- a/pywii/pywii-tools/injectdol.py +++ b/pywii/pywii-tools/injectdol.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii @@ -6,8 +6,8 @@ import pywii as wii wii.loadkeys() if len(sys.argv) != 4: - print "Usage:" - print " python %s "%sys.argv[0] + print("Usage:") + print(" python %s "%sys.argv[0]) sys.exit(1) iso_name, partno, dol_name = sys.argv[1:4] diff --git a/pywii/pywii-tools/partsetios.py b/pywii/pywii-tools/partsetios.py index 21e21e9..90ee68e 100755 --- a/pywii/pywii-tools/partsetios.py +++ b/pywii/pywii-tools/partsetios.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii @@ -6,9 +6,9 @@ import pywii as wii wii.loadkeys() if len(sys.argv) != 4: - print "Usage:" - print " python %s "%sys.argv[0] - print " IOS version should be just the minor number (16, 33, etc) in decimal" + print("Usage:") + print(" python %s "%sys.argv[0]) + print(" IOS version should be just the minor number (16, 33, etc) in decimal") sys.exit(1) iso_name, partno, ios = sys.argv[1:4] diff --git a/pywii/pywii-tools/rsapatch.py b/pywii/pywii-tools/rsapatch.py index 75b7d82..9808bd2 100755 --- a/pywii/pywii-tools/rsapatch.py +++ b/pywii/pywii-tools/rsapatch.py @@ -1,10 +1,10 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii def hexdump(s): - return ' '.join(map(lambda x: "%02x"%x,map(ord,s))) + return ' '.join(["%02x"%x for x in list(map(ord,s))]) isofile = sys.argv[1] disc = WiiDisc(isofile) diff --git a/pywii/pywii-tools/saveinfo.py b/pywii/pywii-tools/saveinfo.py index 32d8705..a5b0ed7 100755 --- a/pywii/pywii-tools/saveinfo.py +++ b/pywii/pywii-tools/saveinfo.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii diff --git a/pywii/pywii-tools/tikfix.py b/pywii/pywii-tools/tikfix.py index 045c045..331f4a3 100755 --- a/pywii/pywii-tools/tikfix.py +++ b/pywii/pywii-tools/tikfix.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii @@ -6,7 +6,7 @@ import pywii as wii wii.loadkeys() tikfile = sys.argv[1] -print "fixing Tik file %s " % tikfile +print("fixing Tik file %s " % tikfile) tik = wii.WiiTik(open(tikfile, "rb").read()) tik.null_signature() tik.brute_sha() diff --git a/pywii/pywii-tools/tikinfo.py b/pywii/pywii-tools/tikinfo.py index 5f53fb0..5b088fc 100755 --- a/pywii/pywii-tools/tikinfo.py +++ b/pywii/pywii-tools/tikinfo.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii @@ -17,12 +17,12 @@ certs = None if len(args) > 0: certs, certlist = wii.parse_certs(open(args.pop(0), "rb").read()) -print "ETicket file %s:"%tikfile +print("ETicket file %s:"%tikfile) tik = wii.WiiTik(open(tikfile, "rb").read()) tik.showinfo(" ") if certs is not None: tik.showsig(certs," ") - print "Certificates:" + print("Certificates:") for cert in certlist: cert.showinfo(" - ") cert.showsig(certs," ") diff --git a/pywii/pywii-tools/tmdfix.py b/pywii/pywii-tools/tmdfix.py index 92525e7..f14f8ba 100755 --- a/pywii/pywii-tools/tmdfix.py +++ b/pywii/pywii-tools/tmdfix.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii @@ -6,7 +6,7 @@ import pywii as wii wii.loadkeys() tmdfile = sys.argv[1] -print "TMD file %s:"%tmdfile +print("TMD file %s:"%tmdfile) tmd = wii.WiiTmd(open(tmdfile, "rb").read()) tmd.null_signature() tmd.brute_sha() diff --git a/pywii/pywii-tools/tmdinfo.py b/pywii/pywii-tools/tmdinfo.py index 0c037b7..93b90b3 100755 --- a/pywii/pywii-tools/tmdinfo.py +++ b/pywii/pywii-tools/tmdinfo.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii @@ -17,12 +17,12 @@ certs = None if len(args) > 0: certs, certlist = wii.parse_certs(open(args.pop(0), "rb").read()) -print "TMD file %s:"%tmdfile +print("TMD file %s:"%tmdfile) tmd = wii.WiiTmd(open(tmdfile, "rb").read()) tmd.showinfo(" ") if certs is not None: tmd.showsig(certs," ") - print "Certificates:" + print("Certificates:") for cert in certlist: cert.showinfo(" - ") cert.showsig(certs," ") diff --git a/pywii/pywii-tools/tmdupdatecr.py b/pywii/pywii-tools/tmdupdatecr.py index 55ac566..8c55909 100755 --- a/pywii/pywii-tools/tmdupdatecr.py +++ b/pywii/pywii-tools/tmdupdatecr.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii @@ -14,7 +14,7 @@ args = sys.argv[1:] tmdfile = args.pop(0) indir = args.pop(0) -print "updating content records of TMD file %s" % tmdfile +print("updating content records of TMD file %s" % tmdfile) tmd = wii.WiiTmd(open(tmdfile, "rb").read()) for i, cr in enumerate(tmd.get_content_records()): diff --git a/pywii/pywii-tools/tmdvers.py b/pywii/pywii-tools/tmdvers.py index 1213779..58f8605 100755 --- a/pywii/pywii-tools/tmdvers.py +++ b/pywii/pywii-tools/tmdvers.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii @@ -14,7 +14,7 @@ if len(args) == 2: else: newvers = int(args.pop(0), 16) -print "setting version of TMD file %s to 0x%04x" % (tmdfile, newvers) +print("setting version of TMD file %s to 0x%04x" % (tmdfile, newvers)) tmd = wii.WiiTmd(open(tmdfile, "rb").read()) tmd.title_version = newvers tmd.update() diff --git a/pywii/pywii-tools/wadinfo.py b/pywii/pywii-tools/wadinfo.py index c7ab162..5ce7058 100755 --- a/pywii/pywii-tools/wadinfo.py +++ b/pywii/pywii-tools/wadinfo.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii diff --git a/pywii/pywii-tools/wadpack-boot2.py b/pywii/pywii-tools/wadpack-boot2.py index 31a7323..2d4ad2a 100755 --- a/pywii/pywii-tools/wadpack-boot2.py +++ b/pywii/pywii-tools/wadpack-boot2.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii diff --git a/pywii/pywii-tools/wadpack.py b/pywii/pywii-tools/wadpack.py index bf562fe..0c37903 100755 --- a/pywii/pywii-tools/wadpack.py +++ b/pywii/pywii-tools/wadpack.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii diff --git a/pywii/pywii-tools/wadunpack.py b/pywii/pywii-tools/wadunpack.py index 2f0c4cf..e2a00ee 100755 --- a/pywii/pywii-tools/wadunpack.py +++ b/pywii/pywii-tools/wadunpack.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys, os, os.path import pywii as wii