-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathunpack.py
128 lines (99 loc) · 3.55 KB
/
unpack.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import glob
import struct
import sys
import os
import io
from PIL import Image
import arc
def checkAudio(data):
magic = struct.unpack_from('<4s', data, 4)[0]
return magic.startswith(b'bw ')
def checkGRPImage(data):
width, height, bpp = struct.unpack_from('<HHH', data, 0)
if not (bpp == 8 or bpp == 24 or bpp == 32):
return
return int(width*height*bpp/8)+16 == len(data)
def unpackGRPImage(data):
width, height, bpp = struct.unpack_from('<HHH', data, 0)
if bpp == 8:
pass
elif bpp == 24:
pass
elif bpp == 32:
pixels = [(r, g, b, a) for b, g, r, a in struct.iter_unpack('<BBBB', data[16:])]
im = Image.new('RGBA', (width, height))
im.putdata(pixels)
out = io.BytesIO()
im.save(out, format='PNG')
return out.getvalue()
def unpack(file, args):
print(file)
print('--------------------')
f = open(file, 'rb')
base, ext = os.path.splitext(file)
os.makedirs(base, exist_ok=True)
magic, fileCount = struct.unpack('<12sL', f.read(0x10))
if not magic.startswith(b'PackFile'):
print('不能识别该文件!')
return
entryRaw = f.read(0x20*fileCount)
dataOffset = f.tell()
entryList = []
ii = 1
for name, offset, size, _, _ in struct.iter_unpack('<16sLLLL', entryRaw):
name = name.rstrip(b'\x00').decode('ascii')
if args.list:
print("(%d/%d)" % (ii, fileCount), name)
ii += 1
continue
f.seek(dataOffset + offset)
entryData = f.read(size)
decryptData = None
entryType = 'NONE'
# print(len(entryData))
if not args.raw:
if entryData.startswith(b'CompressedBG___'):
# print('CompressedBG___', size)
entryType = 'CompressedBG___'
entryData = arc.cbg_decrypt(entryData)
name += '.png'
elif entryData.startswith(b'DSC FORMAT 1.00'):
# print('DSC FORMAT 1.00', name, size)
entryData = arc.dsc_decrypt(entryData)
entryType = 'DSC FORMAT 1.00'
if checkAudio(entryData):
name += '.ogg'
elif checkGRPImage(entryData):
name += '.png'
entryData = unpackGRPImage(entryData)
elif entryData.startswith(b'SDC FORMAT 1.00'):
# print('SDC FORMAT 1.00', size)
entryType = 'SDC FORMAT 1.00'
# check bmp
fn = os.path.join(base, name)
print("(%d/%d)" % (ii, fileCount), fn)
ii += 1
of = open(fn, 'wb')
of.write(entryData)
of.close()
entryList.append((name, entryType))
# fn = os.path.join(base, 'list.txt')
# of = open(fn, 'w');
# for e in entryList:
# of.write('%s %s\n' % e)
# of.close()
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-r", "--raw", action='store_true', help="不解码文件")
parser.add_argument("-l", "--list", action='store_true', help="列出文件")
parser.add_argument("-d", "--dir", help="输出文件夹(默认与arc文件一个目录)")
parser.add_argument('files', nargs='+', help="arc文件")
if __name__ == '__main__':
args = parser.parse_args()
# print(args)
# print("raw {} list {} dir {} files {}".format(args.raw, args.list, args.dir, args.files))
for file in args.files:
for f in glob.glob(file):
base, ext = os.path.splitext(f)
if ext == '.arc':
unpack(f, args)