http://www.zezula.net/en/mpq/mpqformat.html 文件格式
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包、写入文件、包内搜索文件等功能,本文从略。