龙之谷PAK资源文件格式说明及资源打包程序

实际上我没玩过龙之谷这游戏,这篇东西的出现其实是某人要我为这个资源文件写一个打包程序。网上只有资源文件提取工具,而没有资源文件打包程序。这种资源文件的格式在网上也有说明,但是我看那些说明太乱了,其重点似乎是在如何分析这个文件的结构,而不是描述这个文件的结构。既然我弄了这个打包工具出来,就顺便描述一下资源文件格式好了。

为了方便说明,我依照网上给出这个文件格式说明的那篇文章的约定,把被打包成资源文件的那些文件,称为虚拟文件。

另外,本文中出现的“偏移地址”,如果没有特殊说明,都是指从文件头开始计算的偏移地址。文件的虚拟路径指在资源文件中指定的虚拟文件的路径。

资源文件整体结构

资源文件由三个部份组成,首先是文件头,接着是虚拟文件内容,最后是虚拟文件信息。

文件头部分大小是固定的,为1024字节。在这1KB的长度中只有很少一部分被使用。

虚拟文件内容部分,保存着所有虚拟文件的内容。虚拟文件内容是经过压缩的,压缩的时候按照单个文件分别压缩。

文件信息部分包含所有虚拟文件的信息,包括原始文件大小,压缩后大小,文件的虚拟路径等。

文件头部分

文件头又分为4个部分,但只包含3个信息。先来看看其结构。

在西语言中为文件头定义结构体如下:

typedef struct pak_info_t {
char head[256];
unsigned char static1[4];  // 意义不明的固定字节
unsigned int file_num;  // 文件总数
unsigned int filelist_offset;  // 文件信息偏移地址
} pak_info_t;

文件头开头的256个字节是一个字符串,这个字符串的值是固定的,恒为:

"EyedentityGames Packing File 0.1"

程序会根据用户给出的目录(必须是相对路径),遍历目录下的文件,然后将文件信息保存到一个链表中。接着调用zlib一次
接下来的4个字节是一个意义不明的东西。可以认为这四个字节是一个长度为4的字符数组,也可以认为这是一个整型。其值也是固定的,第一个字节可以是0x0B或0x0A,后面三个字节恒为0x00.

再接下来的4个字节是一个无符号整型,记录资源文件中虚拟文件的总数。

最后的四个字节是一个指针,指向资源文件的虚拟文件信息部分的地址。由于虚拟文件信息紧跟着虚拟文件内容,而虚拟文件内容的长度是不定的,所以这个偏移地址也是不定的。故我们需要在写完了虚拟文件内容,确定了虚拟文件信息的偏移地址以后,才能回过头来填写这个值。

注意,前面说过,文件头的大小是固定的,长度是1024字节,而我们定义的这个文件头结构体只有268字节,还差756个字节才够1024字节。实际上,对这个地方可以有两种理解。一种理解是,文件头除了前面的268字节外,后面还有一块长度为756字节的空白区域。另一种理解是,文件头虽然只使用了268字节,但是文件内容必须从0x400位置开始。两种理解都是同样的描述,就看喜欢哪种了。

虚拟文件内容部分

虚拟文件内容从0x400位置开始。首先将每一个虚拟文件的原始文件压缩,然后将压缩后的内容从0x400开始依次写入文件。每个文件内容之间没有空隙,要紧凑地存放。图示如下:

文件的内容是按照单个文件进行压缩的。使用的压缩方法是zlib,压缩级别为1,也就是最快压缩。

文件信息部分

文件信息部分的总体结构和虚拟文件内容部分相似,每个文件都有一个固定大小的文件描述块,长度为316字节,图示如下:

接着是每个文件描述块的内容:

在西语言中定义结构体为:

typedef struct pak_file_info_t {
char path[256];
unsigned int zip_size;  // 原始文件大小
unsigned int size;  // 压缩后的文件大小
unsigned int zip_size1;  // 原始文件大小,和size一样
unsigned int offset;  // 文件内容偏移地址
char empty[44];  //填充用
} pak_file_info_t;

开头的256字节是虚拟文件的虚拟路径。虚拟路径似乎必须以“\”开头,而且不能使用“/”。

接下来的4个字节是一个无符号整型,是虚拟文件对应的原始文件的大小。

再接下来的4个字节是一个无符号整型,是虚拟文件对应的原始文件内容压缩后的大小。

再接着的4个字节是一个无符号整型,和第二个成员一样,也是原始文件内容的大小。

接着的4个字节是一个指针,指向这个虚拟文件的内容的偏移地址。

最后的44个字节是没有意义的,或者说可能是保留用的,总之留出空间即可,其他的不用理会。

这就是一个虚拟文件的描述块,每个虚拟文件的描述块依次紧凑存放。用西语言来描述可以是这个样子的:

pak_file_info_t fileinfo[n];  //共有n个虚拟文件
/* 在这里设置这些虚拟文件的信息 */
fwrite(fileinfo, sizeof(pak_file_info_t), n, fp);

打包程序

程序会根据用户给出的目录(必须是相对路径),遍历目录下的文件,然后将文件信息保存到一个链表中。接着调用zlib依次压缩和保存文件,记录文件的偏移地址和压缩后的大小。完成以后就继续写入文件信息块。最后回头写入文件头。

只有源码,在Linux下编译通过。

pakpack.c

文件结构图

本文发表于 我的东西,并添加了 , , , , 标记。保存永久链接到书签。

发表评论

电子邮件地址不会被公开。