# Mdx文件详解：mdx 2.0 及 mdd 2.0（经验证）

**URL:** <https://forum.freemdict.com/t/topic/42473>\
**Category:** 技术交流与词典编修\
**Created:** [2026 年1 月 3 日 11:49 UTC](https://forum.freemdict.com/t/topic/42473 "2026-01-03T11:49:07Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

作者： ![u3842](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/u/d6d6ee/32.png) [@u3842](https://forum.freemdict.com/u/u3842)\
发布日期： [2026 年1 月 3 日 11:49 UTC](https://forum.freemdict.com/t/topic/42473/1 "2026-01-03T11:49:08Z")

</div>

以下可能并不详尽，描述可能不准确或有错

mdx 2.0和mdd 2.0结构几乎一样，下面有说明

### Header

mdx文件并没有固定的 **文件头** ，其开头4字节表示后面紧跟着的UTF-16编码的 **XML** 的字节数，解析XML时要去掉末尾的0x0000终止符，后面跟着Adler32校验和，其中校验和为小端序，文件中其他Adler32都为大端序，没额外说类型的按大端序处理。

竖小方块表示1字节。横大方块表示若干字节并且看起来长度一样 **不能** 说明大小一样。

 ![image](https://forumcdn.freemdict.com/uploads/default/original/3X/3/6/361a9684592a3aff3b1f51dbe63dcf9daba5ee46.png)

XML解析后看起来是下面这样的（添加了换行和说明）

```auto
<Dictionary 
GeneratedByEngineVersion="2.0" 文件版本，2.0。
RequiredEngineVersion="2.0" 似乎是最低兼容的reader。
Format="Html" 内容的格式，可能的值是"Html"或"Text"，在mdd中，为""。
KeyCaseSensitive="No" 告诉reader要不要区分词条名的大小写。
StripKey="Yes" 未知。
Encrypted="2" 加密，转到二进制，高位为1表示index’s index block被加密；低位为1表示index部分前40字节被加密。2转到二进制为10，高位为1，表示只加密索引的索引。这里不细讲低位为1的加密。
RegisterBy="EMail" 为"EMail"或"DeviceID"，只有Encrypted的低位为1才会用到，用于解密时识别。
Description="描述" 描述。
Title="标题" 标题。
Encoding="UTF-8" indexIndex、 index 和record 里字符的编码方式。在mdd中为“”，indexIndex和index里字符按UTF-16 LE 编码。
CreationDate="2026-1-1" 创建日期。
Compact="Yes" "Yes"表示其中某些字符串将根据StyleSheet中指定的方案进行替换，具体官方bulider文档里有说明。
Compat="Yes" 同上。
Left2Right="Yes" 未知。
DataSourceFormat="106" 未知。
StyleSheet="" 参考compact。
RegCode="0102030405060708090A0B0C0D0E0F" 注册码，或位于mdx同目录下的dictionary.key文件中。
/>

```

### Index Section

这里先说明一下“ **block** ”，不同“block”虽然原始数据不同，但这些block外在格式都一样，都有相同的头，数据都可以被压缩并存进block内。

 ![image](https://forumcdn.freemdict.com/uploads/default/original/3X/d/7/d7e089817108697c7e2a07418a19cd71dd73aa3d.png)  
前4字节：0x0?000000，？=0表示数据不压缩，1表示lzo压缩，2表示zlib压缩  
继续4字节：解压后的数据的Adler32，大端序  
再继续若干字节就是这个block的(被压缩的)数据了

特别地，当Encrypted的高位为1时，index’s index block内有 **加密** (不加密block内前8字节)。具体加密算法是按照字节

1. 异或当前字节在这段的位置i(0开始的十六进制，取位置的最后一字节)
2. 再异或key的第i%16个字节(0开始，0-15)，%取余
3. 再异或上一个加密完毕后的字节，起初没有上一个的，异或0x36
4. 最后互换前4位和后四位，这字节加密完毕

接下来是 **Index** （索引）部分了，8字节表示index block的数量  
接下来8字节表示这个mdx里的词条总数  
接下来8字节表示index’ index block内数据的解压后(如需要)的大小  
接下来8字节表示index’ index block的字节数  
接下来8字节表示所有index block字节数的总和  
再往下4字节就是上面这40字节的Adler32了，小端序。这4字节+(表示 **拼接** 而不是相加)0x95360000的Ripemd128(一种哈希算法)的结果为上面的 **key** ，16字节。

如果Encrypted属性的低位为1，前40字节被Salsa20/8加密。这里不深入探究。

 ![image](https://forumcdn.freemdict.com/uploads/default/original/3X/0/3/037ccc05018f3ef6c0aacd6224a9ea3c387a8c70.png)

接下来就是 **index’ index block** ，只有一个，这个可以称为“索引的索引”，循环记录了相对应的index block内的

第1个index block的词条数(8字节)  
第1个index block的起始词条的单位编码数，可能这么说不准确，如果是头部xml的Encoding=UTF-8或GBK，则直接是后面的长度，如果为UTF-16或为空，则后面的长度要\*2，(2字节)  
……起始词条名（长度不定，不完全等同于正式的词条名，在mdx内：至少没空格，没符号，全小写，比如activoperateavehicle；在mdd内：有额外的\来表示子目录，比如\media\english\ameprons\abrade.mp3）  
……终止符，如果编码为UTF-16则为2字节的0x0000，否则为1字节的0x00  
……终止词条的单位编码数…（2字节，同上）  
……终止词条名（长度不定，同上）  
……终止符，同上  
……字节数(8字节)  
……数据解压后的字节数(8字节)  
第2个index block的词条数(8字节)  
第2个index block的起始词条的单位编码数…(2字节)  
……  
第2个index block的数据解压后的字节数(8字节)  
第3个index block的词条数(8字节)  
……

紧跟着index’s index block后是 **index block** ，有多个，其解压后是这样的

第1个词条 对应在record部分累计解压后的开始位置 (8字节)  
第1个词条的词条名，若干字节，以终止符结尾  
第2个词条 对应在record部分累计解压后的开始位置 (8字节)  
第2个词条……  
第3个……  
……

### Record Section

这里面就是数据占比最多的部分了，主要内容都在这，结构如图。

深棕色的表示对应单个block数据解压后的大小，而上面获取到的累计解压后的开始位置(记为offset)并不能直接定位到相应的block，而是要根据offset算出在哪个block以及在这个block解压后的开始位置，还要有紧接着下一个词条的offset来判断这个词条的结束位置，内容可能在多个block内，mdd直接返回原数据，如果这是mdx，还要去掉末尾的终止符（编码为UTF-16则为2字节的0x0000，否则为1字节的0x00）。

 ![image](https://forumcdn.freemdict.com/uploads/default/original/3X/0/f/0f586411937e3c39c70557309b3e6c0f5b337a2c.png)

依靠这些已经可以读出Encrypted=2或0 的mdx 及 mdd 2.0

来源： [File format specification — mdict4j 文档](https://mdict4j.readthedocs.io/zh-cn/latest/reference/fileformat.html) [GitHub - hehonghui/mdict-analysis](https://github.com/hehonghui/mdict-analysis)

---

<div class="post-metadata">

作者： ![last\_idol](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/last_idol/32/2205_2.png) [@last\_idol](https://forum.freemdict.com/u/last_idol)\
发布日期： [2026 年1 月 3 日 12:10 UTC](https://forum.freemdict.com/t/topic/42473/2 "2026-01-03T12:10:00Z")

</div>

MDX 已经开源了，这个是原作者：

> **[GitHub - raymanzhang/mdx: A rust library for encode/decode mdx format file](https://github.com/raymanzhang/mdx)**
>
> A rust library for encode/decode mdx format file

---

<div class="post-metadata">

作者： ![u3842](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/u/d6d6ee/32.png) [@u3842](https://forum.freemdict.com/u/u3842)\
发布日期： [2026 年1 月 3 日 13:57 UTC](https://forum.freemdict.com/t/topic/42473/3 "2026-01-03T13:57:38Z")

</div>

原来这个就是原作者啊，三个多月才十几star，这热度不应该啊。看了下没有详细的文档，rust不太懂，哎，有时间再研究研究

---

<div class="post-metadata">

作者： ![seid](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/s/b9bd4f/32.png) [@seid](https://forum.freemdict.com/u/seid)\
发布日期： [2026 年1 月 3 日 15:11 UTC](https://forum.freemdict.com/t/topic/42473/4 "2026-01-03T15:11:20Z")

</div>

在开源社区，一般来说，没有文档的开源不认为是真正的开源，软件是很复杂的，特别是大型软件，没有开发文档的大型软件开源其实是没有多大意义的。  
不过mdict不大，所以即使不是真开源，也可以读懂研究透。  
我不会叫mdx开源了，只能说mdx代码泄漏了(官方泄露)

前几年有一个事件，我忘了是什么软件，很出名，因为没有完整的版本历史导致被炮轰。

---

<div class="post-metadata">

作者： ![last\_idol](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/last_idol/32/2205_2.png) [@last\_idol](https://forum.freemdict.com/u/last_idol)\
发布日期： [2026 年1 月 3 日 15:43 UTC](https://forum.freemdict.com/t/topic/42473/5 "2026-01-03T15:43:42Z")

</div>

“If you’re willing to contribute documentation, I’d really appreciate it and can provide any needed support.”

---

<div class="post-metadata">

作者： ![seid](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/s/b9bd4f/32.png) [@seid](https://forum.freemdict.com/u/seid)\
发布日期： [2026 年1 月 3 日 18:17 UTC](https://forum.freemdict.com/t/topic/42473/6 "2026-01-03T18:17:22Z")

</div>

有这句话和没有这句话有什么区别吗？  
还不如没有这句话，  
反正我代码都给你们了，还要扎个呃，

---

<div class="post-metadata">

作者： ![last\_idol](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/last_idol/32/2205_2.png) [@last\_idol](https://forum.freemdict.com/u/last_idol)\
发布日期： [2026 年1 月 4 日 01:34 UTC](https://forum.freemdict.com/t/topic/42473/7 "2026-01-04T01:34:44Z")

</div>

这就是开源社区的标准回复。

---

<div class="post-metadata">

作者： ![u3842](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/u/d6d6ee/32.png) [@u3842](https://forum.freemdict.com/u/u3842)\
发布日期： [2026 年1 月 23 日 02:59 UTC](https://forum.freemdict.com/t/topic/42473/8 "2026-01-23T02:59:34Z")

</div>

研究了几天，总算搞透了，修正了一些错误

---

<div class="post-metadata">

作者： ![zwyyy456](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/z/ec9cab/32.png) [@zwyyy456](https://forum.freemdict.com/u/zwyyy456)\
发布日期： [2026 年1 月 26 日 13:52 UTC](https://forum.freemdict.com/t/topic/42473/9 "2026-01-26T13:52:51Z")

</div>

这个人就是之前 mdict 词典的原作者吗，也是 mdx 格式的设计者？

---

<div class="post-metadata">

作者： ![last\_idol](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/last_idol/32/2205_2.png) [@last\_idol](https://forum.freemdict.com/u/last_idol)\
发布日期： [2026 年1 月 26 日 15:32 UTC](https://forum.freemdict.com/t/topic/42473/10 "2026-01-26T15:32:28Z")

</div>

是的，原作者。
