MPQ文件是暴雪公司的一种私有文档打包格式,广泛应用在其游戏产品中,如魔兽争霸系列、星际争霸系列等、暗黑破坏神系列以及魔兽世界等。MPQ包内保存了几乎全部的游戏资源,包括模型、纹理、材质、动画、音频、视频、单位属性等等。除了游戏资源之外,这些游戏的地图、战役以及一些游戏的进度存档也是都MPQ格式,只是扩展名用了其他的标识。MPQ文档兼具打包和压缩的功能,并且其压缩算法可以根据具体文件格式而有所不同。例如,根据StormLib源代码结构信息,MPQ包至少支持bzip2、huffman、pklib以及一种专门针对wav格式的压缩算法。
MPQ是一种针对读取优化的文档,与其他格式(如zip)相比,它最大的特点是没有树形结构,甚至连文件名都不保存。在存取时,它将文件的全路径名称做两次不同的哈希:h1 = hash1(pathname)、h2 = hash2(pathname),并将这两个哈希值作为索引信息。由于将路径文件名整体作为字符串计算哈希值,整个MPQ包构成平板模式,在物理上没有目录结构。在检索文件时,由于不需要逐级深入目录,MPQ包的读取较为简洁高效。
MPQ是一种古老的包格式,现有许多第三方工具可以读写这种格式,其中很多都公布了源代码,甚至形成了专门的读写库。我找到的各个MPQ相关库总结如下:
名称(标配工具) |
作者 |
备注 |
Storm.dll |
Blizzard |
Diablo I附带的Storm.dll可被其他工具调用。 |
StormLess MPQ Editor |
Tom Amigo |
提供VC6源代码。最新版本发布与2000年。 |
StormLib
(MPQEditor) |
Ladislav Zezula |
由Marko Friedemann将其移植到Linux平台。 |
Libmpq
(MPQ-tools) |
Maik Broemme |
似乎只支持Linux。 |
SFmpq.dll
(WinMPQ) |
ShadowFlare Software |
SFmpq.dll由VC++编写,WinMPQ应用由VB4编写。 |
MPQlib
(MPQMaster) |
Quixotic Yawl Studio |
没有找到源代码,不过从它暴露的语言扩展接口来看,似乎是Delphi写的。 |
Ladislav Zezula同志的StormLib成为使用毫无疑问是Windows平台下C++程序访问MPQ包的最佳选择。我将StormLib的使用心得以要点形式总结如下:
1. 所有的API函数、常量定义、结构体定义都可以在StormLib.h中查到,Zezula的主页上也有大部分函数的介绍,在此就不copy & paste了。
2. 读取文件所需函数:SFileOpenArchive()、SFileCloseArchive()分别为打开、关闭MPQ文件;SFileOpenFileEx()、SFileCloseFile()分别为打开、关闭MPQ包中的文件;SFileReadFile()读取实际数据,隐含解压缩过程。
3. 一个关于FilePointer的小陷阱:SFileSetFilePointer()函数用于设置文件指针,类似于C标准库中的fseek()函数,然而SFileGetFilePos()并不是返回文件指针,而是返回该文件在MPQ包中的物理位置。要得到当前文件指针位置,仍然需要SFileSetFilePointer()函数,将文件指针相对当前位置移动0,其返回值则为当前指针位置,如:
virtual size_t tell() const
{
return (size_t)SFileSetFilePointer(m_hFile, 0, NULL, FILE_CURRENT);
} |
4. StormLib没有提供feof()之类的调用,可以用当前文件指针与文件大小进行比较得到,如
virtual bool eof() const
{
DWORD pos = SFileSetFilePointer(m_hFile, 0, NULL, FILE_CURRENT);
DWORD size = SFileGetFileSize(m_hFile);
return pos>=size;
} |
5. StormLib还提供了创建MPQ包、写入文件、包内搜索文件等功能,本文从略。