Readmdict解析错误

目前只遇到一个词典触发。

问题mdx供各位研究:
疑难字三考.mdx (25.0 KB)

Traceback (most recent call last):
  File "c:\Users\admin\Desktop\new\xwang-mdict-analysis-927f91a5746b\readmdict.py", line 737, in <module>
    mdx = MDX(args.filename, args.encoding, args.substyle, args.passcode)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\admin\Desktop\new\xwang-mdict-analysis-927f91a5746b\readmdict.py", line 660, in __init__
    MDict.__init__(self, fname, encoding, passcode)
  File "c:\Users\admin\Desktop\new\xwang-mdict-analysis-927f91a5746b\readmdict.py", line 115, in __init__
    self._key_list = self._read_keys()
                     ^^^^^^^^^^^^^^^^^
  File "c:\Users\admin\Desktop\new\xwang-mdict-analysis-927f91a5746b\readmdict.py", line 365, in _read_keys
    return self._read_keys_v1v2()
           ^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\admin\Desktop\new\xwang-mdict-analysis-927f91a5746b\readmdict.py", line 448, in _read_keys_v1v2
    key_block_info_list = self._decode_key_block_info(key_block_info)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\admin\Desktop\new\xwang-mdict-analysis-927f91a5746b\readmdict.py", line 197, in _decode_key_block_info
    assert(key_block_info_compressed[:4] == b'\x02\x00\x00\x00')
AssertionError

将

        if self._version >= 2:
            # zlib compression
            assert(key_block_info_compressed[:4] == b'\x02\x00\x00\x00')
            # decrypt if needed
            if self._encrypt & 0x02:
                key = ripemd128(key_block_info_compressed[4:8] + pack(b'<L', 0x3695))
                key_block_info_compressed = key_block_info_compressed[:8] + _fast_decrypt(key_block_info_compressed[8:], key)
            # decompress
            key_block_info = zlib.decompress(key_block_info_compressed[8:])
            # adler checksum
            adler32 = unpack('>I', key_block_info_compressed[4:8])[0]
            assert(adler32 == zlib.adler32(key_block_info) & 0xffffffff)

替换为

        if self._version >= 2:
            # 块头 4 字节是压缩方式(小端):02 00 00 00 = zlib(标准写法),
            # 00 00 00 00 = 不压缩。官方 MdxBuilder 对 Encrypted=2(禁止导出)
            # 的词典写后者,旧实现只认前者,于是报「魔数不匹配」。
            # 后面仍有 adler32 校验兜底,放宽不会误放行损坏文件。
            head = key_block_info_compressed[:4]
            if head == b'\x02\x00\x00\x00': use_zlib = True
            elif head == b'\x00\x00\x00\x00': use_zlib = False
            else: raise ValueError("MDX key block info 魔数不匹配")
            if self._encrypt & 0x02:
                key = ripemd128(key_block_info_compressed[4:8] + pack(b'<L', 0x3695))
                key_block_info_compressed = key_block_info_compressed[:8] + _fast_decrypt(key_block_info_compressed[8:], key)
            payload = key_block_info_compressed[8:]
            key_block_info = zlib.decompress(payload) if use_zlib else payload
            adler32 = unpack('>I', key_block_info_compressed[4:8])[0]
            actual = zlib.adler32(key_block_info) & 0xffffffff
            if adler32 != actual:
                raise ValueError(f"MDX key block info 校验失败 (adler32): 期望 {adler32:#x}, 实际 {actual:#x}")

可以解决。

AI分析如下:

文件没问题,是解析器的兼容性限制。​ 你用官方工具打包的 2.0 + Encrypted=2(禁止导出),这类词典的 key block info 用的是「无压缩」写法,而项目把魔数硬编码成了「zlib」。

线索 结论
740 处 0d 92 01 3d 我算过 zlib.adler32(struct.pack(‘>QQQQQ’,1,1829,80,88,10048)) = 0x0d92013d,正是 40 字节索引头的校验和 → 布局完全标准,偏移没错
88 = 80 + 8 压缩后只比解压后多 8 字节头,说明根本没有 zlib 压缩
[4] 在 832 找到的 02 00 00 00 744+88=832,是 key block 的块头(诊断脚本误判,已修正说明)
744 处 00 00 00 00 块头 compression_method=0(不压缩),不是损坏
解密后 [8:16] = 00 00 00 00 00 00 07 25 大端 = 1829,正好等于 num_entries → 密钥 ripemd128([4:8]+0x3695) 和「只解密 [8:]」项目原本都是对的,唯独解压方式猜错了

提交一个 PR 吧~ ;)

github仓库已归档,bitbucket没有账号,我尝试邮箱联系一下 Xiaoqiang Wang