Compare commits

6 Commits

Author SHA1 Message Date
Archie Halliwell
a31c3bbcc6 fix order so it is the same as in master 2025-04-14 21:35:09 +09:00
Archie Halliwell
9a46141a82 fix TypeError 2025-04-14 21:35:09 +09:00
Archie Halliwell
561041a71c fix freetype dependencies 2025-04-14 21:35:09 +09:00
Archie Halliwell
43de8436d6 fix issue #19 2025-04-14 21:35:09 +09:00
Hector Martin
1536182957 Alameda fixes 2021-03-22 11:49:55 +09:00
Hector Martin
cad274a7fb WIP: Quick and dirty python3 port 2021-03-22 11:14:07 +09:00
41 changed files with 2424 additions and 2468 deletions

View File

@@ -1,85 +1,3 @@
# ARCHIVED
This repository is archived and will not accept any further contributions.
Like most Wii homebrew software, this software depends on [libogc](https://github.com/devkitPro/libogc).
After development of The Homebrew Channel had already started, we discovered that large portions of libogc
were stolen directly from the Nintendo SDK or games using the Nintendo SDK (decompiled and cleaned up).
We thought that at least significant parts of libogc, such as its threading implementation, were original,
and reluctantly continued to use the project while distancing ourselves from it.
It has recently been revealed that the threading/OS implementation in libogc is, in fact,
[stolen from RTEMS](https://github.com/derek57/libogc). The authors of libogc didn't just steal proprietary
Nintendo code, but also saw it fit to steal an *open source* RTOS and remove all attribution and copyright
information. This goes far beyond ignorance about the copyright implications of reverse engineering Nintendo
binaries, and goes straight into outright deliberate, malicious code theft and copyright infringement.
The current developers of libogc are [not interested](https://github.com/devkitPro/libogc/issues/201) in
tracking this issue, finding a solution, nor informing the community of the problematic copyright status of
the project. When we filed an issue about it, they immediately closed it, replied with verbal abuse, and then
completely deleted it from public view.
For this reason, we consider it impossible to legally and legitimately compile this software at this point,
and cannot encourage any further development.
The Wii homebrew community was all built on top of a pile of lies and copyright infringement, and it's all
thanks to shagkur (who did the stealing) and the rest of the team (who enabled it and did nothing when it was
discovered). Together, the developers deceived everyone into believing their work was original.
Please demand that the leaders and major contributors to console or other proprietary device SDKs and
toolkits that you use and work with do things legally, and do not tolerate this kind of behavior.
If you wish to check for yourself, for example, you can compare
[this](https://github.com/devkitPro/libogc/blob/52c525a13fd1762c10395c78875e3260f94368b5/libogc/lwp_threads.c#L580)
function in libogc to
[this](https://github.com/atgreen/RTEMS/blob/2f200c7e642c214accb7cc6bd7f0f1784deec833/c/src/exec/score/src/thread.c#L385)
function in a really old version of RTEMS. While the code has been simplified and many identifiers renamed, it
is clear that the libogc version is a direct descendant of the RTEMS version. It is not possible for two code
implementations to end up this similar purely by chance.
**Update**: The libogc developers have restored the issue and are now claiming that the code
[was not stolen](https://mardy.it/blog/2025/04/no-libogc-did-not-steal-rtems-code.html). What they are in fact
arguing is that the code was not copied verbatim and then changed to obfuscate its origin, but rather that it was
developed by "referencing" RTEMS. Indeed, the original commits of the code to libogc are a less complete copy
of RTEMS than the current version. What that means is that, instead of literally duplicating RTEMS and then
reducing it, they instead *piecewise* incorporated RTEMS code by re-typing or copyediting it line by line,
over time. This is equivalent to opening up a copy of The Lord of the Rings, pulling up a blank document, and
meticulously re-typing the whole story in different words, with different names for the characters, while
preserving the entirety of the plot. Unfortunately for shagkur and the other libogc authors, this is still
plagiarism and copyright infringement. It doesn't matter that they didn't literally Ctrl-C and Ctrl-V the
entirety of RTEMS. The end result is, very clearly, still plagiarized.
Feel free to check out another example:
[this RTEMS function](https://github.com/atgreen/RTEMS/blob/2f200c7e642c214accb7cc6bd7f0f1784deec833/c/src/exec/score/src/thread.c#L1141)
is 1:1 identical to
[this libogc function](https://github.com/devkitPro/libogc/blob/52c525a13fd1762c10395c78875e3260f94368b5/libogc/lwp_threads.c#L388),
other than slightly renamed identifiers, different code formatting, and the `prependit` parameter in the
libogc version and `if` branch (which does seem to be a novel addition). It would be clear in any court of
law that this constitutes copyright infringement, regardless of whether it was achieved in one shot or
incrementally over time. It is simply not possible for this kind of non-trivial code to wind up completely
identical like this, purely on accident. This kind of conduct is, in fact, the same conduct that led libogc
to contain large parts of decompiled Nintendo SDK code verbatim. We just thought that that was a result of a
lack of understanding (or caring) of how copyright works when it related to reverse engineering proprietary
binary code, but it seems shagkur believes that he is entitled to manually copy and re-type *any* code, even
open source code, and the mere action of doing so erases its original copyright.
WinterMute is also is not innocent, and not just by virtue of being complicit with shagkur and enabling his
plagiarism behavior. He, himself, was previously
[caught](https://github.com/devkitPro/libnds/commit/426a369220dcb43320e203f9087de74e43452d84#diff-f376c160388ca187fe35e962eb047fe606338869b515128a6257d3a7a6694ff0R17-R25)
referencing the official Nintendo DS ("nitro") SDK while writing code for libnds\*. WinterMute has a huge
siege mentality issue when it comes to DevkitPro, which is why nobody has been able to get through to him,
as any criticism of his work or the way he manages his project has always been met with extreme hostility.
This is why nothing has ever been done about these issues with the project, even after all these years.
\* Edited to note: This should not be taken to imply that any or all of libnds itself is tainted with SDK
code. The commit in question itself only adds fairly standard cache maintenance functions, and is not itself
evidence that there was substantial copying. It just reflects poorly on WinterMute that he was referencing
the leaked SDK, especially for something as trivial as this. For a more thorough take on the general
mismanagement of the devkitPro project as a whole, please read
[this](https://heyquark.com/brew/2020/07/13/leaving-devkitpro/) blog post. The stories told there track
very closely with our experience with that team way back in the Wii days, and it seems nothing has changed
nor improved after all these years.
# The Homebrew Channel # The Homebrew Channel
This repository contains the public release of the source code for This repository contains the public release of the source code for

View File

@@ -14,14 +14,14 @@ export ALAMEDA := $(CURDIR)/../../pywii/Alameda
export PNG2TPL := $(CURDIR)/tools/png2tpl$(EXE) export PNG2TPL := $(CURDIR)/tools/png2tpl$(EXE)
export MKBNS := $(CURDIR)/tools/mkbns$(EXE) export MKBNS := $(CURDIR)/tools/mkbns$(EXE)
export LZ77 := $(CURDIR)/tools/lz77$(EXE) export LZ77 := $(CURDIR)/tools/lz77$(EXE)
export ADDIMD5 := python2 $(CURDIR)/tools/addimd5.py export ADDIMD5 := python3 $(CURDIR)/tools/addimd5.py
export ARCPACK := python2 $(PYWII)/arcpack.py export ARCPACK := python3 $(PYWII)/arcpack.py
export SOX := sox export SOX := sox
all: channel.imet all: channel.imet
channel.imet: build/data.arc names.txt tools/join-imet.py 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 build/data.arc : build/data/meta/icon.bin build/data/meta/banner.bin build/data/meta/sound.bin
$(ARCPACK) $@ build/data $(ARCPACK) $@ build/data
@@ -45,9 +45,9 @@ build/%.raw : sound/%.wav
$(SOX) $< -r 32000 -c 2 -e signed-integer -b 16 -t raw $@ $(SOX) $< -r 32000 -c 2 -e signed-integer -b 16 -t raw $@
testi : channel.imet testi : channel.imet
python2 $(ALAMEDA)/Alameda.py channel.imet icon python3 $(ALAMEDA)/Alameda.py channel.imet icon
testb : channel.imet testb : channel.imet
python2 $(ALAMEDA)/Alameda.py channel.imet banner python3 $(ALAMEDA)/Alameda.py channel.imet banner
$(PNG2TPL): tools/*.c $(PNG2TPL): tools/*.c
$(MAKE) -C tools png2tpl$(EXE) $(MAKE) -C tools png2tpl$(EXE)

View File

@@ -19,7 +19,7 @@ endif
../build/$(TYPE)/arc/blyt/$(TYPE).brlyt $(ANIMS) : mk$(TYPE).py ../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/anim ] && mkdir -p ../build/$(TYPE)/arc/anim || true
@[ ! -d ../build/$(TYPE)/arc/blyt ] && mkdir -p ../build/$(TYPE)/arc/blyt || 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) ../build/$(TYPE).arc : $(TPLS) ../build/$(TYPE)/arc/blyt/$(TYPE).brlyt $(ANIMS)
$(ARCPACK) ../build/$(TYPE).arc ../build/$(TYPE) $(ARCPACK) ../build/$(TYPE).arc ../build/$(TYPE)

View File

@@ -244,7 +244,7 @@ class BubbleInstance:
for i in tps: for i in tps:
if len(i.Triplets) > 0: if len(i.Triplets) > 0:
if i.Triplets[-1][0] >= self.Start: 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") raise RuntimeError("We Have A Problem")
brlan.Anim[self.Picture.Name][Brlan.A_COORD][Brlan.C_X].Triplets.append((self.Start, self.X, 0)) 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) #print "Freeing instance: [%f-%f]"%(user.Start,user.End)
tis[i] = pic, None tis[i] = pic, None
def printinstances(self): def printinstances(self):
print "Type Instances:" print("Type Instances:")
for tid, tis in enumerate(self.TypeInstances): 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): for i, ti in enumerate(tis):
pic, user = ti pic, user = ti
if user is None: if user is None:
print " %d: Picture %s, free"%(i,pic.Name) print(" %d: Picture %s, free"%(i,pic.Name))
else: 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): def render(self):
for t,c in self.BubbleTypes: for t,c in self.BubbleTypes:
t.makemat(self.Brlyt) t.makemat(self.Brlyt)
@@ -330,9 +330,9 @@ class BubbleCollection:
i.render(self.Brlan) i.render(self.Brlan)
#self.printinstances() #self.printinstances()
print "Fake Start",fakeStart print("Fake Start",fakeStart)
print "Loop Start",loopStart print("Loop Start",loopStart)
print "Loop End",loopEnd print("Loop End",loopEnd)
col = BubbleCollection(brlyt, brlan, bubblepane) col = BubbleCollection(brlyt, brlan, bubblepane)
col.addtype(BubbleType("abubble1", 48, 48),1) col.addtype(BubbleType("abubble1", 48, 48),1)
@@ -374,10 +374,10 @@ for i in col.Instances:
col.render() col.render()
brldata = brlyt.Pack() brldata = brlyt.Pack()
open(sys.argv[1],"w").write(brldata) open(sys.argv[1],"wb").write(brldata)
bradata = brlan.Pack(loopStart) bradata = brlan.Pack(loopStart)
open(sys.argv[2],"w").write(bradata) open(sys.argv[2],"wb").write(bradata)
bradata = brlan.Pack(loopStart, loopEnd) bradata = brlan.Pack(loopStart, loopEnd)
open(sys.argv[3],"w").write(bradata) open(sys.argv[3],"wb").write(bradata)

View File

@@ -111,7 +111,7 @@ brlyt.RootPane.Add(tit)
brldata = brlyt.Pack() brldata = brlyt.Pack()
open(sys.argv[1],"w").write(brldata) open(sys.argv[1],"wb").write(brldata)
brlan = Brlan() 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) bradata = brlan.Pack(60*16)
for a,b,c in brlan.Anim['waveb'][Brlan.A_COORD][Brlan.C_X].Triplets: 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)

View File

@@ -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(hdr)
f2.write(digest) f2.write(digest)
f2.write(data) f2.write(data)

View File

@@ -1,8 +1,8 @@
import os, sys, struct, md5 import os, sys, struct, hashlib
output, datafile, iconarc, bannerarc, soundbns, namesfile = sys.argv[1:] output, datafile, iconarc, bannerarc, soundbns, namesfile = sys.argv[1:]
data = open(datafile,"r").read() data = open(datafile,"rb").read()
names={} names={}
@@ -11,7 +11,7 @@ for i in open(namesfile,"r"):
while b[-1] == "\n": while b[-1] == "\n":
b = b[:-1] b = b[:-1]
b = b.replace("\\n","\n") b = b.replace("\\n","\n")
names[a] = b.decode("utf-8") names[a] = b
def getsize(x): def getsize(x):
return os.stat(x).st_size return os.stat(x).st_size
@@ -20,29 +20,29 @@ def pad(x,l):
if len(x) > l: if len(x) > l:
raise ValueError("%d > %d",len(x),l) raise ValueError("%d > %d",len(x),l)
n = l-len(x) n = l-len(x)
return x + "\x00"*n return x + b"\x00"*n
imet = "\x00"*0x40 imet = b"\x00"*0x40
imet += struct.pack(">4sIIIIII","IMET",0x600,3,getsize(iconarc),getsize(bannerarc),getsize(soundbns),1) 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"]: for i in ["jp", "en", "de", "fr", "sp", "it", "nl", "cn", None, "ko"]:
try: try:
imet += pad(names[i].encode("UTF-16BE"),0x54) imet += pad(names[i].encode("UTF-16BE"),0x54)
except KeyError: except KeyError:
imet += "\x00"*0x54 imet += b"\x00"*0x54
imet += "\x00"*(0x600 - len(imet)) 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(imet)
f.write(data) f.write(data)
fsize = f.tell() fsize = f.tell()
if (fsize % 20) != 0: if (fsize % 20) != 0:
f.write("\x00"*(20-(fsize%20))) f.write(b"\x00"*(20-(fsize%20)))
f.close() f.close()

View File

@@ -17,20 +17,20 @@ import pywii as wii
def LZ77Decompress(data): def LZ77Decompress(data):
inp = 0 inp = 0
dlen = len(data) dlen = len(data)
data += '\0' * 16 data += b'\0' * 16
ret = [] ret = []
while inp < dlen: while inp < dlen:
bitmask = ord(data[inp]) bitmask = data[inp]
inp += 1 inp += 1
for i in xrange(8): for i in range(8):
if bitmask & 0x80: if bitmask & 0x80:
rep = ord(data[inp]) rep = data[inp]
repLength = (rep >> 4) + 3 repLength = (rep >> 4) + 3
inp += 1 inp += 1
repOff = ord(data[inp]) | ((rep & 0x0F) << 8) repOff = data[inp] | ((rep & 0x0F) << 8)
inp += 1 inp += 1
assert repOff <= len(ret) assert repOff <= len(ret)
@@ -44,13 +44,13 @@ def LZ77Decompress(data):
bitmask <<= 1 bitmask <<= 1
return ''.join(ret) return bytes(ret)
class U8(object): class U8(object):
class U8Header(Struct): class U8Header(Struct):
__endian__ = Struct.BE __endian__ = Struct.BE
def __format__(self): def __format__(self):
self.Tag = Struct.string(4) self.Tag = Struct.uint32
self.RootNode = Struct.uint32 self.RootNode = Struct.uint32
self.HeaderSize = Struct.uint32 self.HeaderSize = Struct.uint32
self.DataOffset = Struct.uint32 self.DataOffset = Struct.uint32
@@ -76,7 +76,8 @@ class U8(object):
u8.unpack(data[pos:pos+len(u8)]) u8.unpack(data[pos:pos+len(u8)])
pos += len(u8) pos += len(u8)
assert u8.Tag == 'U\xAA8-' print(hex(u8.Tag))
assert u8.Tag == 0x55aa382d
pos += u8.RootNode - 0x20 pos += u8.RootNode - 0x20
root = self.U8Node() root = self.U8Node()
@@ -84,7 +85,7 @@ class U8(object):
pos += len(root) pos += len(root)
children = [] children = []
for i in xrange(root.Size - 1): for i in range(root.Size - 1):
child = self.U8Node() child = self.U8Node()
child.unpack(data[pos:pos+len(child)]) child.unpack(data[pos:pos+len(child)])
pos += len(child) pos += len(child)
@@ -98,7 +99,7 @@ class U8(object):
path = ['.'] path = ['.']
pathDepth = [root.Size - 1] pathDepth = [root.Size - 1]
for offset,child in enumerate(children): for offset,child in enumerate(children):
name = stringTable[child.NameOffset:].split('\0', 1)[0] name = stringTable[child.NameOffset:].split(b'\0', 1)[0].decode("ascii")
if child.Type == 0x0100: if child.Type == 0x0100:
path.append(name) path.append(name)
pathDepth.append(child.Size-offset-1) pathDepth.append(child.Size-offset-1)
@@ -136,7 +137,7 @@ def IMD5(data):
assert imd5.Tag == 'IMD5' assert imd5.Tag == 'IMD5'
pos = len(imd5) pos = len(imd5)
if data[pos:pos+4] == 'LZ77': if data[pos:pos+4] == b'LZ77':
return LZ77Decompress(data[pos+8:]) return LZ77Decompress(data[pos+8:])
else: else:
return data[pos:] return data[pos:]
@@ -145,7 +146,7 @@ class TPL(object):
class TPLHeader(Struct): class TPLHeader(Struct):
__endian__ = Struct.BE __endian__ = Struct.BE
def __format__(self): def __format__(self):
self.Magic = Struct.string(4) self.Magic = Struct.uint32
self.Count = Struct.uint32 self.Count = Struct.uint32
self.Size = Struct.uint32 self.Size = Struct.uint32
@@ -188,10 +189,10 @@ class TPL(object):
header.unpack(data[:len(header)]) header.unpack(data[:len(header)])
pos = len(header) pos = len(header)
assert header.Magic == '\x00\x20\xAF\x30' assert header.Magic == 0x0020AF30
assert header.Size == 0xc assert header.Size == 0xc
for i in xrange(header.Count): for i in range(header.Count):
offs = self.TexOffsets() offs = self.TexOffsets()
offs.unpack(data[pos:pos+len(offs)]) offs.unpack(data[pos:pos+len(offs)])
pos += len(offs) pos += len(offs)
@@ -221,26 +222,27 @@ class TPL(object):
elif format == 14: elif format == 14:
rgba = self.S3TC(data[texHeader.DataOff:], texHeader.Size) rgba = self.S3TC(data[texHeader.DataOff:], texHeader.Size)
else: else:
print 'Unknown texture format', format print('Unknown texture format', format)
if rgba == None: if rgba == None:
rgba = '\0\0\0\0' * texHeader.Size[0] * texHeader.Size[1] rgba = b'\0\0\0\0' * texHeader.Size[0] * texHeader.Size[1]
image = ImageData(texHeader.Size[1], texHeader.Size[0], 'RGBA', rgba) image = ImageData(texHeader.Size[1], texHeader.Size[0], 'RGBA', rgba)
print format print(format)
return image return image
def I4(self, data, (y, x)): def I4(self, data, xxx_todo_changeme):
out = [0 for i in xrange(x * y)] (y, x) = xxx_todo_changeme
out = [0 for i in range(x * y)]
outp = 0 outp = 0
inp = 0 inp = 0
for i in xrange(0, y, 8): for i in range(0, y, 8):
for j in xrange(0, x, 8): for j in range(0, x, 8):
ofs = 0 ofs = 0
for k in xrange(8): for k in range(8):
off = min(x - j, 8) off = min(x - j, 8)
for sub in xrange(0, off, 2): for sub in range(0, off, 2):
texel = ord(data[inp]) texel = data[inp]
high, low = texel >> 4, texel & 0xF high, low = texel >> 4, texel & 0xF
if (outp + ofs + sub) < (x*y): if (outp + ofs + sub) < (x*y):
out[outp + ofs + sub] = (high << 4) | (high << 20) | (high << 12) | 0xFF<<24 out[outp + ofs + sub] = (high << 4) | (high << 20) | (high << 12) | 0xFF<<24
@@ -252,23 +254,24 @@ class TPL(object):
inp += 1 inp += 1
ofs += x ofs += x
inp += (8 - off) / 2 inp += (8 - off) // 2
outp += off outp += off
outp += x * 7 outp += x * 7
return ''.join(Struct.uint32(p) for p in out) return b''.join(Struct.uint32(p) for p in out)
def I8(self, data, (y, x)): def I8(self, data, xxx_todo_changeme1):
out = [0 for i in xrange(x * y*2)] (y, x) = xxx_todo_changeme1
out = [0 for i in range(x * y*2)]
outp = 0 outp = 0
inp = 0 inp = 0
for i in xrange(0, y, 4): for i in range(0, y, 4):
for j in xrange(0, x, 4): for j in range(0, x, 4):
ofs = 0 ofs = 0
for k in xrange(4): for k in range(4):
off = min(x - j, 4) off = min(x - j, 4)
for sub in xrange(off): for sub in range(off):
texel = ord(data[inp]) texel = data[inp]
out[outp + ofs + sub] = (texel << 24) | (texel << 16) | (texel << 8) | 0xFF out[outp + ofs + sub] = (texel << 24) | (texel << 16) | (texel << 8) | 0xFF
inp += 1 inp += 1
@@ -277,19 +280,20 @@ class TPL(object):
outp += off outp += off
outp += x * 3 outp += x * 3
return ''.join(Struct.uint32(p) for p in out) return b''.join(Struct.uint32(p) for p in out)
def IA4(self, data, (y, x)): def IA4(self, data, xxx_todo_changeme2):
out = [0 for i in xrange(x * y)] (y, x) = xxx_todo_changeme2
out = [0 for i in range(x * y)]
outp = 0 outp = 0
inp = 0 inp = 0
for i in xrange(0, y, 4): for i in range(0, y, 4):
for j in xrange(0, x, 8): for j in range(0, x, 8):
ofs = 0 ofs = 0
for k in xrange(4): for k in range(4):
off = min(x - j, 8) off = min(x - j, 8)
for sub in xrange(off): for sub in range(off):
texel = ord(data[inp]) texel = data[inp]
alpha, inte = texel >> 4, texel & 0xF alpha, inte = texel >> 4, texel & 0xF
if (outp + ofs + sub) < (x*y): if (outp + ofs + sub) < (x*y):
out[outp + ofs + sub] = (inte << 4) | (inte << 12) | (inte << 20) | (alpha << 28) out[outp + ofs + sub] = (inte << 4) | (inte << 12) | (inte << 20) | (alpha << 28)
@@ -300,18 +304,19 @@ class TPL(object):
outp += off outp += off
outp += x * 3 outp += x * 3
return ''.join(Struct.uint32(p) for p in out) return b''.join(Struct.uint32(p) for p in out)
def IA8(self, data, (y, x)): def IA8(self, data, xxx_todo_changeme3):
out = [0 for i in xrange(x * y)] (y, x) = xxx_todo_changeme3
out = [0 for i in range(x * y)]
outp = 0 outp = 0
inp = 0 inp = 0
for i in xrange(0, y, 4): for i in range(0, y, 4):
for j in xrange(0, x, 4): for j in range(0, x, 4):
ofs = 0 ofs = 0
for k in xrange(4): for k in range(4):
off = min(x - j, 4) off = min(x - j, 4)
for sub in xrange(off): for sub in range(off):
if (outp + ofs + sub) < (x*y): if (outp + ofs + sub) < (x*y):
texel = Struct.uint16(data[inp:inp + 2], endian='>') texel = Struct.uint16(data[inp:inp + 2], endian='>')
p = (texel & 0xFF) p = (texel & 0xFF)
@@ -326,18 +331,19 @@ class TPL(object):
outp += off outp += off
outp += x * 3 outp += x * 3
return ''.join(Struct.uint32(p) for p in out) return b''.join(Struct.uint32(p) for p in out)
def RGB565(self, data, (y, x)): def RGB565(self, data, xxx_todo_changeme4):
out = [0 for i in xrange(x * y)] (y, x) = xxx_todo_changeme4
out = [0 for i in range(x * y)]
outp = 0 outp = 0
inp = 0 inp = 0
for i in xrange(0, y, 4): for i in range(0, y, 4):
for j in xrange(0, x, 4): for j in range(0, x, 4):
ofs = 0 ofs = 0
for k in xrange(4): for k in range(4):
off = min(x - j, 4) off = min(x - j, 4)
for sub in xrange(off): for sub in range(off):
if (outp + ofs + sub) < (x*y): if (outp + ofs + sub) < (x*y):
texel = Struct.uint16(data[inp:inp + 2], endian='>') texel = Struct.uint16(data[inp:inp + 2], endian='>')
p = ((texel >> 11) & 0x1F) << 3 p = ((texel >> 11) & 0x1F) << 3
@@ -352,18 +358,19 @@ class TPL(object):
outp += off outp += off
outp += x * 3 outp += x * 3
return ''.join(Struct.uint32(p) for p in out) return b''.join(Struct.uint32(p) for p in out)
def RGB5A3(self, data, (y, x)): def RGB5A3(self, data, xxx_todo_changeme5):
out = [0 for i in xrange(x * y)] (y, x) = xxx_todo_changeme5
out = [0 for i in range(x * y)]
outp = 0 outp = 0
inp = 0 inp = 0
for i in xrange(0, y, 4): for i in range(0, y, 4):
for j in xrange(0, x, 4): for j in range(0, x, 4):
ofs = 0 ofs = 0
for k in xrange(4): for k in range(4):
off = min(x - j, 4) off = min(x - j, 4)
for sub in xrange(off): for sub in range(off):
texel = Struct.uint16(data[inp:inp + 2], endian='>') texel = Struct.uint16(data[inp:inp + 2], endian='>')
if texel & 0x8000: if texel & 0x8000:
p = ((texel >> 10) & 0x1F) << 3 p = ((texel >> 10) & 0x1F) << 3
@@ -384,18 +391,19 @@ class TPL(object):
outp += off outp += off
outp += x * 3 outp += x * 3
return ''.join(Struct.uint32(p) for p in out) return b''.join(Struct.uint32(p) for p in out)
def RGBA8(self, data, (y, x)): def RGBA8(self, data, xxx_todo_changeme6):
out = [0 for i in xrange(x * y)] (y, x) = xxx_todo_changeme6
out = [0 for i in range(x * y)]
outp = 0 outp = 0
inp = 0 inp = 0
for i in xrange(0, y, 4): for i in range(0, y, 4):
for j in xrange(0, x, 4): for j in range(0, x, 4):
ofs = 0 ofs = 0
for k in xrange(4): for k in range(4):
off = min(x - j, 4) off = min(x - j, 4)
for sub in xrange(off): for sub in range(off):
texel = Struct.uint16(data[inp:inp + 2], endian='>')<<16 texel = Struct.uint16(data[inp:inp + 2], endian='>')<<16
texel |= Struct.uint16(data[inp+32:inp + 34], endian='>') texel |= Struct.uint16(data[inp+32:inp + 34], endian='>')
if (outp + ofs + sub) < (x*y): if (outp + ofs + sub) < (x*y):
@@ -408,7 +416,7 @@ class TPL(object):
inp += 32 inp += 32
outp += x * 3 outp += x * 3
return ''.join(Struct.uint32(p) for p in out) return b''.join(Struct.uint32(p) for p in out)
def unpack_rgb565(self,texel): def unpack_rgb565(self,texel):
b = (texel&0x1f)<<3 b = (texel&0x1f)<<3
@@ -420,24 +428,25 @@ class TPL(object):
return (0xff<<24) | (b<<16) | (g<<8) | r return (0xff<<24) | (b<<16) | (g<<8) | r
def icolor(self,a,b,fa,fb,fc): def icolor(self,a,b,fa,fb,fc):
c = 0 c = 0
for i in xrange(0,32,8): for i in range(0,32,8):
xa = (a>>i)&0xff xa = (a>>i)&0xff
xb = (b>>i)&0xff xb = (b>>i)&0xff
xc = min(255,max(0,int((xa*fa + xb*fb)/fc))) xc = min(255,max(0,int((xa*fa + xb*fb)/fc)))
c |= xc<<i c |= xc<<i
return c return c
def S3TC(self, data, (y, x)): def S3TC(self, data, xxx_todo_changeme7):
out = [0 for i in xrange(x * y)] (y, x) = xxx_todo_changeme7
out = [0 for i in range(x * y)]
TILE_WIDTH = 8 TILE_WIDTH = 8
TILE_HEIGHT = 8 TILE_HEIGHT = 8
inp = 0 inp = 0
outp = 0 outp = 0
for i in xrange(0, y, TILE_HEIGHT): for i in range(0, y, TILE_HEIGHT):
for j in xrange(0, x, TILE_WIDTH): for j in range(0, x, TILE_WIDTH):
maxw = min(x - j,TILE_WIDTH) maxw = min(x - j,TILE_WIDTH)
for k in xrange(2): for k in range(2):
for l in xrange(2): for l in range(2):
rgb = [0,0,0,0] rgb = [0,0,0,0]
texel1 = Struct.uint16(data[inp:inp + 2], endian='>') texel1 = Struct.uint16(data[inp:inp + 2], endian='>')
texel2 = Struct.uint16(data[inp + 2:inp + 4], endian='>') texel2 = Struct.uint16(data[inp + 2:inp + 4], endian='>')
@@ -452,7 +461,7 @@ class TPL(object):
rgb[3] = 0 rgb[3] = 0
# color selection (00, 01, 10, 11) # color selection (00, 01, 10, 11)
cm = map(ord,data[inp+4:inp+8]) cm = list(data[inp+4:inp+8])
ofs = l*4 ofs = l*4
for n in range(4): for n in range(4):
if (ofs + outp)<(x*y): if (ofs + outp)<(x*y):
@@ -471,7 +480,7 @@ class TPL(object):
outp += maxw - x * 8 outp += maxw - x * 8
outp += x * (TILE_HEIGHT - 1) outp += x * (TILE_HEIGHT - 1)
return ''.join(Struct.uint32(p) for p in out) return b''.join(Struct.uint32(p) for p in out)
class Object(object): class Object(object):
def __init__(self, name): def __init__(self, name):
@@ -554,7 +563,7 @@ class ItemList(object):
pos = 8 pos = 8
count = self.__unpkcnt__(data[pos:]) count = self.__unpkcnt__(data[pos:])
pos = self.__getlistoff__(data[pos:]) pos = self.__getlistoff__(data[pos:])
for i in xrange(count): for i in range(count):
off = Struct.uint32(data[pos:pos+4], endian='>') + self.OFFSET off = Struct.uint32(data[pos:pos+4], endian='>') + self.OFFSET
if i == (count-1): if i == (count-1):
next = len(data) next = len(data)
@@ -568,11 +577,11 @@ class ItemList(object):
def pack(self,extra=None): def pack(self,extra=None):
extradata = "" extradata = b""
if extra is not None: if extra is not None:
extradata = extra.pack() extradata = extra.pack()
data = "" data = b""
offsets = [] offsets = []
@@ -583,9 +592,9 @@ class ItemList(object):
listlen = len(self.Items) * self.LSIZE listlen = len(self.Items) * self.LSIZE
head = self.__mkheader__() head = self.__mkheader__()
outdata = "" outdata = b""
if self.IS_ATOM: if self.IS_ATOM:
outdata += self.FOURCC + Struct.uint32((len(extradata) + listlen + len(data) + 8 + len(head) + 3) &(~3), endian='>') outdata += self.FOURCC.encode("ascii") + Struct.uint32((len(extradata) + listlen + len(data) + 8 + len(head) + 3) &(~3), endian='>')
outdata += head outdata += head
dataoff = len(outdata) + listlen - self.OFFSET dataoff = len(outdata) + listlen - self.OFFSET
@@ -594,18 +603,18 @@ class ItemList(object):
for n in offsets: for n in offsets:
outdata += Struct.uint32(n + dataoff, endian='>') outdata += Struct.uint32(n + dataoff, endian='>')
if self.LSIZE > 4: if self.LSIZE > 4:
outdata += (self.LSIZE-4)*"\x00" outdata += (self.LSIZE-4)*b"\x00"
outdata += data outdata += data
outdata += extradata outdata += extradata
if len(outdata)%4 != 0: if len(outdata)%4 != 0:
outdata += (4-len(outdata)%4)*"\x00" outdata += (4-len(outdata)%4)*b"\x00"
return outdata return outdata
def __mkheader__(self): def __mkheader__(self):
return Struct.uint16(len(self.Items), endian='>') + "\x00\x00" return Struct.uint16(len(self.Items), endian='>') + b"\x00\x00"
def __unpkcnt__(self, data): def __unpkcnt__(self, data):
return Struct.uint16(data[0:2], endian='>') return Struct.uint16(data[0:2], endian='>')
@@ -668,12 +677,12 @@ class Brlyt(object):
ItemList.__init__(self, data) ItemList.__init__(self, data)
def unpack_item(self, i, data): def unpack_item(self, i, data):
fn = data.split('\0', 1)[0] fn = data.split(b'\0', 1)[0].decode("ascii")
print fn print(fn)
tex = TPL(self.Archive.Files['./arc/timg/' + fn.lower()]).Textures[0] tex = TPL(self.Archive.Files['./arc/timg/' + fn.lower()]).Textures[0]
self.Items.append(Brlyt.BrlytTexture(fn, tex)) self.Items.append(Brlyt.BrlytTexture(fn, tex))
def pack_item(self, i, item): def pack_item(self, i, item):
return item.Name + "\0" return item.Name.encode("ascii") + b"\0"
class BrlytMAT1(ItemList): class BrlytMAT1(ItemList):
LSIZE = 4 LSIZE = 4
@@ -709,20 +718,20 @@ class Brlyt(object):
self.m_8 = bool((value>>27) & 1) self.m_8 = bool((value>>27) & 1)
def show(self): def show(self):
print "Flags: %08x"%self.value print("Flags: %08x"%self.value)
print "ReserveGXMem(" print("ReserveGXMem(")
print " r4 =",self.NumTextures print(" r4 =",self.NumTextures)
print " r5 =",self.NumCoords print(" r5 =",self.NumCoords)
print " r6 =",self.m_2 print(" r6 =",self.m_2)
print " r7 =",self.m_3 print(" r7 =",self.m_3)
print " r8 =",self.m_4 print(" r8 =",self.m_4)
print " r9 =",self.m_5 print(" r9 =",self.m_5)
print " r10 =",self.m_6 print(" r10 =",self.m_6)
print " 0x8(%sp) =",self.m_7 print(" 0x8(%sp) =",self.m_7)
print " 0xC(%sp) =",self.m_8 print(" 0xC(%sp) =",self.m_8)
print " 0x10(%sp) =",self.m_9 print(" 0x10(%sp) =",self.m_9)
print " 0x14(%sp) =",self.m_10 print(" 0x14(%sp) =",self.m_10)
print ")" print(")")
def pack(self): def pack(self):
val = 0 val = 0
@@ -743,7 +752,7 @@ class Brlyt(object):
__endian__ = Struct.BE __endian__ = Struct.BE
def __format__(self): def __format__(self):
self.Name = Struct.string(0x14) self.Name = Struct.string(0x14, stripNulls=True)
self.Color1 = Struct.uint16[4] self.Color1 = Struct.uint16[4]
self.Color2 = Struct.uint16[4] self.Color2 = Struct.uint16[4]
self.Color3 = Struct.uint16[4] self.Color3 = Struct.uint16[4]
@@ -822,63 +831,63 @@ class Brlyt(object):
for i in range(self.FlagData.NumTextures): for i in range(self.FlagData.NumTextures):
texid = Struct.uint16(data[ptr:ptr+2], endian='>') texid = Struct.uint16(data[ptr:ptr+2], endian='>')
texcs = Struct.uint8(data[ptr+2], endian='>') texcs = data[ptr+2]
texct = Struct.uint8(data[ptr+3], endian='>') texct = data[ptr+3]
print " * Texture: %04x %d %d"%(texid,texcs,texct) print(" * Texture: %04x %d %d"%(texid,texcs,texct))
self.Textures.append((texid,texcs,texct)) self.Textures.append((texid,texcs,texct))
ptr += 4 ptr += 4
for i in range(self.FlagData.NumCoords): for i in range(self.FlagData.NumCoords):
dat = [] dat = []
for j in range(5): for j in range(5):
dat.append(Struct.float(data[ptr+j*4:ptr+j*4+4], endian='>')) dat.append(Struct.float(data[ptr+j*4:ptr+j*4+4], endian='>'))
print " * Coords: [",', '.join(["%f"%x for x in dat]),"]" print(" * Coords: [",', '.join(["%f"%x for x in dat]),"]")
ptr += 0x14 ptr += 0x14
self.TextureCoords.append(dat) self.TextureCoords.append(dat)
for i in range(self.FlagData.m_2): for i in range(self.FlagData.m_2):
dat = Struct.uint32(data[ptr:ptr+4], endian='>') dat = Struct.uint32(data[ptr:ptr+4], endian='>')
self.SthB.append(dat) self.SthB.append(dat)
print " * SthB: %08x"%dat print(" * SthB: %08x"%dat)
ptr += 0x04 ptr += 0x04
if self.FlagData.m_7: if self.FlagData.m_7:
self.SthI = Struct.uint32(data[ptr:ptr+4], endian='>') self.SthI = Struct.uint32(data[ptr:ptr+4], endian='>')
print " SthI: %08x"%self.SthI print(" SthI: %08x"%self.SthI)
ptr += 0x04 ptr += 0x04
if self.FlagData.m_8: if self.FlagData.m_8:
self.SthJ = Struct.uint32(data[ptr:ptr+4], endian='>') self.SthJ = Struct.uint32(data[ptr:ptr+4], endian='>')
print " SthJ: %08x"%self.SthJ print(" SthJ: %08x"%self.SthJ)
ptr += 0x04 ptr += 0x04
if self.FlagData.m_4: if self.FlagData.m_4:
self.SthC = Struct.uint32(data[ptr:ptr+4], endian='>') self.SthC = Struct.uint32(data[ptr:ptr+4], endian='>')
print " SthC: %08x"%self.SthC print(" SthC: %08x"%self.SthC)
ptr += 0x04 ptr += 0x04
for i in range(self.FlagData.m_6): for i in range(self.FlagData.m_6):
dat = [] dat = []
for j in range(5): for j in range(5):
dat.append(Struct.float(data[ptr+j*4:ptr+j*4+4], endian='>')) dat.append(Struct.float(data[ptr+j*4:ptr+j*4+4], endian='>'))
self.SthD.append(dat) self.SthD.append(dat)
print " * SthD: [",', '.join(["%f"%x for x in dat]),"]" print(" * SthD: [",', '.join(["%f"%x for x in dat]),"]")
ptr += 0x14 ptr += 0x14
for i in range(self.FlagData.m_5): for i in range(self.FlagData.m_5):
dat = Struct.uint32(data[ptr:ptr+4], endian='>') dat = Struct.uint32(data[ptr:ptr+4], endian='>')
self.SthE.append(dat) self.SthE.append(dat)
print " * SthE: %08x"%dat print(" * SthE: %08x"%dat)
ptr += 0x04 ptr += 0x04
for i in range(self.FlagData.m_3): for i in range(self.FlagData.m_3):
dat = [] dat = []
for j in range(4): for j in range(4):
dat.append(Struct.uint32(data[ptr+j*4:ptr+j*4+4], endian='>')) dat.append(Struct.uint32(data[ptr+j*4:ptr+j*4+4], endian='>'))
self.SthF.append(dat) self.SthF.append(dat)
print " * SthF: [",', '.join(["%08x"%x for x in dat]),"]" print(" * SthF: [",', '.join(["%08x"%x for x in dat]),"]")
ptr += 0x10 ptr += 0x10
if self.FlagData.m_9: if self.FlagData.m_9:
dat = Struct.uint32(data[ptr:ptr+4], endian='>') dat = Struct.uint32(data[ptr:ptr+4], endian='>')
self.SthG = dat self.SthG = dat
print " SthG: %08x"%dat print(" SthG: %08x"%dat)
ptr += 0x04 ptr += 0x04
if self.FlagData.m_10: if self.FlagData.m_10:
dat = Struct.uint32(data[ptr:ptr+4], endian='>') dat = Struct.uint32(data[ptr:ptr+4], endian='>')
self.SthH = dat self.SthH = dat
print " SthH: %08x"%dat print(" SthH: %08x"%dat)
ptr += 0x04 ptr += 0x04
#assert ptr == len(data) #assert ptr == len(data)
@@ -903,7 +912,7 @@ class Brlyt(object):
hdr = Brlyt.BrlytMatHeader() hdr = Brlyt.BrlytMatHeader()
hdr.Name = self.Name + "\x00"*(0x14-len(self.Name)) hdr.Name = self.Name.encode("ascii") + b"\x00"*(0x14-len(self.Name))
hdr.Color1 = self.Color1 hdr.Color1 = self.Color1
hdr.Color2 = self.Color2 hdr.Color2 = self.Color2
hdr.Color3 = self.Color3 hdr.Color3 = self.Color3
@@ -947,16 +956,21 @@ class Brlyt(object):
StdAtom.__format__(self) StdAtom.__format__(self)
self.Flags = Struct.uint16 self.Flags = Struct.uint16
self.Alpha = Struct.uint16 self.Alpha = Struct.uint16
self.Name = Struct.string(0x18) self.Name = Struct.string(0x18, stripNulls=True)
self.Coords = Struct.float[10] self.Coords = Struct.float[10]
class BrlytPIC1(BrlytPAN1): class BrlytPIC1v1(BrlytPAN1):
FOURCC = "pic1" FOURCC = "pic1"
def __format__(self): def __format__(self):
Brlyt.BrlytPAN1.__format__(self) Brlyt.BrlytPAN1.__format__(self)
self.unk = Struct.uint8[16] self.unk = Struct.uint8[16]
self.Material = Struct.uint16 self.Material = Struct.uint16
self.Flags2 = Struct.uint16 self.Flags2 = Struct.uint16
class BrlytPIC1v2(BrlytPIC1v1):
FOURCC = "pic1"
def __format__(self):
Brlyt.BrlytPIC1v1.__format__(self)
self.MaterialCoords = Struct.float[8] self.MaterialCoords = Struct.float[8]
def __init__(self, archive, data, renderer): def __init__(self, archive, data, renderer):
@@ -969,7 +983,7 @@ class Brlyt(object):
self.Objects = {} self.Objects = {}
self.PanePath = [] self.PanePath = []
self.PaneId = 0 self.PaneId = 0
self.Language = "ENG" self.Language = b"ENG"
self.Renderer = renderer self.Renderer = renderer
if data != None: if data != None:
@@ -979,17 +993,17 @@ class Brlyt(object):
pos = 0 pos = 0
header = self.BrlytHeader() header = self.BrlytHeader()
header.unpack(data[:len(header)]) header.unpack(data[:len(header)])
print "BRLYT header:" print("BRLYT header:")
wii.chexdump(data[:len(header)]) wii.chexdump(data[:len(header)])
print " unk1: %08x"%header.Unk print(" unk1: %08x"%header.Unk)
print " unkc: %08x"%header.UnkCount print(" unkc: %08x"%header.UnkCount)
pos += len(header) pos += len(header)
print " %d atoms"%header.AtomCount print(" %d atoms"%header.AtomCount)
assert header.Magic == 'RLYT' assert header.Magic == 'RLYT'
for i in xrange(header.AtomCount): for i in range(header.AtomCount):
atom = StdAtom() atom = StdAtom()
atom.unpack(data[pos:pos+len(atom)]) atom.unpack(data[pos:pos+len(atom)])
@@ -1011,7 +1025,7 @@ class Brlyt(object):
elif atom.FourCC == "grp1": elif atom.FourCC == "grp1":
self.GRP1(atomdata) self.GRP1(atomdata)
else: else:
print "Unknown FOURCC:",atom.FourCC print("Unknown FOURCC:",atom.FourCC)
wii.chexdump(atomdata) wii.chexdump(atomdata)
pos += atom.Size pos += atom.Size
@@ -1021,10 +1035,10 @@ class Brlyt(object):
if isinstance(object,Pane): if isinstance(object,Pane):
atoms += 1 atoms += 1
if isinstance(object,Picture): if isinstance(object,Picture):
atom = Brlyt.BrlytPIC1() atom = Brlyt.BrlytPIC1v2()
else: else:
atom = Brlyt.BrlytPAN1() atom = Brlyt.BrlytPAN1()
atom.Name = object.Name + "\x00"*(0x18-len(object.Name)) atom.Name = object.Name.encode("ascii") + b"\x00"*(0x18-len(object.Name))
atom.Alpha = int(object.Alpha * 256) atom.Alpha = int(object.Alpha * 256)
atom.Flags = object.Flags atom.Flags = object.Flags
atom.Coords = object.Coords atom.Coords = object.Coords
@@ -1032,17 +1046,17 @@ class Brlyt(object):
atom.Flags2 = object.Flags2 atom.Flags2 = object.Flags2
atom.Material = object.Material atom.Material = object.Material
atom.unk = object.Unk atom.unk = object.Unk
atom.MaterialCoords = sum(map(list,object.MaterialCoords),[]) atom.MaterialCoords = sum(object.MaterialCoords,())
data = atom.pack() data = atom.pack()
if len(object.Children) > 0: if len(object.Children) > 0:
atoms += 2 atoms += 2
data += "pas1\x00\x00\x00\x08" data += b"pas1\x00\x00\x00\x08"
for child in object.Children: for child in object.Children:
ac, dc = self._PackObject(child) ac, dc = self._PackObject(child)
data += dc data += dc
atoms += ac atoms += ac
data += "pae1\x00\x00\x00\x08" data += b"pae1\x00\x00\x00\x08"
return atoms, data return atoms, data
else: else:
raise ValueError("Unknown object: "+repr(object)) raise ValueError("Unknown object: "+repr(object))
@@ -1055,7 +1069,7 @@ class Brlyt(object):
header.Magic = "RLYT" header.Magic = "RLYT"
header.AtomCount = 0 header.AtomCount = 0
data = "" data = b""
data += self.mkLYT1() data += self.mkLYT1()
header.AtomCount+=1 header.AtomCount+=1
@@ -1070,7 +1084,7 @@ class Brlyt(object):
header.AtomCount += atoms header.AtomCount += atoms
#uuugly. TODO: fix this crap. #uuugly. TODO: fix this crap.
data += "grp1\x00\x00\x00\x1cRootGroup\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" data += b"grp1\x00\x00\x00\x1cRootGroup\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
header.AtomCount += 1 header.AtomCount += 1
header.Size = len(data) + len(header) header.Size = len(data) + len(header)
@@ -1098,7 +1112,7 @@ class Brlyt(object):
lyt1.unpack(data) lyt1.unpack(data)
self.Width = lyt1.Width self.Width = lyt1.Width
self.Height = lyt1.Height self.Height = lyt1.Height
print "LYT1: %f x %f, flag %d"%(self.Width, self.Height, lyt1.Flag) print("LYT1: %f x %f, flag %d"%(self.Width, self.Height, lyt1.Flag))
self.Renderer.Create(int(self.Width), int(self.Height)) self.Renderer.Create(int(self.Width), int(self.Height))
def TXL1(self, data): def TXL1(self, data):
@@ -1107,13 +1121,13 @@ class Brlyt(object):
i.create_texture() i.create_texture()
def ApplyMask(self, image, mask): def ApplyMask(self, image, mask):
print "Making mask:",image,mask print("Making mask:",image,mask)
print image.width,image.height,mask.width,mask.height print(image.width,image.height,mask.width,mask.height)
if image.height != mask.height or image.width != mask.width: if image.height != mask.height or image.width != mask.width:
raise ValueError("Mask dimensions must be equal to mask dimensions") raise ValueError("Mask dimensions must be equal to mask dimensions")
newdata = [0 for x in xrange(image.height * image.width * 4)] newdata = [0 for x in range(image.height * image.width * 4)]
for pix in xrange(image.height * image.width): for pix in range(image.height * image.width):
newdata[pix*4 + 0] = image.data[pix*4 + 0] newdata[pix*4 + 0] = image.data[pix*4 + 0]
newdata[pix*4 + 1] = image.data[pix*4 + 1] newdata[pix*4 + 1] = image.data[pix*4 + 1]
newdata[pix*4 + 2] = image.data[pix*4 + 2] newdata[pix*4 + 2] = image.data[pix*4 + 2]
@@ -1136,8 +1150,8 @@ class Brlyt(object):
wii.chexdump(data) wii.chexdump(data)
pane = Brlyt.BrlytPAN1() pane = Brlyt.BrlytPAN1()
pane.unpack(data) pane.unpack(data)
p = Pane(pane.Name.split('\0',1)[0], pane.Flags, pane.Alpha/256.0, pane.Coords) 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 print('Pane %s (flags %04x, alpha %f): ' % (p.Name, pane.Flags, pane.Alpha),pane.Coords)
self._addpane(p) self._addpane(p)
def PAS1(self, data): def PAS1(self, data):
@@ -1145,48 +1159,55 @@ class Brlyt(object):
if self.CurPane is None: if self.CurPane is None:
raise ValueError("No current pane!") raise ValueError("No current pane!")
self.PanePath.append(self.CurPane) self.PanePath.append(self.CurPane)
print "Pane start:",'.'.join(map(str,self.PanePath)) print("Pane start:",'.'.join(map(str,self.PanePath)))
self.CurPane = None self.CurPane = None
def PAE1(self, data): def PAE1(self, data):
print "Pane end:",'.'.join(map(str,self.PanePath)) print("Pane end:",'.'.join(map(str,self.PanePath)))
self.PanePath = self.PanePath[:-1] self.PanePath = self.PanePath[:-1]
def PIC1(self, data): def PIC1(self, data):
wii.chexdump(data) wii.chexdump(data)
pic = Brlyt.BrlytPIC1() if len(data) == len(Brlyt.BrlytPIC1v1()):
pic = Brlyt.BrlytPIC1v1()
else:
pic = Brlyt.BrlytPIC1v2()
pic.unpack(data) pic.unpack(data)
mc = []
for i in range(4): kw = {}
mc.append(pic.MaterialCoords[i*2:i*2+2]) if not isinstance(pic, Brlyt.BrlytPIC1v1):
print mc mc = []
p = Picture(pic.Name.split("\0",1)[0], pic.Flags, pic.Alpha/256.0, pic.Coords, pic.unk, pic.Material, pic.Flags2, mc) for i in range(4):
print repr(p.Name) mc.append(pic.MaterialCoords[i*2:i*2+2])
kw["matcoord"] = mc
p = Picture(pic.Name, pic.Flags, pic.Alpha/256.0, pic.Coords, pic.unk, pic.Material, pic.Flags2, *kw)
print(repr(p.Name))
mat = self.Materials[pic.Material] mat = self.Materials[pic.Material]
if mat is not None: if mat is not None:
self._addpane(p) self._addpane(p)
else: else:
print 'Picture %s with null material!' print('Picture %s with null material!')
def GRP1(self, data): def GRP1(self, data):
wii.chexdump(data) wii.chexdump(data)
if len(data) < 0x1c: if len(data) < 0x1c:
pass pass
lang = data[0x8:0x18].split('\0', 1)[0] lang = data[0x8:0x18].split(b'\0', 1)[0]
nitems = Struct.uint16(data[0x18:0x1a], endian='>') nitems = Struct.uint16(data[0x18:0x1a], endian='>')
p = 0x1c p = 0x1c
items = [] items = []
for i in xrange(nitems): for i in range(nitems):
items.append(data[p:].split('\0', 1)[0]) items.append(data[p:p+0x10].split(b'\0', 1)[0].decode("ascii"))
p += 0x10 p += 0x10
for i in items: for i in items:
try: if i not in self.Objects:
if lang != self.Language: print("Missing object:", i)
self.Objects[i].Enabled = False continue
else: if lang != self.Language:
self.Objects[i].Enabled = True self.Objects[i].Enabled = False
except: else:
pass self.Objects[i].Enabled = True
class Brlan(object): class Brlan(object):
A_COORD = "RLPA" A_COORD = "RLPA"
@@ -1222,7 +1243,7 @@ class Brlan(object):
assert header.Magic == 'RLAN' assert header.Magic == 'RLAN'
for i in xrange(header.AtomCount): for i in range(header.AtomCount):
atom = StdAtom() atom = StdAtom()
atom.unpack(data[pos:pos+len(atom)]) atom.unpack(data[pos:pos+len(atom)])
atomdata = data[pos:pos+atom.Size] atomdata = data[pos:pos+atom.Size]
@@ -1231,7 +1252,7 @@ class Brlan(object):
if atom.FourCC == 'pai1': if atom.FourCC == 'pai1':
self.PAI1(atomdata) self.PAI1(atomdata)
else: else:
print "Unknown animation atom: %s"%atom.FourCC print("Unknown animation atom: %s"%atom.FourCC)
class BrlanPAI1(ItemList): class BrlanPAI1(ItemList):
LSIZE=4 LSIZE=4
@@ -1240,7 +1261,7 @@ class Brlan(object):
HDRLEN=12 HDRLEN=12
def unpack(self, data): def unpack(self, data):
self.FrameCount = Struct.uint16(data[8:10], endian='>') self.FrameCount = Struct.uint16(data[8:10], endian='>')
print self.FrameCount print(self.FrameCount)
ItemList.unpack(self, data) ItemList.unpack(self, data)
def __mkheader__(self): def __mkheader__(self):
hdr = Struct.uint16(self.FrameCount, endian='>') hdr = Struct.uint16(self.FrameCount, endian='>')
@@ -1292,13 +1313,13 @@ class Brlan(object):
else: else:
ItemList.__init__(self, data) ItemList.__init__(self, data)
def unpack(self, data): def unpack(self, data):
self.Name = data[:0x14].split("\0",1)[0] self.Name = data[:0x14].split(b"\0",1)[0].decode("ascii")
print self.Name print(self.Name)
ItemList.unpack(self, data) ItemList.unpack(self, data)
def __mkheader__(self): def __mkheader__(self):
hdr = self.Name + "\x00" * (0x14-len(self.Name)) hdr = self.Name.encode("ascii") + b"\x00" * (0x14-len(self.Name))
hdr += Struct.uint8(len(self.Items), endian='>') hdr += Struct.uint8(len(self.Items), endian='>')
hdr += "\x00\x00\x00" hdr += b"\x00\x00\x00"
return hdr return hdr
def __unpkcnt__(self, data): def __unpkcnt__(self, data):
return Struct.uint8(data[0x14:0x15], endian='>') return Struct.uint8(data[0x14:0x15], endian='>')
@@ -1330,7 +1351,7 @@ class Brlan(object):
self.item = 0 self.item = 0
def __iter__(self): def __iter__(self):
return self return self
def next(self): def __next__(self):
if self.item == len(self.cl.Items): if self.item == len(self.cl.Items):
raise StopIteration() raise StopIteration()
else: else:
@@ -1344,13 +1365,13 @@ class Brlan(object):
else: else:
ItemList.__init__(self, data) ItemList.__init__(self, data)
def unpack(self, data): def unpack(self, data):
self.Type = data[0:4] self.Type = data[0:4].decode("ascii")
print " ",self.Type print(" ",self.Type)
ItemList.unpack(self, data) ItemList.unpack(self, data)
def __mkheader__(self): def __mkheader__(self):
hdr = self.Type hdr = self.Type.encode("ascii")
hdr += Struct.uint8(len(self.Items), endian='>') hdr += Struct.uint8(len(self.Items), endian='>')
hdr += "\x00\x00\x00" hdr += b"\x00\x00\x00"
return hdr return hdr
def __unpkcnt__(self, data): def __unpkcnt__(self, data):
return Struct.uint8(data[4:5], endian='>') return Struct.uint8(data[4:5], endian='>')
@@ -1383,18 +1404,18 @@ class Brlan(object):
self.Unk = Struct.uint16(data[2:4], endian='>') self.Unk = Struct.uint16(data[2:4], endian='>')
count = Struct.uint16(data[4:6], endian='>') count = Struct.uint16(data[4:6], endian='>')
pos = Struct.uint32(data[8:12], endian='>') pos = Struct.uint32(data[8:12], endian='>')
print " ",self.Type print(" ",self.Type)
if self.Unk == 0x200: if self.Unk == 0x200:
print " Triplets:" print(" Triplets:")
for i in range(count): for i in range(count):
F = Struct.float(data[pos+0:pos+4], endian='>') F = Struct.float(data[pos+0:pos+4], endian='>')
P = Struct.float(data[pos+4:pos+8], endian='>') P = Struct.float(data[pos+4:pos+8], endian='>')
D = Struct.float(data[pos+8:pos+12], endian='>') D = Struct.float(data[pos+8:pos+12], endian='>')
print " %11f %11f %11f"%(F,P,D) print(" %11f %11f %11f"%(F,P,D))
self.Triplets.append((F,P,D)) self.Triplets.append((F,P,D))
pos += 12 pos += 12
else: else:
print " Unknown format: %04x"%self.Unk print(" Unknown format: %04x"%self.Unk)
def pack(self, offset): def pack(self, offset):
self.Triplets.sort(key=lambda x: x[0]) self.Triplets.sort(key=lambda x: x[0])
t = self.Triplets t = self.Triplets
@@ -1411,7 +1432,7 @@ class Brlan(object):
out = Struct.uint16(self.Type, endian='>') out = Struct.uint16(self.Type, endian='>')
out += Struct.uint16(self.Unk, endian='>') out += Struct.uint16(self.Unk, endian='>')
out += Struct.uint16(len(self.Triplets), endian='>') out += Struct.uint16(len(self.Triplets), endian='>')
out += "\x00\x00" out += b"\x00\x00"
out += Struct.uint32(0xc, endian='>') out += Struct.uint32(0xc, endian='>')
for F,P,D in self.Triplets: for F,P,D in self.Triplets:
out += Struct.float(F-offset, endian='>') out += Struct.float(F-offset, endian='>')
@@ -1511,7 +1532,7 @@ class Renderer(object):
def Create(self, width, height): def Create(self, width, height):
self.Width = width self.Width = width
self.Height = height self.Height = height
print "Render: %f x %f"%(self.Width,self.Height) print("Render: %f x %f"%(self.Width,self.Height))
self.Window = BannerWindow(self.Width, self.Height) self.Window = BannerWindow(self.Width, self.Height)
self.Window.set_exclusive_mouse(False) self.Window.set_exclusive_mouse(False)
@@ -1523,7 +1544,7 @@ class Renderer(object):
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA) glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)
glEnable(GL_BLEND) glEnable(GL_BLEND)
glEnable(GL_TEXTURE_2D) glEnable(GL_TEXTURE_2D)
clock.set_fps_limit(60) #clock.set_fps_limit(60)
def Render(self, item, wireframe=False): def Render(self, item, wireframe=False):
@@ -1532,6 +1553,9 @@ class Renderer(object):
if isinstance(item, Picture): if isinstance(item, Picture):
mat = self.Brlyt.Materials[item.Material] mat = self.Brlyt.Materials[item.Material]
if not mat.Textures:
return
texture = self.Brlyt.Textures[mat.Textures[0][0]].GLTexture texture = self.Brlyt.Textures[mat.Textures[0][0]].GLTexture
mtc = mat.TextureCoords[0] mtc = mat.TextureCoords[0]
x, y, a, b, c, rot, xsc, ysc, xs, ys = item.Coords[:10] x, y, a, b, c, rot, xsc, ysc, xs, ys = item.Coords[:10]
@@ -1638,7 +1662,10 @@ class Renderer(object):
for set in self.Brlan.Anim: for set in self.Brlan.Anim:
for clss in set: for clss in set:
for anim in clss: for anim in clss:
#print set.Name, clss.Type, anim.Type, anim.calc(frame), frame if set.Name not in self.Brlyt.Objects:
print("Missing object for animation: %s (%s)" % (set.Name, clss.Type))
continue
#print(set.Name, clss.Type, anim.Type, anim.calc(frame), frame)
if clss.Type == Brlan.A_COORD: if clss.Type == Brlan.A_COORD:
self.Brlyt.Objects[set.Name].Coords[anim.Type] = anim.calc(frame) self.Brlyt.Objects[set.Name].Coords[anim.Type] = anim.calc(frame)
elif clss.Type == Brlan.A_PARM: elif clss.Type == Brlan.A_PARM:
@@ -1647,8 +1674,9 @@ class Renderer(object):
def MainLoop(self, loop): def MainLoop(self, loop):
frame = 0 frame = 0
print "Starting mainloop: loop =",loop print("Starting mainloop: loop =",loop)
print "Length in frames:",self.Brlan.Anim.FrameCount if self.Brlan:
print("Length in frames:",self.Brlan.Anim.FrameCount)
while not self.Window.has_exit: while not self.Window.has_exit:
self.Window.dispatch_events() self.Window.dispatch_events()
self.Window.clear() self.Window.clear()
@@ -1660,17 +1688,17 @@ class Renderer(object):
self.Render(self.Brlyt.RootPane,False) self.Render(self.Brlyt.RootPane,False)
#self.Render(self.Brlyt.RootPane,True) #self.Render(self.Brlyt.RootPane,True)
#clock.tick() clock.tick()
self.Window.flip() self.Window.flip()
if self.Brlan is not None: if self.Brlan is not None:
self.Animate(frame) self.Animate(frame)
if frame >= self.Brlan.Anim.FrameCount: if frame >= self.Brlan.Anim.FrameCount:
if not loop: if not loop:
print "Animation done!" print("Animation done!")
return True return True
else: else:
print "Looping..." print("Looping...")
frame = -1 frame = -1
frame += 1 frame += 1
@@ -1690,7 +1718,7 @@ class Alameda(object):
def __init__(self, fn, type='icon'): def __init__(self, fn, type='icon'):
renderer = Renderer() renderer = Renderer()
fp = file(fn, 'rb') fp = open(fn, 'rb')
imet = self.IMETHeader() imet = self.IMETHeader()
try: try:
@@ -1703,7 +1731,7 @@ class Alameda(object):
imet.unpack(fp.read(len(imet))) imet.unpack(fp.read(len(imet)))
assert imet.IMET == 'IMET' assert imet.IMET == 'IMET'
print 'English title: %s' % imet.Names[1] print('English title: %s' % imet.Names[1])
root = U8(fp.read()) root = U8(fp.read())
@@ -1722,14 +1750,22 @@ class Alameda(object):
else: else:
banner = U8(IMD5(root.Files['./meta/banner.bin'])) banner = U8(IMD5(root.Files['./meta/banner.bin']))
renderer.Brlyt = Brlyt(banner, banner.Files['./arc/blyt/banner.brlyt'], renderer) renderer.Brlyt = Brlyt(banner, banner.Files['./arc/blyt/banner.brlyt'], renderer)
loop = not banner.Files.has_key('./arc/anim/banner_start.brlan') loop = './arc/anim/banner_start.brlan' not in banner.Files
loop_anim = None
if not loop: if not loop:
renderer.Brlan = Brlan(banner.Files['./arc/anim/banner_start.brlan']) renderer.Brlan = Brlan(banner.Files['./arc/anim/banner_start.brlan'])
if './arc/anim/banner_loop.brlan' in banner.Files:
loop_anim = Brlan(banner.Files['./arc/anim/banner_loop.brlan'])
else: else:
renderer.Brlan = Brlan(banner.Files['./arc/anim/banner.brlan']) renderer.Brlan = Brlan(banner.Files['./arc/anim/banner.brlan'])
if './arc/anim/banner.brlan' in banner.Files:
renderer.Brlan = Brlan(banner.Files['./arc/anim/banner.brlan'])
else:
renderer.Brlan = None
if renderer.MainLoop(loop) and type == 'banner' and not loop: if renderer.MainLoop(loop) and type == 'banner' and not loop:
renderer.Brlan = Brlan(banner.Files['./arc/anim/banner_loop.brlan']) renderer.Brlan = loop_anim
renderer.MainLoop(True) renderer.MainLoop(True)
if __name__=='__main__': if __name__=='__main__':

View File

@@ -4,7 +4,7 @@ class StructType(tuple):
def __getitem__(self, value): def __getitem__(self, value):
return [self] * value return [self] * value
def __call__(self, value, endian='<'): def __call__(self, value, endian='<'):
if isinstance(value, str): if isinstance(value, bytes):
return struct.unpack(endian + tuple.__getitem__(self, 0), value[:tuple.__getitem__(self, 1)])[0] return struct.unpack(endian + tuple.__getitem__(self, 0), value[:tuple.__getitem__(self, 1)])[0]
else: else:
return struct.pack(endian + tuple.__getitem__(self, 0), value) return struct.pack(endian + tuple.__getitem__(self, 0), value)
@@ -12,8 +12,8 @@ class StructType(tuple):
class StructException(Exception): class StructException(Exception):
pass pass
class Struct(object): class Struct:
__slots__ = ('__attrs__', '__baked__', '__defs__', '__endian__', '__next__', '__sizes__', '__values__') __slots__ = ('__attrs__', '__baked__', '__defs__', '__next__', '__sizes__', '__values__')
int8 = StructType(('b', 1)) int8 = StructType(('b', 1))
uint8 = StructType(('B', 1)) uint8 = StructType(('B', 1))
@@ -49,7 +49,7 @@ class Struct(object):
else: else:
sys.settrace(self.__trace__) sys.settrace(self.__trace__)
func() func()
for name in func.func_code.co_varnames: for name in func.__code__.co_varnames:
value = self.__frame__.f_locals[name] value = self.__frame__.f_locals[name]
self.__setattr__(name, value) self.__setattr__(name, value)
@@ -186,11 +186,13 @@ class Struct(object):
if len(temp) != size: if len(temp) != size:
raise StructException('Expected %i byte string, got %i' % (size, len(temp))) raise StructException('Expected %i byte string, got %i' % (size, len(temp)))
if stripNulls:
temp = temp.rstrip(b'\0')
if encoding != None: if encoding != None:
temp = temp.decode(encoding) temp = temp.decode(encoding)
else:
if stripNulls: temp = temp.decode("ascii")
temp = temp.rstrip('\0')
if attrs[0] == '*': if attrs[0] == '*':
name = attrs[1:] name = attrs[1:]
@@ -231,7 +233,7 @@ class Struct(object):
def pack(self): def pack(self):
arraypos, arrayname = None, None arraypos, arrayname = None, None
ret = '' ret = b''
for i in range(len(self.__defs__)): for i in range(len(self.__defs__)):
sdef, size, attrs = self.__defs__[i], self.__sizes__[i], self.__attrs__[i] sdef, size, attrs = self.__defs__[i], self.__sizes__[i], self.__attrs__[i]
@@ -251,9 +253,11 @@ class Struct(object):
if encoding != None: if encoding != None:
temp = temp.encode(encoding) temp = temp.encode(encoding)
elif isinstance(temp, str):
temp = temp.encode("ascii")
temp = temp[:size] temp = temp[:size]
ret += temp + ('\0' * (size - len(temp))) ret += temp + (b'\0' * (size - len(temp)))
elif sdef == Struct: elif sdef == Struct:
if attrs[0] == '*': if attrs[0] == '*':
if arrayname != attrs: if arrayname != attrs:
@@ -299,16 +303,16 @@ if __name__=='__main__':
self.hax = HaxStruct self.hax = HaxStruct
test = TestStruct() test = TestStruct()
test.unpack('\xEF\xBE\xAD\xDE\x00\x00\x80\x3Fdeadbeef\x04\x00\x00\x00test\xCA\xFE\xBA\xBE\xBE\xBA\xFE\xCA') 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.foo == 0xDEADBEEF
assert test.bar == 1.0 assert test.bar == 1.0
assert test.baz == 'deadbeef' assert test.baz == b'deadbeef'
assert test.omg == 4 assert test.omg == 4
assert test.wtf == 'test' assert test.wtf == b'test'
assert test.hax.thing1 == 0xBEBAFECA assert test.hax.thing1 == 0xBEBAFECA
assert test.hax.thing2 == 0xCAFEBABE assert test.hax.thing2 == 0xCAFEBABE
print 'Tests successful' print('Tests successful')
""" """
@Struct.LE @Struct.LE

View File

@@ -1,3 +1,3 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
from wii import * from .wii import *

View File

@@ -1,4 +1,4 @@
#!/usr/bin/python2 #!/usr/bin/python3
# Copyright 2007,2008 Segher Boessenkool <segher@kernel.crashing.org> # Copyright 2007,2008 Segher Boessenkool <segher@kernel.crashing.org>
# Copyright 2008 Hector Martin <marcan@marcansoft.com> # Copyright 2008 Hector Martin <marcan@marcansoft.com>
# Licensed under the terms of the GNU GPL, version 2 # 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 from Crypto.Util.number import bytes_to_long, long_to_bytes
# y**2 + x*y = x**3 + x + b # 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"+\ ec_b = (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" b"\x3b\x33\x3b\x20\xe9\xce\x42\x81\xfe\x11\x5f\x7d\x8f\x90\xad")
def hexdump(s,sep=""): 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=""): def bhex(s,sep=""):
return hexdump(long_to_bytes(s,30),sep) return hexdump(long_to_bytes(s,30),sep)
@@ -41,20 +41,20 @@ class ByteArray(array):
else: else:
array.__setitem__(self, item, value & 0xFF) array.__setitem__(self, item, value & 0xFF)
def __long__(self): def __long__(self):
return bytes_to_long(self.tostring()) return bytes_to_long(self.tobytes())
def __str__(self): 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): 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: class ELT_PY:
SIZEBITS=233 SIZEBITS=233
SIZE=(SIZEBITS+7)/8 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): 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)) self.d = ByteArray(long_to_bytes(initializer,self.SIZE))
elif isinstance(initializer, str): elif isinstance(initializer, bytes):
self.d = ByteArray(initializer) self.d = ByteArray(initializer)
elif isinstance(initializer, ByteArray): elif isinstance(initializer, ByteArray):
self.d = ByteArray(initializer) self.d = ByteArray(initializer)
@@ -80,12 +80,12 @@ class ELT_PY:
return cmp(self.d,other.d) return cmp(self.d,other.d)
def __long__(self): def __long__(self):
return long(self.d) return int(self.d)
def __repr__(self): def __repr__(self):
return repr(self.d).replace("ByteArray","ELT") return repr(self.d).replace("ByteArray","ELT")
def __str__(self): def __bytes__(self):
return str(self.d) return bytes(self.d)
def __nonzero__(self): def __bool__(self):
for x in self.d: for x in self.d:
if x != 0: if x != 0:
return True return True
@@ -184,21 +184,21 @@ class ELT_PY:
def __setitem__(self,item,value): def __setitem__(self,item,value):
self.d[item] = value self.d[item] = value
def tobignum(self): def tobignum(self):
return bytes_to_long(self.d.tostring()) return bytes_to_long(self.d.tobytes())
def tobytes(self): def tobytes(self):
return self.d.tostring() return self.d.tobytes()
class ELT_C(ELT_PY): class ELT_C(ELT_PY):
def __mul__(self,other): def __mul__(self,other):
if not isinstance(other,ELT): if not isinstance(other,ELT):
return NotImplemented 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): def __rdiv__(self,other):
if other != 1: if other != 1:
return ELT_PY.__rdiv__(self,other) 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): def _square(self):
return ELT(_ec.elt_square(self.d.tostring())) return ELT(_ec.elt_square(self.d.tobytes()))
if fastelt: if fastelt:
ELT = ELT_C ELT = ELT_C
@@ -207,7 +207,7 @@ else:
class Point: class Point:
def __init__(self,x,y=None): 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.x = ELT(x[:30])
self.y = ELT(x[30:]) self.y = ELT(x[30:])
elif isinstance(x,Point): elif isinstance(x,Point):
@@ -292,7 +292,7 @@ class Point:
return "(%s,%s)"%(str(self.x),str(self.y)) return "(%s,%s)"%(str(self.x),str(self.y))
def __repr__(self): def __repr__(self):
return "Point"+str(self) return "Point"+str(self)
def __nonzero__(self): def __bool__(self):
return self.x or self.y return self.x or self.y
def tobytes(self): def tobytes(self):
return self.x.tobytes() + self.y.tobytes() return self.x.tobytes() + self.y.tobytes()
@@ -305,15 +305,15 @@ def bn_inv(a,N):
# order of the addition group of points # order of the addition group of points
ec_N = bytes_to_long( ec_N = bytes_to_long(
"\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"+\ b"\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"\x13\xe9\x74\xe7\x2f\x8a\x69\x22\x03\x1d\x26\x03\xcf\xe0\xd7")
# base point # base point
ec_G = Point( ec_G = Point(
"\x00\xfa\xc9\xdf\xcb\xac\x83\x13\xbb\x21\x39\xf1\xbb\x75\x5f"+ b"\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"+ b"\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"+ b"\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"\x8a\x0b\xef\xf8\x67\xa7\xca\x36\x71\x6f\x7e\x01\xf8\x10\x52")
def generate_ecdsa(k, sha): def generate_ecdsa(k, sha):
k = bytes_to_long(k) k = bytes_to_long(k)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
# Copyright 2008 Hector Martin <marcan@marcansoft.com> # Copyright 2008 Hector Martin <marcan@marcansoft.com>
# Licensed under the terms of the GNU GPL, version 2 # Licensed under the terms of the GNU GPL, version 2
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt # 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.Util.number import bytes_to_long, long_to_bytes
from Crypto.Signature import pkcs1_15 from Crypto.Signature import pkcs1_15
import ec from . import ec
WII_RSA4096 = 0 WII_RSA4096 = 0
WII_RSA2048 = 1 WII_RSA2048 = 1
@@ -30,13 +30,13 @@ WII_ECDSA = 2
sigtypes = [ "RSA-4096", "RSA-2048", "EC-DSA" ] sigtypes = [ "RSA-4096", "RSA-2048", "EC-DSA" ]
def load_rsa_key(issuer): 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") path = os.path.join(os.environ["HOME"], ".wii", "dpki", issuer + ".pem")
return RSA.importKey(open(path, "r").read()) return RSA.importKey(open(path, "r").read())
signkeyfuncs = [ load_rsa_key, load_rsa_key, None ] signkeyfuncs = [ load_rsa_key, load_rsa_key, None ]
NULL_IV = "\x00"*16 NULL_IV = b"\x00"*16
keylist = [ keylist = [
"common-key", "common-key",
@@ -86,13 +86,13 @@ known_titles_noregion = {
} }
def hexdump(s,sep=" "): 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): def strcmp(s1,s2):
clen = min(len(s1),len(s2)) clen = min(len(s1),len(s2))
for i in range(clen): for i in range(clen):
if s1[i] == "\0" and s2[i] == "\0": if s1[i] == 0 and s2[i] == 0:
return True return True
if s1[i] != s2[i]: if s1[i] != s2[i]:
return False return False
@@ -101,10 +101,10 @@ def strcmp(s1,s2):
def ascii(s): def ascii(s):
s2 = "" s2 = ""
for c in s: for c in s:
if ord(c)<0x20 or ord(c)>0x7e: if c<0x20 or c>0x7e:
s2 += "." s2 += "."
else: else:
s2 += c s2 += chr(c)
return s2 return s2
def pad(s,c,l): def pad(s,c,l):
@@ -114,15 +114,10 @@ def pad(s,c,l):
def chexdump(s): def chexdump(s):
for i in range(0,len(s),16): 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): def getcstring(s):
s2 = "" return s.split(b"\x00")[0].decode("ascii")
for c in s:
if c == "\x00":
break
s2 += c
return s2
def align(n,a): def align(n,a):
if a == 0: if a == 0:
@@ -132,10 +127,10 @@ def align(n,a):
return n return n
def rangel(n,s): def rangel(n,s):
return range(n,n+s) return list(range(n,n+s))
def xrangel(n,s): def xrangel(n,s):
return xrange(n,n+s) return range(n,n+s)
def falign(f,a): def falign(f,a):
f.seek(align(f.tell(),a)) f.seek(align(f.tell(),a))
@@ -200,7 +195,7 @@ def loadkeys(path = None):
try: try:
keys[key] = open(path + os.sep + key, "rb").read() keys[key] = open(path + os.sep + key, "rb").read()
except: except:
print "Warning: failed to load key %s"%key print("Warning: failed to load key %s"%key)
def loadkeys_dpki(path = None): def loadkeys_dpki(path = None):
if path is None: if path is None:
@@ -210,7 +205,7 @@ def loadkeys_dpki(path = None):
def parse_certs(blob): def parse_certs(blob):
certs = {} certs = {}
certlist = [] certlist = []
while blob != "": while blob != b"":
cert = WiiCert(blob) cert = WiiCert(blob)
certs[cert.name] = cert certs[cert.name] = cert
certlist.append(cert) certlist.append(cert)
@@ -250,7 +245,7 @@ class WiiPKAlgo:
code = ">"+codes[bytes] code = ">"+codes[bytes]
matchlen = len(match) matchlen = len(match)
for pad in xrange(0, 256**bytes): for pad in range(0, 256**bytes):
pad += 0x4612512415125316 pad += 0x4612512415125316
pad %= 256**bytes pad %= 256**bytes
padsig = signature + pack(code, pad) padsig = signature + pack(code, pad)
@@ -270,11 +265,11 @@ class WiiRSA(WiiPKAlgo):
def get_digest(self, signature): def get_digest(self, signature):
lsig = bytes_to_long(signature) lsig = bytes_to_long(signature)
if lsig >= self.n: 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) ldec = pow(lsig, self.e, self.n)
dec = long_to_bytes(ldec) dec = long_to_bytes(ldec)
pad = len(signature) - len(dec) pad = len(signature) - len(dec)
dec = "\x00"*pad+dec dec = b"\x00"*pad+dec
return dec[-20:] return dec[-20:]
def sign(self, data, key): def sign(self, data, key):
@@ -340,11 +335,11 @@ class WiiDisc:
return self.partitions return self.partitions
def showinfo(self): 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() 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): 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: class WiiSigned:
sigsizes = [512, 256, 60] sigsizes = [512, 256, 60]
@@ -370,7 +365,7 @@ class WiiSigned:
def update(self): def update(self):
self.data = pack(">I",self.sigtype+0x10000) + self.signature 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 self.data += self.body
def parse(self): 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])) 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) 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) l = len(match)
if fillshort is None: if fillshort is None:
@@ -408,7 +403,7 @@ class WiiSigned:
if len(issuer) > 39: if len(issuer) > 39:
raise ValueError("issuer name too long!") raise ValueError("issuer name too long!")
self.issuer = issuer.split("-") 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() self.update()
def update_signature(self, sig): 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:] self.data = pack(">I",self.sigtype+0x10000) + self.signature + self.data[len(sig) + 4:]
def null_signature(self): 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:] self.data = pack(">I",self.sigtype+0x10000) + self.signature + self.data[len(self.signature) + 4:]
def sign(self,certs): def sign(self,certs):
@@ -453,22 +448,22 @@ class WiiSigned:
if cert.pkalgo.can_get_digest: if cert.pkalgo.can_get_digest:
signhash = cert.pkalgo.get_digest(self.signature) signhash = cert.pkalgo.get_digest(self.signature)
if myhash == signhash: 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): 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+"%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+" Signature hash: %s"%hexdump(signhash))
else: 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)))
print it+" Signature hash: %s"%hexdump(signhash) print(it+" Signature hash: %s"%hexdump(signhash))
else: else:
sigok = cert.pkalgo.check_digest(self.signature,myhash) sigok = cert.pkalgo.check_digest(self.signature,myhash)
if sigok: 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: 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: 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): class WiiTik(WiiSigned):
def __init__(self, data): def __init__(self, data):
@@ -480,7 +475,7 @@ class WiiTik(WiiSigned):
def parse(self): def parse(self):
self.title_key_enc = self.body[0x7f:0x8f] self.title_key_enc = self.body[0x7f:0x8f]
self.title_id = self.body[0x9c:0xa4] 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]) self.common_key_index = ord(self.body[0xb1:0xb2])
try: try:
@@ -489,7 +484,7 @@ class WiiTik(WiiSigned):
elif self.common_key_index == 1: elif self.common_key_index == 1:
key = keys["korean-key"] key = keys["korean-key"]
else: 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"] key = keys["common-key"]
aes = AES.new(key, AES.MODE_CBC, self.title_key_iv) aes = AES.new(key, AES.MODE_CBC, self.title_key_iv)
self.title_key = aes.decrypt(self.title_key_enc) self.title_key = aes.decrypt(self.title_key_enc)
@@ -505,13 +500,13 @@ class WiiTik(WiiSigned):
return 0x164 return 0x164
def showinfo(self, it=""): def showinfo(self, it=""):
print it+"ETicket: " print(it+"ETicket: ")
print it+" Title ID: "+repr(self.title_id) print(it+" Title ID: "+repr(self.title_id))
print it+" Title key IV: "+hexdump(self.title_key_iv) print(it+" Title key IV: "+hexdump(self.title_key_iv))
print it+" Title key (encrypted): "+hexdump(self.title_key_enc) print(it+" Title key (encrypted): "+hexdump(self.title_key_enc))
print it+" Common key index: %d" % self.common_key_index print(it+" Common key index: %d" % self.common_key_index)
if self.title_key is not None: 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: class WiiPartitionOffsets:
def __init__(self, data): def __init__(self, data):
@@ -528,9 +523,9 @@ class WiiPartitionOffsets:
self.data_size = unpack(">I",self.data[0x18:0x1c])[0]<<2 self.data_size = unpack(">I",self.data[0x18:0x1c])[0]<<2
def showinfo(self, it=""): 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.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): def update(self):
self.data = pack(">II",self.tmd_size, self.tmd_offset>>2) self.data = pack(">II",self.tmd_size, self.tmd_offset>>2)
@@ -600,20 +595,20 @@ class WiiTmd(WiiSigned):
self.update() self.update()
def showinfo(self,it=""): def showinfo(self,it=""):
print it+"TMD: " print(it+"TMD: ")
print it+" Versions: %d, CA CRL %d, Signer CRL %d, System %d-%d"%( 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) 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 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+" Title Type: %d"%self.title_type)
print it+" Group ID: %s"%repr(self.group_id) print(it+" Group ID: %s"%repr(self.group_id))
print it+" Access Rights: 0x%08x"%self.access_rights print(it+" Access Rights: 0x%08x"%self.access_rights)
print it+" Title Version: 0x%x"%self.title_version print(it+" Title Version: 0x%x"%self.title_version)
print it+" Boot Index: %d"%self.boot_index print(it+" Boot Index: %d"%self.boot_index)
print it+" Contents:" print(it+" Contents:")
print it+" ID Index Type Size Hash" print(it+" ID Index Type Size Hash")
for ct in self.get_content_records(): 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): class WiiCert(WiiSigned):
key_sizes = [516, 260, 60] key_sizes = [516, 260, 60]
@@ -638,7 +633,7 @@ class WiiCert(WiiSigned):
self.pkalgo = self.pk_types[self.key_type](self.key) self.pkalgo = self.pk_types[self.key_type](self.key)
def showinfo(self,it=""): 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: class WiiRootCert:
def __init__(self, data): def __init__(self, data):
@@ -650,7 +645,7 @@ class WiiRootCert:
self.key_type = 0 self.key_type = 0
def showinfo(self,it=""): 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: class WiiPartition:
BLOCKS_PER_SUBGROUP = 8 BLOCKS_PER_SUBGROUP = 8
@@ -732,37 +727,37 @@ class WiiPartition:
self.f.write(self.offsets.data) self.f.write(self.offsets.data)
def showinfo(self,it=""): 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.offsets.showinfo(" ")
self.tik.showinfo(it+" ") self.tik.showinfo(it+" ")
self.tik.showsig(self.certs,it+" ") self.tik.showsig(self.certs,it+" ")
self.tmd.showinfo(it+" ") self.tmd.showinfo(it+" ")
self.tmd.showsig(self.certs,it+" ") self.tmd.showsig(self.certs,it+" ")
if self.checkh4hash(): if self.checkh4hash():
print it+" H4 hash check passed" print(it+" H4 hash check passed")
else: else:
print it+" H4 check failed: SHA1(H3) = "+hexdump(self.geth4hash()) print(it+" H4 check failed: SHA1(H3) = "+hexdump(self.geth4hash()))
print it+" Data:" print(it+" Data:")
print it+" Blocks: %d"%self.data_blocks print(it+" Blocks: %d"%self.data_blocks)
print it+" Subgroups: %d (plus %d blocks)"%(self.data_subgroups,self.extra_subgroup_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+" Groups: %d (plus %d blocks)"%(self.data_groups,self.extra_group_blocks))
self.showcerts(it+" ") self.showcerts(it+" ")
def showcerts(self,it=""): def showcerts(self,it=""):
print it+"Certificates: " print(it+"Certificates: ")
for cert in self.certlist: for cert in self.certlist:
cert.showinfo(it+" - ") cert.showinfo(it+" - ")
cert.showsig(self.certs,it+" ") cert.showsig(self.certs,it+" ")
def geth4hash(self): 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): def checkh4hash(self):
return self.geth4hash() == self.tmd.get_content_records()[0].sha return self.geth4hash() == self.tmd.get_content_records()[0].sha
def updateh3(self): def updateh3(self):
self._seek(self.offsets.h3_offset) self._seek(self.offsets.h3_offset)
self.f.write(''.join(self.h3)) self.f.write(b''.join(self.h3))
def updateh4(self): def updateh4(self):
cr = self.tmd.get_content_records()[0] cr = self.tmd.get_content_records()[0]
@@ -903,7 +898,7 @@ class WiiPartition:
else: else:
raise ValueError("Attempted to read group past the end of the partition data") raise ValueError("Attempted to read group past the end of the partition data")
data = "" data = b""
for i in range(nblocks): for i in range(nblocks):
data += self.readblock(blockoff+i) data += self.readblock(blockoff+i)
return data 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): 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 blocks = self.extra_group_blocks
writesize = blocks * self.CIPHER_BLOCK_SIZE 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: else:
raise ValueError("Attempted to write group past the end of the partition data") raise ValueError("Attempted to write group past the end of the partition data")
else: else:
@@ -930,12 +925,12 @@ class WiiPartition:
h0 = [] h0 = []
h1 = [] h1 = []
h2 = "" h2 = b""
for subgroup in range(self.SUBGROUPS_PER_GROUP): for subgroup in range(self.SUBGROUPS_PER_GROUP):
bh1 = "" bh1 = b""
sh0 = [] sh0 = []
for block in range(self.BLOCKS_PER_SUBGROUP): for block in range(self.BLOCKS_PER_SUBGROUP):
bh0 = "" bh0 = b""
for chunk in range(self.DATA_CHUNKS_PER_BLOCK): 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 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() bh0 += SHA.new(data[offset:offset+self.DATA_CHUNK_SIZE]).digest()
@@ -946,16 +941,16 @@ class WiiPartition:
h2 += SHA.new(bh1).digest() h2 += SHA.new(bh1).digest()
h3 = SHA.new(h2).digest() h3 = SHA.new(h2).digest()
data_out = "" data_out = b""
for subgroup in range(self.SUBGROUPS_PER_GROUP): for subgroup in range(self.SUBGROUPS_PER_GROUP):
for block in range(self.BLOCKS_PER_SUBGROUP): for block in range(self.BLOCKS_PER_SUBGROUP):
shablock = "" shablock = ""
shablock += h0[subgroup][block] shablock += h0[subgroup][block]
shablock += "\x00"*20 shablock += b"\x00"*20
shablock += h1[subgroup] shablock += h1[subgroup]
shablock += "\x00"*32 shablock += b"\x00"*32
shablock += h2 shablock += h2
shablock += "\x00"*32 shablock += b"\x00"*32
assert len(shablock) == self.SHA_SIZE, "sha block size messed up" assert len(shablock) == self.SHA_SIZE, "sha block size messed up"
aes = AES.new(self.tik.title_key, AES.MODE_CBC, NULL_IV) aes = AES.new(self.tik.title_key, AES.MODE_CBC, NULL_IV)
shablock = aes.encrypt(shablock) shablock = aes.encrypt(shablock)
@@ -1019,7 +1014,7 @@ class WiiCachedPartition(WiiPartition):
def _dprint(self, s, *args): def _dprint(self, s, *args):
if self.debug: if self.debug:
print s%tuple(args) print(s%tuple(args))
def _readblock(self, blocknum): def _readblock(self, blocknum):
self._dprint("_readblock(0x%x)",blocknum) self._dprint("_readblock(0x%x)",blocknum)
@@ -1174,7 +1169,7 @@ class WiiCachedPartition(WiiPartition):
hb = self.readblock(bstart - 1) hb = self.readblock(bstart - 1)
hb = hb[:hdroff] + data[:header] + hb[hdroff+header:] hb = hb[:hdroff] + data[:header] + hb[hdroff+header:]
self.writeblock(bstart - 1, hb) 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]) self.writeblock(block+bstart, data[header+block*self.PLAIN_BLOCK_SIZE:header+(block+1)*self.PLAIN_BLOCK_SIZE])
if footer: if footer:
fb = self.readblock(bstart+bnum) fb = self.readblock(bstart+bnum)
@@ -1246,11 +1241,11 @@ class WiiApploader:
self.extrafooter = data[0x20+self.textsize+self.trailersize:] self.extrafooter = data[0x20+self.textsize+self.trailersize:]
def showinfo(self, it=""): def showinfo(self, it=""):
print it+"Apploader:" print(it+"Apploader:")
print it+" Date: %s"%self.date print(it+" Date: %s"%self.date)
print it+" Entrypoint: 0x%08x"%self.entry print(it+" Entrypoint: 0x%08x"%self.entry)
print it+" Text size: 0x%x"%self.textsize print(it+" Text size: 0x%x"%self.textsize)
print it+" Trailer size: 0x%x"%self.trailersize print(it+" Trailer size: 0x%x"%self.trailersize)
class WiiPartitionData: class WiiPartitionData:
def __init__(self, partition): def __init__(self, partition):
@@ -1291,11 +1286,11 @@ class WiiPartitionData:
self.dol = dol self.dol = dol
self.part.write(self.doloff, dol) self.part.write(self.doloff, dol)
def showinfo(self,it=""): def showinfo(self,it=""):
print it+"Partition data:" print(it+"Partition data:")
print it+" Game Name: %s"%self.gamename 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+" 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+" ") self.apploader.showinfo(it+" ")
print it+"FST:" print(it+"FST:")
self.fst.show(it+" ") self.fst.show(it+" ")
class FakeFile: class FakeFile:
@@ -1381,7 +1376,7 @@ class WiiWad:
self.f.seek(4) self.f.seek(4)
wt = self.f.read(2) wt = self.f.read(2)
if wt == "\x00\x00": if wt == b"\x00\x00":
self.read_boot2hdr() self.read_boot2hdr()
else: else:
self.read_hdr() self.read_hdr()
@@ -1389,7 +1384,7 @@ class WiiWad:
certdata = self.f.read(self.cert_len) certdata = self.f.read(self.cert_len)
self.certlist = [] self.certlist = []
self.certs = {} self.certs = {}
while certdata != "": while certdata != b"":
cert = WiiCert(certdata) cert = WiiCert(certdata)
self.certs[cert.name] = cert self.certs[cert.name] = cert
self.certlist.append(cert) self.certlist.append(cert)
@@ -1415,8 +1410,8 @@ class WiiWad:
self.f.write(self.tik.data) self.f.write(self.tik.data)
def showinfo(self,it=""): def showinfo(self,it=""):
print it+"Wii Wad:" 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+" 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.showinfo(it+" ")
self.tik.showsig(self.certs,it+" ") self.tik.showsig(self.certs,it+" ")
self.tmd.showinfo(it+" ") self.tmd.showinfo(it+" ")
@@ -1426,15 +1421,15 @@ class WiiWad:
d = self.getcontent(ct.index) d = self.getcontent(ct.index)
sha = SHA.new(d).digest() sha = SHA.new(d).digest()
if sha != ct.sha: if sha != ct.sha:
print it+" SHA-1 for content %08x is invalid:"%ct.cid, hexdump(sha) print(it+" SHA-1 for content %08x is invalid:"%ct.cid, hexdump(sha))
print it+" Expected:",hexdump(ct.sha) print(it+" Expected:",hexdump(ct.sha))
allok=False allok=False
if allok: if allok:
print it+" All content SHA-1 hashes are valid" print(it+" All content SHA-1 hashes are valid")
self.showcerts(it+" ") self.showcerts(it+" ")
def showcerts(self,it=""): def showcerts(self,it=""):
print it+"Certificates: " print(it+"Certificates: ")
for cert in self.certlist: for cert in self.certlist:
cert.showinfo(it+" - ") cert.showinfo(it+" - ")
cert.showsig(self.certs,it+" ") cert.showsig(self.certs,it+" ")
@@ -1447,7 +1442,7 @@ class WiiWad:
if encrypted: if encrypted:
return data 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) aes = AES.new(self.tik.title_key, AES.MODE_CBC, iv)
return aes.decrypt(data)[:ct.size] return aes.decrypt(data)[:ct.size]
@@ -1470,14 +1465,14 @@ class WiiWadMaker(WiiWad):
self.tik_len = len(self.tik.data) self.tik_len = len(self.tik.data)
# if boot2, set type to "ib" # 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: if nandwad:
self.wadtype = 0 self.wadtype = 0
self.ALIGNMENT = 0 self.ALIGNMENT = 0
else: else:
self.wadtype = "ib" self.wadtype = b"ib"
else: else:
self.wadtype = "Is" self.wadtype = b"Is"
self.data_len = 0 self.data_len = 0
self.footer = footer self.footer = footer
@@ -1509,16 +1504,16 @@ class WiiWadMaker(WiiWad):
cr.size = len(data) cr.size = len(data)
self.tmd.update_content_record(i,cr) self.tmd.update_content_record(i,cr)
if len(data)%16 != 0: if len(data)%16 != 0:
data += "\x00"*(16-len(data)%16) data += b"\x00"*(16-len(data)%16)
falign(self.f,0x40) 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) aes = AES.new(self.tik.title_key, AES.MODE_CBC, iv)
self.f.write(aes.encrypt(data)) self.f.write(aes.encrypt(data))
falign(self.f,0x40) falign(self.f,0x40)
def adddata_encrypted(self, data): def adddata_encrypted(self, data):
if len(data)%16 != 0: if len(data)%16 != 0:
data += "\x00"*(16-len(data)%16) data += b"\x00"*(16-len(data)%16)
falign(self.f,0x40) falign(self.f,0x40)
self.f.write(data) self.f.write(data)
falign(self.f,0x40) falign(self.f,0x40)
@@ -1531,7 +1526,7 @@ class WiiWadMaker(WiiWad):
falign(self.f,self.ALIGNMENT) falign(self.f,self.ALIGNMENT)
self.f.truncate() self.f.truncate()
if pad: if pad:
self.f.write("\x00"*0x40) self.f.write(b"\x00"*0x40)
self.updatetmd() self.updatetmd()
self.f.seek(0) self.f.seek(0)
if self.wadtype == 0: if self.wadtype == 0:
@@ -1641,9 +1636,9 @@ class WiiFSTFile:
self.off = off self.off = off
self.size = size self.size = size
def show(self, it=""): 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): def generate(self, offset, stringoff, parent, dataoff, wiigcm=False):
stringdata = self.name + "\x00" stringdata = self.name.encode("ascii") + b"\x00"
off = self.off+dataoff off = self.off+dataoff
if wiigcm: if wiigcm:
off >>= 2 off >>= 2
@@ -1688,9 +1683,9 @@ class WiiFSTDir:
raise ValueError("WTF") raise ValueError("WTF")
def show(self, it=""): def show(self, it=""):
if self.name == "": if self.name == "":
print it+"/" print(it+"/")
else: else:
print it+self.name+"/" print(it+self.name+"/")
for i in self.entries: for i in self.entries:
i.show(it+self.name+"/") i.show(it+self.name+"/")
def dump(self): def dump(self):
@@ -1698,15 +1693,15 @@ class WiiFSTDir:
def add(self,x): def add(self,x):
self.entries.append(x) self.entries.append(x)
def generate(self, offset, stringoff, parent, dataoff, wiigcm=False): def generate(self, offset, stringoff, parent, dataoff, wiigcm=False):
stringdata = self.name + "\x00" stringdata = self.name.encode("ascii") + b"\x00"
myoff = offset myoff = offset
mysoff = stringoff mysoff = stringoff
stringoff+=len(stringdata) stringoff+=len(stringdata)
offset += 1 offset += 1
subdata="" subdata=b""
for e in self.entries: for e in self.entries:
d, s = e.generate(offset, stringoff, myoff, dataoff, wiigcm) d, s = e.generate(offset, stringoff, myoff, dataoff, wiigcm)
offset += len(d)/12 offset += len(d)//12
stringoff += len(s) stringoff += len(s)
stringdata += s stringdata += s
subdata += d subdata += d

View File

@@ -1,11 +1,11 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys import sys
import re import re
import pywii as wii import pywii as wii
hash = wii.SHA.new(open(sys.argv[2]).read()).digest().encode("hex") 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() data = f.read()
f.close() f.close()
data = re.sub('@SHA1SUM@', hash, data) data = re.sub('@SHA1SUM@', hash, data)
open(sys.argv[3], "w").write(data) open(sys.argv[3], "wb").write(data)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path, struct import sys, os, os.path, struct
import pywii as wii import pywii as wii

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path, struct import sys, os, os.path, struct
import pywii as wii import pywii as wii
@@ -7,20 +7,24 @@ fstb = wii.WiiFSTBuilder(0x20)
fstb.addfrom(sys.argv[2]) fstb.addfrom(sys.argv[2])
arc = open(sys.argv[1],"wb") try:
# dummy generate to get length arc = open(sys.argv[1],"wb")
fstlen = len(fstb.fst.generate()) # dummy generate to get length
dataoff = wii.align(0x20+fstlen,0x20) fstlen = len(fstb.fst.generate())
fst = fstb.fst.generate(dataoff) dataoff = wii.align(0x20+fstlen,0x20)
fst = fstb.fst.generate(dataoff)
hdr = struct.pack(">IIII16x",0x55AA382d,0x20,fstlen,dataoff) hdr = struct.pack(">IIII16x",0x55AA382d,0x20,fstlen,dataoff)
arc.write(hdr) arc.write(hdr)
arc.write(fst) arc.write(fst)
wii.falign(arc,0x20)
for f in fstb.files:
data = open(f, "rb").read()
arc.write(data)
wii.falign(arc,0x20) 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

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii
@@ -15,12 +15,12 @@ certfile = args.pop(0)
certs, certlist = wii.parse_certs(open(args.pop(0), "rb").read()) 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 = wii.WiiCert(open(certfile, "rb").read())
cert.showinfo(" ") cert.showinfo(" ")
cert.showsig(certs," ") cert.showsig(certs," ")
print "Certificates:" print("Certificates:")
for cert in certlist: for cert in certlist:
cert.showinfo(" - ") cert.showinfo(" - ")
cert.showsig(certs," ") cert.showsig(certs," ")

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii
@@ -11,7 +11,7 @@ disc.showinfo()
partitions = disc.read_partitions() partitions = disc.read_partitions()
parts = range(len(partitions)) parts = list(range(len(partitions)))
try: try:
pnum = int(sys.argv[2]) pnum = int(sys.argv[2])

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii import pywii
@@ -17,7 +17,7 @@ if sys.argv[1] == "-cetk":
elif sys.argv[1] == "-tmd": elif sys.argv[1] == "-tmd":
signed = pywii.WiiTmd(open(infile, "rb").read()) signed = pywii.WiiTmd(open(infile, "rb").read())
else: else:
print "EYOUFAILIT" print("EYOUFAILIT")
sys.exit(1) sys.exit(1)
certs, certlist = pywii.parse_certs(open(certfile).read()) certs, certlist = pywii.parse_certs(open(certfile).read())
@@ -25,11 +25,11 @@ certs, certlist = pywii.parse_certs(open(certfile).read())
signed.update_issuer(issuer) signed.update_issuer(issuer)
if not signed.sign(certs): if not signed.sign(certs):
print "dpki signing failed" print("dpki signing failed")
sys.exit(1) sys.exit(1)
open(outfile, "wb").write(signed.data) open(outfile, "wb").write(signed.data)
print "successfully signed %s" % outfile print("successfully signed %s" % outfile)
sys.exit(0) sys.exit(0)

View File

@@ -1,10 +1,10 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys import sys
import pywii as wii import pywii as wii
if len(sys.argv) != 3: 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) sys.exit(1)
if sys.argv[1] == "-": if sys.argv[1] == "-":
@@ -12,46 +12,46 @@ if sys.argv[1] == "-":
else: else:
k = open(sys.argv[1],"rb").read() k = open(sys.argv[1],"rb").read()
if len(k) not in (30,60): if len(k) not in (30,60):
print "Failed to read key" print("Failed to read key")
sys.exit(2) sys.exit(2)
if len(k) == 30: 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) q = wii.ec.priv_to_pub(k)
else: else:
q = k q = k
print "Public key:" print("Public key:")
pq = q.encode('hex') pq = q.encode('hex')
print "X =",pq[:30] print("X =",pq[:30])
print " ",pq[30:60] print(" ",pq[30:60])
print "Y =",pq[60:90] print("Y =",pq[60:90])
print " ",pq[90:] print(" ",pq[90:])
print print()
indata = open(sys.argv[2],"rb").read() indata = open(sys.argv[2],"rb").read()
if len(indata) < 64 or indata[:4] != "SIG0": if len(indata) < 64 or indata[:4] != "SIG0":
print "Invalid header" print("Invalid header")
sys.exit(3) sys.exit(3)
r = indata[4:34] r = indata[4:34]
s = indata[34:64] s = indata[34:64]
sha = wii.SHA.new(indata[64:]).digest() sha = wii.SHA.new(indata[64:]).digest()
print "SHA1: %s"%sha.encode('hex') print("SHA1: %s"%sha.encode('hex'))
print print()
print "Signature:" print("Signature:")
print "R =",r[:15].encode('hex') print("R =",r[:15].encode('hex'))
print " ",r[15:].encode('hex') print(" ",r[15:].encode('hex'))
print "S =",s[:15].encode('hex') print("S =",s[:15].encode('hex'))
print " ",s[15:].encode('hex') print(" ",s[15:].encode('hex'))
print print()
if wii.ec.check_ecdsa(q,r,s,sha): if wii.ec.check_ecdsa(q,r,s,sha):
print "Signature is VALID" print("Signature is VALID")
else: else:
print "Signature is INVALID" print("Signature is INVALID")
sys.exit(4) sys.exit(4)

View File

@@ -1,33 +1,33 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os import sys, os
import pywii as wii import pywii as wii
if len(sys.argv) != 2: if len(sys.argv) != 2:
print "Usage: %s keyfile.priv"%sys.argv[0] print("Usage: %s keyfile.priv"%sys.argv[0])
sys.exit(1) sys.exit(1)
print "Generating private key..." print("Generating private key...")
k = wii.ec.gen_priv_key() k = wii.ec.gen_priv_key()
print "Private key:" print("Private key:")
pk = k.encode('hex') pk = k.encode('hex')
print "K =",pk[:30] print("K =",pk[:30])
print " ",pk[30:] print(" ",pk[30:])
print print()
print "Corresponding public key:" print("Corresponding public key:")
q = wii.ec.priv_to_pub(k) q = wii.ec.priv_to_pub(k)
pq = q.encode('hex') pq = q.encode('hex')
print "X =",pq[:30] print("X =",pq[:30])
print " ",pq[30:60] print(" ",pq[30:60])
print "Y =",pq[60:90] print("Y =",pq[60:90])
print " ",pq[90:] print(" ",pq[90:])
fd = open(sys.argv[1],"wb") fd = open(sys.argv[1],"wb")
os.fchmod(fd.fileno(), 0o600) os.fchmod(fd.fileno(), 0o600)
fd.write(k) fd.write(k)
fd.close() fd.close()
print "Saved private key to %s"%sys.argv[1] print("Saved private key to %s"%sys.argv[1])

View File

@@ -1,10 +1,10 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys import sys
import pywii as wii import pywii as wii
if len(sys.argv) not in (2,3): 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) sys.exit(1)
if sys.argv[1] == "-": if sys.argv[1] == "-":
@@ -12,19 +12,19 @@ if sys.argv[1] == "-":
else: else:
k = open(sys.argv[1],"rb").read() k = open(sys.argv[1],"rb").read()
if len(k) != 30: if len(k) != 30:
print "Failed to read private key" print("Failed to read private key")
sys.exit(2) sys.exit(2)
print "Public key:" print("Public key:")
q = wii.ec.priv_to_pub(k) q = wii.ec.priv_to_pub(k)
pq = q.encode('hex') pq = q.encode('hex')
print "X =",pq[:30] print("X =",pq[:30])
print " ",pq[30:60] print(" ",pq[30:60])
print "Y =",pq[60:90] print("Y =",pq[60:90])
print " ",pq[90:] print(" ",pq[90:])
if len(sys.argv) == 3: if len(sys.argv) == 3:
fd = open(sys.argv[2],"wb") fd = open(sys.argv[2],"wb")
fd.write(q) fd.write(q)
fd.close() fd.close()
print "Saved public key to %s"%sys.argv[2] print("Saved public key to %s"%sys.argv[2])

View File

@@ -1,10 +1,9 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys import sys
import pywii as wii import pywii as wii
if len(sys.argv) != 4: 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) sys.exit(1)
if sys.argv[1] == "-": if sys.argv[1] == "-":
@@ -13,20 +12,20 @@ else:
k = open(sys.argv[1],"rb").read() k = open(sys.argv[1],"rb").read()
if len(k) != 30: if len(k) != 30:
print "Failed to read private key" print("Failed to read private key")
sys.exit(2) sys.exit(2)
indata = open(sys.argv[2],"rb").read() indata = open(sys.argv[2],"rb").read()
sha = wii.SHA.new(indata).digest() sha = wii.SHA.new(indata).digest()
print "SHA1: %s"%sha.encode('hex') print("SHA1: %s"%sha.encode('hex'))
print print()
print "Signature:" print("Signature:")
r,s = wii.ec.generate_ecdsa(k,sha) r,s = wii.ec.generate_ecdsa(k,sha)
print "R =",r[:15].encode('hex') print("R =",r[:15].encode('hex'))
print " ",r[15:].encode('hex') print(" ",r[15:].encode('hex'))
print "S =",s[:15].encode('hex') print("S =",s[:15].encode('hex'))
print " ",s[15:].encode('hex') print(" ",s[15:].encode('hex'))
outdata = "SIG0" + r + s + indata outdata = "SIG0" + r + s + indata

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii
@@ -11,8 +11,8 @@ def parseint(d):
return int(d) return int(d)
if len(sys.argv) < 4 or len(sys.argv) > 7: if len(sys.argv) < 4 or len(sys.argv) > 7:
print "Usage:" print("Usage:")
print " python %s <encrypted ISO> <partition number> <file to extract to> [Partition offset] [length]"%sys.argv[0] print(" python %s <encrypted ISO> <partition number> <file to extract to> [Partition offset] [length]"%sys.argv[0])
sys.exit(1) sys.exit(1)
iso_name, partno, data_name = sys.argv[1:4] iso_name, partno, data_name = sys.argv[1:4]
@@ -27,19 +27,19 @@ if len(sys.argv) == 6:
copy_length = parseint(sys.argv[5]) copy_length = parseint(sys.argv[5])
if copy_length is not None and copy_length < 0: if copy_length is not None and copy_length < 0:
print "Error: negative copy length" print("Error: negative copy length")
sys.exit(1) sys.exit(1)
disc = wii.WiiDisc(iso_name) disc = wii.WiiDisc(iso_name)
disc.showinfo() disc.showinfo()
part = wii.WiiCachedPartition(disc, partno, cachesize=32, debug=False, checkhash=False) part = wii.WiiCachedPartition(disc, partno, cachesize=32, debug=False, checkhash=False)
if part_offset >= part.data_bytes: if part_offset >= part.data_bytes:
print "Error: Offset past end of partition" print("Error: Offset past end of partition")
sys.exit(1) sys.exit(1)
if copy_length is None: if copy_length is None:
copy_length = part.data_bytes - part_offset copy_length = part.data_bytes - part_offset
if 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) sys.exit(1)
dataf = open(data_name, "wb") dataf = open(data_name, "wb")
@@ -49,7 +49,7 @@ while left > 0:
blocklen = min(left, 4*1024*1024) blocklen = min(left, 4*1024*1024)
d = part.read(offset, blocklen) d = part.read(offset, blocklen)
if len(d) != blocklen: if len(d) != blocklen:
print "Part EOF reached!" print("Part EOF reached!")
sys.exit(1) sys.exit(1)
dataf.write(d) dataf.write(d)
offset += blocklen offset += blocklen

View File

@@ -1,4 +1,4 @@
#!/usr/bin/python2 #!/usr/bin/python3
import sys, os, os.path import sys, os, os.path
sys.path.append(os.path.realpath(os.path.dirname(sys.argv[0]))+"/../Common") 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") wii.loadkeys(os.environ["HOME"]+os.sep+".wii")
if len(sys.argv) != 4: if len(sys.argv) != 4:
print "Usage:" print("Usage:")
print " python %s <encrypted ISO> <partition number> <dol output>"%sys.argv[0] print(" python %s <encrypted ISO> <partition number> <dol output>"%sys.argv[0])
sys.exit(1) sys.exit(1)
iso_name, partno, dol_name = sys.argv[1:4] iso_name, partno, dol_name = sys.argv[1:4]

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii
@@ -11,8 +11,8 @@ def parseint(d):
return int(d) return int(d)
if len(sys.argv) < 4 or len(sys.argv) > 7: if len(sys.argv) < 4 or len(sys.argv) > 7:
print "Usage:" print("Usage:")
print " python %s <encrypted ISO> <partition number> <root path to extract to> "%sys.argv[0] print(" python %s <encrypted ISO> <partition number> <root path to extract to> "%sys.argv[0])
sys.exit(1) sys.exit(1)
iso_name, partno, data_name = sys.argv[1:4] iso_name, partno, data_name = sys.argv[1:4]
@@ -27,19 +27,19 @@ if len(sys.argv) == 6:
copy_length = parseint(sys.argv[5]) copy_length = parseint(sys.argv[5])
if copy_length is not None and copy_length < 0: if copy_length is not None and copy_length < 0:
print "Error: negative copy length" print("Error: negative copy length")
sys.exit(1) sys.exit(1)
disc = wii.WiiDisc(iso_name) disc = wii.WiiDisc(iso_name)
disc.showinfo() disc.showinfo()
part = wii.WiiCachedPartition(disc, partno, cachesize=32, debug=False, checkhash=False) part = wii.WiiCachedPartition(disc, partno, cachesize=32, debug=False, checkhash=False)
if part_offset >= part.data_bytes: if part_offset >= part.data_bytes:
print "Error: Offset past end of partition" print("Error: Offset past end of partition")
sys.exit(1) sys.exit(1)
if copy_length is None: if copy_length is None:
copy_length = part.data_bytes - part_offset copy_length = part.data_bytes - part_offset
if 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) sys.exit(1)
dataf = open(data_name, "wb") dataf = open(data_name, "wb")
@@ -49,7 +49,7 @@ while left > 0:
blocklen = min(left, 4*1024*1024) blocklen = min(left, 4*1024*1024)
d = part.read(offset, blocklen) d = part.read(offset, blocklen)
if len(d) != blocklen: if len(d) != blocklen:
print "Part EOF reached!" print("Part EOF reached!")
sys.exit(1) sys.exit(1)
dataf.write(d) dataf.write(d)
offset += blocklen offset += blocklen

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii
@@ -6,8 +6,8 @@ import pywii as wii
wii.loadkeys() wii.loadkeys()
if len(sys.argv) != 5: if len(sys.argv) != 5:
print "Usage:" print("Usage:")
print " python %s <encrypted ISO> <partition number> <apploader text> <apploader trailer>"%sys.argv[0] print(" python %s <encrypted ISO> <partition number> <apploader text> <apploader trailer>"%sys.argv[0])
sys.exit(1) sys.exit(1)
iso_name, partno, app_name, trail_name = sys.argv[1:5] iso_name, partno, app_name, trail_name = sys.argv[1:5]

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii
@@ -11,8 +11,8 @@ def parseint(d):
return int(d) return int(d)
if len(sys.argv) < 4 or len(sys.argv) > 7: if len(sys.argv) < 4 or len(sys.argv) > 7:
print "Usage:" print("Usage:")
print " python %s <encrypted ISO> <partition number> <file to inject> [Partition offset] [data offset] [length]"%sys.argv[0] print(" python %s <encrypted ISO> <partition number> <file to inject> [Partition offset] [data offset] [length]"%sys.argv[0])
sys.exit(1) sys.exit(1)
iso_name, partno, data_name = sys.argv[1:4] iso_name, partno, data_name = sys.argv[1:4]
@@ -34,10 +34,10 @@ if copy_length == None:
copy_length = data_len - data_offset copy_length = data_len - data_offset
copy_end = data_offset + copy_length copy_end = data_offset + copy_length
if copy_length < 0: if copy_length < 0:
print "Error: negative copy length" print("Error: negative copy length")
sys.exit(1) sys.exit(1)
if copy_end > data_len: if copy_end > data_len:
print "Error: data file is too small" print("Error: data file is too small")
sys.exit(1) sys.exit(1)
disc = wii.WiiDisc(iso_name) disc = wii.WiiDisc(iso_name)
@@ -52,7 +52,7 @@ while left > 0:
blocklen = min(left, 4*1024*1024) blocklen = min(left, 4*1024*1024)
d = dataf.read(blocklen) d = dataf.read(blocklen)
if len(d) != blocklen: if len(d) != blocklen:
print "File EOF reached!" print("File EOF reached!")
sys.exit(1) sys.exit(1)
part.write(offset, d) part.write(offset, d)
offset += blocklen offset += blocklen

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii
@@ -6,8 +6,8 @@ import pywii as wii
wii.loadkeys() wii.loadkeys()
if len(sys.argv) != 4: if len(sys.argv) != 4:
print "Usage:" print("Usage:")
print " python %s <encrypted ISO> <partition number> <dol to inject>"%sys.argv[0] print(" python %s <encrypted ISO> <partition number> <dol to inject>"%sys.argv[0])
sys.exit(1) sys.exit(1)
iso_name, partno, dol_name = sys.argv[1:4] iso_name, partno, dol_name = sys.argv[1:4]

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii
@@ -6,9 +6,9 @@ import pywii as wii
wii.loadkeys() wii.loadkeys()
if len(sys.argv) != 4: if len(sys.argv) != 4:
print "Usage:" print("Usage:")
print " python %s <encrypted ISO> <partition number> <IOS version>"%sys.argv[0] print(" python %s <encrypted ISO> <partition number> <IOS version>"%sys.argv[0])
print " IOS version should be just the minor number (16, 33, etc) in decimal" print(" IOS version should be just the minor number (16, 33, etc) in decimal")
sys.exit(1) sys.exit(1)
iso_name, partno, ios = sys.argv[1:4] iso_name, partno, ios = sys.argv[1:4]

View File

@@ -1,10 +1,10 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii
def hexdump(s): 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] isofile = sys.argv[1]
disc = WiiDisc(isofile) disc = WiiDisc(isofile)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii
@@ -6,7 +6,7 @@ import pywii as wii
wii.loadkeys() wii.loadkeys()
tikfile = sys.argv[1] tikfile = sys.argv[1]
print "fixing Tik file %s " % tikfile print("fixing Tik file %s " % tikfile)
tik = wii.WiiTik(open(tikfile, "rb").read()) tik = wii.WiiTik(open(tikfile, "rb").read())
tik.null_signature() tik.null_signature()
tik.brute_sha() tik.brute_sha()

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii
@@ -17,12 +17,12 @@ certs = None
if len(args) > 0: if len(args) > 0:
certs, certlist = wii.parse_certs(open(args.pop(0), "rb").read()) 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 = wii.WiiTik(open(tikfile, "rb").read())
tik.showinfo(" ") tik.showinfo(" ")
if certs is not None: if certs is not None:
tik.showsig(certs," ") tik.showsig(certs," ")
print "Certificates:" print("Certificates:")
for cert in certlist: for cert in certlist:
cert.showinfo(" - ") cert.showinfo(" - ")
cert.showsig(certs," ") cert.showsig(certs," ")

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii
@@ -6,7 +6,7 @@ import pywii as wii
wii.loadkeys() wii.loadkeys()
tmdfile = sys.argv[1] tmdfile = sys.argv[1]
print "TMD file %s:"%tmdfile print("TMD file %s:"%tmdfile)
tmd = wii.WiiTmd(open(tmdfile, "rb").read()) tmd = wii.WiiTmd(open(tmdfile, "rb").read())
tmd.null_signature() tmd.null_signature()
tmd.brute_sha() tmd.brute_sha()

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii
@@ -17,12 +17,12 @@ certs = None
if len(args) > 0: if len(args) > 0:
certs, certlist = wii.parse_certs(open(args.pop(0), "rb").read()) 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 = wii.WiiTmd(open(tmdfile, "rb").read())
tmd.showinfo(" ") tmd.showinfo(" ")
if certs is not None: if certs is not None:
tmd.showsig(certs," ") tmd.showsig(certs," ")
print "Certificates:" print("Certificates:")
for cert in certlist: for cert in certlist:
cert.showinfo(" - ") cert.showinfo(" - ")
cert.showsig(certs," ") cert.showsig(certs," ")

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii
@@ -14,7 +14,7 @@ args = sys.argv[1:]
tmdfile = args.pop(0) tmdfile = args.pop(0)
indir = 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()) tmd = wii.WiiTmd(open(tmdfile, "rb").read())
for i, cr in enumerate(tmd.get_content_records()): for i, cr in enumerate(tmd.get_content_records()):

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii
@@ -14,7 +14,7 @@ if len(args) == 2:
else: else:
newvers = int(args.pop(0), 16) 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 = wii.WiiTmd(open(tmdfile, "rb").read())
tmd.title_version = newvers tmd.title_version = newvers
tmd.update() tmd.update()

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2 #!/usr/bin/env python3
import sys, os, os.path import sys, os, os.path
import pywii as wii import pywii as wii