夜行侦探 EVE burst error 游戏文件分析(七)

ghidra / imhex / eve / dosbox / pc98

我们完成了文字的解码,但如果要把文本翻译为中文,还需要根据解码的程序,把编码的过程还原出来。

目录

本系列基本完结,以下是目录供快速翻阅:

  1. 启动、GDT 文件分析一:19 个函数
  2. GDT 文件分析二:ghidra 偏移量、读取、初次绘画
  3. GDT 文件分析三:多次读取、偏移量、调色板
  4. GDT 文件分析四:完整解开及遗留问题
  5. 游戏文本解码
  6. 汉化方案制定
  7. 游戏文本编码
  8. 汉字日文编码、字库、以及第一个汉化文件
  9. 配置一个汉化 demo

从解码到编码

前面我们根据汇编的代码,还原了解码的过程,但是为了写出来编码的程序, 我们还需要进一步理解解码的过程,前面我们梳理过读取的机制:

  1. 文件从 0x18 处开始读取
  2. 读取分为两种形式:
    1. 从文件中直接读取
    2. 从文件中读取索引位置和个数,从字典的对应位置复制
  3. 所有输出的内容会更新到字典中

这个过程省略了两个细节,一是读取方式的确定,另一个是从字典复制的做法:

确定读取方式

程序想要确定是哪种读取模式,必须会写入一个标记,表示接下来是直接读,还是从字典拷, 由于只有两种选择,一个 bit 就可以表示,那么很容易推测程序会一次写入八个标记占满一个 byte。 事实上汇编代码也告诉我们了程序的做法:先读一个 byte 到低位,高位补上 0xff, 每读取一次,从低位判断是哪种读取方式,从高位判断是否需要再读一个标记。 读取完毕后变量右移一位,再判断是否需要读取标记和确定读取方式。

从字典复制的做法

如果是从字典复制,程序会固定读取两个 byte,这两个字节可以标记为:

dd Dc

其中 Ddd 表示要复制的文字在字典中的位置,D 为高位,dd 为低位。

c 表示要复制的个数,但是有一个偏移量 3,也就是说,当 c 为 0 时,表示要复制三个 byte。

从上面的描述我们可以得到两个信息:

  1. 字典的大小是 0x1000,因为索引值在 00xfff 之间
  2. 复制的长度最小为 3,最大为 18。

都是很字面的理解,但是对编码程序很有用。

编码的方法

我们可以理出来一个思路:

  1. 准备字典、缓存
  2. 检查当前位置的内容是否在字典中,返回在字典中的位置,以及个数,不可超过 18
  3. 如果个数小于 2,则直接写入缓存,更新字典
  4. 其他情况,写入双字节的索引和位置,按实际内容更新字典
  5. 记录写入方式及个数
  6. 写入不满 8 个时,回到 2
  7. 写入超过 8 个,将写入方式和缓存依次输出,然后回到 2

这样子我们基本就可以开始写代码了,同样我会忽略代码的部分,不过写代码很容易, 如何验证代码的正确性,这个不晓得各位有没有想过,我们如何确认我们的编码方式是正确的。

最容易想到的做法自然是跟 A01.CC 的原文作比较,但是估计这也是最先排除的做法, 因为解码我们可以还原,但是编码只是我们根据解码的过程理出来的思路, 事实上的实现细节可能会和我们有差别。比如很容易想到的一点,如果字典中出现了多个相同的内容, 那么我们要返回哪一个内容?

其实哪一个都可以,回答了这个问题,我们应该就有了验证的思路了:

  1. 先解码 A01.CC,记录解码后内容
  2. 编码第一步解开的内容
  3. 再解码第二步编码的内容,与 1 比较差异。

我们只要保证 1 和 3 完全相同,那么,虽然编码的方法可能不完美,但也得到了验证。

思路很清晰,但是除错很痛苦,省略两万字的内容,总结一下中间的问题:

  1. 首先保证解码代码的正确性:这是编码的根本,这里主要是边界的问题
  2. 字典索引有一个偏移量:解码的时候就注意到这个问题,没有想清楚这个偏移量有什么用,但是需要照做,不能省略。
  3. 在字典中查找时,不可超过当前字典索引位置:这个也是奇怪的一点,我是觉得字典在编码中应该是完全相同的,但有时会出现个别字节的复制错误,我没有仔细追究问题,凭经验限制了一下查找的范围,问题就消失了,后面如果再遇到再说吧

游戏中验证

我们之前提取了 A01.CC 中的全部文字,现在编码方法已经有了,那么进行中文翻译和替换前, 我们自然是先改一些字符串,看看我们的改动能不能体现到游戏中,比如,我们改一改游戏中的第一个象声词:

把重新编码后的 A01.CC 替换掉原本的文件,再看看效果:

大功告成!

休息一下

看来做个英文版的话,问题不大了,现在我们有了编码的工具,接下来,就是准备 GB 版的字库图,以及翻译的工作了。

我想到一个问题,翻译的时候我岂不是已经把剧本剧透一遍了,是不是应该等别人做好翻译喂我 ^_^