我是帝国II(AOE)过时游戏时代的粉丝。我想用python编写AOE游戏记录(.mgx文件)的解析器。
我在Github上做了一些搜索,发现关于这个的项目很少,最有用的是提供aoc-mgx-formatsome details of .mgx game record files
问题是:
根据参考,.mgx文件的结构如下:
|头段长度(4byte int)下一个位置(4byte int)头段数据……γ
十六进制数据在mgx格式中的字节顺序是little endian。
header_len存储header部分的数据长度(header_len+next_post+header_data)
header_数据存储了我需要的有用信息,但它是用zlib压缩的
我尝试用zlib模块解压header_data中的数据,如下所示:

import struct
import zlib

with open('test.mgx', "rb") as fp:
    # read the header_len bytes and covert it to a int reprents length of Header part
    header_len = struct.unpack("<i", fp.read(4))[0]

    # read next_pos (this is not important for me)
    next_pos = struct.unpack("<i", fp.read(4))[0]

    # then I can get data length of header_data part(compressed with zlib)
    header_data_len = header_len - 8

    compressed_data = fp.read(header_data_len)[::-1] # need to be reversed because byte order is little endian?

    try:
        zlib.decompress(compressed_data)
        print "can be decompressed!"
    except zlib.error as e:
        print e.message

但我在运行程序后得到了这个:
解压缩数据时出现错误-3:头检查不正确
ps:sample.mgx文件可在此处找到:https://github.com/stefan-kolb/aoc-mgx-format/tree/master/parser/recs

最佳答案

您的第一个问题是不应该反转数据;只需去掉[::-1]
但是如果你这样做,而不是得到错误-3,你会得到一个不同的错误-3,通常是关于一个未知的压缩方法。
问题是,这是无头的zlib数据,很像gzip使用的数据。理论上,这意味着有关压缩方法、窗口、start dict等的信息必须在文件的其他地方提供(在gzip的情况下,由gzip头中的信息提供)。但是在实践中,每个人都使用了最大窗口大小的deflate,而不是start dict,所以如果我在设计一个游戏的压缩格式,回到计算每个字节的时候,我只需要对它们进行硬编码。(在现代,确切地说,这已经在RFC中被标准化为“压缩数据格式”,但大多数90年代的PC游戏并没有按照设计遵循RFC…)
所以:

>>> uncompressed_data = zlib.decompress(compressed_data, -zlib.MAX_WBITS)
>>> uncompressed_data[:8] # version
b'VER 9.8\x00'
>>> uncompressed_data[8:12] # unknown_const
b'\xf6(<A'

所以,它不仅是解压的,看起来像一个版本,而且……嗯,我猜任何东西看起来都像一个未知的常量,但是它在规范中是相同的未知常量,所以我认为我们是好的。
正如decompressdocs解释的那样,MAX_WBITS是默认/最常见的窗口大小(通常称为“zlib deflate”而不是“zlib”所使用的唯一大小),传递负值意味着头被抑制;我们可以保留为默认值的其他参数。
另请参见zlibdocs和this answer中的Advanced Functions部分。(感谢OP找到链接。)

08-20 03:41