好的,我研究一下
png和atlas都有明确的文件头和文件尾特征,用于和其他数据切割。skel我只看出来4.1.2前面9个字节就是文件开头,skel的文件结尾该怎么判断啊?
尾部很难判断. 我用的很粗糙的方法. 向后找到下一个文件头特征(PNG、JPG、或其他 skel header) 并限制skel大小不超过1M,取其位置为结束点. 只能说 用这个方法能分割出绝大多数的skel 但有少部分skel超出了这个条件. 所有才有30个左右的skel文件我也没能分割出来.
from pathlib import Path
from io import BufferedReader
def parse(r: BufferedReader, r2: BufferedReader, outPath: Path):
count = int.from_bytes(r.read(4), 'little')
for _ in range(count):
nameLen = r.read(1)[0]
name = bytes(i ^ nameLen for i in r.read(nameLen))
start = int.from_bytes(r.read(4), 'little') - name[-6] - nameLen
size = int.from_bytes(r.read(4), 'little') - name[-7] - nameLen
new = outPath.joinpath(name.decode())
new.parent.mkdir(parents=True, exist_ok=True)
r2.seek(start)
with open(new, 'wb') as w:
w.write(r2.read(size))
def batch(datPath: str = '', outPath: str = '', subfolder: bool = False):
path = Path(datPath) if datPath else Path.cwd()
move = (Path(outPath) if outPath else path).joinpath('Extract')
need = [i for i in (path.rglob('*.dic') if subfolder else path.glob('*.dic'))]
for i in need:
dat = i.parent.joinpath(f'{i.stem}.dat')
if not dat.is_file():
print(f'缺少dat文件 --- {dat.as_posix()}')
continue
with open(i, 'rb') as f, open(dat, 'rb') as f2:
parse(f, f2, move)
if __name__ == '__main__':
path = r'' # 游戏文件所在的路径
outPath = r'' # 导出文件的路径
subfolder = False # 是否查找字文件夹内的`.dic`文件
batch(path, outPath, subfolder)
大概就是这样
起始位置计算是这样的 起始位置 - 名字字节的结尾第6个字节 - 名字长度
大小也差不多, 不过是减去名字字节的结尾第7个字节
大佬,这是用PY批处理是吗?
太强了! 不愧是大佬. 这才是优雅的提取方式.
对, 你只需要把dat和dic文件放在一个文件夹里, 然后path设置为那个文件夹的路径, 运行脚本就行了
能讲讲思路吗?
这孰能生巧…我经常处理二进制文件, 所以猜测这种简单的结构比较轻松, 主要对比前几个文件的起始位置和大小, 然后猜测运算结果, 这一步花了点时间
辛苦大佬了,对了,这些文件里有语音吗?
我没检查, 测了下随机导出了几个文件, 确定拆分没问题我就把文件都删了