MPQ Archives
The StormLib library
When I began to deal with MPQ archives, I hardly played the game of Diablo and looked for a way how to extract a music from the game. In that time was possible to use the Storm.dll library for file extraction without any restrictions. Later, StarCraft was released and no one knew how to extract files from its archives. The DLL from Diablo didn'd work with StarCraft archives and no one was able to use Storm.dll from StarCraft.
Later on, Tom Amigo as the first on the world decrypted the MPQ file format and on his pages published a MPQ Editor, which worked without Storm.dll. He refused requests for sending sources with the reason of violating copyrights of Blizzard Entertainment. (Publishing MPQ editor was obviously not a problem). Opposing him, I started to dissassemble of Storm.dll, to obtain source codes of functions which work with MPQ archives. Later Tom Amigo released some parts of his sources, but the StormLib library was already written.
The StormLib library is a pack of modules, written in C++, which are able to read and also to write files from/to the MPQ archives. The original version was written for the Win32 platform, but Marko Friedemann has ported it also to Linux. It's free library, you can download it from the Downloads section. When you make any bug fixes or improvements, please, send me the fixed version.
When writing an own application, working with MPQ archves, it's necessary to decide, whether to use StormLib library or to link the Storm.dll. The following table briefly shows (dis)advantages of both libraries
| StormLib | Storm.dll | |
|---|---|---|
| The StormLib is very small and it's possible to link it to the application. It's not necessary to deploy any additional DLLs. | When using Storm.dll, you have to deploy Storm.dll with your app. | |
| During work on the last version, I made stress tests of StormLib. The code is very stable. | Stability of Storm.dll is good, when you don't try to use older versions to new archives. | |
| StormLib is compatible with all currently released Blizzard games (up to World of Warcraft - The Burning Crusade). | Since World of Warcraft, There is no standalone Storm.dll. | |
| StormLib can use both file names and file ordinal numbers to open them. | Storm.dll requires file name for opening an archived file. | |
|
Archive opening and creating File searching, opening, reading, adding, renaming, deleting. |
Archive opening File opening and reading. |
|
| StormLib is written in C++, so it's easy portable to other platforms. Currently, also Linux version exist. | Storm.dll is available only on Windows and on Linux with WINE. |
Function prototypes correspond with the prototypes used in the Storm.dll library. When it is necessary to rewrite a program to use StormLib instead of Storm.dll (and vice versa), it't usually not a great problem.
Function SFileSetLocale sets preferred language version of files that will be opened. From the moment of call, all atempts to open a file from archives will try the language version first. If required version will not be found, open function uses languale neutral function.
LCID WINAPI SFileSetLocale( LCID lcLocale // Required locale version );Parameters
Function always succeeds and returns lcLocale.
Function SFileGetLocale simply returns the currently selected locale ID.
LCID WINAPI SFileGetLocale();Parameters
Function always succeeds and returns the currently selected locale ID.
Function SFileOpenArchive opens a MPQ archive for reading.
BOOL WINAPI SFileOpenArchive( const char * szMpqName, // Archive file name DWORD dwPriority, // Archive priority DWORD dwFlags, // Open flags HANDLE * phMPQ // Pointer to result HANDLE );Parameters
When the function succeeds, it returns nonzero and phMPQ contains the handle of the opened archive. When the archive cannot be open, function returns FALSE. More informations about the error can be obtained from return value of GetLastError().
Function SFileCloseArchive closes an open archive.
BOOL WINAPI SFileOpenArchive( HANDLE hMPQ // Handle of open archive );Parameters
When the function succeeds, it returns nonzero and the arhive is closed. If fails, function returns FALSE. More informations about the error can be obtained from return value of GetLastError().
RemarksIf the archive was modified since it was open, the function implemented in StormLib also updates the MPQ header, hash table and block table.
Function SFileOpenFileEx opens a file from within an archive.
BOOL WINAPI SFileOpenFileEx( HANDLE hMPQ, // Handle of open archive const char * szFileName, // Name of a file to open. DWORD dwSearchScope, // Search scope for the file. HANDLE phFile // Pointer to result HANDLE. );Parameters
When the function succeeds, it returns nonzero and phFile contains handle of open file. If fails, function returns FALSE. More informations about the error can be obtained from return value of GetLastError().
Function SFileCloseFile closes an archived file.
BOOL WINAPI SFileCloseFile( HANDLE hFile // Handle of open file );Parameters
When the function succeeds, it returns nonzero and the file is closed. If fails, function returns FALSE. More informations about the error can be obtained from return value of GetLastError().
Function SFileGetFileSize returns the size of an open file.
DWORD WINAPI SFileGetFileSize( HANDLE hFile, // Handle of open file DWORD * pdwFileSizeHigh // For storing upper 32 bitsof the file size );Parameters
When the function succeeds, it returns the file size. If fails, return value is 0xFFFFFFFF. More informations about the error can be obtained from return value of GetLastError().
RemarksUpper 32 bits (the pdwFileSizeHigh parametr) isnot used by both Storm.dll and StormLib. When the pointer is valid, the function fills the variable with zero.
Function SFileSetFilePointer sets a new position of file pointer.
LONG WINAPI SFileSetFilePointer( HANDLE hFile, // Handle of open file LONG lFilePos // New file position LONG * plFilePosHigh // Upper 32 bits of file position DWORD dwMethod // File position on which the move is relative to );Parameters
When the function succeeds, it returns the new file position. If fails, it returns 0xFFFFFFFF. More informations about the error can be obtained from return value of GetLastError().
Function SFileReadFile reads data from an open archived file.
BOOL WINAPI SFileReadFile( HANDLE hFile, // Handle of open file void * pBuffer, // Buffer for storing read data DWORD dwToRead, // Number of bytes to read DWORD * pdwRead, // Number of bytes read LPOVERLAPPED lpOverlapped // Pointer to OVERLAPPED structure );Parameters
When the function succeeds, it returns nonzero. Buffer pointed by pBuffer contains the read bytes and pdwRead contains number of bytes read. If fails, function returns FALSE. More informations about the error can be obtained from return value of GetLastError().
RemarksThe following functions are implemented only in StormLib. Storm.dll does not support these functions.
Function SFileExtractFile extract complete file from an archive. It is a "helper", useful in nearly each application working with MPQs.
BOOL WINAPI SFileExtractFile( HANDLE hMpq, // Archive handle const char * szToExtract, // Name of file to extract const char * szExtracted // Name of local (disk) file );Parameters
When the function succeeds, it returns nonzero. In this case, the file has been successfully created and its content successfully written. If an error, function returns FALSE. More informations about the error can be obtained from return value of GetLastError().
Function SFileCreateArchiveEx opens or creates an archive file. It can also convert an existing file to MPQ archive. After the archive is open/created, it is accessible for reading and writing.
BOOL WINAPI SFileCreateArchiveEx( const char * szMpqName, // Archive file name DWORD dwCreationDisposition, // Open or create DWORD dwHashTableSize, // Size of hash table HANDLE * phMPQ // Pointer to result HANDLE );Parameters
| Value | When the archive does not exist | When an archive already exists |
|---|---|---|
| CREATE_NEW | Creates new MPQ archive | Returns error |
| CREATE_ALWAYS | Creates new MPQ archive | Existing file will be overwritten and function creates a new MPQ archive. |
| OPEN_EXISTING | Returns error | Opens the archive |
| OPEN_ALWAYS | Opens archive or converts the file to MPQ archive | Opens the archive |
When the function succeeds, it returns nonzero and phMPQ contains the handle of open archive. When the archive cannot be open/created, function returns FALSE. More informations about the error can be obtained from return value of GetLastError().
Function SFileAddFile adds a file into the archive. The archive must be open for writing by SFileCreateArchiveEx.
BOOL WINAPI SFileAddFile( HANDLE hMPQ, // Handle of open archive const char * szFileName, // Name of a file to add const char * szArchivedName, // Archived file name DWORD dwFlags // A way of file storing in the archive );Parameters
Function returns nonzero, when the file was successfully added into the archive. On error, functions return FALSE. More informations about the error could be returned by GetLastError().
RemarksIt is not possible to combine flags MPQ_FILE_COMPRESS_PKWARE and MPQ_FILE_COMPRESS_MULTI. If the function is called with both flags, returns error.
Locale ID of the file will be set to value recently set using SFileSetLocale.
Function SFileAddWave adds a WAVE file into the archive. The archive must be open for writing by SFileCreateArchiveEx. Unlike SFileAddFile, function optimizes the compression for pattern of WAVE files, doing better compression than if they were added using SFileAddFile.
BOOL WINAPI SFileAddWave( HANDLE hMPQ, // Handle of open archive const char * szFileName, // Name of a file to add const char * szArchivedName, // Archived file name DWORD dwFlags // A way of file storing in the archive DWORD dwQuality // Required quality );Parameters
Function returns nonzero, when the file was successfully added into the archive. On error, functions return FALSE. More informations about the error could be returned by GetLastError().
RemarksIt is not possible to combine flags MPQ_FILE_COMPRESS_PKWARE and MPQ_FILE_COMPRESS_MULTI. If the function is called with both flags, returns error.
Locale ID of the file will be set to value recently set using SFileSetLocale.
Function SFileRemoveFile removes a file from the archive. The archive must be open for writing using SFileCreateArchiveEx.
BOOL WINAPI SFileRemoveFile( HANDLE hMPQ, // Handle of open archive const char * szFileName // Name of file to remove );Parameters
Function returns nonzero, if the file was successfully removed from the archive. On error returns FALSE. More informations about the error returns the GetLastError() function.
Function SFileRenameFile renames a file within MPQ archive. The archive must be open for writing using SFileCreateArchiveEx.
BOOL WINAPI SFileRenameFile( HANDLE hMPQ, // Handle of open archive const char * szOldFileName, // Original name of the file const char * szNewFileName, // New name of the file );Parameters
Function returns nonzero, if the file was successfully renamed. On error returns FALSE. More informations about the error returns the GetLastError() function.
Functions SFileFindFirstFile and SFileFindFirstFileEx search files in MPQ archive. Because MPQ archives do not contain file names, these functions need file list for successfull search.
BOOL WINAPI SFileFindFirstFileEx( HANDLE hMPQ, // Handle of open archive const char * szMask, // Wildcard mask SFILE_FIND_DATA * lpFindFileData, // Struct with search result const char * szFileList, // File list name BOOL bCheckIfExist // Check if the file exists ); BOOL WINAPI SFileFindFirstFile( HANDLE hMPQ, // Handle of open archive const char * szMask, // Wildcard mask SFILE_FIND_DATA * lpFindFileData, // Struct with search result const char * szFileList // File list name );Parameters
struct SFILE_FIND_DATA
{
char cFileName[MAX_PATH]; // Full name of the found file
char * szPlainName; // Pointer to file part
LCID lcLocale; // Locale version
DWORD dwFileSize; // File size in bytes
DWORD dwFileFlags; // File flags (compressed or encrypted)
};
Return value
Function returns a search handle, if a match file was found in the archive. This search handle must be freed by calling SFileFindClose. On error returns NULL. More informations about the error returns the GetLastError() function.
RemarksIf there are more language versions of the same file, file search will return one entry for each language version as successfull search result.
An application should correctly test if a file was not returned multiple times. Depending on the given file list, the function may not return all files in the archive and also can return one file multiple times.
An application may not modify the structure during search.
Function SFileFindNextFile continues search began by SFileFindFirstFile(Ex).
BOOL WINAPI SFileFindNextFile( HANDLE hFind, // Search handle SFILE_FIND_DATA * lpFindFileData // Struct with search result );Parameters
Function returns nonzero, if a matching file was successfully found in the archive. On error returns FALSE. More informations about the error returns the GetLastError() function.
Function SFileFindClose ends the search started by SFileFindFirstFile(Ex). Must be used when the search is done.
BOOL WINAPI SFileFindClose( HANDLE hFind // Search handle );Parameters
Function returns nonzero, if a matching file was successfully found in the archive. On error returns FALSE. More informations about the error returns the GetLastError() function.