bump version to 0.7

support relative paths
--tmdinfo no longer fails when an IOS-tmd is check
don't enforce decrypt=false on unpacking CLI
This commit is contained in:
Christopher Roy Bratusek 2013-06-17 10:00:37 +02:00
parent 138af060a3
commit e573cd1f2f
6 changed files with 103 additions and 77 deletions

View File

@ -1,3 +1,9 @@
-- 0.7 --
* cli-options now can properly handle relative paths
* --tmdinfo does now longer fail when checking an IOS
* don't enforce decrypt=false on unpacking cli
* automatic whitespace fixes
-- 0.6 -- -- 0.6 --
* fixed a string in german translation * fixed a string in german translation
* fixed selecting file in TMD-Viewer * fixed selecting file in TMD-Viewer

View File

@ -10,7 +10,7 @@ from PyQt4.QtCore import pyqtSignature
from Ui_AboutQwad import Ui_Dialog from Ui_AboutQwad import Ui_Dialog
def Version(): def Version():
return "0.5" return "0.7"
def Author(): def Author():
return "Christopher Roy Bratusek <nano@tuxfamily.org>" return "Christopher Roy Bratusek <nano@tuxfamily.org>"

View File

@ -342,6 +342,18 @@ class UnpackingCLI(Thread):
print e print e
print "Done" print "Done"
class UnpackingCLIX(Thread):
def __init__(self, wadpath, dirpath):
Thread.__init__(self)
self.wadpath = wadpath
self.dirpath = dirpath
def run(self):
try:
WAD.loadFile(self.wadpath).dumpDir(self.dirpath)
except Exception, e:
print e
print "Done"
class Packing(Unpacking): class Packing(Unpacking):
def __init__(self, dirpath, wadpath, QMW, deletedir = False): def __init__(self, dirpath, wadpath, QMW, deletedir = False):
Unpacking.__init__(self, wadpath, dirpath, QMW) Unpacking.__init__(self, wadpath, dirpath, QMW)
@ -349,9 +361,9 @@ class Packing(Unpacking):
def run(self): def run(self):
self.qobject.emit(SIGNAL("working"),PACKING) self.qobject.emit(SIGNAL("working"),PACKING)
try: try:
print self.dirpath
print self.wadpath print self.wadpath
WAD.loadDir(self.dirpath).dumpFile(self.wadpath) print self.dirpath
WAD.loadDir(self.dirpath).dumpFile(self.wadpath)
if self.deletedir: if self.deletedir:
print "Cleaning temporary files" print "Cleaning temporary files"
self.qobject.emit(SIGNAL("working"),CLEANING) self.qobject.emit(SIGNAL("working"),CLEANING)
@ -393,6 +405,8 @@ class nusDownloading(Unpacking):
self.version = None self.version = None
self.decrypt = decrypt self.decrypt = decrypt
self.titleid = titleid self.titleid = titleid
print self.titleid
print self.version
def run(self): def run(self):
self.qobject.emit(SIGNAL("working"),DOWNLOADING) self.qobject.emit(SIGNAL("working"),DOWNLOADING)
try: try:
@ -425,7 +439,7 @@ class nusDownloadingCLI(UnpackingCLI):
try: try:
if self.pack: if self.pack:
self.dirpath = tempfile.gettempdir() + "/NUS_"+ str(time.time()).replace(".","") self.dirpath = tempfile.gettempdir() + "/NUS_"+ str(time.time()).replace(".","")
NUS(self.titleid, self.version).download(self.dirpath, decrypt = False) NUS(self.titleid, self.version).download(self.dirpath, decrypt = self.decrypt)
self.packing = PackingCLI(self.dirpath, str(self.outputdir), True) self.packing = PackingCLI(self.dirpath, str(self.outputdir), True)
self.packing.start() self.packing.start()
else: else:
@ -446,7 +460,10 @@ def ShowTMD(tmdpath):
print "Title Version : %s" % tmd.tmd.title_version print "Title Version : %s" % tmd.tmd.title_version
print "Title Boot Index : %s" % tmd.tmd.boot_index print "Title Boot Index : %s" % tmd.tmd.boot_index
print "Title Contents : %s" % tmd.tmd.numcontents print "Title Contents : %s" % tmd.tmd.numcontents
print "Title IOS : %s" % TitleIDs.TitleSwapDict["%s" % ("%016x" % tmd.tmd.iosversion)] if ("%016x" % tmd.tmd.iosversion) == "0000000000000000":
print "Title IOS : --"
else:
print "Title IOS : %s" % TitleIDs.TitleSwapDict["%s" % ("%016x" % tmd.tmd.iosversion)]
print "Title Access Rights: %s" % tmd.tmd.access_rights print "Title Access Rights: %s" % tmd.tmd.access_rights
print "Title Type : %s" % tmd.tmd.title_type print "Title Type : %s" % tmd.tmd.title_type
print "Title Group ID : %s" % tmd.tmd.group_id print "Title Group ID : %s" % tmd.tmd.group_id

View File

@ -8,6 +8,11 @@ from PyQt4.QtCore import QTranslator, QString, QLocale
from GUI.VenPri import MWQwad, nusDownloadingCLI, PackingCLI, UnpackingCLI, ShowTMD from GUI.VenPri import MWQwad, nusDownloadingCLI, PackingCLI, UnpackingCLI, ShowTMD
from TitleIDs import TitleDict, IOSdict, swap_dic, ChannelCLIDict, ChannelJAPDict, ChannelPALDict, ChannelUSADict, ChannelJAPVerDict, ChannelPALVerDict, ChannelUSAVerDict from TitleIDs import TitleDict, IOSdict, swap_dic, ChannelCLIDict, ChannelJAPDict, ChannelPALDict, ChannelUSADict, ChannelJAPVerDict, ChannelPALVerDict, ChannelUSAVerDict
if os.getenv("QWAD_X_DIR"):
os.chdir(os.getenv("QWAD_X_DIR"))
else:
os.chdir(os.getenv("HOME"))
class MultipleOption(Option): class MultipleOption(Option):
ACTIONS = Option.ACTIONS + ("extend",) ACTIONS = Option.ACTIONS + ("extend",)
STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",) STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
@ -20,10 +25,9 @@ class MultipleOption(Option):
else: else:
Option.take_action(self, action, dest, opt, value, values, parser) Option.take_action(self, action, dest, opt, value, values, parser)
VERSION = '0.6' VERSION = '0.7'
def opts(): def opts():
os.chdir(sys.path[0])
description = """NUS-Downloader, WadManager and TMD-Viewer for Linux""" description = """NUS-Downloader, WadManager and TMD-Viewer for Linux"""
parser = OptionParser(option_class=MultipleOption, parser = OptionParser(option_class=MultipleOption,
usage='usage: qwad [OPTIONS] ARGUMENT', usage='usage: qwad [OPTIONS] ARGUMENT',
@ -72,7 +76,7 @@ def opts():
xarg = TitleDict[str(options.download[0])] xarg = TitleDict[str(options.download[0])]
nusdow = nusDownloadingCLI(int(str(xarg).lower(),16), args[0], args[1], args[2], args[3]) nusdow = nusDownloadingCLI(int(str(xarg).lower(),16), args[0], args[1], args[2], args[3])
else: else:
nusdow = nusDownloadingCLI(int(str(options.download[0]).lower(),16), args[0], args[1], args[2], args[3]) nusdow = nusDownloadingCLI(int(str(options.download[0]).lower(),16), args[0], args[1], args[2], args[3])
nusdow.start() nusdow.start()
sys.exit(0) sys.exit(0)
@ -165,8 +169,6 @@ def main():
# load Qt translations # load Qt translations
qttranslator = QTranslator() qttranslator = QTranslator()
qttranslator.load(QString("qt_%1").arg(QLocale.system().name())) qttranslator.load(QString("qt_%1").arg(QLocale.system().name()))
# change directory in $HOME, so that file-seletors don't start in Qwads source/data directory
os.chdir(os.getenv("HOME"))
# misc stuff # misc stuff
Vapp = QApplication(sys.argv) Vapp = QApplication(sys.argv)
Vapp.setOrganizationName("Nanolx") Vapp.setOrganizationName("Nanolx")

View File

@ -4,7 +4,7 @@ import zlib
class U8(WiiArchive): class U8(WiiArchive):
"""This class can unpack and pack U8 archives, which are used all over the Wii. They are often used in Banners and contents in Downloadable Titles. Please remove all headers and compression first, kthx. """This class can unpack and pack U8 archives, which are used all over the Wii. They are often used in Banners and contents in Downloadable Titles. Please remove all headers and compression first, kthx.
The f parameter is either the source folder to pack, or the source file to unpack.""" The f parameter is either the source folder to pack, or the source file to unpack."""
class U8Header(Struct): class U8Header(Struct):
__endian__ = Struct.BE __endian__ = Struct.BE
@ -26,32 +26,32 @@ class U8(WiiArchive):
def _dump(self): def _dump(self):
header = self.U8Header() header = self.U8Header()
rootnode = self.U8Node() rootnode = self.U8Node()
# constants # constants
header.tag = "U\xAA8-" header.tag = "U\xAA8-"
header.rootnode_offset = 0x20 header.rootnode_offset = 0x20
header.zeroes = "\x00" * 16 header.zeroes = "\x00" * 16
rootnode.type = 0x0100 rootnode.type = 0x0100
nodes = [] nodes = []
strings = "\x00" strings = "\x00"
data = '' data = ''
for item, value in self.files: for item, value in self.files:
node = self.U8Node() node = self.U8Node()
recursion = item.count('/') recursion = item.count('/')
if(recursion < 0): if(recursion < 0):
recursion = 0 recursion = 0
name = item[item.rfind('/') + 1:] name = item[item.rfind('/') + 1:]
node.name_offset = len(strings) node.name_offset = len(strings)
strings += name + '\x00' strings += name + '\x00'
if(value == None): if(value == None):
node.type = 0x0100 node.type = 0x0100
node.data_offset = recursion node.data_offset = recursion
node.size = len(nodes) node.size = len(nodes)
for one, two in self.files: for one, two in self.files:
if(one[:len(item)] == item): # find nodes in the folder if(one[:len(item)] == item): # find nodes in the folder
@ -64,15 +64,15 @@ class U8(WiiArchive):
node.size = sz node.size = sz
node.type = 0x0000 node.type = 0x0000
nodes.append(node) nodes.append(node)
header.header_size = ((len(nodes) + 1) * len(rootnode)) + len(strings) header.header_size = ((len(nodes) + 1) * len(rootnode)) + len(strings)
header.data_offset = align(header.header_size + header.rootnode_offset, 64) header.data_offset = align(header.header_size + header.rootnode_offset, 64)
rootnode.size = len(nodes) + 1 rootnode.size = len(nodes) + 1
for i in range(len(nodes)): for i in range(len(nodes)):
if(nodes[i].type == 0x0000): if(nodes[i].type == 0x0000):
nodes[i].data_offset += header.data_offset nodes[i].data_offset += header.data_offset
fd = '' fd = ''
fd += header.pack() fd += header.pack()
fd += rootnode.pack() fd += rootnode.pack()
@ -81,7 +81,7 @@ class U8(WiiArchive):
fd += strings fd += strings
fd += "\x00" * (header.data_offset - header.rootnode_offset - header.header_size) fd += "\x00" * (header.data_offset - header.rootnode_offset - header.header_size)
fd += data fd += data
return fd return fd
def _dumpDir(self, dir): def _dumpDir(self, dir):
if(not os.path.isdir(dir)): if(not os.path.isdir(dir)):
@ -115,35 +115,35 @@ class U8(WiiArchive):
self._tmpPath = self._tmpPath[:self._tmpPath.find('/') + 1] self._tmpPath = self._tmpPath[:self._tmpPath.find('/') + 1]
def _load(self, data): def _load(self, data):
offset = 0 offset = 0
header = self.U8Header() header = self.U8Header()
header.unpack(data[offset:offset + len(header)]) header.unpack(data[offset:offset + len(header)])
offset += len(header) offset += len(header)
assert header.tag == "U\xAA8-" assert header.tag == "U\xAA8-"
offset = header.rootnode_offset offset = header.rootnode_offset
rootnode = self.U8Node() rootnode = self.U8Node()
rootnode.unpack(data[offset:offset + len(rootnode)]) rootnode.unpack(data[offset:offset + len(rootnode)])
offset += len(rootnode) offset += len(rootnode)
nodes = [] nodes = []
for i in range(rootnode.size - 1): for i in range(rootnode.size - 1):
node = self.U8Node() node = self.U8Node()
node.unpack(data[offset:offset + len(node)]) node.unpack(data[offset:offset + len(node)])
offset += len(node) offset += len(node)
nodes.append(node) nodes.append(node)
strings = data[offset:offset + header.data_offset - len(header) - (len(rootnode) * rootnode.size)] strings = data[offset:offset + header.data_offset - len(header) - (len(rootnode) * rootnode.size)]
offset += len(strings) offset += len(strings)
recursion = [rootnode.size] recursion = [rootnode.size]
recursiondir = [] recursiondir = []
counter = 0 counter = 0
for node in nodes: for node in nodes:
counter += 1 counter += 1
name = strings[node.name_offset:].split('\0', 1)[0] name = strings[node.name_offset:].split('\0', 1)[0]
if(node.type == 0x0100): # folder if(node.type == 0x0100): # folder
recursion.append(node.size) recursion.append(node.size)
recursiondir.append(name) recursiondir.append(name)
@ -154,7 +154,7 @@ class U8(WiiArchive):
offset += node.size offset += node.size
else: # unknown type -- wtf? else: # unknown type -- wtf?
pass pass
sz = recursion.pop() sz = recursion.pop()
if(sz != counter + 1): if(sz != counter + 1):
recursion.append(sz) recursion.append(sz)
@ -190,7 +190,7 @@ class U8(WiiArchive):
self.files[i] = (self.files[i][0], val) self.files[i] = (self.files[i][0], val)
return return
self.files.append((key, val)) self.files.append((key, val))
class WAD(WiiArchive): class WAD(WiiArchive):
def __init__(self, boot2 = False): def __init__(self, boot2 = False):
@ -206,7 +206,7 @@ class WAD(WiiArchive):
else: else:
headersize, data_offset, certsize, tiksize, tmdsize, padding = struct.unpack('>IIIII12s', data[:32]) headersize, data_offset, certsize, tiksize, tmdsize, padding = struct.unpack('>IIIII12s', data[:32])
pos = 32 pos = 32
rawcert = data[pos:pos + certsize] rawcert = data[pos:pos + certsize]
pos += certsize pos += certsize
if(self.boot2 != True): if(self.boot2 != True):
@ -220,7 +220,7 @@ class WAD(WiiArchive):
if(tiksize % 64 != 0): if(tiksize % 64 != 0):
pos += 64 - (tiksize % 64) pos += 64 - (tiksize % 64)
self.tik = Ticket.load(rawtik) self.tik = Ticket.load(rawtik)
rawtmd = data[pos:pos + tmdsize] rawtmd = data[pos:pos + tmdsize]
pos += tmdsize pos += tmdsize
if(self.boot2 == True): if(self.boot2 == True):
@ -228,7 +228,7 @@ class WAD(WiiArchive):
else: else:
pos += 64 - (tmdsize % 64) pos += 64 - (tmdsize % 64)
self.tmd = TMD.load(rawtmd) self.tmd = TMD.load(rawtmd)
titlekey = self.tik.getTitleKey() titlekey = self.tik.getTitleKey()
contents = self.tmd.getContents() contents = self.tmd.getContents()
for i in range(0, len(contents)): for i in range(0, len(contents)):
@ -244,11 +244,11 @@ class WAD(WiiArchive):
def _loadDir(self, dir): def _loadDir(self, dir):
origdir = os.getcwd() origdir = os.getcwd()
os.chdir(dir) os.chdir(dir)
self.tmd = TMD.loadFile("tmd") self.tmd = TMD.loadFile("tmd")
self.tik = Ticket.loadFile("tik") self.tik = Ticket.loadFile("tik")
self.cert = open("cert", "rb").read() self.cert = open("cert", "rb").read()
contents = self.tmd.getContents() contents = self.tmd.getContents()
for i in range(len(contents)): for i in range(len(contents)):
self.contents.append(open("%08x.app" % i, "rb").read()) self.contents.append(open("%08x.app" % i, "rb").read())
@ -256,52 +256,52 @@ class WAD(WiiArchive):
def _dumpDir(self, dir): def _dumpDir(self, dir):
origdir = os.getcwd() origdir = os.getcwd()
os.chdir(dir) os.chdir(dir)
contents = self.tmd.getContents() contents = self.tmd.getContents()
for i in range(len(contents)): for i in range(len(contents)):
open("%08x.app" % i, "wb").write(self.contents[i]) open("%08x.app" % i, "wb").write(self.contents[i])
self.tmd.dumpFile("tmd") self.tmd.dumpFile("tmd")
self.tik.dumpFile("tik") self.tik.dumpFile("tik")
open("cert", "wb").write(self.cert) open("cert", "wb").write(self.cert)
os.chdir(origdir) os.chdir(origdir)
def _dump(self, fakesign = True): def _dump(self, fakesign = True):
titlekey = self.tik.getTitleKey() titlekey = self.tik.getTitleKey()
contents = self.tmd.getContents() contents = self.tmd.getContents()
apppack = "" apppack = ""
for i, content in enumerate(contents): for i, content in enumerate(contents):
if(fakesign): if(fakesign):
content.hash = str(Crypto().createSHAHash(self.contents[content.index])) content.hash = str(Crypto().createSHAHash(self.contents[content.index]))
content.size = len(self.contents[content.index]) content.size = len(self.contents[content.index])
encdata = Crypto().encryptContent(titlekey, content.index, self.contents[content.index]) encdata = Crypto().encryptContent(titlekey, content.index, self.contents[content.index])
apppack += encdata apppack += encdata
if(len(encdata) % 64 != 0): if(len(encdata) % 64 != 0):
apppack += "\x00" * (64 - (len(encdata) % 64)) apppack += "\x00" * (64 - (len(encdata) % 64))
if(fakesign): if(fakesign):
self.tmd.setContents(contents) self.tmd.setContents(contents)
self.tmd.fakesign() self.tmd.fakesign()
self.tik.fakesign() self.tik.fakesign()
rawtmd = self.tmd.dump() rawtmd = self.tmd.dump()
rawcert = self.cert rawcert = self.cert
rawtik = self.tik.dump() rawtik = self.tik.dump()
sz = 0 sz = 0
for i in range(len(contents)): for i in range(len(contents)):
sz += contents[i].size sz += contents[i].size
if(sz % 64 != 0): if(sz % 64 != 0):
sz += 64 - (contents[i].size % 64) sz += 64 - (contents[i].size % 64)
if(self.boot2 != True): if(self.boot2 != True):
pack = struct.pack('>I4s6I', 32, "Is\x00\x00", len(rawcert), 0, len(rawtik), len(rawtmd), sz, 0) pack = struct.pack('>I4s6I', 32, "Is\x00\x00", len(rawcert), 0, len(rawtik), len(rawtmd), sz, 0)
pack += "\x00" * 32 pack += "\x00" * 32
else: else:
pack = struct.pack('>IIIII12s', 32, align(len(rawcert) + len(rawtik) + len(rawtmd), 0x40), len(rawcert), len(rawtik), len(rawtmd), "\x00" * 12) pack = struct.pack('>IIIII12s', 32, align(len(rawcert) + len(rawtik) + len(rawtmd), 0x40), len(rawcert), len(rawtik), len(rawtmd), "\x00" * 12)
pack += rawcert pack += rawcert
if(len(rawcert) % 64 != 0 and self.boot2 != True): if(len(rawcert) % 64 != 0 and self.boot2 != True):
pack += "\x00" * (64 - (len(rawcert) % 64)) pack += "\x00" * (64 - (len(rawcert) % 64))
@ -311,10 +311,10 @@ class WAD(WiiArchive):
pack += rawtmd pack += rawtmd
if(len(rawtmd) % 64 != 0 and self.boot2 != True): if(len(rawtmd) % 64 != 0 and self.boot2 != True):
pack += "\x00" * (64 - (len(rawtmd) % 64)) pack += "\x00" * (64 - (len(rawtmd) % 64))
if(self.boot2 == True): if(self.boot2 == True):
pack += "\x00" * (align(len(rawcert) + len(rawtik) + len(rawtmd), 0x40) - (len(rawcert) + len(rawtik) + len(rawtmd))) pack += "\x00" * (align(len(rawcert) + len(rawtik) + len(rawtmd), 0x40) - (len(rawcert) + len(rawtik) + len(rawtmd)))
pack += apppack pack += apppack
return pack return pack
def __getitem__(self, idx): def __getitem__(self, idx):
@ -325,7 +325,7 @@ class WAD(WiiArchive):
out = "" out = ""
out += "Wii WAD:\n" out += "Wii WAD:\n"
out += str(self.tmd) out += str(self.tmd)
out += str(self.tik) out += str(self.tik)
return out return out
@ -338,7 +338,7 @@ class CCF():
self.rootOffset = Struct.uint32 self.rootOffset = Struct.uint32
self.filesCount = Struct.uint32 self.filesCount = Struct.uint32
self.zeroes8 = Struct.string(8) self.zeroes8 = Struct.string(8)
class CCFFile(Struct): class CCFFile(Struct):
__endian__ = Struct.LE __endian__ = Struct.LE
def __format__(self): def __format__(self):
@ -350,86 +350,86 @@ class CCF():
def __init__(self, fileName): def __init__(self, fileName):
self.fileName = fileName self.fileName = fileName
self.fd = open(fileName, 'r+b') self.fd = open(fileName, 'r+b')
def compress(self, folder): def compress(self, folder):
fileList = [] fileList = []
fileHdr = self.CCFHeader() fileHdr = self.CCFHeader()
files = os.listdir(folder) files = os.listdir(folder)
fileHdr.magic = "\x43\x43\x46\x00" fileHdr.magic = "\x43\x43\x46\x00"
fileHdr.zeroes12 = '\x00' * 12 fileHdr.zeroes12 = '\x00' * 12
fileHdr.rootOffset = 0x20 fileHdr.rootOffset = 0x20
fileHdr.zeroes8 = '\x00' * 8 fileHdr.zeroes8 = '\x00' * 8
currentOffset = len(fileHdr) currentOffset = len(fileHdr)
packedFiles = 0 packedFiles = 0
previousFileEndOffset = 0 previousFileEndOffset = 0
for file in files: for file in files:
if os.path.isdir(folder + '/' + file) or file == '.DS_Store': if os.path.isdir(folder + '/' + file) or file == '.DS_Store':
continue continue
else: else:
fileList.append(file) fileList.append(file)
fileHdr.filesCount = len(fileList) fileHdr.filesCount = len(fileList)
self.fd.write(fileHdr.pack()) self.fd.write(fileHdr.pack())
self.fd.write('\x00' * (fileHdr.filesCount * len(self.CCFFile()))) self.fd.write('\x00' * (fileHdr.filesCount * len(self.CCFFile())))
for fileNumber in range(len(fileList)): for fileNumber in range(len(fileList)):
fileEntry = self.CCFFile() fileEntry = self.CCFFile()
compressedBuffer = zlib.compress(open(folder + '/' + fileList[fileNumber]).read()) compressedBuffer = zlib.compress(open(folder + '/' + fileList[fileNumber]).read())
fileEntry.fileName = fileList[fileNumber] fileEntry.fileName = fileList[fileNumber]
fileEntry.fileSize = len(compressedBuffer) fileEntry.fileSize = len(compressedBuffer)
fileEntry.fileSizeDecompressed = os.stat(folder + '/' + fileList[fileNumber]).st_size fileEntry.fileSizeDecompressed = os.stat(folder + '/' + fileList[fileNumber]).st_size
fileEntry.fileOffset = align(self.fd.tell(), 32) / 32 fileEntry.fileOffset = align(self.fd.tell(), 32) / 32
print 'File {0} ({1}Kb) placed at offset 0x{2:X}'.format(fileEntry.fileName, fileEntry.fileSize / 1024, fileEntry.fileOffset * 32) print 'File {0} ({1}Kb) placed at offset 0x{2:X}'.format(fileEntry.fileName, fileEntry.fileSize / 1024, fileEntry.fileOffset * 32)
self.fd.seek(len(fileHdr) + fileNumber * len(self.CCFFile())) self.fd.seek(len(fileHdr) + fileNumber * len(self.CCFFile()))
self.fd.write(fileEntry.pack()) self.fd.write(fileEntry.pack())
self.fd.seek(fileEntry.fileOffset * 32) self.fd.seek(fileEntry.fileOffset * 32)
self.fd.write(compressedBuffer) self.fd.write(compressedBuffer)
self.fd.close() self.fd.close()
def decompress(self): def decompress(self):
fileHdr = self.CCFHeader() fileHdr = self.CCFHeader()
hdrData = self.fd.read(len(fileHdr)) hdrData = self.fd.read(len(fileHdr))
fileHdr.unpack(hdrData) fileHdr.unpack(hdrData)
print 'Found {0} file/s and root node at 0x{1:X}'.format(fileHdr.filesCount, fileHdr.rootOffset) print 'Found {0} file/s and root node at 0x{1:X}'.format(fileHdr.filesCount, fileHdr.rootOffset)
if fileHdr.magic != "\x43\x43\x46\x00": if fileHdr.magic != "\x43\x43\x46\x00":
raise ValueError("Wrong magic, 0x{0}".format(fileHdr.magic)) raise ValueError("Wrong magic, 0x{0}".format(fileHdr.magic))
try: try:
os.mkdir(os.path.dirname(self.fileName) + '/' + self.fd.name.replace(".", "_") + "_out") os.mkdir(os.path.dirname(self.fileName) + '/' + self.fd.name.replace(".", "_") + "_out")
except: except:
pass pass
os.chdir(os.path.dirname(self.fileName) + '/' + self.fd.name.replace(".", "_") + "_out") os.chdir(os.path.dirname(self.fileName) + '/' + self.fd.name.replace(".", "_") + "_out")
currentOffset = len(fileHdr) currentOffset = len(fileHdr)
for x in range(fileHdr.filesCount): for x in range(fileHdr.filesCount):
self.fd.seek(currentOffset) self.fd.seek(currentOffset)
fileEntry = self.CCFFile() fileEntry = self.CCFFile()
fileData = self.fd.read(len(fileEntry)) fileData = self.fd.read(len(fileEntry))
fileEntry.unpack(fileData) fileEntry.unpack(fileData)
fileEntry.fileOffset = fileEntry.fileOffset * 32 fileEntry.fileOffset = fileEntry.fileOffset * 32
print 'File {0} at offset 0x{1:X}'.format(fileEntry.fileName, fileEntry.fileOffset) print 'File {0} at offset 0x{1:X}'.format(fileEntry.fileName, fileEntry.fileOffset)
print 'File size {0}Kb ({1}Kb decompressed)'.format(fileEntry.fileSize / 1024, fileEntry.fileSizeDecompressed / 1024) print 'File size {0}Kb ({1}Kb decompressed)'.format(fileEntry.fileSize / 1024, fileEntry.fileSizeDecompressed / 1024)
output = open(fileEntry.fileName.rstrip('\0'), 'w+b') output = open(fileEntry.fileName.rstrip('\0'), 'w+b')
self.fd.seek(fileEntry.fileOffset) self.fd.seek(fileEntry.fileOffset)
if fileEntry.fileSize == fileEntry.fileSizeDecompressed: if fileEntry.fileSize == fileEntry.fileSizeDecompressed:
print 'The file is stored uncompressed' print 'The file is stored uncompressed'
@ -439,7 +439,7 @@ class CCF():
decompressedBuffer = zlib.decompress(self.fd.read(fileEntry.fileSize)) decompressedBuffer = zlib.decompress(self.fd.read(fileEntry.fileSize))
output.write(decompressedBuffer) output.write(decompressedBuffer)
output.close() output.close()
currentOffset += len(fileEntry) currentOffset += len(fileEntry)
if(__name__ == '__main__'): if(__name__ == '__main__'):

1
qwad
View File

@ -1,3 +1,4 @@
#!/bin/sh #!/bin/sh
export QWAD_X_DIR="${PWD}"
PYTHONPATH="/usr/share/Qwad/" PYTHONPATH="/usr/share/Qwad/"
python /usr/share/Qwad/Qwad.pyw $@ python /usr/share/Qwad/Qwad.pyw $@