3 # requires Pillow and zstandard for Python
4 # on msys, install Pillow with
5 # pacman -S mingw-w64-x86_64-python-pillow
6 # zstd needs to be compiled, because the one in pip3 fails to do so:
7 # pacman -S mingw-w64-x86_64-python-setuptools mingw-w64-x86_64-zstd
8 # git clone https://github.com/indygreg/python-zstandard.git --recursive && cd python-zstandard
9 # python setup.py build_ext --external clean
11 # ./unpak.py pakfile.pak outdir tools/default_crcmap.txt
12 # any files not found in crcmap will go to the "nonmatching" folder
20 PAK_MAGIC
= b
'\x11\xde\x37\x10\x68\x75\xb6\xe8'
23 print('usage: unpak <input.pak> <outdir> [<crcmap>]')
26 pakfname
= sys
.argv
[1]
28 mapfname
= "crcmap.txt"
30 mapfname
= sys
.argv
[3]
35 with
open(mapfname
, 'r') as f
:
38 if line
== '' or line
[0] == '#':
41 crcstr
= tok
[0].strip()
42 if crcstr
.startswith('0x'):
43 crc
= int(crcstr
[2:], 16)
46 path
= os
.path
.join(outpath
, tok
[1].strip())
48 crcmap
[crc
].append(path
)
52 print('could not open {0}: {1}'.format(mapfname
, e
))
54 except ValueError as e
:
55 print('invalid integer in {0}: {1}'.format(mapfname
, e
))
58 unmatchdir
= os
.path
.join(outpath
, "nonmatching")
59 if not os
.path
.exists(unmatchdir
):
60 os
.makedirs(unmatchdir
)
65 with
open(pakfname
, "rb") as f
:
66 magic
= f
.read(len(PAK_MAGIC
))
67 if magic
!= PAK_MAGIC
:
68 print('invalid magic in PAK ' + pakfname
)
70 texcount
= int.from_bytes(f
.read(8), byteorder
='little')
71 print('reading {0} textures from {1}'.format(texcount
, pakfname
))
72 for i
in range(texcount
):
73 crc
= int.from_bytes(f
.read(4), byteorder
='little')
74 size
= int.from_bytes(f
.read(4), byteorder
='little')
75 offset
= int.from_bytes(f
.read(8), byteorder
='little')
76 width
= int.from_bytes(f
.read(8), byteorder
='little')
77 height
= int.from_bytes(f
.read(8), byteorder
='little')
78 texlist
.append((crc
, size
, offset
, width
, height
))
79 for (crc
, size
, ofs
, w
, h
) in texlist
:
82 img
= Image
.frombytes('RGBA', (w
, h
), zstd
.decompress(data
))
84 for path
in crcmap
[crc
]:
85 [fpath
, fname
] = os
.path
.split(path
)
86 if not os
.path
.exists(fpath
):
90 print('unknown crc: {0:08x}'.format(crc
))
91 path
= os
.path
.join(unmatchdir
, "{0:08x}.png".format(crc
))
94 print('could not open {0}: {1}'.format(pakfname
, e
))